From bbcc036ef5e1cafd453098fee665f257155533ac Mon Sep 17 00:00:00 2001 From: Dan Enman Date: Thu, 9 May 2024 00:10:47 -0300 Subject: [PATCH] fix: `verification_method` is not required for DID Document Re. https://www.w3.org/TR/did-core/#did-document-properties, the veriication_method property is not required. In fact, the TBD-hosted DID document used is tests does not include the Verification method. Make it optional, especially during (de-)serialization to ensure compatibility with the spec. Note: the web5-spec disagrees with the DID-core spec on this, it may be a legacy but it's possible the web5-spec should be updated as well to match did-core. --- crates/web5/src/dids/document.rs | 12 +++-- .../dids/methods/dht/document_packet/mod.rs | 54 ++++++++++--------- crates/web5/src/dids/methods/jwk.rs | 8 +-- .../dids/methods/spruce_mappers/document.rs | 7 +-- crates/web5/src/jws.rs | 42 +++++++++++---- crates/web5/src/jwt/jws.rs | 6 ++- 6 files changed, 82 insertions(+), 47 deletions(-) diff --git a/crates/web5/src/dids/document.rs b/crates/web5/src/dids/document.rs index 7988cef6..fe6ff53f 100644 --- a/crates/web5/src/dids/document.rs +++ b/crates/web5/src/dids/document.rs @@ -10,8 +10,8 @@ pub struct Document { pub controller: Option>, #[serde(rename = "alsoKnownAs", skip_serializing_if = "Option::is_none")] pub also_known_as: Option>, - #[serde(rename = "verificationMethod")] - pub verification_method: Vec, + #[serde(rename = "verificationMethod", skip_serializing_if = "Option::is_none")] + pub verification_method: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub authentication: Option>, #[serde(rename = "assertionMethod", skip_serializing_if = "Option::is_none")] @@ -132,6 +132,8 @@ impl Document { } VerificationMethodType::VerificationMethod => { self.verification_method + .clone() + .ok_or(DocumentError::VerificationMethodNotFound)? .first() .cloned() .ok_or(DocumentError::VerificationMethodNotFound)? @@ -143,6 +145,8 @@ impl Document { let verification_method = self .verification_method + .clone() + .ok_or(DocumentError::VerificationMethodNotFound)? .iter() .find(|method| method.id == *key_id) .cloned() @@ -171,7 +175,7 @@ mod tests { fn test_get_verification_method() { let document = Document { id: "did:example:123".to_string(), - verification_method: vec![ + verification_method: Some(vec![ VerificationMethod { id: "did:example:123#key1".to_string(), r#type: "JsonWebKey2020".to_string(), @@ -184,7 +188,7 @@ mod tests { controller: "did:example:123".to_string(), public_key_jwk: Jwk::default(), }, - ], + ]), authentication: Some(vec!["did:example:123#key1".to_string()]), ..Default::default() }; diff --git a/crates/web5/src/dids/methods/dht/document_packet/mod.rs b/crates/web5/src/dids/methods/dht/document_packet/mod.rs index f52017e4..2d44d07a 100644 --- a/crates/web5/src/dids/methods/dht/document_packet/mod.rs +++ b/crates/web5/src/dids/methods/dht/document_packet/mod.rs @@ -82,10 +82,10 @@ impl Document { // 1.1 Add identity key verification method let identity_key_id = format!("{}#0", did_uri); - let id_key_vm = self - .verification_method - .iter() - .find(|vm| vm.id == identity_key_id); + let id_key_vm = match self.verification_method { + None => None, + Some(ref vms) => vms.iter().find(|vm| vm.id == identity_key_id), + }; match id_key_vm { None => { return Err(DocumentPacketError::DocumentError( @@ -104,22 +104,26 @@ impl Document { // 1.2 Add all other verification methods let mut idx = 1; - self.verification_method - .iter() - .try_for_each(|vm| -> Result<(), DocumentPacketError> { - // skip identity key because we already added it - if vm.id == identity_key_id { - return Ok(()); - } - - let vm_record = vm.to_resource_record(did_uri, idx)?.to_owned(); - answers.push(vm_record); - root_record.vm.push(idx); - vm_id_to_idx.insert(vm.id.clone(), idx); - - idx += 1; - Ok(()) - })?; + match self.verification_method { + None => {} + Some(ref vms) => { + vms.iter() + .try_for_each(|vm| -> Result<(), DocumentPacketError> { + // skip identity key because we already added it + if vm.id == identity_key_id { + return Ok(()); + } + + let vm_record = vm.to_resource_record(did_uri, idx)?.to_owned(); + answers.push(vm_record); + root_record.vm.push(idx); + vm_id_to_idx.insert(vm.id.clone(), idx); + + idx += 1; + Ok(()) + })?; + } + } // 2. Add verification relationships to root_record // 2.1 Add assertion methods to root_record @@ -310,7 +314,7 @@ impl Document { context: None, controller, also_known_as, - verification_method: verification_methods, + verification_method: Some(verification_methods), authentication, assertion_method, key_agreement, @@ -369,7 +373,7 @@ mod tests { fn test_to_and_from_packet_full_featured() { let did_uri = "did:dht:123"; - let verification_method1 = generate_identity_key_vm(&did_uri); + let verification_method1 = generate_identity_key_vm(did_uri); let verification_method2 = generate_additional_vm(did_uri); let service = Service { @@ -403,7 +407,7 @@ mod tests { verification_method2.id.clone(), ]), service: Some(vec![service]), - verification_method: vec![verification_method1, verification_method2], + verification_method: Some(vec![verification_method1, verification_method2]), }; let packet = document @@ -420,10 +424,10 @@ mod tests { fn test_to_and_from_packet() { let did_uri = "did:dht:123"; - let verification_method = generate_identity_key_vm(&did_uri); + let verification_method = generate_identity_key_vm(did_uri); let document = Document { id: did_uri.to_string(), - verification_method: vec![verification_method], + verification_method: Some(vec![verification_method]), ..Default::default() }; diff --git a/crates/web5/src/dids/methods/jwk.rs b/crates/web5/src/dids/methods/jwk.rs index c7468b4f..4c69a847 100644 --- a/crates/web5/src/dids/methods/jwk.rs +++ b/crates/web5/src/dids/methods/jwk.rs @@ -63,7 +63,7 @@ impl Create for DidJwk { let document = Document { id: uri.clone(), - verification_method: vec![verification_method.clone()], + verification_method: Some(vec![verification_method.clone()]), authentication: Some(vec![verification_method_id.clone()]), assertion_method: Some(vec![verification_method_id.clone()]), capability_invocation: Some(vec![verification_method_id.clone()]), @@ -123,7 +123,9 @@ mod tests { fn create_produces_correct_did_document() { let bearer_did = create_did_jwk(); - let verification_method_id = bearer_did.document.verification_method[0].id.clone(); + let verification_method_id = bearer_did.document.verification_method.unwrap()[0] + .id + .clone(); assert_eq!( bearer_did.document.authentication.unwrap()[0], verification_method_id @@ -161,7 +163,7 @@ mod tests { let did_document = result.did_document.unwrap(); assert_eq!(did_document.id, bearer_did.identifier.uri); - let verification_method_id = did_document.verification_method[0].id.clone(); + let verification_method_id = did_document.verification_method.unwrap()[0].id.clone(); assert_eq!( did_document.authentication.unwrap()[0], verification_method_id diff --git a/crates/web5/src/dids/methods/spruce_mappers/document.rs b/crates/web5/src/dids/methods/spruce_mappers/document.rs index 39434cef..5964997d 100644 --- a/crates/web5/src/dids/methods/spruce_mappers/document.rs +++ b/crates/web5/src/dids/methods/spruce_mappers/document.rs @@ -85,7 +85,7 @@ impl Document { also_known_as: spruce_document .also_known_as .map(|aka| aka.into_iter().map(|uri| uri.to_string()).collect()), - verification_method: verification_methods, + verification_method: Some(verification_methods), authentication, assertion_method, key_agreement, @@ -241,11 +241,12 @@ mod tests { "https://w3id.org/security/suites/jws-2020/v1".to_string() ]) ); + let vm = &document.verification_method.unwrap(); assert_eq!(document.controller, None); assert_eq!(document.also_known_as, None); - assert_eq!(document.verification_method.len(), 1); + assert_eq!(vm.len(), 1); - let vm = &document.verification_method[0]; + let vm = &vm[0]; assert_eq!(vm.id, format!("{}#0", expected_did_uri)); assert_eq!(vm.r#type, "JsonWebKey2020".to_string()); assert_eq!(vm.controller, expected_did_uri); diff --git a/crates/web5/src/jws.rs b/crates/web5/src/jws.rs index 0d315125..097be1d0 100644 --- a/crates/web5/src/jws.rs +++ b/crates/web5/src/jws.rs @@ -158,7 +158,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -200,7 +202,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -251,7 +255,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "".to_string(), @@ -292,7 +298,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -333,7 +341,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "UNSUPPORTED_ALG".to_string(), @@ -374,7 +384,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -415,7 +427,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -456,7 +470,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -498,7 +514,9 @@ mod tests { ) .expect("failed to create bearer did"); - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let header = JwsHeader { alg: "EdDSA".to_string(), @@ -521,7 +539,11 @@ mod tests { }, ) .expect("failed to create bearer did"); - let invalid_key_id = invalid_bearer_did.document.verification_method[0] + let invalid_key_id = invalid_bearer_did + .document + .verification_method + .clone() + .unwrap()[0] .id .clone(); diff --git a/crates/web5/src/jwt/jws.rs b/crates/web5/src/jwt/jws.rs index 86bd752e..7a738f93 100644 --- a/crates/web5/src/jwt/jws.rs +++ b/crates/web5/src/jwt/jws.rs @@ -98,7 +98,9 @@ mod tests { ..Default::default() }; - let key_id = bearer_did.document.verification_method[0].id.clone(); + let key_id = bearer_did.document.verification_method.clone().unwrap()[0] + .id + .clone(); let jwt = Jwt::sign( &bearer_did, &KeySelector::KeyId { @@ -115,7 +117,7 @@ mod tests { assert_eq!("JWT".to_string(), jwt_decoded.header.typ); assert_eq!(key_id, jwt_decoded.header.kid); assert_eq!( - bearer_did.document.verification_method[0] + bearer_did.document.verification_method.clone().unwrap()[0] .public_key_jwk .alg, jwt_decoded.header.alg