diff --git a/did-ethr/src/lib.rs b/did-ethr/src/lib.rs index 8f3b9fc8c..dd2573c65 100644 --- a/did-ethr/src/lib.rs +++ b/did-ethr/src/lib.rs @@ -446,34 +446,35 @@ mod tests { issue_options.verification_method = Some(URI::String(did.to_string() + "#controller")); } eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); let proof = vc - .generate_proof(&key, &issue_options, &DIDEthr) + .generate_proof(&key, &issue_options, &DIDEthr, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDEthr).await; + let verification_result = vc.verify(None, &DIDEthr, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDEthr).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDEthr, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); use ssi::ldp::ProofSuite; let proof_bad = ssi::ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - .sign(&vc_no_proof, &issue_options, &DIDEthr, &other_key, None) + .sign(&vc_no_proof, &issue_options, &DIDEthr, &mut context_loader, &other_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDEthr).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDEthr, &mut context_loader).await.errors.len() > 0); // Make it into a VP use ssi::one_or_many::OneOrMany; @@ -497,13 +498,13 @@ mod tests { vp_issue_options.verification_method = Some(URI::String(did.to_string() + "#controller")); vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); let vp_proof = vp - .generate_proof(&key, &vp_issue_options, &DIDEthr) + .generate_proof(&key, &vp_issue_options, &DIDEthr, &mut context_loader) .await .unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDEthr).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDEthr, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); @@ -518,14 +519,14 @@ mod tests { }, _ => unreachable!(), } - let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDEthr).await; + let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDEthr, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:example:bad".to_string())); - assert!(vp2.verify(None, &DIDEthr).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDEthr, &mut context_loader).await.errors.len() > 0); } #[tokio::test] @@ -533,7 +534,8 @@ mod tests { use ssi::vc::Credential; let vc: Credential = serde_json::from_str(include_str!("../tests/vc.jsonld")).unwrap(); eprintln!("vc {:?}", vc); - let verification_result = vc.verify(None, &DIDEthr).await; + let mut context_loader = ssi::jsonld::ContextLoader::default(); + let verification_result = vc.verify(None, &DIDEthr, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } diff --git a/did-key/src/lib.rs b/did-key/src/lib.rs index caaad46d7..93b870d76 100644 --- a/did-key/src/lib.rs +++ b/did-key/src/lib.rs @@ -508,22 +508,23 @@ mod tests { let did = DIDKey.generate(&Source::Key(&key)).unwrap(); let verification_method = get_verification_method(&did, &DIDKey).await.unwrap(); let mut issue_options = LinkedDataProofOptions::default(); + let mut context_loader = ssi::jsonld::ContextLoader::default(); vc.issuer = Some(Issuer::URI(URI::String(did.clone()))); issue_options.verification_method = Some(URI::String(verification_method)); let proof = vc - .generate_proof(&key, &issue_options, &DIDKey) + .generate_proof(&key, &issue_options, &DIDKey, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDKey).await; + let verification_result = vc.verify(None, &DIDKey, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer is verified vc.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc.verify(None, &DIDKey).await.errors.len() > 0); + assert!(vc.verify(None, &DIDKey, &mut context_loader).await.errors.len() > 0); } #[async_std::test] @@ -547,21 +548,22 @@ mod tests { let verification_method = get_verification_method(&did, &DIDKey).await.unwrap(); let mut issue_options = LinkedDataProofOptions::default(); + let mut context_loader = ssi::jsonld::ContextLoader::default(); issue_options.verification_method = Some(URI::String(verification_method)); let proof = vc - .generate_proof(&key, &issue_options, &DIDKey) + .generate_proof(&key, &issue_options, &DIDKey, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDKey).await; + let verification_result = vc.verify(None, &DIDKey, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer is verified vc.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc.verify(None, &DIDKey).await.errors.len() > 0); + assert!(vc.verify(None, &DIDKey, &mut context_loader).await.errors.len() > 0); } #[async_std::test] @@ -585,20 +587,21 @@ mod tests { let verification_method = get_verification_method(&did, &DIDKey).await.unwrap(); let mut issue_options = LinkedDataProofOptions::default(); + let mut context_loader = ssi::jsonld::ContextLoader::default(); issue_options.verification_method = Some(URI::String(verification_method)); let proof = vc - .generate_proof(&key, &issue_options, &DIDKey) + .generate_proof(&key, &issue_options, &DIDKey, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDKey).await; + let verification_result = vc.verify(None, &DIDKey, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer is verified vc.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc.verify(None, &DIDKey).await.errors.len() > 0); + assert!(vc.verify(None, &DIDKey, &mut context_loader).await.errors.len() > 0); } } diff --git a/did-pkh/src/lib.rs b/did-pkh/src/lib.rs index 0aebd7727..1599eddec 100644 --- a/did-pkh/src/lib.rs +++ b/did-pkh/src/lib.rs @@ -917,6 +917,7 @@ mod tests { ..Default::default() }; eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); /* let proof = vc.generate_proof(&key, &issue_options).await.unwrap(); @@ -924,36 +925,36 @@ mod tests { // Sign with proof suite directly because there is not currently a way to do it // for Eip712Signature2021 in did-pkh otherwise. let proof = proof_suite - .sign(&vc, &issue_options, &DIDPKH, &key, None) + .sign(&vc, &issue_options, &DIDPKH, &mut context_loader, &key, None) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); println!("VC: {}", serde_json::to_string_pretty(&vc).unwrap()); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDPKH).await; + let verification_result = vc.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:pkh:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let proof_bad = proof_suite - .sign(&vc_no_proof, &issue_options, &DIDPKH, &wrong_key, None) + .sign(&vc_no_proof, &issue_options, &DIDPKH, &mut context_loader, &wrong_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); // Mess with proof signature to make verify fail let mut vc_fuzzed = vc.clone(); fuzz_proof_value(&mut vc_fuzzed.proof); - let vp_verification_result = vc_fuzzed.verify(None, &DIDPKH).await; + let vp_verification_result = vc_fuzzed.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); @@ -978,27 +979,27 @@ mod tests { vp_issue_options.eip712_domain = vp_eip712_domain_opt; // let vp_proof = vp.generate_proof(&key, &vp_issue_options).await.unwrap(); let vp_proof = proof_suite - .sign(&vp, &vp_issue_options, &DIDPKH, &key, None) + .sign(&vp, &vp_issue_options, &DIDPKH, &mut context_loader, &key, None) .await .unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDPKH).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); // Mess with proof signature to make verify fail let mut vp_fuzzed = vp.clone(); fuzz_proof_value(&mut vp_fuzzed.proof); - let vp_verification_result = vp_fuzzed.verify(Some(vp_issue_options), &DIDPKH).await; + let vp_verification_result = vp_fuzzed.verify(Some(vp_issue_options), &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // Test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:pkh:example:bad".to_string())); - assert!(vp2.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); } async fn credential_prepare_complete_verify_did_pkh_tz( @@ -1030,9 +1031,10 @@ mod tests { ..Default::default() }; eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); let prep = proof_suite - .prepare(&vc, &issue_options, &DIDPKH, &key, None) + .prepare(&vc, &issue_options, &DIDPKH, &mut context_loader, &key, None) .await .unwrap(); @@ -1044,29 +1046,29 @@ mod tests { println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDPKH).await; + let verification_result = vc.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:pkh:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let proof_bad = proof_suite - .sign(&vc_no_proof, &issue_options, &DIDPKH, &wrong_key, None) + .sign(&vc_no_proof, &issue_options, &DIDPKH, &mut context_loader, &wrong_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); // Mess with proof signature to make verify fail let mut vc_fuzzed = vc.clone(); fuzz_proof_value(&mut vc_fuzzed.proof); - let vp_verification_result = vc_fuzzed.verify(None, &DIDPKH).await; + let vp_verification_result = vc_fuzzed.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); @@ -1090,7 +1092,7 @@ mod tests { vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); let prep = proof_suite - .prepare(&vp, &vp_issue_options, &DIDPKH, &key, None) + .prepare(&vp, &vp_issue_options, &DIDPKH, &mut context_loader, &key, None) .await .unwrap(); let sig = sign_tezos(&prep, algorithm, &key); @@ -1098,21 +1100,21 @@ mod tests { vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDPKH).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); // Mess with proof signature to make verify fail let mut vp_fuzzed = vp.clone(); fuzz_proof_value(&mut vp_fuzzed.proof); - let vp_verification_result = vp_fuzzed.verify(Some(vp_issue_options), &DIDPKH).await; + let vp_verification_result = vp_fuzzed.verify(Some(vp_issue_options), &DIDPKH, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // Test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:pkh:example:bad".to_string())); - assert!(vp2.verify(None, &DIDPKH).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDPKH, &mut context_loader).await.errors.len() > 0); } fn sign_tezos(prep: &ssi::ldp::ProofPreparation, algorithm: Algorithm, key: &JWK) -> String { @@ -1433,7 +1435,8 @@ mod tests { async fn test_verify_vc(vc_str: &str, num_warnings: usize) { let mut vc = ssi::vc::Credential::from_json_unsigned(vc_str).unwrap(); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDPKH).await; + let mut context_loader = ssi::jsonld::ContextLoader::default(); + let verification_result = vc.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); assert_eq!(verification_result.warnings.len(), num_warnings); @@ -1441,7 +1444,7 @@ mod tests { let mut map = std::collections::HashMap::new(); map.insert("foo".to_string(), serde_json::json!("bar")); vc.property_set = Some(map); - let verification_result = vc.verify(None, &DIDPKH).await; + let verification_result = vc.verify(None, &DIDPKH, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.len() > 0); } diff --git a/did-sol/src/lib.rs b/did-sol/src/lib.rs index 3122a6c74..61ed3e594 100644 --- a/did-sol/src/lib.rs +++ b/did-sol/src/lib.rs @@ -274,34 +274,35 @@ mod tests { issue_options.verification_method = Some(URI::String(did.to_string() + "#controller")); } eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); let proof = vc - .generate_proof(&key, &issue_options, &DIDSol) + .generate_proof(&key, &issue_options, &DIDSol, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDSol).await; + let verification_result = vc.verify(None, &DIDSol, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDSol).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDSol, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); use ssi::ldp::ProofSuite; let proof_bad = ssi::ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - .sign(&vc_no_proof, &issue_options, &DIDSol, &other_key, None) + .sign(&vc_no_proof, &issue_options, &DIDSol, &mut context_loader, &other_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDSol).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDSol, &mut context_loader).await.errors.len() > 0); // Make it into a VP use ssi::one_or_many::OneOrMany; @@ -324,14 +325,15 @@ mod tests { vp.holder = Some(URI::String(did.to_string())); vp_issue_options.verification_method = Some(URI::String(did.to_string() + "#controller")); vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vp_proof = vp - .generate_proof(&key, &vp_issue_options, &DIDSol) + .generate_proof(&key, &vp_issue_options, &DIDSol, &mut context_loader) .await .unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDSol).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDSol, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); @@ -346,14 +348,14 @@ mod tests { }, _ => unreachable!(), } - let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDSol).await; + let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDSol, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:example:bad".to_string())); - assert!(vp2.verify(None, &DIDSol).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDSol, &mut context_loader).await.errors.len() > 0); } /* diff --git a/did-tezos/src/lib.rs b/did-tezos/src/lib.rs index b4702ce5d..435739e39 100644 --- a/did-tezos/src/lib.rs +++ b/did-tezos/src/lib.rs @@ -784,6 +784,7 @@ mod tests { issue_options.verification_method = Some(URI::String(did.to_string() + "#blockchainAccountId")); eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); // let proof = vc.generate_proof(&key, &issue_options, &DIDTZ).await.unwrap(); let proof_str = r###" @@ -854,26 +855,26 @@ mod tests { println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &didtz).await; + let verification_result = vc.verify(None, &didtz, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &didtz).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &didtz, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); use ssi::ldp::ProofSuite; let proof_bad = ssi::ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - .sign(&vc_no_proof, &issue_options, &didtz, &other_key, None) + .sign(&vc_no_proof, &issue_options, &didtz, &mut context_loader, &other_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &didtz).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &didtz, &mut context_loader).await.errors.len() > 0); // Make it into a VP use ssi::one_or_many::OneOrMany; @@ -898,6 +899,7 @@ mod tests { Some(URI::String(did.to_string() + "#blockchainAccountId")); vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); eprintln!("vp: {}", serde_json::to_string_pretty(&vp).unwrap()); + let mut context_loader = ssi::jsonld::ContextLoader::default(); // let vp_proof = vp.generate_proof(&key, &vp_issue_options, &DIDTZ).await.unwrap(); let vp_proof_str = r###" { @@ -968,7 +970,7 @@ mod tests { vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &didtz).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &didtz, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); @@ -983,14 +985,14 @@ mod tests { }, _ => unreachable!(), } - let vp_verification_result = vp1.verify(Some(vp_issue_options), &didtz).await; + let vp_verification_result = vp1.verify(Some(vp_issue_options), &didtz, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:example:bad".to_string())); - assert!(vp2.verify(None, &didtz).await.errors.len() > 0); + assert!(vp2.verify(None, &didtz, &mut context_loader).await.errors.len() > 0); } #[tokio::test] @@ -1018,34 +1020,35 @@ mod tests { issue_options.verification_method = Some(URI::String(did.to_string() + "#blockchainAccountId")); eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); let proof = vc - .generate_proof(&key, &issue_options, &DIDTZ) + .generate_proof(&key, &issue_options, &DIDTZ, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDTZ).await; + let verification_result = vc.verify(None, &DIDTZ, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); use ssi::ldp::ProofSuite; let proof_bad = ssi::ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - .sign(&vc_no_proof, &issue_options, &DIDTZ, &other_key, None) + .sign(&vc_no_proof, &issue_options, &DIDTZ, &mut context_loader, &other_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); // Make it into a VP use ssi::one_or_many::OneOrMany; @@ -1070,14 +1073,15 @@ mod tests { Some(URI::String(did.to_string() + "#blockchainAccountId")); vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); eprintln!("vp: {}", serde_json::to_string_pretty(&vp).unwrap()); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vp_proof = vp - .generate_proof(&key, &vp_issue_options, &DIDTZ) + .generate_proof(&key, &vp_issue_options, &DIDTZ, &mut context_loader) .await .unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDTZ).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDTZ, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); @@ -1092,14 +1096,14 @@ mod tests { }, _ => unreachable!(), } - let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDTZ).await; + let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDTZ, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:example:bad".to_string())); - assert!(vp2.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); } #[tokio::test] @@ -1463,34 +1467,35 @@ mod tests { issue_options.verification_method = Some(URI::String(did.to_string() + "#blockchainAccountId")); eprintln!("vm {:?}", issue_options.verification_method); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let vc_no_proof = vc.clone(); let proof = vc - .generate_proof(&key, &issue_options, &DIDTZ) + .generate_proof(&key, &issue_options, &DIDTZ, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDTZ).await; + let verification_result = vc.verify(None, &DIDTZ, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification let mut vc_bad_issuer = vc.clone(); vc_bad_issuer.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc_bad_issuer.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vc_bad_issuer.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_p256().unwrap(); use ssi::ldp::ProofSuite; let proof_bad = ssi::ldp::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - .sign(&vc_no_proof, &issue_options, &DIDTZ, &other_key, None) + .sign(&vc_no_proof, &issue_options, &DIDTZ, &mut context_loader, &other_key, None) .await .unwrap(); vc_wrong_key.add_proof(proof_bad); vc_wrong_key.validate().unwrap(); - assert!(vc_wrong_key.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vc_wrong_key.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); // Make it into a VP use ssi::one_or_many::OneOrMany; @@ -1516,13 +1521,13 @@ mod tests { vp_issue_options.proof_purpose = Some(ProofPurpose::Authentication); eprintln!("vp: {}", serde_json::to_string_pretty(&vp).unwrap()); let vp_proof = vp - .generate_proof(&key, &vp_issue_options, &DIDTZ) + .generate_proof(&key, &vp_issue_options, &DIDTZ, &mut context_loader) .await .unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); - let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDTZ).await; + let vp_verification_result = vp.verify(Some(vp_issue_options.clone()), &DIDTZ, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.is_empty()); @@ -1537,13 +1542,13 @@ mod tests { }, _ => unreachable!(), } - let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDTZ).await; + let vp_verification_result = vp1.verify(Some(vp_issue_options), &DIDTZ, &mut context_loader).await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); // test that holder is verified let mut vp2 = vp.clone(); vp2.holder = Some(URI::String("did:example:bad".to_string())); - assert!(vp2.verify(None, &DIDTZ).await.errors.len() > 0); + assert!(vp2.verify(None, &DIDTZ, &mut context_loader).await.errors.len() > 0); } } diff --git a/did-web/src/lib.rs b/did-web/src/lib.rs index 3a1424d50..738adb619 100644 --- a/did-web/src/lib.rs +++ b/did-web/src/lib.rs @@ -309,20 +309,21 @@ mod tests { let key: JWK = serde_json::from_str(key_str).unwrap(); let mut issue_options = LinkedDataProofOptions::default(); issue_options.verification_method = Some(URI::String("did:web:localhost#key1".to_string())); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let proof = vc - .generate_proof(&key, &issue_options, &DIDWeb) + .generate_proof(&key, &issue_options, &DIDWeb, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDWeb).await; + let verification_result = vc.verify(None, &DIDWeb, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); // test that issuer property is used for verification vc.issuer = Some(Issuer::URI(URI::String("did:example:bad".to_string()))); - assert!(vc.verify(None, &DIDWeb).await.errors.len() > 0); + assert!(vc.verify(None, &DIDWeb, &mut context_loader).await.errors.len() > 0); PROXY.with(|proxy| { proxy.replace(None); diff --git a/examples/issue-revocation-list.rs b/examples/issue-revocation-list.rs index d25cfafde..203462611 100644 --- a/examples/issue-revocation-list.rs +++ b/examples/issue-revocation-list.rs @@ -8,6 +8,7 @@ async fn main() { use std::convert::TryFrom; let key: ssi::jwk::JWK = serde_json::from_str(key_str).unwrap(); let resolver = &ssi::did::example::DIDExample; + let mut context_loader = ssi::jsonld::ContextLoader::default(); use ssi::revocation::{ RevocationList2020, RevocationList2020Credential, RevocationList2020Subject, }; @@ -25,11 +26,11 @@ async fn main() { let verification_method = "did:example:foo#key1".to_string(); proof_options.verification_method = Some(ssi::vc::URI::String(verification_method)); let proof = vc - .generate_proof(&key, &proof_options, resolver) + .generate_proof(&key, &proof_options, resolver, &mut context_loader) .await .unwrap(); vc.add_proof(proof); - let result = vc.verify(None, resolver).await; + let result = vc.verify(None, resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } diff --git a/examples/issue-status-list.rs b/examples/issue-status-list.rs index 77245b344..9c1f34948 100644 --- a/examples/issue-status-list.rs +++ b/examples/issue-status-list.rs @@ -22,12 +22,13 @@ async fn main() { let mut proof_options = ssi::vc::LinkedDataProofOptions::default(); let verification_method = "did:example:12345#key1".to_string(); proof_options.verification_method = Some(ssi::vc::URI::String(verification_method)); + let mut context_loader = ssi::jsonld::ContextLoader::default(); let proof = vc - .generate_proof(&key, &proof_options, resolver) + .generate_proof(&key, &proof_options, resolver, &mut context_loader) .await .unwrap(); vc.add_proof(proof); - let result = vc.verify(None, resolver).await; + let result = vc.verify(None, resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } diff --git a/examples/issue.rs b/examples/issue.rs index 9f9f8273f..75adb9d7a 100644 --- a/examples/issue.rs +++ b/examples/issue.rs @@ -21,14 +21,15 @@ async fn main() { let verification_method = "did:example:foo#key1".to_string(); proof_options.verification_method = Some(ssi::vc::URI::String(verification_method)); let proof_format = std::env::args().skip(1).next(); + let mut context_loader = ssi::jsonld::ContextLoader::default(); match &proof_format.unwrap()[..] { "ldp" => { let proof = vc - .generate_proof(&key, &proof_options, resolver) + .generate_proof(&key, &proof_options, resolver, &mut context_loader) .await .unwrap(); vc.add_proof(proof); - let result = vc.verify(None, resolver).await; + let result = vc.verify(None, resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } @@ -42,7 +43,7 @@ async fn main() { .generate_jwt(Some(&key), &proof_options, resolver) .await .unwrap(); - let result = ssi::vc::Credential::verify_jwt(&jwt, None, resolver).await; + let result = ssi::vc::Credential::verify_jwt(&jwt, None, resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } diff --git a/examples/present.rs b/examples/present.rs index 2e20e2f7e..08ddff75f 100644 --- a/examples/present.rs +++ b/examples/present.rs @@ -44,14 +44,15 @@ async fn main() { proof_options.proof_purpose = Some(ssi::vc::ProofPurpose::Authentication); proof_options.challenge = Some("example".to_string()); + let mut context_loader = ssi::jsonld::ContextLoader::default(); match &proof_format_out[..] { "ldp" => { let proof = vp - .generate_proof(&key, &proof_options, resolver) + .generate_proof(&key, &proof_options, resolver, &mut context_loader) .await .unwrap(); vp.add_proof(proof); - let result = vp.verify(Some(proof_options), resolver).await; + let result = vp.verify(Some(proof_options), resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } @@ -66,7 +67,7 @@ async fn main() { .await .unwrap(); print!("{}", jwt); - let result = ssi::vc::Presentation::verify_jwt(&jwt, None, resolver).await; + let result = ssi::vc::Presentation::verify_jwt(&jwt, None, resolver, &mut context_loader).await; if result.errors.len() > 0 { panic!("verify failed: {:#?}", result); } diff --git a/src/eip712.rs b/src/eip712.rs index 665137cc7..971124472 100644 --- a/src/eip712.rs +++ b/src/eip712.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use serde_json::{Number, Value}; use thiserror::Error; +use crate::jsonld::ContextLoader; use crate::keccak_hash::bytes_to_lowerhex; use crate::ldp::LinkedDataDocument; use crate::vc::Proof; @@ -790,9 +791,10 @@ impl TypedData { pub async fn from_document_and_options( document: &(dyn LinkedDataDocument + Sync), proof: &Proof, + context_loader: &mut ContextLoader, ) -> Result { let doc_dataset = document - .to_dataset_for_signing(None) + .to_dataset_for_signing(None, context_loader) .await .map_err(|e| TypedDataConstructionError::DocumentToDataset(e.to_string()))?; let doc_dataset_normalized = crate::urdna2015::normalize(&doc_dataset) @@ -801,7 +803,7 @@ impl TypedData { #[allow(clippy::redundant_closure)] doc_statements_normalized.sort_by_cached_key(|x| String::from(x)); let sigopts_dataset = proof - .to_dataset_for_signing(Some(document)) + .to_dataset_for_signing(Some(document), context_loader) .await .map_err(|e| TypedDataConstructionError::ProofToDataset(e.to_string()))?; let sigopts_dataset_normalized = crate::urdna2015::normalize(&sigopts_dataset) @@ -1514,7 +1516,7 @@ mod tests { ]; let values: Vec = props .iter() - .map(|(name_, value)| Value::from((*value).clone()).as_str().unwrap().to_string()) + .map(|(_name_, value)| Value::from((*value).clone()).as_str().unwrap().to_string()) .collect(); assert_eq!(values, expected_values); } @@ -1900,16 +1902,16 @@ mod tests { // Verify the VC/proof let mut vc = vc.clone(); + let mut context_loader = crate::jsonld::ContextLoader::default(); vc.add_proof(proof.clone()); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); assert_eq!(sig_hex, "0x5fb8f18f21f54c2df8a2720d0afcee7dbbb18e4b7a22ce6e8183633d63b076d329122584db769cd78b6cd5a7094ede5ceaa43317907539187f1f0d8875f99e051b"); } - use crate::ldp::resolve_vm; use crate::vc::{LinkedDataProofOptions, ProofPurpose, URI}; #[async_std::test] @@ -1966,6 +1968,7 @@ mod tests { async fn to_dataset_for_signing( &self, _parent: Option<&(dyn LinkedDataDocument + Sync)>, + _context_loader: &mut ContextLoader, ) -> Result { todo!(); } @@ -2035,7 +2038,8 @@ mod tests { let basic_doc = ExampleDocument(TEST_BASIC_DOCUMENT.clone()); let resolver = MOCK_ETHR_DID_RESOLVER.clone(); - let verification_result = proof.verify(&basic_doc, &resolver).await; + let mut context_loader = crate::jsonld::ContextLoader::default(); + let verification_result = proof.verify(&basic_doc, &resolver, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } @@ -2217,7 +2221,8 @@ mod tests { let nested_doc = ExampleDocument(TEST_NESTED_DOCUMENT.clone()); let resolver = MOCK_ETHR_DID_RESOLVER.clone(); - let verification_result = proof.verify(&nested_doc, &resolver).await; + let mut context_loader = crate::jsonld::ContextLoader::default(); + let verification_result = proof.verify(&nested_doc, &resolver, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } @@ -2256,7 +2261,8 @@ mod tests { let nested_doc = ExampleDocument(TEST_NESTED_DOCUMENT.clone()); let resolver = MOCK_ETHR_DID_RESOLVER.clone(); - let verification_result = proof.verify(&nested_doc, &resolver).await; + let mut context_loader = crate::jsonld::ContextLoader::default(); + let verification_result = proof.verify(&nested_doc, &resolver, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); @@ -2374,7 +2380,8 @@ mod tests { let nested_doc = ExampleDocument(TEST_NESTED_DOCUMENT.clone()); let resolver = MOCK_ETHR_DID_RESOLVER.clone(); - let verification_result = proof.verify(&nested_doc, &resolver).await; + let mut context_loader = crate::jsonld::ContextLoader::default(); + let verification_result = proof.verify(&nested_doc, &resolver, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } diff --git a/src/jsonld.rs b/src/jsonld.rs index 5d75ca31d..772779e75 100644 --- a/src/jsonld.rs +++ b/src/jsonld.rs @@ -1,8 +1,9 @@ //! [JSON-LD](https://www.w3.org/TR/json-ld11/) functionality -use std::collections::BTreeMap as Map; +use std::collections::{BTreeMap as Map, HashMap}; use std::convert::TryFrom; use std::str::FromStr; +use std::sync::Arc; use crate::error::Error; use crate::rdf::{ @@ -10,6 +11,7 @@ use crate::rdf::{ Object, Predicate, StringLiteral, Subject, Triple, LANG_STRING_IRI_STR, }; +use async_std::sync::RwLock; use futures::future::{BoxFuture, FutureExt}; use iref::{Iri, IriBuf}; use json::JsonValue; @@ -326,7 +328,9 @@ lazy_static! { }; } +#[derive(Clone)] pub struct StaticLoader; + impl Loader for StaticLoader { type Document = JsonValue; fn load<'a>( @@ -375,7 +379,6 @@ impl Loader for StaticLoader { ZCAP_V1_CONTEXT => Ok(ZCAP_V1_CONTEXT_DOCUMENT.clone()), CACAO_ZCAP_V1_CONTEXT => Ok(CACAO_ZCAP_V1_CONTEXT_DOCUMENT.clone()), _ => { - eprintln!("unknown context {}", url); Err(json_ld::ErrorCode::LoadingDocumentFailed.into()) } } @@ -384,6 +387,104 @@ impl Loader for StaticLoader { } } +pub type ContextMap = HashMap>; + +#[derive(Clone)] +pub struct ContextLoader { + // Specifies if StaticLoader is meant to be checked first. + static_loader: Option, + // This map holds the optional, additional context objects. This is where any app-specific context + // objects would go. The Arc> is necessary because json_ld::Loader trait unfortunately + // has a method that uses `&mut self`. + context_map: Option>>, +} + +impl std::fmt::Debug for ContextLoader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.debug_struct("ContextLoader") + .finish_non_exhaustive() + } +} + +impl ContextLoader { + /// Constructs an "empty" ContextLoader. + pub fn empty() -> Self { + Self { static_loader: None, context_map: None } + } + /// Using the builder pattern, the StaticLoader can be enabled so that contexts are checked + /// against it before being checked against context_map. + pub fn with_static_loader(mut self) -> Self { + self.static_loader = Some(StaticLoader); + self + } + /// Using the builder pattern, the map of additional contexts can be set. These context objects + /// will be checked after StaticLoader (if it's specified). preparsed_context_map should map + /// the context URLs to their JSON content. + pub fn with_context_map_from(mut self, preparsed_context_map: HashMap) -> Result { + let context_map = + preparsed_context_map + .iter() + .map(|(url, jsonld)| -> Result<(String, RemoteDocument), Error> { + let doc = json::parse(jsonld)?; + let iri = Iri::new(url)?; + Ok((url.clone(), RemoteDocument::new(doc, iri))) + }) + .collect::>, Error>>()?; + self.context_map = Some(Arc::new(RwLock::new(context_map))); + Ok(self) + } +} + +/// The default ContextLoader only uses StaticLoader. +impl std::default::Default for ContextLoader { + fn default() -> Self { + Self { static_loader: Some(StaticLoader), context_map: None } + } +} + +impl Loader for ContextLoader { + type Document = JsonValue; + fn load<'a>( + &'a mut self, + url: Iri<'_>, + ) -> BoxFuture<'a, Result, json_ld::Error>> { + let url_buf: IriBuf = url.into(); + async move { + if let Some(static_loader) = &mut self.static_loader { + match static_loader.load(url_buf.as_iri()).await { + Ok(x) => { + // The url was present in StaticLoader. + return Ok(x); + } + Err(e) => { + if e.code() == json_ld::ErrorCode::LoadingDocumentFailed { + // This is ok, the url just wasn't found in StaticLoader. Fall through + // to self.context_map. + } else { + // Any other error is a legit error. + return Err(e); + } + } + } + } + // If we fell through, then try self.context_map. + if let Some(context_map) = &mut self.context_map { + context_map + .read() + .await + .get(url_buf.as_str()) + .map(|rd| rd.clone()) + .ok_or_else(|| { + json_ld::ErrorCode::LoadingDocumentFailed.into() + }) + } else { + Err(json_ld::ErrorCode::LoadingDocumentFailed.into()) + } + } + .boxed() + } +} + impl FromStr for RdfDirection { type Err = Error; fn from_str(purpose: &str) -> Result { diff --git a/src/ldp.rs b/src/ldp.rs index 0bc644abb..8b213176d 100644 --- a/src/ldp.rs +++ b/src/ldp.rs @@ -17,6 +17,7 @@ use crate::did_resolve::{dereference, Content, DIDResolver, DereferencingInputMe use crate::eip712::TypedData; use crate::error::Error; use crate::hash::sha256; +use crate::jsonld::ContextLoader; use crate::jwk::Base64urlUInt; use crate::jwk::{Algorithm, Params as JWKParams, JWK}; use crate::jws::Header; @@ -215,6 +216,7 @@ pub trait LinkedDataDocument { async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result; } @@ -226,6 +228,7 @@ pub trait ProofSuite { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result; @@ -235,6 +238,7 @@ pub trait ProofSuite { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result; @@ -250,6 +254,7 @@ pub trait ProofSuite { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result; } @@ -366,6 +371,7 @@ impl LinkedDataProofs { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -380,7 +386,7 @@ impl LinkedDataProofs { let mut options = options.clone(); ensure_or_pick_verification_relationship(&mut options, document, key, resolver).await?; suite - .sign(document, &options, resolver, key, extra_proof_properties) + .sign(document, &options, resolver, context_loader, key, extra_proof_properties) .await } @@ -390,6 +396,7 @@ impl LinkedDataProofs { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -409,6 +416,7 @@ impl LinkedDataProofs { document, &options, resolver, + context_loader, public_key, extra_proof_properties, ) @@ -420,9 +428,10 @@ impl LinkedDataProofs { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let suite = get_proof_suite(proof.type_.as_str())?; - suite.verify(proof, document, resolver).await + suite.verify(proof, document, resolver, context_loader).await } } @@ -461,9 +470,10 @@ pub async fn resolve_vm( async fn to_jws_payload( document: &(dyn LinkedDataDocument + Sync), proof: &Proof, + context_loader: &mut ContextLoader, ) -> Result, Error> { - let sigopts_dataset = proof.to_dataset_for_signing(Some(document)).await?; - let doc_dataset = document.to_dataset_for_signing(None).await?; + let sigopts_dataset = proof.to_dataset_for_signing(Some(document), context_loader).await?; + let doc_dataset = document.to_dataset_for_signing(None, context_loader).await?; let doc_dataset_normalized = urdna2015::normalize(&doc_dataset)?; let doc_normalized = doc_dataset_normalized.to_nquads()?; let sigopts_dataset_normalized = urdna2015::normalize(&sigopts_dataset)?; @@ -482,6 +492,7 @@ async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, type_: &str, algorithm: Algorithm, @@ -495,7 +506,7 @@ async fn sign( let proof = Proof::new(type_) .with_options(options) .with_properties(extra_proof_properties); - sign_proof(document, proof, key, algorithm).await + sign_proof(document, proof, key, algorithm, context_loader).await } async fn sign_proof( @@ -503,8 +514,9 @@ async fn sign_proof( mut proof: Proof, key: &JWK, algorithm: Algorithm, + context_loader: &mut ContextLoader, ) -> Result { - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let jws = crate::jws::detached_sign_unencoded_payload(algorithm, &message, key)?; proof.jws = Some(jws); Ok(proof) @@ -513,6 +525,7 @@ async fn sign_proof( async fn sign_nojws( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, + context_loader: &mut ContextLoader, key: &JWK, type_: &str, algorithm: Algorithm, @@ -530,7 +543,7 @@ async fn sign_nojws( if !document_has_context(document, context_uri)? { proof.context = serde_json::json!([context_uri]); } - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let sig = crate::jws::sign_bytes(algorithm, &message, key)?; let sig_multibase = multibase::encode(multibase::Base::Base58Btc, sig); proof.proof_value = Some(sig_multibase); @@ -541,6 +554,7 @@ async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, type_: &str, algorithm: Algorithm, @@ -554,15 +568,16 @@ async fn prepare( let proof = Proof::new(type_) .with_options(options) .with_properties(extra_proof_properties); - prepare_proof(document, proof, algorithm).await + prepare_proof(document, proof, algorithm, context_loader).await } async fn prepare_proof( document: &(dyn LinkedDataDocument + Sync), proof: Proof, algorithm: Algorithm, + context_loader: &mut ContextLoader, ) -> Result { - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let (jws_header, signing_input) = crate::jws::prepare_detached_unencoded_payload(algorithm, &message)?; Ok(ProofPreparation { @@ -575,6 +590,7 @@ async fn prepare_proof( async fn prepare_nojws( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, + context_loader: &mut ContextLoader, public_key: &JWK, type_: &str, algorithm: Algorithm, @@ -592,7 +608,7 @@ async fn prepare_nojws( if !document_has_context(document, context_uri)? { proof.context = serde_json::json!([context_uri]); } - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; Ok(ProofPreparation { proof, jws_header: None, @@ -616,6 +632,7 @@ async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; let verification_method = proof @@ -623,7 +640,7 @@ async fn verify( .as_ref() .ok_or(Error::MissingVerificationMethod)?; let key = resolve_key(verification_method, resolver).await?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; crate::jws::detached_verify(jws, &message, &key)?; Ok(Default::default()) } @@ -632,6 +649,7 @@ async fn verify_nojws( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, algorithm: Algorithm, ) -> Result { let proof_value = proof @@ -643,7 +661,7 @@ async fn verify_nojws( .as_ref() .ok_or(Error::MissingVerificationMethod)?; let key = resolve_key(verification_method, resolver).await?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; let (_base, sig) = multibase::decode(proof_value)?; crate::jws::verify_bytes_warnable(algorithm, &message, &key, &sig) } @@ -657,6 +675,7 @@ impl ProofSuite for RsaSignature2018 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -664,6 +683,7 @@ impl ProofSuite for RsaSignature2018 { document, options, resolver, + context_loader, key, "RsaSignature2018", Algorithm::RS256, @@ -676,6 +696,7 @@ impl ProofSuite for RsaSignature2018 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -683,6 +704,7 @@ impl ProofSuite for RsaSignature2018 { document, options, resolver, + context_loader, public_key, "RsaSignature2018", Algorithm::RS256, @@ -695,8 +717,9 @@ impl ProofSuite for RsaSignature2018 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - verify(proof, document, resolver).await + verify(proof, document, resolver, context_loader).await } async fn complete( &self, @@ -716,6 +739,7 @@ impl ProofSuite for Ed25519Signature2018 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -723,6 +747,7 @@ impl ProofSuite for Ed25519Signature2018 { document, options, resolver, + context_loader, key, "Ed25519Signature2018", Algorithm::EdDSA, @@ -735,6 +760,7 @@ impl ProofSuite for Ed25519Signature2018 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -742,6 +768,7 @@ impl ProofSuite for Ed25519Signature2018 { document, options, resolver, + context_loader, public_key, "Ed25519Signature2018", Algorithm::EdDSA, @@ -754,8 +781,9 @@ impl ProofSuite for Ed25519Signature2018 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - verify(proof, document, resolver).await + verify(proof, document, resolver, context_loader).await } async fn complete( &self, @@ -775,12 +803,14 @@ impl ProofSuite for Ed25519Signature2020 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { sign_nojws( document, options, + context_loader, key, "Ed25519Signature2020", Algorithm::EdDSA, @@ -794,20 +824,23 @@ impl ProofSuite for Ed25519Signature2020 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - verify_nojws(proof, document, resolver, Algorithm::EdDSA).await + verify_nojws(proof, document, resolver, context_loader, Algorithm::EdDSA).await } async fn prepare( &self, document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { prepare_nojws( document, options, + context_loader, public_key, "Ed25519Signature2020", Algorithm::EdDSA, @@ -836,6 +869,7 @@ impl ProofSuite for EcdsaSecp256k1Signature2019 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -843,6 +877,7 @@ impl ProofSuite for EcdsaSecp256k1Signature2019 { document, options, resolver, + context_loader, key, "EcdsaSecp256k1Signature2019", Algorithm::ES256K, @@ -855,6 +890,7 @@ impl ProofSuite for EcdsaSecp256k1Signature2019 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -862,6 +898,7 @@ impl ProofSuite for EcdsaSecp256k1Signature2019 { document, options, resolver, + context_loader, public_key, "EcdsaSecp256k1Signature2019", Algorithm::ES256K, @@ -874,8 +911,9 @@ impl ProofSuite for EcdsaSecp256k1Signature2019 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - verify(proof, document, resolver).await + verify(proof, document, resolver, context_loader).await } async fn complete( &self, @@ -895,6 +933,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -914,7 +953,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { .with_options(options) .with_properties(extra_proof_properties) }; - sign_proof(document, proof, key, Algorithm::ES256KR).await + sign_proof(document, proof, key, Algorithm::ES256KR, context_loader).await } async fn prepare( @@ -922,6 +961,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -936,7 +976,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { .with_options(options) .with_properties(extra_proof_properties) }; - prepare_proof(document, proof, Algorithm::ES256KR).await + prepare_proof(document, proof, Algorithm::ES256KR, context_loader).await } async fn complete( @@ -952,6 +992,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; let verification_method = proof @@ -965,7 +1006,7 @@ impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { { return Err(Error::VerificationMethodMismatch); } - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; let (_header, jwk) = crate::jws::detached_recover(jws, &message)?; let mut warnings = VerificationWarnings::default(); if let Err(_e) = vm.match_jwk(&jwk) { @@ -991,6 +1032,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1014,7 +1056,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .with_options(options) .with_properties(props) }; - sign_proof(document, proof, key, Algorithm::EdBlake2b).await + sign_proof(document, proof, key, Algorithm::EdBlake2b, context_loader).await } async fn prepare( @@ -1022,6 +1064,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1039,7 +1082,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .with_options(options) .with_properties(props) }; - prepare_proof(document, proof, Algorithm::EdBlake2b).await + prepare_proof(document, proof, Algorithm::EdBlake2b, context_loader).await } async fn complete( @@ -1055,6 +1098,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; let jwk: JWK = match proof.property_set { @@ -1071,7 +1115,7 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .ok_or(Error::MissingVerificationMethod)?; let vm = resolve_vm(verification_method, resolver).await?; vm.match_jwk(&jwk)?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; crate::jws::detached_verify(jws, &message, &jwk)?; Ok(Default::default()) } @@ -1087,6 +1131,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1109,7 +1154,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .with_options(options) .with_properties(props) }; - sign_proof(document, proof, key, Algorithm::ESBlake2b).await + sign_proof(document, proof, key, Algorithm::ESBlake2b, context_loader).await } async fn prepare( @@ -1117,6 +1162,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1134,7 +1180,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .with_options(options) .with_properties(props) }; - prepare_proof(document, proof, Algorithm::ESBlake2b).await + prepare_proof(document, proof, Algorithm::ESBlake2b, context_loader).await } async fn complete( @@ -1150,6 +1196,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; let jwk: JWK = match proof.property_set { @@ -1166,7 +1213,7 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { .ok_or(Error::MissingVerificationMethod)?; let vm = resolve_vm(verification_method, resolver).await?; vm.match_jwk(&jwk)?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; crate::jws::detached_verify(jws, &message, &jwk)?; Ok(Default::default()) } @@ -1183,6 +1230,7 @@ impl ProofSuite for Eip712Signature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1193,7 +1241,7 @@ impl ProofSuite for Eip712Signature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let typed_data = TypedData::from_document_and_options(document, &proof).await?; + let typed_data = TypedData::from_document_and_options(document, &proof, context_loader).await?; let bytes = typed_data.bytes()?; let ec_params = match &key.params { JWKParams::EC(ec) => ec, @@ -1215,6 +1263,7 @@ impl ProofSuite for Eip712Signature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1224,7 +1273,7 @@ impl ProofSuite for Eip712Signature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let typed_data = TypedData::from_document_and_options(document, &proof).await?; + let typed_data = TypedData::from_document_and_options(document, &proof, context_loader).await?; Ok(ProofPreparation { proof, jws_header: None, @@ -1247,6 +1296,7 @@ impl ProofSuite for Eip712Signature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let sig_hex = proof .proof_value @@ -1263,7 +1313,7 @@ impl ProofSuite for Eip712Signature2021 { "EcdsaSecp256k1RecoveryMethod2020" => (), _ => return Err(Error::VerificationMethodMismatch), }; - let typed_data = TypedData::from_document_and_options(document, proof).await?; + let typed_data = TypedData::from_document_and_options(document, proof, context_loader).await?; let bytes = typed_data.bytes()?; if !sig_hex.starts_with("0x") { return Err(Error::HexString); @@ -1304,6 +1354,7 @@ impl ProofSuite for EthereumEip712Signature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + _context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1344,6 +1395,7 @@ impl ProofSuite for EthereumEip712Signature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + _context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1383,6 +1435,7 @@ impl ProofSuite for EthereumEip712Signature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + _context_loader: &mut ContextLoader, ) -> Result { let sig_hex = proof .proof_value @@ -1438,6 +1491,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1448,7 +1502,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let signing_string = string_from_document_and_options(document, &proof).await?; + let signing_string = string_from_document_and_options(document, &proof, context_loader).await?; let hash = crate::keccak_hash::prefix_personal_message(&signing_string); let ec_params = match &key.params { JWKParams::EC(ec) => ec, @@ -1470,6 +1524,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1479,7 +1534,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let signing_string = string_from_document_and_options(document, &proof).await?; + let signing_string = string_from_document_and_options(document, &proof, context_loader).await?; Ok(ProofPreparation { proof, jws_header: None, @@ -1504,6 +1559,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let sig_hex = proof .proof_value @@ -1526,7 +1582,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { let rec_id = k256::ecdsa::recoverable::Id::try_from(dec_sig[64] % 27)?; let sig = k256::ecdsa::Signature::try_from(&dec_sig[..64])?; let sig = k256::ecdsa::recoverable::Signature::new(&sig, rec_id)?; - let signing_string = string_from_document_and_options(document, proof).await?; + let signing_string = string_from_document_and_options(document, proof, context_loader).await?; let hash = crate::keccak_hash::prefix_personal_message(&signing_string); let recovered_key = sig.recover_verify_key(&hash)?; use crate::jwk::ECParams; @@ -1551,9 +1607,10 @@ impl ProofSuite for EthereumPersonalSignature2021 { async fn micheline_from_document_and_options( document: &(dyn LinkedDataDocument + Sync), proof: &Proof, + context_loader: &mut ContextLoader, ) -> Result, Error> { - let sigopts_dataset = proof.to_dataset_for_signing(Some(document)).await?; - let doc_dataset = document.to_dataset_for_signing(None).await?; + let sigopts_dataset = proof.to_dataset_for_signing(Some(document), context_loader).await?; + let doc_dataset = document.to_dataset_for_signing(None, context_loader).await?; let doc_dataset_normalized = urdna2015::normalize(&doc_dataset)?; let doc_normalized = doc_dataset_normalized.to_nquads()?; let sigopts_dataset_normalized = urdna2015::normalize(&sigopts_dataset)?; @@ -1582,9 +1639,10 @@ async fn micheline_from_document_and_options_jcs( async fn string_from_document_and_options( document: &(dyn LinkedDataDocument + Sync), proof: &Proof, + context_loader: &mut ContextLoader, ) -> Result { - let sigopts_dataset = proof.to_dataset_for_signing(Some(document)).await?; - let doc_dataset = document.to_dataset_for_signing(None).await?; + let sigopts_dataset = proof.to_dataset_for_signing(Some(document), context_loader).await?; + let doc_dataset = document.to_dataset_for_signing(None, context_loader).await?; let doc_dataset_normalized = urdna2015::normalize(&doc_dataset)?; let doc_normalized = doc_dataset_normalized.to_nquads()?; let sigopts_dataset_normalized = urdna2015::normalize(&sigopts_dataset)?; @@ -1602,6 +1660,7 @@ impl ProofSuite for TezosSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1617,7 +1676,7 @@ impl ProofSuite for TezosSignature2021 { .with_options(options) .with_properties(props) }; - let micheline = micheline_from_document_and_options(document, &proof).await?; + let micheline = micheline_from_document_and_options(document, &proof, context_loader).await?; let sig = crate::jws::sign_bytes(algorithm, &micheline, key)?; let mut sig_prefixed = Vec::new(); let prefix: &[u8] = match algorithm { @@ -1638,6 +1697,7 @@ impl ProofSuite for TezosSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1654,7 +1714,7 @@ impl ProofSuite for TezosSignature2021 { .with_options(options) .with_properties(props) }; - let micheline = micheline_from_document_and_options(document, &proof).await?; + let micheline = micheline_from_document_and_options(document, &proof, context_loader).await?; let micheline_string = hex::encode(micheline); Ok(ProofPreparation { proof, @@ -1680,6 +1740,7 @@ impl ProofSuite for TezosSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let sig_bs58 = proof .proof_value @@ -1703,7 +1764,7 @@ impl ProofSuite for TezosSignature2021 { return Err(Error::VerificationMethodMismatch); } - let micheline = micheline_from_document_and_options(document, proof).await?; + let micheline = micheline_from_document_and_options(document, proof, context_loader).await?; let account_id_opt: Option = match vm.blockchain_account_id { Some(account_id_string) => Some(account_id_string.parse()?), None => None, @@ -1740,6 +1801,7 @@ impl ProofSuite for TezosJcsSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1756,7 +1818,7 @@ impl ProofSuite for TezosJcsSignature2021 { .with_options(options) .with_properties(props) }; - let micheline = micheline_from_document_and_options(document, &proof).await?; + let micheline = micheline_from_document_and_options(document, &proof, context_loader).await?; let sig = crate::jws::sign_bytes(algorithm, &micheline, key)?; let mut sig_prefixed = Vec::new(); let prefix: &[u8] = match algorithm { @@ -1777,6 +1839,7 @@ impl ProofSuite for TezosJcsSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + _context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1821,6 +1884,7 @@ impl ProofSuite for TezosJcsSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + _context_loader: &mut ContextLoader, ) -> Result { let sig_bs58 = proof .proof_value @@ -1894,6 +1958,7 @@ impl ProofSuite for SolanaSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1903,7 +1968,7 @@ impl ProofSuite for SolanaSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let tx = crate::soltx::LocalSolanaTransaction::with_message(&message); let bytes = tx.to_bytes(); let sig = crate::jws::sign_bytes(Algorithm::EdDSA, &bytes, key)?; @@ -1917,6 +1982,7 @@ impl ProofSuite for SolanaSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -1926,7 +1992,7 @@ impl ProofSuite for SolanaSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let tx = crate::soltx::LocalSolanaTransaction::with_message(&message); let bytes = tx.to_bytes(); Ok(ProofPreparation { @@ -1951,6 +2017,7 @@ impl ProofSuite for SolanaSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let sig_b58 = proof .proof_value @@ -1965,7 +2032,7 @@ impl ProofSuite for SolanaSignature2021 { return Err(Error::VerificationMethodMismatch); } let key = vm.public_key_jwk.ok_or(Error::MissingKey)?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; let tx = crate::soltx::LocalSolanaTransaction::with_message(&message); let bytes = tx.to_bytes(); let sig = bs58::decode(&sig_b58).into_vec()?; @@ -2036,6 +2103,7 @@ impl ProofSuite for AleoSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2050,7 +2118,7 @@ impl ProofSuite for AleoSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; let sig = crate::aleo::sign(&message, &key)?; let sig_mb = multibase::encode(multibase::Base::Base58Btc, sig); proof.proof_value = Some(sig_mb); @@ -2062,6 +2130,7 @@ impl ProofSuite for AleoSignature2021 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2071,7 +2140,7 @@ impl ProofSuite for AleoSignature2021 { .with_options(options) .with_properties(extra_proof_properties) }; - let message = to_jws_payload(document, &proof).await?; + let message = to_jws_payload(document, &proof, context_loader).await?; Ok(ProofPreparation { proof, jws_header: None, @@ -2094,6 +2163,7 @@ impl ProofSuite for AleoSignature2021 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { const NETWORK_ID: &str = "1"; const NAMESPACE: &str = "aleo"; @@ -2124,7 +2194,7 @@ impl ProofSuite for AleoSignature2021 { account_id.chain_id.namespace.to_string(), )); } - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; crate::aleo::verify(&message, &account_id.account_address, &sig)?; Ok(Default::default()) } @@ -2139,6 +2209,7 @@ impl ProofSuite for EcdsaSecp256r1Signature2019 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2146,6 +2217,7 @@ impl ProofSuite for EcdsaSecp256r1Signature2019 { document, options, resolver, + context_loader, key, "EcdsaSecp256r1Signature2019", Algorithm::ES256, @@ -2158,6 +2230,7 @@ impl ProofSuite for EcdsaSecp256r1Signature2019 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2165,6 +2238,7 @@ impl ProofSuite for EcdsaSecp256r1Signature2019 { document, options, resolver, + context_loader, public_key, "EcdsaSecp256r1Signature2019", Algorithm::ES256, @@ -2177,8 +2251,9 @@ impl ProofSuite for EcdsaSecp256r1Signature2019 { proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - verify(proof, document, resolver).await + verify(proof, document, resolver, context_loader).await } async fn complete( &self, @@ -2209,6 +2284,7 @@ impl ProofSuite for JsonWebSignature2020 { document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2225,13 +2301,14 @@ impl ProofSuite for JsonWebSignature2020 { .with_options(options) .with_properties(extra_proof_properties) }; - sign_proof(document, proof, key, algorithm).await + sign_proof(document, proof, key, algorithm, context_loader).await } async fn prepare( &self, document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -2248,13 +2325,14 @@ impl ProofSuite for JsonWebSignature2020 { .with_options(options) .with_properties(extra_proof_properties) }; - prepare_proof(document, proof, algorithm).await + prepare_proof(document, proof, algorithm, context_loader).await } async fn verify( &self, proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; let verification_method = proof @@ -2262,7 +2340,7 @@ impl ProofSuite for JsonWebSignature2020 { .as_ref() .ok_or(Error::MissingVerificationMethod)?; let (header_b64, signature_b64) = crate::jws::split_detached_jws(jws)?; - let message = to_jws_payload(document, proof).await?; + let message = to_jws_payload(document, proof, context_loader).await?; let crate::jws::DecodedJWS { header, signing_input, @@ -2355,6 +2433,7 @@ mod tests { async fn to_dataset_for_signing( &self, _parent: Option<&(dyn LinkedDataDocument + Sync)>, + _context_loader: &mut ContextLoader, ) -> Result { use crate::rdf; let mut dataset = DataSet::default(); @@ -2388,8 +2467,9 @@ mod tests { ..Default::default() }; let resolver = DIDExample; + let mut context_loader = crate::jsonld::ContextLoader::default(); let doc = ExampleDocument; - let _proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &key, None) + let _proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &mut context_loader, &key, None) .await .unwrap(); } @@ -2406,7 +2486,8 @@ mod tests { }; let doc = ExampleDocument; let resolver = DIDExample; - let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &key, None) + let mut context_loader = crate::jsonld::ContextLoader::default(); + let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &mut context_loader, &key, None) .await .unwrap(); println!("{}", serde_json::to_string(&proof).unwrap()); @@ -2426,7 +2507,8 @@ mod tests { }; let doc = ExampleDocument; let resolver = DIDExample; - let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &key, None) + let mut context_loader = crate::jsonld::ContextLoader::default(); + let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &mut context_loader, &key, None) .await .unwrap(); println!("{}", serde_json::to_string(&proof).unwrap()); @@ -2445,7 +2527,8 @@ mod tests { }; let doc = ExampleDocument; let resolver = DIDExample; - let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &key, None) + let mut context_loader = crate::jsonld::ContextLoader::default(); + let proof = LinkedDataProofs::sign(&doc, &issue_options, &resolver, &mut context_loader, &key, None) .await .unwrap(); println!("{}", serde_json::to_string(&proof).unwrap()); @@ -2551,8 +2634,9 @@ mod tests { for proof in vc.proof.iter().flatten() { n_proofs += 1; let resolver = ExampleResolver; + let mut context_loader = crate::jsonld::ContextLoader::default(); let warnings = EcdsaSecp256k1RecoverySignature2020 - .verify(&proof, &vc, &resolver) + .verify(&proof, &vc, &resolver, &mut context_loader) .await .unwrap(); assert!(warnings.is_empty()); @@ -2676,23 +2760,24 @@ mod tests { }; let resolver = ED2020ExampleResolver { issuer_document }; + let mut context_loader = crate::jsonld::ContextLoader::default(); println!("{}", serde_json::to_string(&vc).unwrap()); // reissue VC let new_proof = Ed25519Signature2020 - .sign(&vc, &issue_options, &resolver, &sk_jwk, None) + .sign(&vc, &issue_options, &resolver, &mut context_loader, &sk_jwk, None) .await .unwrap(); println!("{}", serde_json::to_string(&new_proof).unwrap()); // check new VC proof and original proof Ed25519Signature2020 - .verify(&new_proof, &vc, &resolver) + .verify(&new_proof, &vc, &resolver, &mut context_loader) .await .unwrap(); let orig_proof = vc.proof.iter().flatten().next().unwrap(); Ed25519Signature2020 - .verify(orig_proof, &vc, &resolver) + .verify(orig_proof, &vc, &resolver, &mut context_loader) .await .unwrap(); @@ -2707,26 +2792,26 @@ mod tests { ..Default::default() }; let new_proof = Ed25519Signature2020 - .sign(&vp, &vp_issue_options, &resolver, &sk_jwk, None) + .sign(&vp, &vp_issue_options, &resolver, &mut context_loader, &sk_jwk, None) .await .unwrap(); println!("{}", serde_json::to_string(&new_proof).unwrap()); // check new VP proof and original proof Ed25519Signature2020 - .verify(&new_proof, &vp, &resolver) + .verify(&new_proof, &vp, &resolver, &mut context_loader) .await .unwrap(); let orig_proof = vp.proof.iter().flatten().next().unwrap(); Ed25519Signature2020 - .verify(orig_proof, &vp, &resolver) + .verify(orig_proof, &vp, &resolver, &mut context_loader) .await .unwrap(); // Try using prepare/complete let pk_jwk = sk_jwk.to_public(); let prep = Ed25519Signature2020 - .prepare(&vp, &vp_issue_options, &resolver, &pk_jwk, None) + .prepare(&vp, &vp_issue_options, &resolver, &mut context_loader, &pk_jwk, None) .await .unwrap(); let signing_input_bytes = match prep.signing_input { @@ -2737,7 +2822,7 @@ mod tests { let sig_mb = multibase::encode(multibase::Base::Base58Btc, sig); let completed_proof = Ed25519Signature2020.complete(prep, &sig_mb).await.unwrap(); Ed25519Signature2020 - .verify(&completed_proof, &vp, &resolver) + .verify(&completed_proof, &vp, &resolver, &mut context_loader) .await .unwrap(); } @@ -2797,6 +2882,7 @@ mod tests { let vc_str = include_str!("../tests/lds-aleo2021-vc0.jsonld"); let mut vc = Credential::from_json_unsigned(vc_str).unwrap(); let resolver = ExampleResolver; + let mut context_loader = crate::jsonld::ContextLoader::default(); if vc.proof.iter().flatten().next().is_none() { // Issue VC / Generate Test Vector @@ -2807,7 +2893,7 @@ mod tests { ..Default::default() }; let proof = AleoSignature2021 - .sign(&vc, &vc_issue_options, &resolver, &private_key, None) + .sign(&vc, &vc_issue_options, &resolver, &mut context_loader, &private_key, None) .await .unwrap(); credential.add_proof(proof.clone()); @@ -2824,7 +2910,7 @@ mod tests { // Verify VC let proof = vc.proof.iter().flatten().next().unwrap(); let warnings = AleoSignature2021 - .verify(&proof, &vc, &resolver) + .verify(&proof, &vc, &resolver, &mut context_loader) .await .unwrap(); assert!(warnings.is_empty()); diff --git a/src/revocation.rs b/src/revocation.rs index 88060b14b..906a3a47a 100644 --- a/src/revocation.rs +++ b/src/revocation.rs @@ -1,5 +1,5 @@ use crate::did_resolve::DIDResolver; -use crate::jsonld::{REVOCATION_LIST_2020_V1_CONTEXT, STATUS_LIST_2021_V1_CONTEXT}; +use crate::jsonld::{ContextLoader, REVOCATION_LIST_2020_V1_CONTEXT, STATUS_LIST_2021_V1_CONTEXT}; use crate::one_or_many::OneOrMany; use crate::vc::{Credential, CredentialStatus, Issuer, VerificationResult, URI}; use async_trait::async_trait; @@ -333,6 +333,7 @@ impl CredentialStatus for RevocationList2020Status { &self, credential: &Credential, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { let mut result = VerificationResult::new(); // TODO: prefix errors or change return type @@ -396,7 +397,7 @@ impl CredentialStatus for RevocationList2020Status { } Ok(()) => {} } - let vc_result = revocation_list_credential.verify(None, resolver).await; + let vc_result = revocation_list_credential.verify(None, resolver, context_loader).await; for warning in vc_result.warnings { result .warnings @@ -465,6 +466,7 @@ impl CredentialStatus for StatusList2021Entry { &self, credential: &Credential, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { let mut result = VerificationResult::new(); // TODO: prefix errors or change return type @@ -525,7 +527,7 @@ impl CredentialStatus for StatusList2021Entry { } Ok(()) => {} } - let vc_result = status_list_credential.verify(None, resolver).await; + let vc_result = status_list_credential.verify(None, resolver, context_loader).await; for warning in vc_result.warnings { result.warnings.push(format!("Status list: {}", warning)); } diff --git a/src/vc.rs b/src/vc.rs index 17b0a09cf..91d5862c1 100644 --- a/src/vc.rs +++ b/src/vc.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use crate::did_resolve::DIDResolver; use crate::error::Error; -use crate::jsonld::{json_to_dataset, StaticLoader}; +use crate::jsonld::{ContextLoader, json_to_dataset}; use crate::jwk::{JWTKeys, JWK}; use crate::jws::Header; use crate::ldp::{ @@ -256,6 +256,7 @@ pub trait CredentialStatus: Sync { &self, credential: &Credential, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult; } @@ -1058,8 +1059,9 @@ impl Credential { jwt: &str, options_opt: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { - let (_vc, result) = Self::decode_verify_jwt(jwt, options_opt, resolver).await; + let (_vc, result) = Self::decode_verify_jwt(jwt, options_opt, resolver, context_loader).await; result } @@ -1067,6 +1069,7 @@ impl Credential { jwt: &str, options_opt: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> (Option, VerificationResult) { let checks = options_opt .as_ref() @@ -1178,7 +1181,7 @@ impl Credential { } // Try verifying each proof until one succeeds for proof in proofs { - let mut result = proof.verify(&vc, resolver).await; + let mut result = proof.verify(&vc, resolver, context_loader).await; results.append(&mut result); if results.errors.is_empty() { results.checks.push(Check::Proof); @@ -1186,7 +1189,7 @@ impl Credential { }; } if checks.contains(&Check::CredentialStatus) { - results.append(&mut vc.check_status(resolver).await); + results.append(&mut vc.check_status(resolver, context_loader).await); } (Some(vc), results) } @@ -1301,6 +1304,7 @@ impl Credential { &self, options: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { let checks = options .as_ref() @@ -1319,7 +1323,7 @@ impl Credential { let mut results = VerificationResult::new(); // Try verifying each proof until one succeeds for proof in proofs { - let mut result = proof.verify(self, resolver).await; + let mut result = proof.verify(self, resolver, context_loader).await; results.append(&mut result); if result.errors.is_empty() { results.checks.push(Check::Proof); @@ -1327,7 +1331,7 @@ impl Credential { }; } if checks.contains(&Check::CredentialStatus) { - results.append(&mut self.check_status(resolver).await); + results.append(&mut self.check_status(resolver, context_loader).await); } results } @@ -1340,8 +1344,9 @@ impl Credential { jwk: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - LinkedDataProofs::sign(self, options, resolver, jwk, None).await + LinkedDataProofs::sign(self, options, resolver, context_loader, jwk, None).await } /// Prepare to generate a linked data proof. Returns the signing input for the caller to sign @@ -1351,8 +1356,9 @@ impl Credential { public_key: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - LinkedDataProofs::prepare(self, options, resolver, public_key, None).await + LinkedDataProofs::prepare(self, options, resolver, context_loader, public_key, None).await } pub fn add_proof(&mut self, proof: Proof) { @@ -1369,7 +1375,7 @@ impl Credential { } /// Check the credentials [status](https://www.w3.org/TR/vc-data-model/#status) - pub async fn check_status(&self, resolver: &dyn DIDResolver) -> VerificationResult { + pub async fn check_status(&self, resolver: &dyn DIDResolver, context_loader: &mut ContextLoader) -> VerificationResult { let status = match self.credential_status { Some(ref status) => status, None => return VerificationResult::error("Missing credentialStatus"), @@ -1392,7 +1398,7 @@ impl Credential { )) } }; - let mut result = checkable_status.check(self, resolver).await; + let mut result = checkable_status.check(self, resolver, context_loader).await; if !result.errors.is_empty() { return result; } @@ -1406,10 +1412,11 @@ impl CheckableStatus { &self, credential: &Credential, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { match self { - Self::RevocationList2020Status(status) => status.check(credential, resolver).await, - Self::StatusList2021Entry(status) => status.check(credential, resolver).await, + Self::RevocationList2020Status(status) => status.check(credential, resolver, context_loader).await, + Self::StatusList2021Entry(status) => status.check(credential, resolver, context_loader).await, } } } @@ -1424,6 +1431,7 @@ impl LinkedDataDocument for Credential { async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result { let mut copy = self.clone(); copy.proof = None; @@ -1432,8 +1440,7 @@ impl LinkedDataDocument for Credential { Some(parent) => parent.get_contexts()?, None => None, }; - let mut loader = StaticLoader; - json_to_dataset(&json, more_contexts.as_ref(), false, None, &mut loader).await + json_to_dataset(&json, more_contexts.as_ref(), false, None, context_loader).await } fn to_value(&self) -> Result { @@ -1587,6 +1594,7 @@ impl Presentation { jwt: &str, options_opt: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> (Option, VerificationResult) { let checks = options_opt .as_ref() @@ -1708,7 +1716,7 @@ impl Presentation { } // Try verifying each proof until one succeeds for proof in proofs { - let mut result = proof.verify(&vp, resolver).await; + let mut result = proof.verify(&vp, resolver, context_loader).await; if result.errors.is_empty() { result.checks.push(Check::Proof); return (Some(vp), result); @@ -1722,8 +1730,9 @@ impl Presentation { jwt: &str, options_opt: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { - let (_vp, result) = Self::decode_verify_jwt(jwt, options_opt, resolver).await; + let (_vp, result) = Self::decode_verify_jwt(jwt, options_opt, resolver, context_loader).await; result } @@ -1761,8 +1770,9 @@ impl Presentation { jwk: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - LinkedDataProofs::sign(self, options, resolver, jwk, None).await + LinkedDataProofs::sign(self, options, resolver, context_loader, jwk, None).await } /// Prepare to generate a linked data proof. Returns the signing input for the caller to sign @@ -1772,8 +1782,9 @@ impl Presentation { public_key: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> Result { - LinkedDataProofs::prepare(self, options, resolver, public_key, None).await + LinkedDataProofs::prepare(self, options, resolver, context_loader, public_key, None).await } pub fn add_proof(&mut self, proof: Proof) { @@ -1849,6 +1860,7 @@ impl Presentation { &self, options: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { let checks = options .as_ref() @@ -1873,7 +1885,7 @@ impl Presentation { let mut results = VerificationResult::new(); // Try verifying each proof until one succeeds for proof in proofs { - let mut result = proof.verify(self, resolver).await; + let mut result = proof.verify(self, resolver, context_loader).await; if result.errors.is_empty() { result.checks.push(Check::Proof); return result; @@ -1955,6 +1967,7 @@ impl LinkedDataDocument for Presentation { async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result { let mut copy = self.clone(); copy.proof = None; @@ -1963,8 +1976,7 @@ impl LinkedDataDocument for Presentation { Some(parent) => parent.get_contexts()?, None => None, }; - let mut loader = StaticLoader; - json_to_dataset(&json, more_contexts.as_ref(), false, None, &mut loader).await + json_to_dataset(&json, more_contexts.as_ref(), false, None, context_loader).await } fn to_value(&self) -> Result { @@ -2068,8 +2080,9 @@ impl Proof { &self, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { - LinkedDataProofs::verify(self, document, resolver) + LinkedDataProofs::verify(self, document, resolver, context_loader) .await .into() } @@ -2155,6 +2168,7 @@ impl LinkedDataDocument for Proof { async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result { let mut copy = self.clone(); copy.jws = None; @@ -2164,9 +2178,8 @@ impl LinkedDataDocument for Proof { Some(parent) => parent.get_contexts()?, None => None, }; - let mut loader = StaticLoader; let dataset = - json_to_dataset(&json, more_contexts.as_ref(), false, None, &mut loader).await?; + json_to_dataset(&json, more_contexts.as_ref(), false, None, context_loader).await?; verify_proof_consistency(self, &dataset)?; Ok(dataset) } @@ -2552,8 +2565,9 @@ pub(crate) mod tests { .unwrap(); println!("{:?}", signed_jwt); + let mut context_loader = crate::jsonld::ContextLoader::default(); let (vc_opt, verification_result) = - Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample).await; + Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); let _vc = vc_opt.unwrap(); assert_eq!(verification_result.errors.len(), 0); @@ -2596,8 +2610,9 @@ pub(crate) mod tests { .unwrap(); println!("{:?}", signed_jwt); + let mut context_loader = crate::jsonld::ContextLoader::default(); let (vc1_opt, verification_result) = - Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample).await; + Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); let vc1 = vc1_opt.unwrap(); @@ -2613,7 +2628,7 @@ pub(crate) mod tests { .await .unwrap(); let (_vc_opt, verification_result) = - Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample).await; + Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.len() > 0); } @@ -2654,8 +2669,9 @@ pub(crate) mod tests { .unwrap(); println!("{:?}", signed_jwt); + let mut context_loader = crate::jsonld::ContextLoader::default(); let (vc1_opt, verification_result) = - Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample).await; + Credential::decode_verify_jwt(&signed_jwt, Some(options.clone()), &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } @@ -2678,14 +2694,15 @@ pub(crate) mod tests { let mut issue_options = LinkedDataProofOptions::default(); issue_options.verification_method = Some(URI::String("did:example:foo#key1".to_string())); + let mut context_loader = crate::jsonld::ContextLoader::default(); let proof = vc - .generate_proof(&key, &issue_options, &DIDExample) + .generate_proof(&key, &issue_options, &DIDExample, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); @@ -2701,7 +2718,7 @@ pub(crate) mod tests { }, } println!("{}", serde_json::to_string_pretty(&vc).unwrap()); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.len() >= 1); } @@ -2725,14 +2742,15 @@ pub(crate) mod tests { let mut issue_options = LinkedDataProofOptions::default(); issue_options.verification_method = Some(URI::String("did:example:foo#key3".to_string())); + let mut context_loader = crate::jsonld::ContextLoader::default(); let proof = vc - .generate_proof(&key, &issue_options, &DIDExample) + .generate_proof(&key, &issue_options, &DIDExample, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); @@ -2748,7 +2766,7 @@ pub(crate) mod tests { }, } println!("{}", serde_json::to_string_pretty(&vc).unwrap()); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.len() >= 1); } @@ -2771,14 +2789,15 @@ pub(crate) mod tests { let mut issue_options = LinkedDataProofOptions::default(); issue_options.verification_method = Some(URI::String("did:example:foo#key1".to_string())); + let mut context_loader = crate::jsonld::ContextLoader::default(); let proof = vc - .generate_proof(&key, &issue_options, &DIDExample) + .generate_proof(&key, &issue_options, &DIDExample, &mut context_loader) .await .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); } @@ -2802,11 +2821,12 @@ pub(crate) mod tests { let mut issue_options = LinkedDataProofOptions::default(); issue_options.proof_purpose = Some(ProofPurpose::AssertionMethod); issue_options.verification_method = Some(URI::String("did:example:foo#key1".to_string())); + let mut context_loader = crate::jsonld::ContextLoader::default(); let algorithm = key.get_algorithm().unwrap(); let public_key = key.to_public(); let preparation = vc - .prepare_proof(&public_key, &issue_options, &DIDExample) + .prepare_proof(&public_key, &issue_options, &DIDExample, &mut context_loader) .await .unwrap(); let signing_input = match preparation.signing_input { @@ -2820,7 +2840,7 @@ pub(crate) mod tests { println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.is_empty()); @@ -2836,7 +2856,7 @@ pub(crate) mod tests { }, } println!("{}", serde_json::to_string_pretty(&vc).unwrap()); - let verification_result = vc.verify(None, &DIDExample).await; + let verification_result = vc.verify(None, &DIDExample, &mut context_loader).await; println!("{:#?}", verification_result); assert!(verification_result.errors.len() >= 1); } @@ -2866,6 +2886,7 @@ _:c14n0 , + _context_loader: &mut ContextLoader, ) -> Result { Err(Error::NotImplemented) } @@ -2874,8 +2895,9 @@ _:c14n0 . "#; let vc: Credential = serde_json::from_str(credential_str).unwrap(); - let credential_dataset = vc.to_dataset_for_signing(None).await.unwrap(); + let mut context_loader = crate::jsonld::ContextLoader::default(); + let credential_dataset = vc.to_dataset_for_signing(None, &mut context_loader).await.unwrap(); let credential_dataset_normalized = urdna2015::normalize(&credential_dataset).unwrap(); let credential_urdna2015 = credential_dataset_normalized.to_nquads().unwrap(); eprintln!("credential:\n{}", credential_urdna2015); @@ -2916,10 +2939,12 @@ _:c14n0 0); } @@ -2947,18 +2972,25 @@ _:c14n0 vc, _ => unreachable!(), }; - let result = vc.verify(None, &DIDExample).await; + let result = vc.verify(None, &DIDExample, &mut context_loader).await; assert!(result.errors.is_empty()); assert!(result.warnings.is_empty()); // LDP VC in JWT VP let vp_jwt = include_str!("../examples/vp.jwt"); let (vp_opt, result) = - Presentation::decode_verify_jwt(vp_jwt, Some(verify_options.clone()), &DIDExample) + Presentation::decode_verify_jwt(vp_jwt, Some(verify_options.clone()), &DIDExample, &mut context_loader) .await; println!("{:#?}", result); assert!(result.errors.is_empty()); @@ -3007,14 +3041,14 @@ _:c14n0 vc, _ => unreachable!(), }; - let result = vc.verify(None, &DIDExample).await; + let result = vc.verify(None, &DIDExample, &mut context_loader).await; assert!(result.errors.is_empty()); assert!(result.warnings.is_empty()); // JWT VC in LDP VP let vp_str = include_str!("../examples/vp-jwtvc.jsonld"); let vp = Presentation::from_json(vp_str).unwrap(); - let result = vp.verify(Some(verify_options.clone()), &DIDExample).await; + let result = vp.verify(Some(verify_options.clone()), &DIDExample, &mut context_loader).await; println!("{:#?}", result); assert!(result.errors.is_empty()); assert!(result.warnings.is_empty()); @@ -3022,14 +3056,14 @@ _:c14n0 jwt, _ => unreachable!(), }; - let result = Credential::verify_jwt(&vc_jwt, None, &DIDExample).await; + let result = Credential::verify_jwt(&vc_jwt, None, &DIDExample, &mut context_loader).await; assert!(result.errors.is_empty()); assert!(result.warnings.is_empty()); // JWT VC in JWT VP let vp_jwt = include_str!("../examples/vp-jwtvc.jwt"); let (vp_opt, result) = - Presentation::decode_verify_jwt(vp_jwt, Some(verify_options.clone()), &DIDExample) + Presentation::decode_verify_jwt(vp_jwt, Some(verify_options.clone()), &DIDExample, &mut context_loader) .await; println!("{:#?}", result); let vp = vp_opt.unwrap(); @@ -3040,7 +3074,7 @@ _:c14n0 jwt, _ => unreachable!(), }; - let result = Credential::verify_jwt(&vc_jwt, None, &DIDExample).await; + let result = Credential::verify_jwt(&vc_jwt, None, &DIDExample, &mut context_loader).await; assert!(result.errors.is_empty()); assert!(result.warnings.is_empty()); } @@ -3095,9 +3129,10 @@ _:c14n0 unreachable!(), } let vp_verification_result = vp1 - .verify(Some(vp_issue_options.clone()), &DIDExample) + .verify(Some(vp_issue_options.clone()), &DIDExample, &mut context_loader) .await; println!("{:#?}", vp_verification_result); assert!(vp_verification_result.errors.len() >= 1); @@ -3277,7 +3315,7 @@ _:c14n0 0); + assert!(vp2.verify(None, &DIDExample, &mut context_loader).await.errors.len() > 0); // Test JWT VP let vp_jwt_issue_options = LinkedDataProofOptions { @@ -3295,7 +3333,7 @@ _:c14n0 0); @@ -3318,14 +3357,14 @@ _:c14n0 , resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { match &self.proof { None => VerificationResult::error("No applicable proof"), Some(proof) => { - let mut result = proof.verify(self, resolver).await; + let mut result = proof.verify(self, resolver, context_loader).await; if proof.proof_purpose != Some(ProofPurpose::CapabilityDelegation) { result.errors.push("Incorrect Proof Purpose".into()); }; @@ -150,6 +151,7 @@ where jwk: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, capability_chain: &[&str], ) -> Result { let mut ps = Map::::new(); @@ -157,7 +159,7 @@ where "capabilityChain".into(), serde_json::to_value(capability_chain)?, ); - LinkedDataProofs::sign(self, options, resolver, jwk, Some(ps)).await + LinkedDataProofs::sign(self, options, resolver, context_loader, jwk, Some(ps)).await } /// Prepare to generate a linked data proof. Returns the signing input for the caller to sign @@ -167,6 +169,7 @@ where public_key: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, capability_chain: &[&str], ) -> Result { let mut ps = Map::::new(); @@ -174,7 +177,7 @@ where "capabilityChain".into(), serde_json::to_value(capability_chain)?, ); - LinkedDataProofs::prepare(self, options, resolver, public_key, Some(ps)).await + LinkedDataProofs::prepare(self, options, resolver, context_loader, public_key, Some(ps)).await } pub fn set_proof(self, proof: Proof) -> Self { @@ -199,6 +202,7 @@ where async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result { let mut copy = self.clone(); copy.proof = None; @@ -207,8 +211,7 @@ where Some(parent) => parent.get_contexts()?, None => None, }; - let mut loader = StaticLoader; - json_to_dataset(&json, more_contexts.as_ref(), false, None, &mut loader).await + json_to_dataset(&json, more_contexts.as_ref(), false, None, context_loader).await } fn to_value(&self) -> Result { @@ -260,6 +263,7 @@ where &self, options: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, // TODO make this a list for delegation chains target_capability: &Delegation, ) -> VerificationResult @@ -268,7 +272,7 @@ where P: Serialize + Send + Sync + Clone, { let mut result = target_capability.validate_invocation(self); - let mut r2 = self.verify_signature(options, resolver).await; + let mut r2 = self.verify_signature(options, resolver, context_loader).await; result.append(&mut r2); result } @@ -277,11 +281,12 @@ where &self, _options: Option, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, ) -> VerificationResult { match &self.proof { None => VerificationResult::error("No applicable proof"), Some(proof) => { - let mut result = proof.verify(self, resolver).await; + let mut result = proof.verify(self, resolver, context_loader).await; if proof.proof_purpose != Some(ProofPurpose::CapabilityInvocation) { result.errors.push("Incorrect Proof Purpose".into()); }; @@ -299,11 +304,12 @@ where jwk: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, target: &URI, ) -> Result { let mut ps = Map::::new(); ps.insert("capability".into(), serde_json::to_value(target)?); - LinkedDataProofs::sign(self, options, resolver, jwk, Some(ps)).await + LinkedDataProofs::sign(self, options, resolver, context_loader, jwk, Some(ps)).await } /// Prepare to generate a linked data proof. Returns the signing input for the caller to sign @@ -313,11 +319,12 @@ where public_key: &JWK, options: &LinkedDataProofOptions, resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, target: &URI, ) -> Result { let mut ps = Map::::new(); ps.insert("capability".into(), serde_json::to_value(target)?); - LinkedDataProofs::prepare(self, options, resolver, public_key, Some(ps)).await + LinkedDataProofs::prepare(self, options, resolver, context_loader, public_key, Some(ps)).await } pub fn set_proof(self, proof: Proof) -> Self { @@ -341,6 +348,7 @@ where async fn to_dataset_for_signing( &self, parent: Option<&(dyn LinkedDataDocument + Sync)>, + context_loader: &mut ContextLoader, ) -> Result { let mut copy = self.clone(); copy.proof = None; @@ -349,8 +357,7 @@ where Some(parent) => parent.get_contexts()?, None => None, }; - let mut loader = StaticLoader; - json_to_dataset(&json, more_contexts.as_ref(), false, None, &mut loader).await + json_to_dataset(&json, more_contexts.as_ref(), false, None, context_loader).await } fn to_value(&self) -> Result { @@ -476,6 +483,7 @@ mod tests { #[async_std::test] async fn round_trip() { let dk = DIDExample; + let mut context_loader = crate::jsonld::ContextLoader::default(); let alice_did = "did:example:foo"; let alice_vm = format!("{}#key2", alice_did); @@ -515,22 +523,22 @@ mod tests { ..Default::default() }; let signed_del = del.clone().set_proof( - del.generate_proof(&alice, &ldpo_alice, &dk, &[]) + del.generate_proof(&alice, &ldpo_alice, &dk, &mut context_loader, &[]) .await .unwrap(), ); let signed_inv = inv.clone().set_proof( - inv.generate_proof(&bob, &ldpo_bob, &dk, &del.id) + inv.generate_proof(&bob, &ldpo_bob, &dk, &mut context_loader, &del.id) .await .unwrap(), ); // happy path - let s_d_v = signed_del.verify(None, &dk).await; + let s_d_v = signed_del.verify(None, &dk, &mut context_loader).await; assert!(s_d_v.errors.is_empty()); assert!(s_d_v.checks.iter().any(|c| c == &Check::Proof)); - let s_i_v = signed_inv.verify(None, &dk, &signed_del).await; + let s_i_v = signed_inv.verify(None, &dk, &mut context_loader, &signed_del).await; assert!(s_i_v.errors.is_empty()); assert!(s_i_v.checks.iter().any(|c| c == &Check::Proof)); @@ -544,9 +552,9 @@ mod tests { }; // invalid proof for data - assert!(!bad_sig_del.verify(None, &dk).await.errors.is_empty()); + assert!(!bad_sig_del.verify(None, &dk, &mut context_loader).await.errors.is_empty()); assert!(!bad_sig_inv - .verify(None, &dk, &signed_del) + .verify(None, &dk, &mut context_loader, &signed_del) .await .errors .is_empty()); @@ -557,12 +565,12 @@ mod tests { ..del.clone() }; let proof = wrong_del - .generate_proof(&alice, &ldpo_alice, &dk, &[]) + .generate_proof(&alice, &ldpo_alice, &dk, &mut context_loader, &[]) .await .unwrap(); let signed_wrong_del = wrong_del.set_proof(proof); assert!(!signed_inv - .verify(None, &dk, &signed_wrong_del) + .verify(None, &dk, &mut context_loader, &signed_wrong_del) .await .errors .is_empty());