Repository navigation
Fix RDF canonicalization and selective disclosure over Data Integrity proof sets - #709
Conversation
timothee-haudebourg
left a comment
There was a problem hiding this comment.
Approving, with just a request to select the selective proof between all the proofs, not just the first two.
| // A proof set may pair full-document signatures (e.g. `ecdsa-rdfc-2019`) | ||
| // with one SD base proof (e.g. `ecdsa-sd-2023`). Only the SD proof can | ||
| // be derived from, so select it and ignore the others. | ||
| let mut selective = self.proofs.iter().filter(|p| p.suite().is_selective()); | ||
| match (selective.next(), selective.next()) { | ||
| (Some(proof), None) => { | ||
| proof | ||
| .suite() | ||
| .select(&self.claims, proof.borrowed(), params, options) | ||
| .await | ||
| } | ||
| Some(_) => Err(SelectionError::AmbiguousProof), | ||
| None => Err(SelectionError::MissingProof), | ||
| // More than one derivable proof. | ||
| (Some(_), Some(_)) => Err(SelectionError::AmbiguousProof), | ||
| // No derivable proof (empty set, or only full-document signatures). | ||
| (None, _) => Err(SelectionError::MissingProof), |
There was a problem hiding this comment.
Hmm this is weird. Why do you only look at the first two proofs? You should iterate over all the proofs:
let mut selected = None;
for proof in &self.proofs {
if proof.suite().is_selective() && selected.replace(proof).is_some() {
return Err(AmbiguousProof)
}
}
select.ok_or(MissingProof).select(...).await| // Sort by N-Quad serialization, as RDFC-1.0 and the verifier do. The | ||
| // structural `LexicalQuad` order differs when IRI and blank-node subjects | ||
| // mix (`_` sorts after `<`), which would desync `mandatory_indexes`. | ||
| canonical_quads.sort_by_cached_key(|quad| ssi_rdf::NQuadsStatement(quad).to_string()); |
There was a problem hiding this comment.
Sounds like this is an issue with rdf-types more than anything. Let's keep it as a work around for now, but can you flag that?
| // An already-canonical `related` is appended to the path as-is. | ||
| // Recursing on it instead re-issues a temporary identifier in | ||
| // 5.4.5 and corrupts the path (wrong labels for symmetric | ||
| // blank-node structures, e.g. repeated `@list`s). |
There was a problem hiding this comment.
sounds like an AI comment. You don't need to justify why you don't do something.
| .as_ref() | ||
| { | ||
| recursion_list.push((*canonical_identifier).to_owned()); | ||
| path.push_str(canonical_identifier.as_str()); |
There was a problem hiding this comment.
I double checked the spec and indeed it should be added to path. I see no version of the spec that says to add to recursion_list, so it's a genuine and probably old bug that we have in there. I don't even know how we missed it with all the tests that we have, we must be lucky.
Description
Fixes several issues found while verifying and deriving OpenBadge v3 credentials issued by other Data Integrity implementations.
to_rdf. Thelinked_datapath rewrote context-coerced datatypes (for example https://www.w3.org/2001/XMLSchema#boolean) to the http form, so signatures over such quads never verified. Applies to the standard suites,ecdsa-sd-2023andbbs-2023.ssi-json-ld. Undefined terms raise an error as required by Data Integrity 2.4.3, never silently dropped.DataIntegrity::selectpicks the single selective proof from a proof set and ignores full-document signatures. NewSelectiveCryptographicSuite::is_selectivehas a default of true, so existing implementors are unaffected.Compatibility
MissingProofinstead ofNonSelectiveSuiteorAmbiguousProofwhen no selective proof is present.T: Serialize, which all in-tree claim types already satisfy.Optional section
ssi-json-ldand its use incanonicalization.rs,ecdsa_sd_2023/transformation/derive.rsandbbs_2023/transformation/derived.rs.sd-primitives/canonicalize.rsand the proof selection change incore/src/lib.rs, since both affect which quads the mandatory indexes point at.Tested