CoRIM verifier#

Note: The CoRIM verifier is experimental. It is the direction for NVIDIA’s attestation-verification workflow, but its behavior, interfaces, supported evidence, and EAR output may change.

The CoRIM verifier is the SDK’s parallel path to the legacy TCG RIM-based verifier. It appraises a Conceptual Message Wrapper (CMW) against CoRIM reference manifests and returns an Entity Attestation Result (EAR). It follows CoRIM draft 11 and implements a subset of that draft. See Supported CoRIM CDDL for the constructs that are appraised, parsed, ignored, or rejected. The feature first shipped in NVIDIA Attestation SDK 2.0.0.

The legacy path continues to use the legacy TCG RIM workflow and returns a claims collection with a detached EAT.

CMW evidence --> local CoRIM verifier --> EAR JSON --> relying-party policy
                                      \
                                       +--> signed EAR JWT --> remote relying party

Standards direction and scope#

This path uses IETF RATS concepts at its integration boundary: CMW carries evidence, CoRIM supplies reference values, ConciseEvidence can carry device evidence, and EAR carries the appraisal result. The current implementation accepts JSON CMW input; CMW CBOR is reserved but not implemented. GPU and SPDM input media types, EAR profiles, and ear_nvidia_* extension claims are NVIDIA-specific.

Live GPU evidence collection through NVML does not yet support current-generation devices because their CoRIMs are not published. Support follows once those CoRIMs are available.

Processing flow#

An Environment-Claim Tuple (ECT) ties measurements to an environment, and the Appraisal Claims Set (ACS) holds those ECTs during appraisal. The verifier normalizes evidence, certificate extensions, CoEV, and CoRIM reference triples into ECTs before comparing them.

The verifier runs these stages in order:

  1. Read the JSON CMW collection: evidence, nonce, certificates, appraisal settings, and hints.

  2. Authenticate each evidence item: signature, certificate chain, nonce, and OCSP when revocation checking is on.

  3. Convert the authenticated evidence into evidence ECTs and read its rim-locators. DiceTcbInfo extensions in the validated certificate chain contribute ECTs, if present.

  4. Resolve each locator against the URL policy and rewrites, then fetch the signed CoRIM from the CoRIM store or RIM service.

  5. Convert those documents into reference ECTs and dependency triples.

  6. Compare evidence ECTs against reference ECTs and evaluate the dependency graph.

  7. Emit the attestation result.

Dependency triples connect a domain environment to its trustee environments. The verifier evaluates trustees first, marks a domain failed when one of its trustees fails, and rejects dependency cycles.

Evidence inputs#

The verifier accepts these evidence forms:

Source

Evidence mapping

RIM discovery

EAT

TCG DICE Concise Evidence from the measurements claim becomes evidence ECTs.

rim-locators come from the EAT claims.

SPDM 1.1 with embedded CoEV

The verifier authenticates the SPDM measurement transcript and turns the embedded TCG DICE Concise Evidence into ECTs.

rim-locators come from the SPDM table of contents.

SPDM 1.1 with fetched CoEV

A RIM service can return CoEV alongside the CoRIM. The verifier checks the CoEV signature and turns its measurements into ECTs.

Locator is constructed with attester-specific code.

X.509 DiceTcbInfo

DiceTcbInfo and MultiDiceTcbInfo extensions in the validated evidence certificate chain become evidence ECTs.

Certificate extensions supply no locator.

Authentication runs before CoRIM comparison. The verifier checks the evidence signature and the certificate chain, checks a per-item nonce when one is supplied, and runs OCSP checks when revocation checking is on.

DiceTcbInfo conversion#

Certificate-chain conversion follows draft-ietf-rats-evidence-trans-02 §4.2. type, vendor, model, layer, and index populate the environment class map, a DiceUeid extension populates the instance identifier, and version, svn, vendorInfo, fwid, and the operational flags populate the measurement values. MultiDiceTcbInfo produces one ECT for each contained DiceTcbInfo entry.

The implementation departs from §4.2 as follows:

Draft rule

Implementation

Step 3.iii copies every FWID in the list.

Only the first FWID becomes a digest. The rest are logged and dropped.

Step 3.iii copies integrityRegisters.

Dropped. The verifier does not support integrity registers at this time.

Step 4 sets ECT.authority from the certificate signer.

Not set. Authority tracking is not implemented.

Step 3.iv reads recovery and debug as inverted.

Read in positive polarity, following TCG DICE Attestation Architecture v1.2 §A.1. The draft text contradicts the bit names.

Step 3.iv reads a flag bit only where the mask sets it.

A flags value with no flagsMask is treated as a mask of all ones.

Step 3.iii copies FWID.hashAlg into digests.digest.alg.

The OID is translated to a Named Information identifier. See below.

The draft sets no width limit on layer, index, or svn.

Each must fit an unsigned 32-bit integer.

Step 3.ii takes the UEID from the certificate’s DiceUeid extension.

Same, and a certificate without that extension falls back to a chain-level UEID.

FWID.hashAlg cannot be copied literally. DICE carries a DER object identifier, while CoRIM defines digest.alg as int / text, so every implementation has to choose one of those two forms. This verifier emits the integer: the NIST OIDs for SHA-256, SHA-384, and SHA-512 become Named Information hash identifiers 1, 7, and 8. Any other hash OID fails the conversion.

SPDM and Concise Evidence conversion#

SPDM and CoEV evidence follows TCG DICE Concise Evidence Binding for SPDM v1.1. CoEV parsing is permissive: an unsupported field is logged and skipped.

An SPDM 1.1 transcript is the GET_MEASUREMENTS request followed by the MEASUREMENTS response. Its trailing 96 bytes are an ECDSA P-384 signature over the rest, checked against the companion certificate chain. SHA-384 and P-384 are assumed for every chain. The request nonce becomes eat_nonce, and freshness is compared only when the caller supplies a per-item nonce. The measurement hash algorithm is absent from the transcript, so the verifier infers it from the digest length and defaults to SHA-384.

The table of contents is a #6.570-tagged value in the measurement manifest at index 0xFD. A transcript without one is legitimate.

CoEV item

Status

Implemented behavior

spdm-toc.tagged-evidence key 0

Appraised

One to eight tagged concise evidence documents.

spdm-toc.rim-locators key 1

Appraised

Up to eight locator maps. Their URIs join the RIM locator list.

ev-triples.evidence-triples key 0

Appraised

One to 100 records, each with one environment and one to 50 measurements. Each record becomes one evidence ECT.

ev-triples keys 1 through 5

Ignored

Identity, dependency, membership, CoSWID, and attest-key triples are logged and skipped. A map carrying no triple at all fails the evidence item.

concise-evidence.evidence-id key 1

Parsed

A tagged UUID, retained and reported.

profile on either map

Parsed

Retained. Comparison rules do not vary by profile.

Extension keys

Ignored

Unknown keys are tolerated. A schema-defined key that lands in the extension array is reported as malformed.

A measurement can carry spdm-indirect (§7.1) in place of its value. Each index names an SPDM measurement block whose DMTF value type selects the target field:

DMTF value type

Target

0x00 through 0x7F

A digest under the derived hash algorithm.

0x86

version, which must be ASCII.

0x87

svn, little-endian, which must fit an unsigned 32-bit integer.

Any other value

raw-value. Bit 7 marks a raw bit stream, so device mode 0x85 and the rest of that range land here.

RIM discovery and validation#

The verifier uses RIM locations in this order:

  1. rim-locators extracted from primary evidence.

  2. A platform-specific synthesized locator when the required evidence facts and hints.fwversion are available.

  3. One or more fallback locators configured on the verifier.

The verifier checks each locator against its URL policy before retrieval. A configured URL rewrite redirects an allowed locator to a mirror or local test file, and the original locator must still pass the policy.

CoRIM signature verification is on by default: the verifier checks the COSE Sign1 signature against the configured CoRIM root and records the signing certificate status. Revocation checks are on by default as well. Disabling signature verification accepts unsigned CoRIM payloads. Use this mode only for testing. A CoRIM that fails to fetch, verify, or parse leaves its evidence item unaffirmed.

Supported CoRIM CDDL#

The tables below separate data that affects appraisal from data the verifier only parses or ignores.

Status values:

  • Appraised: the value affects reference matching or dependency evaluation.

  • Verified: the value takes part in a cryptographic or freshness check.

  • Parsed: the verifier keeps or reports the value, and it does not affect the appraisal decision.

  • Ignored: the verifier accepts the value and discards it.

  • Rejected: the verifier returns a schema or unsupported-feature error.

Support for additional CoRIM constructs will be added in future releases based on need.

CoRIM envelope and map#

CDDL item

Status

Implemented behavior

signed-corim COSE_Sign1 envelope

Verified

Enabled by default. The payload must decode as a tagged unsigned CoRIM map.

tagged-unsigned-corim-map tag 501

Parsed

Required around the unsigned CoRIM payload.

corim-map.id

Parsed

Text and 16-byte UUID identifiers are accepted and reported in the verifier claims.

corim-map.tags

Appraised

One to 25 tags are accepted. Per-tag behavior is listed below.

corim-map.dependent-rims

Rejected

Chained dependent CoRIM processing is not implemented.

corim-map.profile

Parsed

URI and tagged OID values are accepted. The local verifier applies generic comparison rules to every profile.

corim-map.rim-validity

Parsed

Integer not-before and not-after times are accepted and retained. Floating-point times are rejected. Appraisal does not enforce the validity window.

corim-map.entities

Parsed

Entity name, optional registration identifier, and roles are retained. They do not affect comparison.

corim-map extension entries

Rejected

The CDDL decoder accepts extension keys, but wrapper construction rejects them as unsupported.

Tag types and CoMID fields#

CDDL item

Status

Implemented behavior

concise-mid-tag tag 506

Appraised

Reference and dependency triples are extracted.

concise-swid-tag tag 505

Ignored

The tag is accepted but contributes no ECTs.

concise-tl-tag tag 508

Ignored

The tag is accepted but contributes no ECTs.

concise-mid-tag.language

Parsed

Retained as tag metadata.

concise-mid-tag.tag-identity.tag-id

Parsed

Text and UUID identifiers are accepted.

concise-mid-tag.tag-identity.tag-version

Ignored

Accepted by the schema but not used by the verifier model.

concise-mid-tag.entities

Parsed

Entity name, optional registration identifier, and roles are retained.

concise-mid-tag.linked-tags

Rejected

Linked-tag traversal is not implemented.

concise-mid-tag.triples

Appraised

Supported triple categories are listed below.

concise-mid-tag extension entries

Rejected

The CDDL decoder accepts extension keys, but wrapper construction rejects them as unsupported.

Triple categories#

Triple CDDL item

Status

Implemented behavior

reference-triples key 0

Appraised

Each reference ECT supplies an environment and one to 50 reference measurements.

endorsed-triples key 1

Ignored

Accepted but does not affect appraisal.

identity-triples key 2

Rejected

Identity processing is not implemented.

attest-key-triples key 3

Rejected

Attestation-key processing is not implemented.

dependency-triples key 4

Appraised

Each domain environment can name one to 64 trustee environments.

membership-triples key 5

Rejected

Membership processing is not implemented.

coswid-triples key 6

Rejected

CoSWID triple processing is not implemented.

conditional-endorsement-series-triples key 8

Ignored

Accepted but does not affect appraisal.

conditional-endorsement-triples key 10

Ignored

Accepted but does not affect appraisal.

A CoRIM containing only ignored tag or triple types produces no reference ECTs and cannot affirm evidence.

Environment maps#

Reference environment fields constrain the evidence fields they name. A field the reference omits matches anything, and extra evidence fields never cause a mismatch.

All properties of the environment-map available as of draft 11 are supported.

Measurement maps and values#

measurement-map.mkey is optional and can be a tagged OID, tagged UUID, unsigned integer, or text. Each measurement key must be unique within an ECT. Duplicate keys in a reference or evidence ECT are ambiguous and rejected. This limitation may be relaxed in a future release.

CDDL item

Status

Implemented behavior

measurement-map.mval.version key 0

Appraised

The version value and version scheme must both match. Schemes 1 through 5, semver 16384, and arbitrary integer or text scheme identifiers are accepted.

measurement-map.mval.svn key 1

Appraised

Exact SVN and minimum-SVN tag 553 are supported. An evidence SVN must be a concrete value.

measurement-map.mval.digests key 2

Appraised

Integer and text algorithm identifiers are both accepted. Duplicate algorithms are rejected.

measurement-map.mval.flags key 3

Appraised

Configured, secure, recovery, debug, replay-protected, integrity-protected, runtime-meas, immutable, tcb, and confidentiality-protected are supported. Only flags present in the reference constrain evidence.

measurement-map.mval.raw-value key 4

Appraised

Tagged byte strings are compared exactly. Tagged masked values compare only bits selected by the mask. Value and mask lengths must match.

measurement-map.mval.raw-value-mask-DEPRECATED key 5

Rejected

The deprecated separate mask field is not supported.

measurement-map.mval.mac-addr key 6

Rejected

The comparison model has no MAC-address representation.

measurement-map.mval.ip-addr key 7

Rejected

The comparison model has no IP-address representation.

measurement-map.mval.serial-number key 8

Rejected

The comparison model has no serial-number representation.

measurement-map.mval.ueid key 9

Rejected

The comparison model has no UEID measurement representation.

measurement-map.mval.uuid key 10

Rejected

The comparison model has no UUID measurement representation.

measurement-map.mval.name key 11

Appraised

Exact text comparison.

measurement-map.mval.spdm-indirect key 12

Rejected

Rejected in CoRIM. Accepted only when converting CoEV evidence, which also needs the referenced SPDM measurement record.

measurement-map.mval.cryptokeys key 13

Rejected

Cryptographic-key claim comparison is not implemented.

measurement-map.mval.integrity-registers key 14

Rejected

Integrity-register comparison is not implemented.

measurement-map.mval.int-range key 15

Appraised

A reference can contain an exact integer or a tagged inclusive range. A null lower or upper bound is open-ended. Evidence must contain a concrete integer.

measurement-map.authorized-by

Rejected

Authority tracking is not implemented.

measurement-values-map extension entries

Rejected

Arbitrary extension keys are absent from the generated CDDL and fail decoding.

Appraisal behavior#

Root environment OID#

The verifier identifies a root environment from environment.class.class-id. The class identifier must be a tagged OID under the NVIDIA CoRIM arc:

1.3.6.1.4.1.5703.1300.<path>.1.<leaf>

<path> holds zero or more arcs, the penultimate arc must be 1, and <leaf> can be any arc.

After fallback handling, evidence must contain exactly one recognized root. A compatible reference environment with a root OID anchors the appraisal scope. The scope contains the root and every trustee reachable through dependency triples. Environments outside the appraisal scope do not contribute to the final attestation results.

The root also names the purpose of the appraisal. A purpose is a measurement keyed by the text purpose whose name value labels the device state that the root describes, so one device can have several roots for several operating modes. This allows different operating modes to describe different TCBs through domain-dependency triples.

When neither evidence nor reference ECTs contain a recognized root, the verifier injects the synthetic root 1.3.6.1.4.1.5703.1300.999.1.1 with a purpose value of DEFAULT. The synthetic root depends on every reference environment. This fallback does not apply when only one side lacks a root.

ACS processing#

The verifier implements this subset of ACS processing:

Check

Behavior

Environment identity

Reference fields constrain evidence fields. Extra evidence identity fields are ignored. Duplicate evidence environments are rejected.

Reference measurements

Every reference measurement key must exist and match in the selected evidence ECT. Extra evidence measurements are permitted.

Alternative configurations

Multiple reference ECTs for one environment are treated as alternatives. Any matching alternative can corroborate the environment.

ECT merging

Compatible or disjoint reference ECTs for one environment would need merging, which is not implemented, so the verifier rejects them.

Root selection

The root and its transitive trustees define the in-scope outcomes. Multiple recognized evidence roots are rejected.

Dependencies

The domain dependency graph is evaluated in reverse topological order. Cycles and dependencies without a corresponding reference environment are rejected. Trustee failure propagates to the dependent domain.

Unmatched evidence

An evidence environment with no applicable reference is reported as unmatched.

Purpose

Checked on the root as described under Root environment OID.

Authority

Authority tracking is not yet implemented.

CMW input#

The verifier consumes a JSON Conceptual Message Wrapper (CMW) collection. Each record is a two-element array containing a media type and a base64url-encoded payload.

cmw = {
  "__cmwc_t": "tag:nvidia.com,2026:verifier-input/profiles/base/pre-1.0.0",
  ? "nonce": nonce-record,
  ? "appraisal-settings": json-record,
  + tstr => evidence-item,
}

evidence-item = {
  "__cmwc_t": "tag:nvidia.com,2026:evidence-item/v1",
  "evidence": evidence-record,
  ? "nonce": nonce-record,
  ? "certificate": certificate-record,
  ? "hints": json-record,
  * tstr => any,
}

evidence-record = [
  media-type: tstr,
  payload: base64url,
]

nonce-record = [
  media-type: "application/octet-stream",
  nonce: base64url,
]

certificate-record = [
  media-type: "application/vnd.nvidia.pem-cert-chain",
  certificate-chain: base64url,
]

json-record = [
  media-type: "application/json",
  json: base64url,
]

base64url = tstr

A collection must contain at least one evidence item. Every collection-level key other than __cmwc_t, nonce, and appraisal-settings labels an evidence item, for example gpu0. Those three reserved names cannot label evidence. The evidence media type selects the handler, and an unsupported media type fails that item. Evidence formats that do not carry their own certificate chain need the certificate record.

After base64url decoding, the recognized JSON settings and hints have this shape:

appraisal-settings-json = {
  ? "ars": {
    ? "digest-algos": [* (int / tstr)],
    * tstr => any,
  },
  * tstr => any,
}

hints-json = {
  ? "fwversion": tstr,
  * tstr => any,
}

ars.digest-algos selects the input digests that the attestation result carries. Name SHA-256, SHA-384, or SHA-512 by Named Information identifier or algorithm name.

Output CDDL#

EAR format reference is the source of truth for the claims currently emitted by the verifier. Custom implementations should ensure that the EAR profile is understood before applying policy.

ear = {
  "eat_profile": "tag:nvidia.com,2026:ear/profiles/composite/generic/pre-1.0.0",
  "iat": int,
  "nbf": int,
  "exp": int,
  ? "iss": tstr,
  ? "jti": tstr,
  "ear_verifier_id": verifier-id,
  ? "ear_nvidia_inputs": input-summary,
  ? "eat_nonce": base64url,
  "ear_status": ear-status,
  "submods": { * tstr => ear-submodule },
}

ear-status = "affirming" / "contraindicated"

verifier-id = {
  "developer": "https://developer.nvidia.com/attestation",
  "build": tstr,
}

input-summary = {
  "digests": [+ input-digest],
}

input-digest = {
  "alg": "sha-256" / "sha-384" / "sha-512",
  "val": base64url,
}

ear-submodule = {
  "eat_profile": "tag:nvidia.com,2026-05:ear/profiles/gpu/1.0.0",
  ? "evidence_profile": tstr,
  "ear_status": ear-status,
  ? "ear_nvidia_purpose": tstr,
  ? "eat_nonce": base64url,
  "ear_verifier_claims": verifier-claims,
  ? "ear_attester_claims": { + tstr => tstr },
  ? "ear_nvidia_error_details": [+ error-detail],
}

verifier-claims = {
  "ear_nvidia_evidence": evidence-result,
  ? "ear_nvidia_rims": [+ rim-result],
  ? "ear_nvidia_evidence_rim_cmp": comparison-result,
}

evidence-result = {
  "signature_verified": bool,
  ? "parsed": bool,
  ? "nonce_match": bool,
  ? "cert_chain": [+ certificate-result],
  ? "akpub": tstr,
}

rim-result = {
  "fetched": bool,
  "locator": tstr,
  "parsed": bool,
  ? "signature_verified": bool,
  ? "id": tstr,
  ? "cert_chain": [+ certificate-result],
  ? "error": error-detail,
}

certificate-result = {
  "expired": bool,
  "expiration_date": tstr,
  "cert_check_status": tstr,
  ? "ocsp_response_status": bool,
  ? "ocsp_response_produced_at": tstr,
  ? "ocsp_crl_status": tstr,
  ? "revocation_reason": tstr,
  ? "ocsp_response_revoked_at": tstr,
  ? "ocsp_nonce_matches": bool,
  ? "ocsp_crl_response_expired": bool,
  ? "ocsp_crl_response_expiration_date": tstr,
}

comparison-result = {
  "matched_env": [* environment],
  "mismatched_env": [* environment],
  "unmatched_env": [* environment],
}

environment = {
  ? "class": {
    ? "class_id": tstr,
    ? "vendor": tstr,
    ? "model": tstr,
    ? "layer": uint,
    ? "index": uint,
  },
  ? "instance": tstr,
  ? "group": tstr,
}

error-detail = {
  "code": int,
  "message": tstr,
  ? "details": tstr,
  ? "related_envs": [+ environment],
}

base64url = tstr

The verifier returns the ear object as JSON and as the claim set of an Entity Attestation Result (EAR) JWT. The JWT protected header and signature fall outside this CDDL. An optional member is omitted when its processing stage produces no value.

Result semantics#

Each evidence label becomes a submodule in the result. A submodule is affirming only when evidence authentication succeeds, no error diagnostic is present, a compatible reference root anchors the single evidence root, and the root plus every environment reachable through its dependency graph passes. Outcomes outside the rooted subtree do not change the status. Every other completed appraisal is contraindicated. The top-level status is the least favorable submodule status.

The result includes:

  • evidence signature and certificate-chain information;

  • every requested CoRIM locator and its fetch, parse, signature, and certificate status;

  • matched, mismatched, and unmatched environments;

  • whether ECTs derived from certificate-chain DiceTcbInfo matched;

  • attester claims extracted from claims-from-evidence ECTs;

  • structured verifier errors and comparison diagnostics;

  • optional input digests selected by ars.digest-algos.

Evidence claims passed to the relying party#

Only ECTs with a claims-from-evidence environment OID produce dynamic attester claims. Accepted top-level EAT fields stay parser inputs and never become claims. A value reaches ear_attester_claims only when a claims-from-evidence ECT encodes it. The certificate-derived hwmodel fallback below is the one exception. The OID must be under the NVIDIA CoRIM arc, with 2 as its penultimate arc:

1.3.6.1.4.1.5703.1300.<path>.2.<leaf>

Each claims-from-evidence ECT must contain exactly one measurement. Its measurement key must be text and becomes the claim name in the EAR. Exactly one of these measurement values supplies the claim value:

Measurement value

EAR value

name

The text value.

raw-value

The bytes interpreted as UTF-8 text.

version

The version value without its scheme.

Claim names and values are strings. Invalid UTF-8, a duplicate claim name, or an invalid claims-from-evidence ECT fails appraisal.

A claim is corroborated when a compatible reference ECT has a passing comparison. A claim with no compatible reference or a failing comparison is uncorroborated. Forwarded claim values appear in submods.<label>.ear_attester_claims. Environment comparison results appear separately in ear_verifier_claims.ear_nvidia_evidence_rim_cmp.

Claim names come from the measurement keys rather than a fixed list. When no evidence claim is named hwmodel, the verifier adds one from the validated end-entity certificate’s DMTF otherName product field. An evidence-supplied hwmodel takes precedence. The corroborated root purpose is emitted separately as ear_nvidia_purpose.

AR4SI trustworthiness vectors are not supported. Appraisal policy identifiers are not emitted.

Local appraisal workflow#

Initialize the SDK once, collect evidence with a nonce, and build a CMW:

nvat_nonce_t nonce = NULL;
nvat_gpu_evidence_source_t source = NULL;
nvat_gpu_evidence_t *evidence = NULL;
size_t evidence_count = 0;
nvat_cmw_collection_t cmw = NULL;
nvat_str_t serialized_cmw = NULL;

nvat_rc_t rc = nvat_nonce_create(&nonce, 32);
if (rc == NVAT_RC_OK)
    rc = nvat_gpu_evidence_source_nvml_create(&source);
if (rc == NVAT_RC_OK)
    rc = nvat_gpu_evidence_collect(source, nonce, &evidence, &evidence_count);
if (rc == NVAT_RC_OK)
    rc = nvat_cmw_collection_create_from_gpu_evidence(
        &cmw, evidence, evidence_count, nonce);
if (rc == NVAT_RC_OK)
    rc = nvat_cmw_collection_serialize(
        cmw, NVAT_CMW_FORMAT_JSON, &serialized_cmw);

For an existing SPDM measurement transcript and PEM certificate chain, use nvat_cmw_collection_create_from_spdm_transcript() instead. Pass the expected nonce when the application requires freshness checking.

Create a CoRIM store and an AIA OCSP client before creating the verifier:

nvat_corim_store_t store = NULL;
nvat_ocsp_client_t aia_ocsp = NULL;
nvat_local_corim_verifier_t verifier = NULL;

rc = nvat_corim_store_create(&store, service_key, http_options);
if (rc == NVAT_RC_OK)
    rc = nvat_ocsp_client_create_aia(
        &aia_ocsp, NULL, service_key, http_options, NULL, NULL, 0);
if (rc == NVAT_RC_OK)
    rc = nvat_local_corim_verifier_create(&verifier, &store, aia_ocsp);

The verifier takes ownership of store on success. CoRIM signature and certificate revocation verification are enabled by default. URL rewrites and additional allowed prefixes must be configured on the store before it is passed to the verifier. Use the signature and revocation toggles only with controlled test artifacts. See Configure the CoRIM verifier for store caching, source configuration, fallbacks, input digests, and HTTP/TLS settings.

Create EAR signing options and appraise the serialized CMW:

nvat_ear_signing_options_t signing = NULL;
nvat_str_t ear_jwt = NULL;
nvat_str_t ear_json = NULL;
char *cmw_data = NULL;
size_t cmw_len = 0;

rc = nvat_detached_eat_options_create(
    &signing, signing_key_pem, "https://verifier.example.com", "key-1");
if (rc == NVAT_RC_OK)
    rc = nvat_str_get_data(serialized_cmw, &cmw_data);
if (rc == NVAT_RC_OK)
    rc = nvat_str_length(serialized_cmw, &cmw_len);
if (rc == NVAT_RC_OK)
    rc = nvat_local_corim_verifier_verify_cmw(
        verifier, (const uint8_t *)cmw_data, cmw_len, NVAT_CMW_FORMAT_JSON,
        signing, &ear_jwt, &ear_json);

Sign production EARs with a signing key. The issuer should be the HTTPS verifier base URL that the relying party will select, and kid must identify the corresponding JWKS key. Unsigned alg=none EARs are for tests only.

Relying-party policy#

For a locally produced EAR, apply Rego directly to the returned JSON. The complete EAR JSON object is supplied to the policy as input. The policy must declare package policy and define nv_match as a boolean decision. The SDK evaluates that rule at data.policy.nv_match:

nvat_relying_party_policy_t policy = NULL;
char *json = NULL;

rc = nvat_relying_party_policy_create_rego_from_str(&policy, policy_text);
if (rc == NVAT_RC_OK)
    rc = nvat_str_get_data(ear_json, &json);
if (rc == NVAT_RC_OK)
    rc = nvat_apply_relying_party_policy_to_ear(policy, json);

NVAT_RC_RP_POLICY_MISMATCH means the policy rejected the appraisal. It does not mean that EAR generation or signature verification failed.

Signed EARs at a remote relying party#

EAR JSON received across a process or network boundary is untrusted. Send the compact JWT and authenticate it before evaluating policy:

nvat_str_t verified_ear_json = NULL;
char *json = NULL;

rc = nvat_verify_ear(
    signed_ear_jwt, verifier_base_url, service_key, expected_nonce,
    http_options, NULL /* jwt_validation_options */, &verified_ear_json);
if (rc == NVAT_RC_OK)
    rc = nvat_str_get_data(verified_ear_json, &json);
if (rc == NVAT_RC_OK)
    rc = nvat_apply_relying_party_policy_to_ear(policy, json);

nvat_str_free(&verified_ear_json);

The relying party selects a non-empty HTTPS verifier URL. The SDK obtains its JWKS from <verifier_base_url>/.well-known/jwks.json, verifies the JWT signature and issuer, and returns EAR JSON only after authentication succeeds. It does not validate EAR schema or decide whether the appraisal is acceptable.

service_key is optional. It is sent only to HTTPS nvidia.com hosts and subdomains, and is suppressed for other verifier URLs. If expected_nonce is provided, the signed eat_nonce must match it. The returned EAR string is NULL on every failure and must be released with nvat_str_free() on success.

CLI equivalent#

The command-line version of this flow is documented in the CoRIM workflow: collect-evidence-v2, attest-v2, then verify-token --token-type ear at a relying-party boundary.