Add Arm CCA profile support - #75
a-trikalinou wants to merge 18 commits into
Conversation
Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>
There was a problem hiding this comment.
🟡 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-ccaand 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 forCcaRealmProfile::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_nameclones 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; returnOption<&str>and uses.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
7and5literals. 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
cryptokeysbyte lengths (32,48, and64) 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-bytessigner 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. Requirekeys.len() == 1here, 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-byto be absent, but this validator never checksm.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 withauthorized_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-byto be absent, but the realm validator does not enforce that constraint. Sincecore_fields_matchdoes 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.
There was a problem hiding this comment.
🟡 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_matchexplicitly omitscryptokeys(seevalidate.rs:603-607), but this profile uses that field as the required value forcca.rotpk.*andcca.software-component. As a result, two valid ROTPK measurements with the same mkey but different keys both returnSome(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_entryis called only for unknown integerMeasurementValuesMap::extra_entries; the CCA names are structuralmeasurement-map.mkeyvalues, and the diagnose walker currently ignores that value. Therefore--diagnosenever 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 existingPsaProfileAPI (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 likecca.rem00even though the profile defines onlycca.rem0throughcca.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 requiresClone,Debug, andPartialEqat minimum (andEqis valid here becauseProfileChoiceis 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
Debuginstead of the required clone/equality traits. Add the standard derives, includingEqfor 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 usescca.software-componentwhile the evidence usescca.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
| /// 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 |
| /// Recognize a CCA Realm measurement key. | ||
| pub fn is_cca_realm_mkey(name: &str) -> bool { | ||
| match name { | ||
| "cca.rim" | "cca.rpv" => true, | ||
| _ => { |
| "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>
There was a problem hiding this comment.
🔵 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/1andhttp://arm.com/cca/realm/1, not thetag:arm.com,2025:...#1.0.0strings here. A real draft-04 CoRIM therefore cannot be looked up inProfileRegistry, 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(...)), notMeasuredElement::Textvalues. Restricting this helper to text means actual draft platform measurements returnNonebefore the CCA matcher runs; supporting the profile requires handling those tagged map forms, not just parsingcca.*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 textmkeys. Consequentlymkey_namereturnsNonefor 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, butcore_fields_matchdeliberately 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 returnSome(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_entryis called only for integermval.extra_entries, while CCA names are inmeasurement-map.mkeyand 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.rem00andcca.rem003because they parse to an index in range, butis_valid_cca_realm_measurementonly accepts the exactcca.rem0throughcca.rem3names. 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
7and5literals. 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 existingPsaProfile/AzureProfileAPIs 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-componentwhile the evidence usescca.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
There was a problem hiding this comment.
🔵 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_matchexplicitly excludescryptokeysand comparesraw-valueby 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_matchintentionally omitsMeasurementValuesMap::cryptokeys. Forcca.rotpk.*, the cryptokey is the only measurement value beyond the mkey, and forcca.software-componentit is part of the value, so different keys can still returnSome(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_entryis only called for unknown integer entries inMeasurementValuesMap::extra_entries; themeasurement-mapkey 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 frominspect_measurement_mapinstead 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 as01, sois_cca_realm_mkey("cca.rem01")returns true although the profile only definescca.rem0throughcca.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 samekeys.len() == 1constraint 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-digestrequires 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-valueto be the tagged-masked-raw-value variant (#6.563), butis_some()also accepts plain tagged bytes and does not reject the other fields orauthorized-bythat the CCA map forbids. A plainRawValueChoice::Bytestherefore 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 tou8and checking only the numeric bounds accepts values such ascca.rotpk.CM.02.03, allowing a non-conformingmkeythrough. 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 forRawValueChoice::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_valueby exact!=and cannot apply(evidence & mask) == (value & mask). Delegating this pair tocore_fields_matchwill 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-componentversuscca.rotpk.CM.2.3) before reachingis_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
There was a problem hiding this comment.
🟡 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, butcore_fields_matchintentionally skips that field. Thus two otherwise-valid measurements with the same mkey/digests and different singleCryptoKey::Bytesvalues returnSome(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-50andprofile/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-50andprofile/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
Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>
There was a problem hiding this comment.
🟡 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_registryincorim-cli/src/convert.rs:264-274, and it still registers only Intel, Azure, and PSA. As a result, theconvertsubcommand 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-digesttype 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::Maskedas well. A masked raw value is not a validcca.rpv; restrict this condition toSome(RawValueChoice::Bytes(_)).
"cca.rpv" => m.mval.raw_value.is_some(),
corim/src/profile/cca/mod.rs:195
core_fields_matchintentionally does not comparecryptokeys, 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 returntrue; 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-valueis a masked value whose comparison must apply the mask.core_fields_matchcomparesRawValueChoicewith 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-mapextension keys and the diagnostic walker ignores structuralmkeyvalues. Consequently--diagnoseneither 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 onlyraw-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-partyPsaProfileandAzureProfileAPIs. 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])), butis_some()also accepts the plain tagged-bytes variant (and any additional mval fields). This lets malformed configuration measurements pass profile validation; requireRawValueChoice::Maskedand 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) andhttp://arm.com/cca/realm/1(realm), not thesetag: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 (
#601for the software-component identifier and#602for platform-config), not these text names; the attestation verification key is a separate attest-key triple rather than acca.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/#602mkeys, realmintegrity-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-componentwhile the evidence usescca.rotpk.CM.2.3, somatch_measurementreturns 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
There was a problem hiding this comment.
🔵 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 storespk-hashinraw-valueas tagged bytes. Reusingis_cca_rotpk_mvalhere rejects correctly transformed evidence, and the later cryptokey equality check would reject it as well. Add an evidence validator for a single bytesraw-valueof 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
There was a problem hiding this comment.
🔵 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_groupskips them too, so one valid ROTPK plustee.somethingreturnstrue. 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
There was a problem hiding this comment.
🔵 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, becauseenvironment_matchestreats 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
There was a problem hiding this comment.
🔵 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, andmval_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, enablingccahas 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
There was a problem hiding this comment.
🔵 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_profilestill filters evidence solely withenvironment_matches(validate.rs:448-461). Consequently, conditional endorsements can use CCA evidence that this profile rejects (for example, Platform evidence without a RAND UEID). Applyevidence_claim_validin that appraisal path as well and add a regression test.
corim/src/profile/cca/mod.rs:634 - These
continuepaths let a Realm triple containing a validcca.rimplus an arbitrary non-text or unknown measurement pass validation. Draft v04 §3.2.3 says every Realmmeasurement-mapmkey MUST be one ofcca.rim,cca.rpv, orcca.rem0…cca.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
There was a problem hiding this comment.
🟡 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
Co-authored-by: a-trikalinou <139903738+a-trikalinou@users.noreply.github.com>
There was a problem hiding this comment.
🔵 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
mkeyis absent, non-text, or not a recognized CCA Platform key instead of skipping them. As written, a triple containing validcca.software-componentandcca.platform-configentries plus an arbitrarytee.somethingentry 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, anddiagnose_mval_entryis only called for integermeasurement-values-mapextensions, not textmeasurement-map.mkeyvalues. 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
This pull request adds support for the Arm CCA (Confidential Compute Architecture) endorsements profile to the
corimandcorim-clicrates. 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-ccafeature to thecorimcrate, 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
ccaprofile in thecorim-clicrate, making it available as a default feature and ensuring that the CLI recognizes and processes CCA measurements. [1] [2] [3] [4]Testing:
Related Issues
Checklist
cargo test --allpassescargo fmt --all -- --checkpassescargo clippy --all -- -D warningspasses