Skip to content

Repository files navigation

corim

Concise Reference Integrity Manifest (CoRIM) — Rust implementation of draft-ietf-rats-corim-10.

This crate provides CBOR-native Rust types for the CoRIM / CoMID CDDL schema, a builder API, validation/appraisal logic, and signed CoRIM (COSE_Sign1) support for Remote Attestation (RATS) Endorsements and Reference Values.

Features

  • Full CDDL coverage — types for corim-map, concise-mid-tag (CoMID), concise-tl-tag (CoTL), all 9 triple types (reference, endorsed, identity, attest-key, domain dependency/membership, CoSWID, conditional endorsement, conditional endorsement series), measurement-values-map with all fields (digests, SVN, flags, raw-value, MAC/IP addresses, integrity registers, int-range, crypto keys, etc.).

  • Signed CoRIM (#6.18) — decode, validate, and construct COSE_Sign1-corim structures per §4.2. Supports both attached and detached payload modes. No cryptographic dependencies — the caller signs/verifies externally using the emitted Sig_structure1 TBS blob. Protected header extraction includes corim-meta, CWT-Claims, and hash-envelope fields.

  • Zero-dependency CBOR — built-in CBOR encoder/decoder with deterministic encoding per RFC 8949 §4.2.1. No external CBOR library required. The CborCodec trait allows plugging in alternative backends in the future.

  • no_std support — the corim library crate compiles with #![no_std] + alloc. The std feature (default) adds SystemTime-based validation. The json feature requires std.

  • Integer-keyed CBOR maps — derive macros (CborSerialize / CborDeserialize) emit deterministic CBOR with integer keys per RFC 8949 §4.2.1.

  • Builder API — fluent ComidBuilder, CotlBuilder, CorimBuilder, and SignedCorimBuilder for constructing tagged CoRIM payloads. ComidBuilder has an opt-in environment catalog (declare_env / EnvRef / add_*_for(…)) for sharing one EnvironmentMap across multiple triples, plus a strict_links lint that flags conditional/endorsed triples whose condition env is not anchored by any reference triple in the same CoMID.

  • Validation & Appraisal — reference value matching (Phase 3) and conditional endorsement series application (Phase 4) per §9 of the spec.

  • Profile frameworkcorim::profile defines a Profile trait, a ProfileRegistry, and a MatchContext (epoch-aware) so downstream crates can plug in CoRIM profiles that introduce extra measurement-values-map fields or non-core CBOR tags. The first-party Intel profile (draft-cds-rats-intel-corim-profile) ships under the profile-intel Cargo feature with an IntelProfile, the #6.60010 expression decoder, and tdate-aware match semantics.

  • CoSWID — structured ConciseSwidTag, SwidEntity, SwidLink types per RFC 9393 with co-constraint validation (patch/supplemental, tag-creator role, patches link).

  • Optional JSONjson feature gate adds Value ↔ serde_json::Value conversion with integer-to-string key remapping and type-choice JSON format.

  • TCG / NVIDIA decode interop — accepts the legacy #6.500 / #6.502 outer wrappers, bare corim-map payloads, and TCG-style #6.506(map) CoMID nesting seen in real-world signed CoRIMs (notably NVIDIA NIC firmware). Decode-only; encoders always emit draft-10 wire format. See corim::compat for the full list.

MSRV

Rust 1.85.

Quick start

use corim::builder::{ComidBuilder, CorimBuilder};
use corim::types::common::{TagIdChoice, MeasuredElement};
use corim::types::corim::CorimId;
use corim::types::environment::{ClassMap, EnvironmentMap};
use corim::types::measurement::{Digest, MeasurementMap, MeasurementValuesMap};
use corim::types::triples::ReferenceTriple;

let env = EnvironmentMap {
    class: Some(ClassMap {
        class_id: None,
        vendor: Some("ACME".into()),
        model: Some("Widget".into()),
        layer: None,
        index: None,
    }),
    instance: None,
    group: None,
};

let meas = MeasurementMap {
    mkey: Some(MeasuredElement::Text("firmware".into())),
    mval: MeasurementValuesMap {
        digests: Some(vec![Digest::new(7, vec![0xAA; 48])]),
        ..MeasurementValuesMap::default()
    },
    authorized_by: None,
};

// Build a CoMID with reference values
let comid = ComidBuilder::new(TagIdChoice::Text("my-comid-tag".into()))
    .add_reference_triple(ReferenceTriple::new(env, vec![meas]))
    .build()
    .unwrap();

// Wrap in a CoRIM and encode to tag-501-wrapped CBOR
let bytes = CorimBuilder::new(CorimId::Text("my-corim".into()))
    .add_comid_tag(comid).unwrap()
    .build_bytes().unwrap();

// Decode and validate
let (_corim, _comids) = corim::validate::decode_and_validate(&bytes).unwrap();

Compliance notes

This crate implements CoRIM per draft-ietf-rats-corim-10.

Feature Status
CoMID (§5) — #6.506 ✅ Fully modeled — types, builder, validation, appraisal
CoTL (§6) — #6.508 ✅ Fully modeled — ConciseTlTag, CotlBuilder, validity checks
CoSWID (RFC 9393) — #6.505 ✅ Structured — ConciseSwidTag, SwidEntity, SwidLink; payload/evidence opaque
Signed CoRIM (§4.2) — #6.18 ✅ Decode, validate, construct (attached + detached); no crypto dependency
CDDL extension sockets ❌ Not modeled; unknown keys silently skipped for forward compatibility
CoTS (concise-ta-stores) ❌ Separate draft, not modeled
no_std + alloc ✅ Library crate compiles without std; std feature is default-on

Signed CoRIM

The crate supports creating and parsing signed CoRIM documents (#6.18 / COSE_Sign1-corim) without any cryptographic dependencies. The caller performs signature operations externally.

use corim::types::signed::{SignedCorimBuilder, CwtClaims};

// 1. Build unsigned CoRIM payload bytes (tag-501-wrapped)
let corim_bytes: Vec<u8> = /* CorimBuilder::build_bytes() */ vec![];

// 2. Create a signed CoRIM builder
let mut builder = SignedCorimBuilder::new(-7, corim_bytes) // ES256
    .set_cwt_claims(CwtClaims::new("ACME Corp"));

// 3. Get the Sig_structure1 TBS blob
let tbs = builder.to_be_signed(&[]).unwrap();

// 4. Sign with your crypto library (ring, openssl, etc.)
let signature = vec![0u8; 64]; // placeholder

// 5. Produce the final signed CoRIM
let signed_bytes = builder.build_with_signature(signature).unwrap();

For detached payloads, use build_detached_with_signature() and to_be_signed_detached() on the decoded envelope. See the types::signed module documentation for the full API.

Crate structure

Crate Description
corim Main library — types, builder, validation, signed CoRIM, CBOR engine
corim-macros Proc-macro derives for integer-keyed CBOR map serde
corim-cli CLI tool for validating and inspecting CoRIM documents

CBOR implementation

This crate includes a built-in minimal CBOR encoder/decoder. No external CBOR library is needed.

What's supported — the CBOR subset used by CoRIM:

  • All CBOR major types (unsigned/negative int, byte/text strings, arrays, maps, tags)
  • Deterministic encoding per RFC 8949 §4.2.1 (canonical map key sorting)
  • Semantic tags (essential for CoRIM type-choice dispatching)
  • Half/single/double precision float decoding

Limitations (none affect CoRIM functionality):

  • No indefinite-length encoding (rejected on decode; CoRIM uses definite only)
  • Float encoding always uses float64 (CoRIM rarely uses floats)
  • No CBOR simple values beyond false/true/null (not used in CoRIM)
  • Nesting depth limited by call stack (~100+ levels; CoRIM is typically 5–10)

CLI tool

The corim-cli binary validates, inspects, and generates both unsigned (tag 501) and signed (tag 18) CoRIM documents. It is organized into subcommands:

# Validate an unsigned CoRIM
corim-cli validate --skip-expiry myfile.corim

# Validate a signed CoRIM (auto-detected)
corim-cli validate --skip-expiry signed.corim

# JSON output
corim-cli validate -f json myfile.corim

# Non-aborting structural diagnose pass — prints issues without rejecting
corim-cli validate --diagnose myfile.corim

# Structural conformance check against a known-good baseline (JSON or CBOR)
corim-cli validate myfile.corim --baseline golden.json

# Generate an unsigned CoRIM from a JSON template
corim-cli generate template.json -o out.cbor

# Convert an unsigned CoRIM back to a JSON template (inverse of generate)
corim-cli convert myfile.corim -o template.json

# Extract the unsigned CoRIM payload from a signed CoRIM
corim-cli extract signed.cose -o unsigned.cbor

# Sign (bring-your-own-signer): prepare a staging envelope + to-be-signed bytes,
# sign the TBS externally (HSM / openssl / ...), then inject the signature
corim-cli sign prepare unsigned.cbor --alg ES256 --signer-name "ACME Ltd." \
    --x5chain leaf.pem --out-staging staging.cose --out-tbs tbs.bin
corim-cli sign finalize staging.cose --signature sig.bin -o signed.cose

validate --baseline — structural conformance check

--baseline <FILE> compares the CoRIM under validation against a known-good reference and fails if they are not structurally the same. The reference may be JSON, CBOR, or a signed CoRIM (auto-detected and validated first). This is meant for generation pipelines: run it right after generate to catch a dropped or mistyped field before the CoRIM ships.

The structure/value boundary follows draft-ietf-rats-corim-11 §8.2.4.4. Structure — which must match — is the environment, the measurement keys, the presence and type of each measurement attribute, the digest algorithm(s), and the authorities. Values — which may differ — are the measured bytes and scalars: digest values, SVN numbers, flags, raw values, versions, and the like.

corim-cli validate candidate.cbor --baseline golden.json
  • Exit 0 — structurally conformant (any value-only differences are listed but do not fail).
  • Exit 3 — a structural mismatch (missing, unexpected, or retyped field).
  • --format json emits the full diff as { result, conformant, baseline_format, target_format, compared, summary, structural_mismatches, value_differences }.

Signed CoRIMs — protected-header comparison. When both the baseline and the target are signed, the COSE protected headers are compared too (in addition to the payload, when present). Structural header fields — alg, content-type, hash-envelope mode, the CWT iss (signer identity), and the presence of corim-meta / CWT-Claims / kid / x5chain / x5bag / x5t / x5u — must match; signer name, sub, timestamps, certificate bytes, and other details are reported as value differences. Detached (nil-payload) signed CoRIMs are supported: only the header is compared. What was compared depends on the formats of the two files:

baseline \ target signed unsigned
signed protected header (+ payload if both present) payload
unsigned payload payload

The output notes the detected format of each file (e.g. signed CoRIM (detached payload)) and what was compared.

extract / sign — signed CoRIM workflow

The tool performs no cryptography, so signing is a two-step, bring-your-own-signer flow:

  1. sign prepare wraps an unsigned CoRIM in a COSE_Sign1 protected header (algorithm, CWT-Claims signer identity, and an x5chain certificate chain from DER or PEM files, leaf-first) and writes a staging envelope (placeholder signature) plus the raw Sig_structure1 to-be-signed bytes.
  2. Sign the TBS bytes with your own key/HSM per the chosen COSE algorithm.
  3. sign finalize injects that signature into the staging envelope, producing the final signed CoRIM.

extract reverses signing: it pulls the embedded unsigned CoRIM payload back out of a signed CoRIM (attached payloads only). validate on a signed CoRIM checks structure only and prints a note that the signature is not cryptographically verified.

generate — build a CoRIM from a JSON template

generate builds an unsigned CoRIM from a hand-authored JSON template. A template has a corim-id, an optional profile, optional CoRIM-level fields (rim-validity, entities, dependent-rims), and one or more tag arrays (comids, coswids, cotls). Each tag is deserialized into its decoded type (CoMID gets the full triples tree), then encoded and wrapped by the builder.

Map keys may be written as prose names ("tag-identity", "triples", "vendor", "svn", …); the CLI rewrites them to the CBOR integer keys the core json layer expects using a context-aware state machine (it knows, e.g., that "version" is key 1 in tag-identity but key 0 in measurement-values-map). Raw integer-string keys ("1", "4", …) are still accepted, and the rewrite is idempotent — so prose, integer, and mixed templates all produce identical output. Triple records may be written as labeled objects using the CDDL field names (e.g. a conditional-endorsement-series triple as { "common-condition": { "environment": …, "claims-list": … }, "series": [ { "condition": …, "addition": … } ] }) or as the legacy positional arrays; both are accepted, and convert emits the labeled form.

corim-id and profile accept either a plain string (text id / URI) or a type-choice object for the other variants — corim-id as { "type": "uuid", "value": "…" }, profile as { "type": "oid", "value": "<base64>" }. rim-validity is { "not-before"?: <epoch>, "not-after": <epoch> } (epoch seconds).

Any object may carry a $comment (or //) key as an authoring note; these are stripped before encoding and never reach the CBOR output. The template stays valid standard JSON, so any JSON tool accepts it. Comments can annotate objects (the root, a CoMID, a triple record, an environment, …) but not bare array elements or scalars.

Profile-defined measurement-values-map extension keys can be written by alias (e.g. "tcbstatus": "UpToDate" instead of "-700": ...) when the template's profile field names a profile the CLI was compiled with. See corim-cli/templates/azure_ndpa.json for a worked example (equivalent to the build_corim_ovl3_tdisp_ndpa example). Signed CoRIM generation is out of scope — sign the output separately via SignedCorimBuilder.

Byte-string fields are authored as base64 text (matching the output of corim-cli validate -f json). Bare bstr positions — digest values, ueid, uuid, mac-addr, ip-addr, and integrity-registers digests — are decoded to CBOR bytes automatically, as is the bstr inside byte-bearing type-choice tags the core layer leaves as text (oid, cose-key, key-thumbprint, cert-thumbprint, cert-path-thumbprint, pkix-asn1der-cert, masked-raw-value). All three ovl3_tdisp reference examples (NDPA, SOCMANA, SFUA) reproduce byte-identically from templates. Remaining gaps: signed CoRIMs, and type-choice variants the core json layer does not round-trip.

convert — dump a CoRIM back to a JSON template

convert is the inverse of generate. It decodes a tag-501 unsigned CoRIM and emits a prose-keyed JSON template (to -o FILE, or stdout) that feeds straight back into generate, reproducing the original bytes:

corim-cli convert myfile.corim -o template.json
corim-cli generate template.json -o roundtrip.corim   # byte-identical

This differs from validate -f json, which prints a validation summary (validity, counts, triple types), not the CoRIM contents. Use convert when you want the full structure as editable JSON, and validate --edn for CBOR Extended Diagnostic Notation. All three ovl3_tdisp reference examples round-trip convertgenerate byte-identically. Signed CoRIMs are out of scope — convert the payload instead.

Two worked examples show how to build fixtures directly with the builder API (they write the CoRIM to stdout):

# minimal unsigned CoRIM fixture
cargo run -p corim-cli --example gen_sample > sample.corim

# minimal signed CoRIM fixture (COSE_Sign1 with a placeholder signature)
cargo run -p corim-cli --example gen_signed_sample > signed.corim

corim-cli is a local development tool and is not published to crates.io.

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit Contributor License Agreements.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.

See CONTRIBUTING.md for detailed guidelines.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

License

MIT

About

Rust Implementation of CoRIM (Concise Reference Integrity Manifest)

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages