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

# 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

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