Skip to content

Commit

Permalink
Extra validation for w3c credentials and presentations (#325)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Whitehead <cywolf@gmail.com>
  • Loading branch information
andrewwhitehead authored Feb 12, 2024
1 parent 9481ae0 commit bae5868
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/data_types/w3c/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<W3CCredential>(cred);
assert!(res.is_err());
}
}
13 changes: 13 additions & 0 deletions src/data_types/w3c/presentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<W3CPresentation>(pres);
assert!(res.is_err());
}
}
64 changes: 64 additions & 0 deletions src/services/w3c/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}

Expand Down Expand Up @@ -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<SchemaId, Schema>,
cred_defs: HashMap<CredentialDefinitionId, CredentialDefinition>,
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<SchemaId, Schema>,
mut cred_defs: HashMap<CredentialDefinitionId, CredentialDefinition>,
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());
}
}

0 comments on commit bae5868

Please sign in to comment.