fix(notary): validate claim response formats#405
Conversation
Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 500340828a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for format in &claim.formats { | ||
| if format != FORMAT_CLAIM_RESULT_JSON && format != FORMAT_CCCEV_JSONLD { | ||
| return Err(EvidenceConfigError::UnsupportedClaimFormat { |
There was a problem hiding this comment.
Stop selecting SD-JWT as an evaluation format
After this loop rejects application/dc+sd-jwt for every claim, credential-enabled deployments still expose it as an enabled format because runtime/catalog.rs inserts FORMAT_SD_JWT_VC whenever credential profiles exist, and api/request.rs feeds all enabled ids into evaluation content negotiation. A caller sending Accept: application/dc+sd-jwt, application/vnd.registry-notary.claim-result+json;q=0.5 will have negotiation select SD-JWT and then fail with FormatUnsupported, even though the canonical evaluation response is acceptable; the catalog/negotiation path needs to exclude credential-only formats for evaluation responses.
Useful? React with 👍 / 👎.
| let supported_by_claim = allowed_claims | ||
| .iter() | ||
| .any(|claim| claim.formats.iter().any(|candidate| candidate == format)); | ||
| let supported_by_profile = allowed_profiles | ||
| .iter() | ||
| .any(|profile| profile.format == *format); | ||
| if !supported_by_claim && !supported_by_profile { | ||
| if !supported_by_claim { |
There was a problem hiding this comment.
Require canonical format for subject-access issuance
When subject_access.allowed_operations.issue_credential is true, this validation still accepts an allow-list such as only application/ld+json; profile="cccev" because it only checks that some allowed claim supports the format. The OID4VCI credential path now creates its internal evaluation with FORMAT_CLAIM_RESULT_JSON, and require_subject_access_evaluation_for_operation denies that request if the canonical format is not in subject_access.allowed_formats, so the configuration loads successfully but all subject-access credential issuance is rejected with FormatDenied; validate that the canonical evaluation format is allowed whenever issuance is enabled.
Useful? React with 👍 / 👎.
| let supported_by_claim = allowed_claims | ||
| .iter() | ||
| .any(|claim| claim.formats.iter().any(|candidate| candidate == format)); | ||
| let supported_by_profile = allowed_profiles | ||
| .iter() | ||
| .any(|profile| profile.format == *format); | ||
| if !supported_by_claim && !supported_by_profile { | ||
| if !supported_by_claim { |
There was a problem hiding this comment.
Require canonical format for delegated credential issuance
For delegated relationships that list credential_profiles, this still accepts allowed_formats containing only the CCCEV renderer as long as an allowed claim supports it. Direct delegated credential issuance now requires the stored evaluation to be application/vnd.registry-notary.claim-result+json, so such a configuration loads but cannot produce an issuable delegated evaluation: canonical evaluation is denied by the relationship allow-list, while CCCEV evaluation is later rejected before signing. Require the canonical format whenever delegated credential profiles are configured.
Useful? React with 👍 / 👎.
Summary
Root cause
The pre-1.0 configuration mixed two trust surfaces: formats used to evaluate registry-backed claims and formats used to render credentials. That allowed
application/dc+sd-jwtto appear as a claim evaluation format even though issuance needs a canonical stored registry evaluation first.User and developer impact
formatskeeps the canonical defaultsubject_access.allowed_formatsgoverns evaluation renderers onlycredential_profilescontinues to govern SD-JWT credential outputThis is the current-base replacement for stale draft PR #352 and targets the temporary
release/1.0integration branch.Validation
6abefa9eb01e2a7df0088ac65a46502d7f67dbda; Cargo.lock unchangedMerge only after the full remote matrix is green on exact head
500340828a03f1dc41994cc2d88cd9e0088579cf.