1use std::sync::Arc;
9
10use ndn_packet::Name;
11
12use crate::Certificate;
13use crate::did::{
14 document::{DidDocument, VerificationMethod, VerificationRef},
15 encoding::name_to_did,
16};
17
18const GENERIC_NAME_COMPONENT: u64 = 8;
20const KEY_COMPONENT: &[u8] = b"KEY";
21
22pub fn cert_to_did_document(cert: &Certificate, x25519_key: Option<&[u8]>) -> DidDocument {
35 let identity_name = strip_key_suffix(cert.name.as_ref());
36 let did = name_to_did(&identity_name);
37 let key_id = format!("{did}#key-0");
38
39 let vm = VerificationMethod::ed25519_jwk(&key_id, &did, &cert.public_key);
40
41 let mut doc = DidDocument {
42 context: vec![
43 "https://www.w3.org/ns/did/v1".to_string(),
44 "https://w3id.org/security/suites/jws-2020/v1".to_string(),
45 ],
46 id: did.clone(),
47 controller: None,
48 verification_methods: vec![vm],
49 authentication: vec![VerificationRef::Reference(key_id.clone())],
50 assertion_method: vec![VerificationRef::Reference(key_id.clone())],
51 key_agreement: vec![],
52 capability_invocation: vec![VerificationRef::Reference(key_id.clone())],
53 capability_delegation: vec![VerificationRef::Reference(key_id)],
54 service: vec![],
55 also_known_as: vec![],
56 };
57
58 if let Some(x25519_bytes) = x25519_key {
60 let ka_id = format!("{did}#key-agreement-0");
61 let ka_vm = VerificationMethod::x25519_jwk(&ka_id, &did, x25519_bytes);
62 doc.verification_methods.push(ka_vm);
63 doc.key_agreement.push(VerificationRef::Reference(ka_id));
64 }
65
66 if let Some(issuer) = &cert.issuer {
68 let issuer_identity = strip_key_suffix(issuer.as_ref());
69 let issuer_did = name_to_did(&issuer_identity);
70 if issuer_did != did {
71 doc.also_known_as.push(issuer_did);
72 }
73 }
74
75 doc
76}
77
78pub fn build_zone_did_document(
90 zone_key: &crate::zone::ZoneKey,
91 x25519_key: Option<&[u8]>,
92 services: Vec<crate::did::document::Service>,
93) -> DidDocument {
94 let did = zone_key.zone_root_did();
95 let key_id = format!("{did}#key-0");
96
97 let vm = VerificationMethod::ed25519_jwk(&key_id, &did, zone_key.public_key_bytes());
98
99 let mut doc = DidDocument {
100 context: vec![
101 "https://www.w3.org/ns/did/v1".to_string(),
102 "https://w3id.org/security/suites/jws-2020/v1".to_string(),
103 ],
104 id: did.clone(),
105 controller: None,
106 verification_methods: vec![vm],
107 authentication: vec![VerificationRef::Reference(key_id.clone())],
108 assertion_method: vec![VerificationRef::Reference(key_id.clone())],
109 key_agreement: vec![],
110 capability_invocation: vec![VerificationRef::Reference(key_id.clone())],
111 capability_delegation: vec![VerificationRef::Reference(key_id)],
112 service: services,
113 also_known_as: vec![],
114 };
115
116 if let Some(x25519_bytes) = x25519_key {
117 let ka_id = format!("{did}#key-agreement-0");
118 let ka_vm = VerificationMethod::x25519_jwk(&ka_id, &did, x25519_bytes);
119 doc.verification_methods.push(ka_vm);
120 doc.key_agreement.push(VerificationRef::Reference(ka_id));
121 }
122
123 doc
124}
125
126pub fn build_zone_succession_document(
133 old_zone_key: &crate::zone::ZoneKey,
134 successor_did: impl Into<String>,
135) -> DidDocument {
136 let did = old_zone_key.zone_root_did();
137 let key_id = format!("{did}#key-0");
138 let vm = VerificationMethod::ed25519_jwk(&key_id, &did, old_zone_key.public_key_bytes());
139
140 DidDocument {
141 context: vec!["https://www.w3.org/ns/did/v1".to_string()],
142 id: did.clone(),
143 controller: None,
144 verification_methods: vec![vm],
145 authentication: vec![VerificationRef::Reference(key_id.clone())],
146 assertion_method: vec![],
147 key_agreement: vec![],
148 capability_invocation: vec![],
149 capability_delegation: vec![],
150 service: vec![],
151 also_known_as: vec![successor_did.into()],
152 }
153}
154
155pub fn did_document_to_trust_anchor(doc: &DidDocument, name: Arc<Name>) -> Option<Certificate> {
159 let key_bytes = doc.ed25519_public_key()?;
160 Some(Certificate {
161 name,
162 public_key: bytes::Bytes::copy_from_slice(&key_bytes),
163 valid_from: 0,
164 valid_until: u64::MAX,
165 issuer: None,
166 signed_region: None,
167 sig_value: None,
168 })
169}
170
171pub(crate) fn strip_key_suffix(name: &Name) -> Name {
175 let comps = name.components();
176 let key_pos = comps
177 .iter()
178 .rposition(|c| c.typ == GENERIC_NAME_COMPONENT && c.value.as_ref() == KEY_COMPONENT);
179 match key_pos {
180 Some(pos) if pos > 0 => Name::from_components(comps[..pos].iter().cloned()),
181 _ => name.clone(),
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn strip_key_suffix_basic() {
191 let name: Name = "/com/acme/alice/KEY/v=123/self".parse().unwrap();
192 let stripped = strip_key_suffix(&name);
193 let expected: Name = "/com/acme/alice".parse().unwrap();
194 assert_eq!(stripped, expected);
195 }
196
197 #[test]
198 fn strip_key_suffix_no_key() {
199 let name: Name = "/com/acme/alice".parse().unwrap();
200 let stripped = strip_key_suffix(&name);
201 assert_eq!(stripped, name);
202 }
203
204 #[test]
205 fn cert_to_did_doc_has_required_relationships() {
206 use bytes::Bytes;
207 let name: Name = "/com/acme/alice/KEY/v=1/self".parse().unwrap();
208 let cert = Certificate {
209 name: Arc::new(name),
210 public_key: Bytes::from(vec![0u8; 32]),
211 valid_from: 0,
212 valid_until: u64::MAX,
213 issuer: None,
214 signed_region: None,
215 sig_value: None,
216 };
217 let doc = cert_to_did_document(&cert, None);
218 let identity_name: Name = "/com/acme/alice".parse().unwrap();
221 let expected_did = crate::did::encoding::name_to_did(&identity_name);
222 assert_eq!(doc.id, expected_did);
223 assert!(!doc.authentication.is_empty());
224 assert!(!doc.assertion_method.is_empty());
225 assert!(!doc.capability_invocation.is_empty());
226 assert!(!doc.capability_delegation.is_empty());
227 assert!(doc.key_agreement.is_empty()); }
229
230 #[test]
231 fn cert_to_did_doc_with_x25519() {
232 use bytes::Bytes;
233 let name: Name = "/com/acme/alice/KEY/v=1/self".parse().unwrap();
234 let cert = Certificate {
235 name: Arc::new(name),
236 public_key: Bytes::from(vec![0u8; 32]),
237 valid_from: 0,
238 valid_until: u64::MAX,
239 issuer: None,
240 signed_region: None,
241 sig_value: None,
242 };
243 let x25519 = [0xABu8; 32];
244 let doc = cert_to_did_document(&cert, Some(&x25519));
245 assert!(!doc.key_agreement.is_empty());
246 assert_eq!(doc.verification_methods.len(), 2);
247 let ka_vm = &doc.verification_methods[1];
249 let crv = ka_vm
250 .public_key_jwk
251 .as_ref()
252 .and_then(|jwk| jwk.get("crv"))
253 .and_then(|v| v.as_str());
254 assert_eq!(crv, Some("X25519"));
255 }
256}