Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion RFC_REFERENCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This document tracks all RFCs and Internet-Drafts referenced by the `corim` crat
- The implementation adds support for a new specification
- An RFC errata affects our implementation

**Last reviewed**: April 13, 2026
**Last reviewed**: April 17, 2026

---

Expand Down Expand Up @@ -181,11 +181,41 @@ This is an **Internet-Draft**, not a finalized RFC. Changes to watch for:
| Registry | URL | Used in |
|----------|-----|---------|
| CBOR Tags | https://www.iana.org/assignments/cbor-tags | `types/tags.rs` — tags 1, 18, 37, 111, 501, 505, 506, 508, 550–564 |
| COSE Algorithms | https://www.iana.org/assignments/cose/cose.xhtml#algorithms | `types/signed.rs` → `CoseAlgorithm` enum (RFC 9864 fully-specified identifiers) |
| Named Information Hash Algorithm | https://www.iana.org/assignments/named-information | `types/measurement.rs` — `Digest` algorithm IDs |
| CoSWID Items | https://www.iana.org/assignments/coswid | `types/tags.rs` — CoSWID key indices 0–57 |

---

### RFC 9864 — Fully-Specified Algorithms for JOSE and COSE

| | |
|-|-|
| **Status** | Standards Track — **Stable** (October 2025) |
| **URL** | https://www.rfc-editor.org/rfc/rfc9864.html |
| **Updates** | RFC 7518, RFC 8037, RFC 9053 |
| **Used in** | `types/signed.rs` → `CoseAlgorithm` enum |

#### Impact on this crate

RFC 9864 deprecates polymorphic COSE algorithm identifiers and defines
fully-specified replacements:

| Deprecated | Value | Replacement | Value | Status in our enum |
|-----------|-------|-------------|-------|--------------------|
| ES256 | -7 | ESP256 | -9 | Both modeled; ES256 marked deprecated |
| ES384 | -35 | ESP384 | -51 | Both modeled; ES384 marked deprecated |
| ES512 | -36 | ESP512 | -52 | Both modeled; ES512 marked deprecated |
| EdDSA | -8 | Ed25519 / Ed448 | -19 / -53 | Both modeled; EdDSA marked deprecated |

PS256/PS384/PS512 are NOT deprecated by RFC 9864 (§6.1).

The deprecated variants are retained in `CoseAlgorithm` for decode interop
with existing signed CoRIM documents. `CoseAlgorithm::is_deprecated()`
returns `true` for the old polymorphic identifiers.

---

## How to Update This Document

When a new revision of `draft-ietf-rats-corim` is published:
Expand Down
23 changes: 3 additions & 20 deletions corim-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ fn main() {

/// Information extracted from a signed CoRIM's COSE_Sign1 wrapper.
struct SignedInfo {
alg: i64,
alg: corim::types::signed::CoseAlgorithm,
signer_name: Option<String>,
content_type: Option<String>,
signature_len: usize,
Expand Down Expand Up @@ -282,7 +282,7 @@ fn try_decode_signed(
fn print_signed_header_only(info: &SignedInfo) {
println!("✓ Signed CoRIM (tag 18) — header decoded\n");
println!("═══ COSE_Sign1 Header ═══");
println!(" Algorithm: {}", cose_alg_name(info.alg));
println!(" Algorithm: {}", info.alg);
if let Some(ref ct) = info.content_type {
println!(" Content-Type: {}", ct);
}
Expand Down Expand Up @@ -364,7 +364,7 @@ fn print_text_output(
// Show signed CoRIM info if present
if let Some(ref info) = signed_info {
println!(" [SIGNED] COSE_Sign1 (tag 18)");
println!(" Algorithm: {}", cose_alg_name(info.alg));
println!(" Algorithm: {}", info.alg);
if let Some(ref ct) = info.content_type {
println!(" Content-Type: {}", ct);
}
Expand Down Expand Up @@ -479,20 +479,3 @@ fn json_escape(s: &str) -> String {
.replace('"', "\\\"")
.replace('\n', "\\n")
}

/// Map a COSE algorithm identifier to a human-readable name.
fn cose_alg_name(alg: i64) -> String {
match alg {
-7 => "ES256 (-7)".into(),
-35 => "ES384 (-35)".into(),
-36 => "ES512 (-36)".into(),
-37 => "PS256 (-37)".into(),
-38 => "PS384 (-38)".into(),
-39 => "PS512 (-39)".into(),
-257 => "PS256 (-257)".into(),
-258 => "PS384 (-258)".into(),
-259 => "PS512 (-259)".into(),
-65535 => "HSS-LMS (-65535)".into(),
other => format!("{}", other),
}
}
4 changes: 3 additions & 1 deletion corim/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ pub use self::measurement::{
Digest, FlagsMap, IntRangeChoice, IntegrityRegisters, IpAddr, MacAddr, MeasurementMap,
MeasurementValuesMap, RawValueChoice, SvnChoice,
};
pub use self::signed::{CoseSign1Corim, CwtClaims, ProtectedCorimHeaderMap, SignedCorimBuilder};
pub use self::signed::{
CoseAlgorithm, CoseSign1Corim, CwtClaims, ProtectedCorimHeaderMap, SignedCorimBuilder,
};
pub use self::triples::{
AttestKeyTriple, CesCondition, ConditionalEndorsementSeriesTriple,
ConditionalEndorsementTriple, ConditionalSeriesRecord, CoswidTriple, DomainDependencyTriple,
Expand Down
158 changes: 149 additions & 9 deletions corim/src/types/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,144 @@ use crate::cbor;
use crate::cbor::value::Value;
use crate::Validate;

// ===================================================================
// COSE Algorithm Identifiers (IANA "COSE Algorithms" registry)
// Updated per RFC 9864 — fully-specified algorithm identifiers.
// ===================================================================

/// COSE signing algorithm identifier per
/// [IANA COSE Algorithms](https://www.iana.org/assignments/cose/cose.xhtml#algorithms),
/// updated by [RFC 9864](https://www.rfc-editor.org/rfc/rfc9864.html).
///
/// RFC 9864 deprecates polymorphic algorithm identifiers (ES256, ES384,
/// ES512, EdDSA) and defines fully-specified replacements (ESP256, ESP384,
/// ESP512, Ed25519, Ed448). The deprecated variants are retained for
/// decode interop but marked with `#[deprecated]` doc attributes.
///
/// Used in the `alg` (key 1) field of the COSE_Sign1 protected header.
/// The `Unknown` variant provides forward compatibility with algorithm
/// identifiers not yet modeled here.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum CoseAlgorithm {
// --- Fully-specified algorithms (RFC 9864 §2) ---
/// ESP256 (-9) — ECDSA using P-256 curve and SHA-256. Replaces ES256.
Esp256,
/// Ed25519 (-19) — EdDSA using the Ed25519 parameter set. Replaces EdDSA.
Ed25519,
/// PS256 (-37) — RSASSA-PSS w/ SHA-256.
Ps256,
/// PS384 (-38) — RSASSA-PSS w/ SHA-384.
Ps384,
/// PS512 (-39) — RSASSA-PSS w/ SHA-512.
Ps512,
/// ESP384 (-51) — ECDSA using P-384 curve and SHA-384. Replaces ES384.
Esp384,
/// ESP512 (-52) — ECDSA using P-521 curve and SHA-512. Replaces ES512.
Esp512,
/// Ed448 (-53) — EdDSA using the Ed448 parameter set. Replaces EdDSA.
Ed448,

// --- Deprecated polymorphic algorithms (RFC 9864 §4.2.2) ---
// Retained for decode interop with existing signed CoRIM documents.
/// ES256 (-7) — **Deprecated per RFC 9864.** Use [`Esp256`](Self::Esp256).
Es256,
/// EdDSA (-8) — **Deprecated per RFC 9864.** Use [`Ed25519`](Self::Ed25519) or [`Ed448`](Self::Ed448).
EdDsa,
/// ES384 (-35) — **Deprecated per RFC 9864.** Use [`Esp384`](Self::Esp384).
Es384,
/// ES512 (-36) — **Deprecated per RFC 9864.** Use [`Esp512`](Self::Esp512).
Es512,

/// An algorithm identifier not explicitly modeled above.
Unknown(i64),
}

impl CoseAlgorithm {
/// Convert from the IANA integer identifier.
pub fn from_i64(n: i64) -> Self {
match n {
-7 => Self::Es256,
-8 => Self::EdDsa,
-9 => Self::Esp256,
-19 => Self::Ed25519,
-35 => Self::Es384,
-36 => Self::Es512,
-37 => Self::Ps256,
-38 => Self::Ps384,
-39 => Self::Ps512,
-51 => Self::Esp384,
-52 => Self::Esp512,
-53 => Self::Ed448,
other => Self::Unknown(other),
}
}

/// Convert to the IANA integer identifier.
pub fn to_i64(self) -> i64 {
match self {
Self::Es256 => -7,
Self::EdDsa => -8,
Self::Esp256 => -9,
Self::Ed25519 => -19,
Self::Es384 => -35,
Self::Es512 => -36,
Self::Ps256 => -37,
Self::Ps384 => -38,
Self::Ps512 => -39,
Self::Esp384 => -51,
Self::Esp512 => -52,
Self::Ed448 => -53,
Self::Unknown(n) => n,
}
}

/// Human-readable name for display.
pub fn name(&self) -> &'static str {
match self {
Self::Esp256 => "ESP256",
Self::Ed25519 => "Ed25519",
Self::Ps256 => "PS256",
Self::Ps384 => "PS384",
Self::Ps512 => "PS512",
Self::Esp384 => "ESP384",
Self::Esp512 => "ESP512",
Self::Ed448 => "Ed448",
Self::Es256 => "ES256 (deprecated)",
Self::EdDsa => "EdDSA (deprecated)",
Self::Es384 => "ES384 (deprecated)",
Self::Es512 => "ES512 (deprecated)",
Self::Unknown(_) => "Unknown",
}
}

/// Returns `true` if this algorithm is deprecated per RFC 9864.
pub fn is_deprecated(&self) -> bool {
matches!(self, Self::Es256 | Self::EdDsa | Self::Es384 | Self::Es512)
}
}

impl core::fmt::Display for CoseAlgorithm {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Unknown(n) => write!(f, "Unknown({})", n),
_ => write!(f, "{} ({})", self.name(), self.to_i64()),
}
}
}

impl From<i64> for CoseAlgorithm {
fn from(n: i64) -> Self {
Self::from_i64(n)
}
}

impl From<CoseAlgorithm> for i64 {
fn from(alg: CoseAlgorithm) -> Self {
alg.to_i64()
}
}

// ===================================================================
// COSE Header Label Constants (RFC 9052 / draft-ietf-rats-corim-10 §4.2)
// ===================================================================
Expand Down Expand Up @@ -260,7 +398,7 @@ fn value_to_epoch(v: &Value) -> Result<i64, String> {
#[derive(Clone, Debug, PartialEq)]
pub struct ProtectedCorimHeaderMap {
/// COSE algorithm identifier (key 1).
pub alg: i64,
pub alg: CoseAlgorithm,
/// Content type (key 3) — present for inline signing.
/// Should be "application/rim+cbor" per the spec.
pub content_type: Option<String>,
Expand Down Expand Up @@ -316,7 +454,7 @@ impl Serialize for ProtectedCorimHeaderMap {
count += self.extra.len();

let mut map = s.serialize_map(Some(count))?;
map.serialize_entry(&COSE_HEADER_ALG, &self.alg)?;
map.serialize_entry(&COSE_HEADER_ALG, &self.alg.to_i64())?;
if let Some(ref ct) = self.content_type {
map.serialize_entry(&COSE_HEADER_CONTENT_TYPE, ct)?;
}
Expand Down Expand Up @@ -504,8 +642,9 @@ impl<'de> Deserialize<'de> for ProtectedCorimHeaderMap {
}
}

let alg =
alg.ok_or_else(|| serde::de::Error::custom("protected header: missing alg (key 1)"))?;
let alg = alg
.ok_or_else(|| serde::de::Error::custom("protected header: missing alg (key 1)"))?
.into();

// If CWT claims were found flat in the header (not under key 15),
// synthesize a CwtClaims struct from the individual fields.
Expand Down Expand Up @@ -928,7 +1067,7 @@ pub fn validate_signed_corim_payload_detached(
/// ```
#[must_use]
pub struct SignedCorimBuilder {
alg: i64,
alg: CoseAlgorithm,
content_type: String,
corim_meta: Option<CorimMetaMap>,
cwt_claims: Option<CwtClaims>,
Expand All @@ -942,14 +1081,15 @@ pub struct SignedCorimBuilder {
impl SignedCorimBuilder {
/// Create a new builder with the specified COSE algorithm and CoRIM payload bytes.
///
/// The `alg` parameter is the COSE algorithm identifier (e.g., -7 for ES256,
/// -35 for ES384, -36 for ES512, -257 for PS256).
/// The `alg` parameter is the COSE algorithm identifier. Use
/// [`CoseAlgorithm`] variants (e.g., `CoseAlgorithm::Es256`) or convert
/// from an integer with `.into()` (e.g., `(-7i64).into()`).
///
/// The `corim_payload` must be the CBOR-encoded `tagged-unsigned-corim-map`
/// (i.e., tag-501-wrapped bytes as produced by [`crate::builder::CorimBuilder::build_bytes`]).
pub fn new(alg: i64, corim_payload: Vec<u8>) -> Self {
pub fn new(alg: impl Into<CoseAlgorithm>, corim_payload: Vec<u8>) -> Self {
Self {
alg,
alg: alg.into(),
content_type: CORIM_CONTENT_TYPE.into(),
corim_meta: None,
cwt_claims: None,
Expand Down
Loading
Loading