From c6433d12ec7de55ce8f6f6c3c572f084f1d05b32 Mon Sep 17 00:00:00 2001 From: Andrew Whitehead Date: Thu, 8 Feb 2024 11:44:20 -0800 Subject: [PATCH 1/2] verify match with presented issuer ID and verification method Signed-off-by: Andrew Whitehead --- src/services/w3c/verifier.rs | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/services/w3c/verifier.rs b/src/services/w3c/verifier.rs index 0d81b2cd..867c4746 100644 --- a/src/services/w3c/verifier.rs +++ b/src/services/w3c/verifier.rs @@ -370,6 +370,24 @@ fn check_request_data( )?; } + for (cred, proof) in presentation + .verifiable_credential + .as_slice() + .iter() + .zip(credential_proofs) + { + let Some(cred_def_issuer) = cred_defs.get(&proof.cred_def_id).map(|cd| &cd.issuer_id) else { + return Err(err_msg!("Missing credential definition")); + }; + if cred_def_issuer != &cred.issuer { + return Err(err_msg!("Inconsistent issuer ID")); + } + let di_proof = cred.get_data_integrity_proof()?; + if di_proof.verification_method != proof.cred_def_id.0 { + return Err(err_msg!("Inconsistent credential definition ID")); + } + } + Ok(()) } @@ -892,4 +910,50 @@ pub(crate) mod tests { .unwrap_err(); assert_eq!(ErrorKind::Input, err.kind()); } + + #[rstest] + #[case(_presentation_request_with_single_attribute())] + fn test_check_cred_def_id_mismatch_fails( + schemas: HashMap, + cred_defs: HashMap, + presentation: W3CPresentation, + #[case] presentation_request: PresentationRequestPayload, + ) { + let mut cred_proofs = presentation.credential_proofs(); + cred_proofs[0].cred_def_id = "other:id".try_into().unwrap(); + + let err = check_request_data( + &presentation_request, + &presentation, + &schemas, + &cred_defs, + None, + &cred_proofs, + ) + .unwrap_err(); + assert_eq!(ErrorKind::Input, err.kind()); + } + + #[rstest] + #[case(_presentation_request_with_single_attribute())] + fn test_check_issuer_id_mismatch_fails( + schemas: HashMap, + mut cred_defs: HashMap, + presentation: W3CPresentation, + #[case] presentation_request: PresentationRequestPayload, + ) { + let cred_def = cred_defs.iter_mut().next().unwrap().1; + cred_def.issuer_id = "other:id".try_into().unwrap(); + + let err = check_request_data( + &presentation_request, + &presentation, + &schemas, + &cred_defs, + None, + &presentation.credential_proofs(), + ) + .unwrap_err(); + assert_eq!(ErrorKind::Input, err.kind()); + } } From 102702d33a5225556cacba52264028c385f9c48b Mon Sep 17 00:00:00 2001 From: Andrew Whitehead Date: Thu, 8 Feb 2024 11:44:38 -0800 Subject: [PATCH 2/2] reject unknown attributes in w3c credentials and presentations Signed-off-by: Andrew Whitehead --- src/data_types/w3c/credential.rs | 13 +++++++++++++ src/data_types/w3c/presentation.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/data_types/w3c/credential.rs b/src/data_types/w3c/credential.rs index 2d337b7c..ef8c848a 100644 --- a/src/data_types/w3c/credential.rs +++ b/src/data_types/w3c/credential.rs @@ -20,6 +20,7 @@ use crate::Result; /// Note, that this definition is tied to AnonCreds W3C form #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct W3CCredential { #[serde(rename = "@context")] pub context: Contexts, @@ -162,4 +163,16 @@ mod tests { serde_json::from_str(&out_json).expect("Error deserializing w3c credential"); assert_eq!(cred1, cred2); } + + #[test] + fn serde_w3c_credential_deny_unknown() { + let cred_json = include_str!("sample_credential.json"); + let mut cred: serde_json::Value = + serde_json::from_str(cred_json).expect("Error deserializing w3c credential"); + cred.as_object_mut() + .unwrap() + .insert("prop".into(), "val".into()); + let res = serde_json::from_value::(cred); + assert!(res.is_err()); + } } diff --git a/src/data_types/w3c/presentation.rs b/src/data_types/w3c/presentation.rs index 93e909bb..52f1723e 100644 --- a/src/data_types/w3c/presentation.rs +++ b/src/data_types/w3c/presentation.rs @@ -11,6 +11,7 @@ use crate::Result; /// Note, that this definition is tied to AnonCreds W3C form #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] +#[serde(deny_unknown_fields)] pub struct W3CPresentation { #[serde(rename = "@context")] pub context: Contexts, @@ -69,4 +70,16 @@ mod tests { serde_json::from_str(&out_json).expect("Error deserializing w3c presentation"); assert_eq!(pres1, pres2); } + + #[test] + fn serde_w3c_presentation_deny_unknown() { + let pres_json = include_str!("sample_presentation.json"); + let mut pres: serde_json::Value = + serde_json::from_str(pres_json).expect("Error deserializing w3c presentation"); + pres.as_object_mut() + .unwrap() + .insert("prop".into(), "val".into()); + let res = serde_json::from_value::(pres); + assert!(res.is_err()); + } }