Skip to content

Add Arm CCA profile support - #75

Open
a-trikalinou wants to merge 18 commits into
mainfrom
feat/cca-profile-validation
Open

a-trikalinou wants to merge 18 commits into
mainfrom
feat/cca-profile-validation

Conversation

@a-trikalinou

Copy link
Copy Markdown
Contributor

This pull request adds support for the Arm CCA (Confidential Compute Architecture) endorsements profile to the corim and corim-cli crates. The changes introduce a new feature flag and implementation for handling CCA-specific measurement keys and profiles, including validation, diagnosis, and profile registration. Comprehensive tests are also included to ensure correct behavior for the new profile.

CCA Profile Support:

  • Added a new profile-cca feature to the corim crate, implementing support for the Arm CCA endorsements profile as defined in draft-ydb-rats-cca-endorsements-04. This includes profile URIs, recognition and validation of CCA-specific measurement keys, and integration with the core profile trait system. [1] [2] [3] [4]

  • Registered the new cca profile in the corim-cli crate, making it available as a default feature and ensuring that the CLI recognizes and processes CCA measurements. [1] [2] [3] [4]

Testing:

  • Added a dedicated test suite for the CCA profile, covering key recognition, measurement validation, profile matching, and diagnosis labeling to ensure the correctness and robustness of the implementation.

Related Issues

Checklist

  • I have read the CONTRIBUTING guidelines
  • All new source files include the Microsoft copyright header
  • New public APIs have doc comments
  • Tests have been added or updated
  • cargo test --all passes
  • cargo fmt --all -- --check passes
  • cargo clippy --all -- -D warnings passes

Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical signer-key matching and moderate CCA validation and diagnosis issues must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds feature-gated Arm CCA endorsement profile support to corim, with CLI registration and dedicated tests.

Changes:

  • Implements CCA profile recognition, validation, and matching.
  • Adds profile-cca and CLI integration.
  • Adds CCA profile tests.
File summaries
File Summary
corim/tests/profile_cca_tests.rs Adds CCA behavior tests.
corim/src/profile/cca/mod.rs Implements CCA profiles and measurement handling.
corim/src/profile.rs Exposes the feature-gated CCA module.
corim/Cargo.toml Adds the profile-cca feature.
corim-cli/src/main.rs Registers CCA profiles for CLI inspection.
corim-cli/src/generate.rs Registers CCA profiles for generation.
corim-cli/Cargo.toml Enables CCA by default in the CLI.
Review details

Suppressed comments (9)

corim/src/profile/cca/mod.rs:137

  • This public constructor is undocumented, unlike the constructors of the existing first-party profiles. Add a /// description for the new API (and likewise for CcaRealmProfile::new).
}

corim/src/profile/cca/mod.rs:151

  • This new public profile type is missing the /// API documentation required for public types in this crate. Add a short description before exposing the Realm profile.
}

corim/src/profile/cca/mod.rs:156

  • This public constructor is undocumented, unlike the constructors of the existing first-party profiles. Add a /// description for the new API.
}

corim/src/profile/cca/mod.rs:81

  • mkey_name clones every text key even though all callers only compare or inspect it. This helper runs for each reference/evidence candidate pair, so the new profile adds avoidable heap allocations on the appraisal hot path; return Option<&str> and use s.as_str() instead.
fn mkey_name(mkey: &Option<MeasuredElement>) -> Option<String> {

corim/src/profile/cca/mod.rs:61

  • The allowed ROTPK index/slot limits are protocol constraints but are embedded as bare 7 and 5 literals. Define named constants with the applicable draft section cited, as the rest of the crate does for wire/protocol values, so the accepted key grammar is discoverable and maintained in one place.
                return false;
            }
            matches!(family, Some("CM") | Some("DM"))
                && idx
                    .and_then(|s| s.parse::<u8>().ok())
                    .is_some_and(|n| n <= 7)
                && slot

corim/src/profile/cca/mod.rs:98

  • The accepted cryptokeys byte lengths (32, 48, and 64) are also protocol/profile constraints encoded as magic numbers. Move them to named constants and cite the CCA draft section that defines the permitted key representation; otherwise future changes to the profile can silently leave this validator inconsistent.
                    !keys.is_empty()
                        && keys.iter().all(|k| match k {

corim/src/profile/cca/mod.rs:96

  • The CCA profile requires exactly one tagged-bytes signer ID for each software component, but this only checks that the list is non-empty. A component with two valid signer IDs is therefore accepted as a valid CCA measurement. Require keys.len() == 1 here, and cover the multi-key case in the tests.
        "cca.software-component" => {
            m.mval.digests.as_ref().is_some_and(|d| !d.is_empty())
                && m.mval.cryptokeys.as_ref().is_some_and(|keys| {

corim/src/profile/cca/mod.rs:89

  • CCA platform measurement maps require authorized-by to be absent, but this validator never checks m.authorized_by; the core matcher also ignores it. A malformed platform reference/evidence pair can therefore pass as long as its other fields match. Reject measurements with authorized_by.is_some() before the key-specific checks.
}

fn is_valid_cca_platform_measurement(m: &MeasurementMap) -> bool {
    let Some(mkey) = mkey_name(&m.mkey) else {

corim/src/profile/cca/mod.rs:120

  • CCA realm measurement maps also require authorized-by to be absent, but the realm validator does not enforce that constraint. Since core_fields_match does not compare this field, an otherwise matching realm measurement with an authority list is accepted. Apply the same absence check used for platform measurements.
}

fn is_valid_cca_realm_measurement(m: &MeasurementMap) -> bool {
    let Some(mkey) = mkey_name(&m.mkey) else {
  • Files reviewed: 7/7 changed files
  • Comments generated: 6
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/tests/profile_cca_tests.rs Outdated
Copilot AI review requested due to automatic review settings September 15, 2026 23:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical CCA identifiers, data models, and validation do not conform to the referenced draft.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (8)

corim/src/profile/cca/mod.rs:197

  • core_fields_match explicitly omits cryptokeys (see validate.rs:603-607), but this profile uses that field as the required value for cca.rotpk.* and cca.software-component. As a result, two valid ROTPK measurements with the same mkey but different keys both return Some(true) because no other core field distinguishes them. Compare the CCA-owned key material in the profile verdict and add a mismatch regression test.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:202

  • diagnose_mval_entry is called only for unknown integer MeasurementValuesMap::extra_entries; the CCA names are structural measurement-map.mkey values, and the diagnose walker currently ignores that value. Therefore --diagnose never labels an actual CCA measurement, while this hook can label an unrelated extension whose text happens to be a CCA name. Add a mkey-specific diagnosis path (and an end-to-end inspect test), or remove this override.
    fn diagnose_mval_entry(&self, _key: i64, value: &Value) -> Option<String> {
        match value {
            Value::Text(s) if is_cca_platform_mkey(s) => Some(format!("{} = {}", s, s)),

corim/src/profile/cca/mod.rs:134

  • The new public profile type and constructor are missing /// documentation, unlike the existing PsaProfile API (profile/psa/mod.rs:77-85). Add docs that identify the CCA Platform profile and cite the draft before exposing this API; apply the same documentation to the Realm type below.
#[derive(Debug)]
pub struct CcaPlatformProfile {

corim/src/profile/cca/mod.rs:76

  • parse::<u8>() accepts strings such as "00" (and an optional +), so this recognizer returns true for names like cca.rem00 even though the profile defines only cca.rem0 through cca.rem3. That also makes the diagnosis hook label non-profile keys as valid CCA names. Match the exact suffixes instead of parsing a general integer.
            let Some(rest) = name.strip_prefix("cca.rem") else {
                return false;
            };
            rest.parse::<u8>().is_ok_and(|n| n <= 3)

corim/src/profile/cca/mod.rs:133

  • This new public profile type derives only Debug, but the crate's public-type contract requires Clone, Debug, and PartialEq at minimum (and Eq is valid here because ProfileChoice is equatable). Add the standard derives so consumers can store and compare profile values consistently.
#[derive(Debug)]

corim/src/profile/cca/mod.rs:152

  • The Realm profile has the same public-type derive gap: it exposes only Debug instead of the required clone/equality traits. Add the standard derives, including Eq for this field-less state wrapper.
#[derive(Debug)]

corim/tests/profile_cca_tests.rs:130

  • This test returns at the earlier mkey-mismatch branch, so it never exercises is_valid_cca_platform_measurement: the reference uses cca.software-component while the evidence uses cca.rotpk.CM.2.3. Use the same key on both measurements and make one required field invalid, otherwise the platform validation logic is untested.
fn platform_match_rejects_invalid_cca_structures() {
    let profile = CcaPlatformProfile::new();
    let reference = measurement_with_mkey("cca.software-component", &[0x11, 0x22, 0x33]);
    let evidence = rotpk_measurement("cca.rotpk.CM.2.3", &[0xAA; 32]);

corim/tests/profile_cca_tests.rs:105

  • These tests construct the same non-draft text-mkey/cryptokey layout as the implementation, so they can pass without exercising real CCA CBOR. There is no test for the draft's tagged platform mkeys, integrity-register RIM/REM values, 64-byte RPV, or profile lookup through ProfileRegistry; add decode/round-trip and end-to-end diagnosis/appraisal fixtures from the profile examples.
fn platform_match_accepts_same_cca_mkey_and_same_core_values() {
    let profile = CcaPlatformProfile::new();
    let reference =
        software_component_measurement("cca.software-component", &[0x11, 0x22, 0x33], &[0xAA; 32]);
    let evidence =
  • Files reviewed: 7/7 changed files
  • Comments generated: 4
  • Review effort level: Lite

Comment thread corim/src/profile/cca/mod.rs Outdated
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment on lines +40 to +44
/// Recognize a CCA Platform measurement key, per draft-ydb-rats-cca-endorsements-04.
pub fn is_cca_platform_mkey(name: &str) -> bool {
match name {
"cca.software-component" | "cca.platform-config" | "cca.platform-manufacturing-config" => {
true
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment on lines +68 to +72
/// Recognize a CCA Realm measurement key.
pub fn is_cca_realm_mkey(name: &str) -> bool {
match name {
"cca.rim" | "cca.rpv" => true,
_ => {
Comment thread corim/src/profile/cca/mod.rs Outdated
Comment on lines +94 to +98
"cca.software-component" => {
m.mval.digests.as_ref().is_some_and(|d| !d.is_empty())
&& m.mval.cryptokeys.as_ref().is_some_and(|keys| {
!keys.is_empty()
&& keys.iter().all(|k| match k {
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 16, 2026 15:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

CCA identifiers, measurement representations, validation, diagnosis, documentation, and test coverage have unresolved issues.

Review details

Suppressed comments (14)

corim/src/profile/cca/mod.rs:38

  • These identifiers do not match draft-ydb-rats-cca-endorsements-04: its profile examples/registration use http://arm.com/cca/ssd/1 and http://arm.com/cca/realm/1, not the tag:arm.com,2025:...#1.0.0 strings here. A real draft-04 CoRIM therefore cannot be looked up in ProfileRegistry, so none of the new profile behavior is applied.
/// Profile URI for CCA Platform endorsements.
pub const CCA_PLATFORM_PROFILE_URI: &str = "tag:arm.com,2025:endorsements/cca_platform#1.0.0";
/// Profile URI for CCA Realm endorsements.
pub const CCA_REALM_PROFILE_URI: &str = "tag:arm.com,2025:endorsements/cca_realm#1.0.0";

corim/src/profile/cca/mod.rs:85

  • The draft-04 platform examples encode the software-component and platform-config identifiers as tagged measured elements (#6.601(arm-swcomp-id) and #6.602(...)), not MeasuredElement::Text values. Restricting this helper to text means actual draft platform measurements return None before the CCA matcher runs; supporting the profile requires handling those tagged map forms, not just parsing cca.* strings.
fn mkey_name(mkey: &Option<MeasuredElement>) -> Option<String> {
    match mkey {
        Some(MeasuredElement::Text(s)) => Some(s.clone()),
        _ => None,
    }

corim/src/profile/cca/mod.rs:223

  • Draft-04 realm reference values put RIM/REM measurements under mval.integrity-registers (rim, rem0..rem3) and represent RPV as a raw value; they do not use these names as text mkeys. Consequently mkey_name returns None for the documented representation and this method defers to generic matching before the CCA-specific validation runs, so the realm profile does not recognize or enforce the draft shape.
        let ref_mkey = mkey_name(&reference.mkey)?;
        let ev_mkey = mkey_name(&evidence.mkey)?;

        if ref_mkey != ev_mkey {
            return Some(false);

corim/src/profile/cca/mod.rs:197

  • The CCA platform validator requires cryptokeys, but core_fields_match deliberately excludes measurement-values key 13 (corim/src/validate.rs:603-607). As a result, two otherwise-valid software-component or ROTPK measurements with different key material still return Some(true), so the profile does not appraise the value it requires; compare the cryptokeys in the CCA-specific verdict before returning success.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:204

  • This override cannot label CCA measurement keys in the CLI: Profile::diagnose_mval_entry is called only for integer mval.extra_entries, while CCA names are in measurement-map.mkey and the diagnose walker does nothing for key 0. The direct unit test therefore does not exercise the claimed diagnosis behavior; add a mkey-specific diagnosis path or remove this hook.
    fn diagnose_mval_entry(&self, _key: i64, value: &Value) -> Option<String> {
        match value {
            Value::Text(s) if is_cca_platform_mkey(s) => Some(format!("{} = {}", s, s)),
            _ => None,
        }

corim/src/profile/cca/mod.rs:76

  • This parser accepts names such as cca.rem00 and cca.rem003 because they parse to an index in range, but is_valid_cca_realm_measurement only accepts the exact cca.rem0 through cca.rem3 names. That makes the public recognizer and the matching/diagnosis paths disagree; restrict the suffix to the four canonical strings.
            rest.parse::<u8>().is_ok_and(|n| n <= 3)

corim/src/profile/cca/mod.rs:63

  • The ROTPK index and slot bounds are protocol constraints, but the acceptance grammar embeds them as unexplained 7 and 5 literals. Name these limits as documented CCA constants (with the draft section) so the supported key space is auditable and cannot be changed in one branch without updating the specification reference.
                && idx
                    .and_then(|s| s.parse::<u8>().ok())
                    .is_some_and(|n| n <= 7)
                && slot
                    .and_then(|s| s.parse::<u8>().ok())
                    .is_some_and(|n| n <= 5)

corim/src/profile/cca/mod.rs:111

  • The allowed CCA key lengths are unnamed protocol literals and the same predicate is duplicated for software components and ROTPKs. Extract a documented helper/constant set and reuse it in both branches so the accepted encodings stay consistent when the profile evolves.
                            crate::types::common::CryptoKey::Bytes(b) => {
                                matches!(b.len(), 32 | 48 | 64)
                            }
                            _ => false,
                        })
                })
        }
        "cca.platform-config" | "cca.platform-manufacturing-config" => m.mval.raw_value.is_some(),
        _ if is_cca_platform_mkey(&mkey) => m.mval.cryptokeys.as_ref().is_some_and(|keys| {
            !keys.is_empty()
                && keys.len() == 1
                && keys.iter().all(|k| match k {
                    crate::types::common::CryptoKey::Bytes(b) => matches!(b.len(), 32 | 48 | 64),

corim/src/profile/cca/mod.rs:134

  • This newly public profile type has no rustdoc, unlike the existing PSA/Azure profile types. Add a short description identifying the CCA Platform endorsements profile so downstream users get documented API output.
#[derive(Debug)]
pub struct CcaPlatformProfile {

corim/src/profile/cca/mod.rs:139

  • This newly public constructor is undocumented, while the other first-party profile constructors provide rustdoc. Add a brief constructor comment for the public API.
    pub fn new() -> Self {

corim/src/profile/cca/mod.rs:158

  • This newly public constructor is undocumented, while the other first-party profile constructors provide rustdoc. Add a brief constructor comment for the public API.
    pub fn new() -> Self {

corim/src/profile/cca/mod.rs:153

  • This newly public profile type has no rustdoc, unlike the existing PSA/Azure profile types. Add a short description identifying the CCA Realm endorsements profile so downstream users get documented API output.
#[derive(Debug)]
pub struct CcaRealmProfile {

corim/src/profile/cca/mod.rs:136

  • The new public CCA profile types and their public new() constructors are missing rustdoc, unlike the existing PsaProfile/AzureProfile APIs and the repository rule that all public APIs be documented (CONTRIBUTING.md:74). Add documentation for both profile structs and constructors before exposing this feature.
#[derive(Debug)]
pub struct CcaPlatformProfile {
    id: ProfileChoice,
}

corim/tests/profile_cca_tests.rs:130

  • This test never reaches the CCA shape-validation branch: the reference uses cca.software-component while the evidence uses cca.rotpk.CM.2.3, so the earlier mkey-mismatch return makes the assertion pass regardless of whether invalid structures are rejected. Use the same mkey for an actually malformed software-component pair (and add a separate ROTPK case if desired).
fn platform_match_rejects_invalid_cca_structures() {
    let profile = CcaPlatformProfile::new();
    let reference = measurement_with_mkey("cca.software-component", &[0x11, 0x22, 0x33]);
    let evidence = rotpk_measurement("cca.rotpk.CM.2.3", &[0xAA; 32]);
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved validation, matching, diagnosis, documentation, and test issues remain.

Review details

Suppressed comments (12)

corim/src/profile.rs:196

  • This module documentation overstates the core matcher: core_fields_match explicitly excludes cryptokeys and compares raw-value by exact equality, so it does not implement CCA signer/ROTPK or masked-config semantics. Update this description to reflect the profile-specific comparisons that the module must perform.
/// already knows how to compare the underlying `digests` / `raw-value`
/// fields, so this module focuses on profile identification and
/// enforcement that the `mkey` names belong to the CCA profile.

corim/src/profile/cca/mod.rs:197

  • core_fields_match intentionally omits MeasurementValuesMap::cryptokeys. For cca.rotpk.*, the cryptokey is the only measurement value beyond the mkey, and for cca.software-component it is part of the value, so different keys can still return Some(true) when the other core fields match. Include the CCA cryptokey values in this profile-specific comparison and add a differing-key regression test.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:204

  • diagnose_mval_entry is only called for unknown integer entries in MeasurementValuesMap::extra_entries; the measurement-map key 0 is ignored by the current walker. This implementation therefore never labels actual CCA mkeys, while it can mislabel an unrelated extension whose value happens to be the same text. Add a profile path for structural mkeys and invoke it from inspect_measurement_map instead of treating them as mval entries.
    fn diagnose_mval_entry(&self, _key: i64, value: &Value) -> Option<String> {
        match value {
            Value::Text(s) if is_cca_platform_mkey(s) => Some(format!("{} = {}", s, s)),
            _ => None,
        }

corim/src/profile/cca/mod.rs:76

  • rest.parse::<u8>() accepts non-canonical suffixes such as 01, so is_cca_realm_mkey("cca.rem01") returns true although the profile only defines cca.rem0 through cca.rem3; the later exact-match validator then rejects the same string. Match the four literal suffixes to keep recognition and validation consistent.
            rest.parse::<u8>().is_ok_and(|n| n <= 3)

corim/src/profile/cca/mod.rs:153

  • The new public profile type and its public constructor lack rustdoc, unlike the existing first-party profile APIs. Document both so generated API docs explain which CCA profile each type handles.
#[derive(Debug)]
pub struct CcaRealmProfile {

corim/src/profile/cca/mod.rs:98

  • The CCA software-component CDDL requires exactly one signer-id entry. !keys.is_empty() permits two or more keys, so malformed reference/evidence measurements pass this shape check; use the same keys.len() == 1 constraint already applied to ROTPK measurements.
                && m.mval.cryptokeys.as_ref().is_some_and(|keys| {
                    !keys.is_empty()
                        && keys.iter().all(|k| match k {

corim/src/profile/cca/mod.rs:95

  • CCA's cca-digest requires a text algorithm identifier, a 32/48/64-byte value, and distinct algorithms within the digest list. This branch only checks that the list is non-empty, so integer/short/duplicate digests are accepted as valid CCA software-component measurements. Add a shared CCA digest validator and use it here and for the Realm digest branches.
            m.mval.digests.as_ref().is_some_and(|d| !d.is_empty())

corim/src/profile/cca/mod.rs:106

  • The CCA config and manufacturing-config CDDL requires raw-value to be the tagged-masked-raw-value variant (#6.563), but is_some() also accepts plain tagged bytes and does not reject the other fields or authorized-by that the CCA map forbids. A plain RawValueChoice::Bytes therefore passes this CCA shape check. Validate the required variant and the complete allowed map shape.
        "cca.platform-config" | "cca.platform-manufacturing-config" => m.mval.raw_value.is_some(),

corim/src/profile/cca/mod.rs:63

  • The draft's ROTPK grammar is cca.rotpk.[CD]M.[0-7].[0-5], so each index and slot is exactly one digit. Parsing to u8 and checking only the numeric bounds accepts values such as cca.rotpk.CM.02.03, allowing a non-conforming mkey through. Require a one-character token before parsing, or match the exact grammar.
                && idx
                    .and_then(|s| s.parse::<u8>().ok())
                    .is_some_and(|n| n <= 7)
                && slot
                    .and_then(|s| s.parse::<u8>().ok())
                    .is_some_and(|n| n <= 5)

corim/src/profile/cca/mod.rs:128

  • CCA RPV is encoded with the tagged-bytes (#6.560) raw-value variant, but this accepts any raw-value variant, including the masked form. Consequently an invalid masked RPV can pass profile validation; check specifically for RawValueChoice::Bytes.
        "cca.rpv" => m.mval.raw_value.is_some(),

corim/src/profile/cca/mod.rs:197

  • CCA platform configuration references use a masked raw value, while the transformed evidence carries tagged bytes; the core matcher compares raw_value by exact != and cannot apply (evidence & mask) == (value & mask). Delegating this pair to core_fields_match will reject valid evidence that differs only outside the mask. Add a CCA-specific masked-raw comparison and delegate only the remaining structural fields.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/tests/profile_cca_tests.rs:130

  • This test cannot exercise CCA shape validation: it exits at the earlier mkey mismatch (cca.software-component versus cca.rotpk.CM.2.3) before reaching is_valid_cca_platform_measurement. Use the same mkey with one invalid mval, or a valid reference and invalid evidence, so the test proves the structural guard.
    let reference = measurement_with_mkey("cca.software-component", &[0x11, 0x22, 0x33]);
    let evidence = rotpk_measurement("cca.rotpk.CM.2.3", &[0xAA; 32]);
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Moderate issues remain in CCA key matching, diagnosis support, and public API documentation.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (3)

corim/src/profile/cca/mod.rs:195

  • The CCA signer/ROTPK is stored in mval.cryptokeys, but core_fields_match intentionally skips that field. Thus two otherwise-valid measurements with the same mkey/digests and different single CryptoKey::Bytes values return Some(true), accepting the wrong signer or root key. Include the validated cryptokey lists in this profile-specific comparison and add a mismatch regression test.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:137

  • This new public profile type and constructor are missing rustdoc, unlike the existing first-party profile APIs (for example, profile/azure/mod.rs:42-50 and profile/psa/mod.rs:77-85). Add documentation describing the profile URI and registration behavior so this public API follows the crate's documentation convention.
#[derive(Debug)]
pub struct CcaPlatformProfile {
    id: ProfileChoice,
}

impl CcaPlatformProfile {
    pub fn new() -> Self {

corim/src/profile/cca/mod.rs:156

  • This new public profile type and constructor are missing rustdoc, unlike the existing first-party profile APIs (for example, profile/azure/mod.rs:42-50 and profile/psa/mod.rs:77-85). Add documentation describing the profile URI and registration behavior so this public API follows the crate's documentation convention.
#[derive(Debug)]
pub struct CcaRealmProfile {
    id: ProfileChoice,
}

impl CcaRealmProfile {
    pub fn new() -> Self {
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread corim/src/profile/cca/mod.rs Outdated
Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 17, 2026 19:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical and moderate issues affect CCA conformance, validation, matching, diagnosis, and CLI conversion.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (14)

corim-cli/src/main.rs:33

  • The CLI has a separate build_registry in corim-cli/src/convert.rs:264-274, and it still registers only Intel, Azure, and PSA. As a result, the convert subcommand cannot resolve the newly enabled CCA profile; add the two CCA registrations there as well or centralize registry construction.
    #[cfg(feature = "cca")]
    registry.register(Box::new(corim::profile::cca::CcaPlatformProfile::new()));
    #[cfg(feature = "cca")]
    registry.register(Box::new(corim::profile::cca::CcaRealmProfile::new()));

corim/src/profile/cca/mod.rs:89

  • The CCA cca-digest type requires a text algorithm identifier and a 32-, 48-, or 64-byte hash, not merely a non-empty generic digest list. This accepts invalid values such as the integer algorithm and 3-byte digest used by the new test helpers, so malformed software-component measurements pass profile validation. Validate each digest's algorithm and value shape before matching.
            m.mval.digests.as_ref().is_some_and(|d| !d.is_empty())

corim/src/profile/cca/mod.rs:126

  • The CCA RPV definition requires the tagged-bytes raw-value variant, but this accepts RawValueChoice::Masked as well. A masked raw value is not a valid cca.rpv; restrict this condition to Some(RawValueChoice::Bytes(_)).
        "cca.rpv" => m.mval.raw_value.is_some(),

corim/src/profile/cca/mod.rs:195

  • core_fields_match intentionally does not compare cryptokeys, but CCA uses these values as the software-component signer ID and ROTPK reference value. With the same mkey and otherwise valid shapes, a reference key and a different evidence key will reach this line and return true; compare the CCA cryptokeys explicitly before returning the verdict.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:195

  • For CCA configuration measurements, raw-value is a masked value whose comparison must apply the mask. core_fields_match compares RawValueChoice with exact equality, so a valid evidence value that differs only in unmasked bits is rejected. Add CCA-specific masked-raw-value matching instead of delegating this field to the generic matcher.
        Some(crate::validate::core_fields_match(reference, evidence))

corim/src/profile/cca/mod.rs:26

  • The new module advertises diagnosis labels for CCA mkey names, but the only profile diagnosis hook is for integer measurement-values-map extension keys and the diagnostic walker ignores structural mkey values. Consequently --diagnose neither labels nor validates these CCA names; either add structural-mkey diagnostic support or remove this promised behavior.
//! - identifying the CCA profile URI,
//! - validating the CCA-specific `mkey` names,
//! - providing diagnosis labels for those names,
//! - enforcing the CCA-specific measurement-map shapes.

corim/src/profile/cca/mod.rs:126

  • The realm CDDL also defines closed per-mkey maps: RIM/REM contain only digests, while RPV contains only raw-value. These branches only test presence, so extra fields can make an invalid realm measurement pass when the generic matcher ignores them. Reject fields outside the allowed shape for each realm key.
    match mkey.as_str() {
        "cca.rim" | "cca.rem0" | "cca.rem1" | "cca.rem2" | "cca.rem3" => {
            m.mval.digests.as_ref().is_some_and(|d| !d.is_empty())
        }
        "cca.rpv" => m.mval.raw_value.is_some(),

corim/src/profile/cca/mod.rs:132

  • The new public profile type and its new() constructor have no rustdoc, unlike the existing first-party PsaProfile and AzureProfile APIs. Add documentation for this public API before exposing the feature.
pub struct CcaPlatformProfile {

corim/src/profile/cca/mod.rs:151

  • The new public realm profile type and its new() constructor also lack rustdoc. Keep the public CCA API consistent with the documented first-party profile types.
pub struct CcaRealmProfile {

corim/src/profile/cca/mod.rs:100

  • CCA platform and manufacturing configuration maps require the masked raw-value variant (#6.563([value, mask])), but is_some() also accepts the plain tagged-bytes variant (and any additional mval fields). This lets malformed configuration measurements pass profile validation; require RawValueChoice::Masked and enforce the profile-specific map shape.
        "cca.platform-config" | "cca.platform-manufacturing-config" => m.mval.raw_value.is_some(),

corim/src/profile/cca/mod.rs:37

  • The draft-04 profile identifiers are http://arm.com/cca/ssd/1 (platform) and http://arm.com/cca/realm/1 (realm), not these tag:arm.com,2025... URIs. With the constants as written, a conforming CoRIM's profile lookup misses both registered implementations, so the new profile matching hooks are never selected.
/// Profile URI for CCA Platform endorsements.
pub const CCA_PLATFORM_PROFILE_URI: &str = "tag:arm.com,2025:endorsements/cca_platform#1.0.0";
/// Profile URI for CCA Realm endorsements.
pub const CCA_REALM_PROFILE_URI: &str = "tag:arm.com,2025:endorsements/cca_realm#1.0.0";

corim/src/profile/cca/mod.rs:46

  • The draft's platform reference-value mkeys are tagged maps (#601 for the software-component identifier and #602 for platform-config), not these text names; the attestation verification key is a separate attest-key triple rather than a cca.rotpk... measurement key. This recognizer therefore cannot match conforming platform CoMIDs and instead accepts a non-draft wire model. Supporting this requires adding the tagged mkey types/decoding and matching those structures.
        "cca.software-component" | "cca.platform-config" | "cca.platform-manufacturing-config" => {
            true
        }
        _ => {
            let Some(rest) = name.strip_prefix("cca.rotpk.") else {

corim/tests/profile_cca_tests.rs:19

  • These tests construct synthetic text mkeys and put realm values in digests; they do not encode/decode the draft wire forms (tagged #601/#602 mkeys, realm integrity-registers, and the registered profile URIs). The suite can therefore pass while conforming CCA examples are rejected or bypass the profile. Add fixture-based round-trip and matching tests for the draft examples.
fn measurement_with_mkey(mkey: &str, digest_val: &[u8]) -> MeasurementMap {
    MeasurementMap {
        mkey: Some(MeasuredElement::Text(mkey.into())),
        mval: MeasurementValuesMap {
            digests: Some(vec![Digest::new(7, digest_val.to_vec())]),

corim/tests/profile_cca_tests.rs:132

  • This test does not exercise the CCA structure validator: the reference uses cca.software-component while the evidence uses cca.rotpk.CM.2.3, so match_measurement returns at the mkey-mismatch branch before checking the malformed reference mval. Use the same mkey with an invalid mval on one side to cover the intended validation path.
fn platform_match_rejects_invalid_cca_structures() {
    let profile = CcaPlatformProfile::new();
    let reference = measurement_with_mkey("cca.software-component", &[0x11, 0x22, 0x33]);
    let evidence = rotpk_measurement("cca.rotpk.CM.2.3", &[0xAA; 32]);
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread corim/src/profile/cca/mod.rs
Copilot AI review requested due to automatic review settings September 17, 2026 22:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Correct ROTPK evidence is rejected because the implementation expects the reference-side cryptokey representation.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

corim/src/profile/cca/mod.rs:298

  • The evidence-side ROTPK shape is incorrect. In draft-ydb-rats-cca-endorsements-04 §3.1.3.3, endorsement/reference ROTPK IDs use cryptokeys, but the Platform Token evidence transformation stores pk-hash in raw-value as tagged bytes. Reusing is_cca_rotpk_mval here rejects correctly transformed evidence, and the later cryptokey equality check would reject it as well. Add an evidence validator for a single bytes raw-value of 32/48/64 bytes and compare those bytes against the reference's single cryptokey; update the ROTPK acceptance tests to use that evidence shape.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 17, 2026 22:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

ROTPK triples currently accept unrelated non-ROTPK measurements.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

corim/src/profile/cca/mod.rs:553

  • A ROTPK triple can still contain arbitrary non-ROTPK measurements: the counting loop skips unknown/non-text mkeys, and valid_rotpk_group skips them too, so one valid ROTPK plus tee.something returns true. This contradicts the §3.1.3.3 rule (and the intended “only ROTPK measurements” behavior) that each ROTPK array entry occupies its own reference triple. Require every measurement in this branch to have been counted as ROTPK.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 17, 2026 22:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

CCA matching can currently corroborate evidence whose environment violates the profile’s identity requirements.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

corim/src/validate.rs:347

  • Only the reference environment is profile-validated. A valid class-wide Platform reference (no instance) will therefore match evidence carrying a non-UEID/absent instance, because environment_matches treats the absent condition field as a wildcard; Realm evidence with an explicit instance is likewise accepted. The CCA evidence transformations require a RAND UEID for Platform evidence and no instance for Realm evidence. Add a defaulted profile hook for validating each evidence environment/claim and invoke it before matching, then implement the CCA rules there.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 17, 2026 22:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The advertised CLI integration has no CCA-specific effect because CLI paths do not consume the implemented validation and matching hooks.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

corim-cli/Cargo.toml:46

  • The new CLI feature does not currently make CCA measurements recognized or validated as described. The CLI registry is only queried for diagnose_mval_entry, mval_json_alias, and mval_json_name, but both CCA profiles leave those hooks at their default, and the CLI validation path never invokes the new matching/triple hooks. As a result, enabling cca has no CCA-specific CLI behavior. Please wire CCA recognition into a CLI-consumed hook/validation path, or remove the CLI feature and narrow the PR claim to library appraisal support.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 17, 2026 22:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Conditional endorsements bypass evidence validation, and Realm validation accepts unrecognized measurements.

Review details

Suppressed comments (3)

Previously missed (3) — in code that hasn't changed since the last review.

corim/src/profile.rs:330

  • This evidence-level hook is only consulted by match_reference_values_with_profile; apply_endorsement_series_with_profile still filters evidence solely with environment_matches (validate.rs:448-461). Consequently, conditional endorsements can use CCA evidence that this profile rejects (for example, Platform evidence without a RAND UEID). Apply evidence_claim_valid in that appraisal path as well and add a regression test.
    corim/src/profile/cca/mod.rs:634
  • These continue paths let a Realm triple containing a valid cca.rim plus an arbitrary non-text or unknown measurement pass validation. Draft v04 §3.2.3 says every Realm measurement-map mkey MUST be one of cca.rim, cca.rpv, or cca.rem0cca.rem3; reject unrecognized maps instead of ignoring them.
    corim/src/profile/cca/mod.rs:46
  • The new profile URI constants lack the governing draft sections, and the mkey string constants below have the same omission. These are wire-protocol values, so document the source beside each constant (profile URIs: draft v04 §3.1.1/§3.2.1; mkeys: §3.1.3.1–§3.1.3.4 and §3.2.3) to keep the definitions auditable.
  • Files reviewed: 10/10 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Copilot AI review requested due to automatic review settings September 17, 2026 23:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

CCA attestation-key endorsements remain exempt from profile-specific validation.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread corim-cli/src/main.rs
Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 17, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Platform profile validation accepts otherwise valid triples containing unrecognized measurements, and the claimed diagnosis support is not implemented.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

corim/src/profile/cca/mod.rs:555

  • Reject measurements whose mkey is absent, non-text, or not a recognized CCA Platform key instead of skipping them. As written, a triple containing valid cca.software-component and cca.platform-config entries plus an arbitrary tee.something entry still passes profile validation. Draft-04 §3.1.3 defines the platform reference triple in terms of these CCA measurement maps and requires it to completely describe the platform measurements; the Realm validator below already fails closed for unrecognized entries.

corim/tests/profile_cca_tests.rs:964

  • This test confirms that the CCA profiles provide no diagnosis labeling—the hook returns None, and diagnose_mval_entry is only called for integer measurement-values-map extensions, not text measurement-map.mkey values. This conflicts with the PR description's claims that diagnosis support and diagnosis-labeling tests are included. Either add an mkey-aware diagnosis path or update the PR description to limit the feature to recognition, validation, and matching.
fn diagnosis_does_not_treat_mkeys_as_mval_extensions() {
    let profile = CcaPlatformProfile::new();
    assert_eq!(
        profile.diagnose_mval_entry(
            -999,
            &corim::cbor::value::Value::Text("cca.software-component".into())
        ),
        None
  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants