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.
For store, network, and verifier settings, see Configure the CoRIM verifier. The shape of the result is described in the EAR format reference.
Local appraisal#
Collect GPU evidence with a nonce, wrap it in a CMW collection, configure the store and OCSP client, then create the verifier:
use nv_attestation_sdk::{
AiaOptions, CmwCollection, CmwFormat, CorimStore, EarSigningOptions,
GpuEvidenceSource, LocalCorimVerifier, Nonce, NvatSdk, OcspClient,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let _sdk = NvatSdk::init_default()?;
let nonce = Nonce::generate(32)?;
let evidence = GpuEvidenceSource::from_nvml()?.collect(&nonce)?;
let cmw = CmwCollection::from_gpu_evidence(&evidence, &nonce)?;
let mut store = CorimStore::new(None, None)?;
store.enable_in_memory_cache(16 * 1024 * 1024, 3600)?;
let ocsp_client = OcspClient::create_aia(AiaOptions::default())?;
let verifier = LocalCorimVerifier::new(store, Some(&ocsp_client))?;
let signing = EarSigningOptions::new(
&std::fs::read_to_string("/etc/nvat/ear-signing-key.pem")?,
"https://verifier.example.com",
"ear-signing-key-1",
)?;
let ear = verifier.verify_cmw_collection(&cmw, CmwFormat::Json, Some(&signing))?;
println!("{}", ear.json);
println!("{}", ear.jwt);
Ok(())
}
The store is consumed by LocalCorimVerifier::new, so configure its cache,
allowed locator prefixes, and rewrites before creating the verifier. Use
CmwFormat::Json; CBOR input is reserved but not implemented.
EAR results and policy#
EarResult::json and EarResult::jwt represent the same appraisal. Supplying
EarSigningOptions signs the JWT; omitting it produces an unsigned JWT for
test use only.
A successful Rust call means the CMW was processed. It does not by itself mean
that an application accepts the appraisal. Inspect ear_status and the
submodule results, then evaluate the EAR JSON against the application’s policy.
Policies that depend on an intended attestation context must also check
ear_nvidia_purpose when it is present.
Use RelyingPartyPolicy::apply_to_ear_json to evaluate an EAR JSON object:
use nv_attestation_sdk::RelyingPartyPolicy;
let policy = RelyingPartyPolicy::from_rego(rego_source)?;
policy.apply_to_ear_json(&ear.json)?;
This evaluates the policy only; it does not alter the EAR or its ear_status.
For a signed EAR received from another process or service, authenticate it first, then apply the policy to the returned JSON:
use nv_attestation_sdk::{verify_ear, RelyingPartyPolicy};
let ear_json = verify_ear(&ear_jwt, "https://verifier.example.com")?;
let policy = RelyingPartyPolicy::from_rego(rego_source)?;
policy.apply_to_ear_json(&ear_json)?;
verify_ear fetches the verifier’s JWKS and validates the JWT before returning
JSON. Use verify_ear_with_options when the relying party needs an expected
nonce, custom HTTP/TLS settings, JWT clock-skew settings, or a service key for
an NVIDIA-hosted JWKS endpoint.
Thread safety#
LocalCorimVerifier is Send and Sync; a service can share one configured
verifier across worker threads. CorimStore is Send but not Sync and is
consumed by LocalCorimVerifier::new, so configure it fully before sharing the
verifier. An enabled CoRIM cache is shared by workers through that verifier.
CmwCollection and evidence collections belong to one request. Initialize
NvatSdk once before starting worker threads and keep it alive for the process
lifetime. OcspClient is Send and Sync and can be shared with the CoRIM
verifier.
More examples#
The complete example is available in the source tree: corim_local_attestation.rs.
For concurrency guidance, see Thread Safety.