1use std::collections::HashSet;
2use std::sync::Arc;
3
4use ndn_packet::{Data, Name, SignatureType};
5
6use crate::cert_cache::Certificate;
7use crate::safe_data::TrustPath;
8use crate::verifier::Verifier;
9use crate::{SafeData, TrustError, VerifyOutcome};
10
11use super::{ValidationResult, Validator, now_ns};
12
13impl Validator {
14 pub async fn validate_chain(&self, data: &Data) -> ValidationResult {
21 let Some(sig_info) = data.sig_info() else {
22 return ValidationResult::Invalid(TrustError::InvalidSignature);
23 };
24
25 if sig_info.sig_type == SignatureType::DigestSha256 {
28 use sha2::{Digest, Sha256};
29 let hash = Sha256::digest(data.signed_region());
30 if hash.as_slice() == data.sig_value() {
31 let safe = SafeData {
32 inner: Data::decode(data.raw().clone())
33 .expect("already decoded, re-decode cannot fail"),
34 trust_path: TrustPath::DigestSha256,
35 verified_at: now_ns(),
36 };
37 return ValidationResult::Valid(Box::new(safe));
38 }
39 return ValidationResult::Invalid(TrustError::InvalidSignature);
40 }
41
42 let first_key: Arc<Name> = if let Some(name) = &sig_info.key_locator {
49 Arc::clone(name)
50 } else if let Some(digest) = &sig_info.key_digest {
51 match self.cert_cache.get_by_key_digest(digest) {
52 Some(cert) => Arc::clone(&cert.name),
53 None => return ValidationResult::Invalid(TrustError::InvalidSignature),
54 }
55 } else {
56 return ValidationResult::Invalid(TrustError::InvalidSignature);
57 };
58
59 if !self
60 .schema
61 .read()
62 .expect("schema RwLock poisoned")
63 .allows(&data.name, &first_key)
64 {
65 return ValidationResult::Invalid(TrustError::SchemaMismatch);
66 }
67
68 let now = now_ns();
69 let mut chain_names: Vec<Name> = Vec::new();
70 let mut seen: HashSet<Arc<Name>> = HashSet::new();
71
72 let mut current_signed_region: &[u8] = data.signed_region();
74 let mut current_sig_value: &[u8] = data.sig_value();
75 let mut current_key_name: Arc<Name> = first_key;
76
77 let mut owned_signed_region: bytes::Bytes;
79 let mut owned_sig_value: bytes::Bytes;
80
81 for _depth in 0..self.max_chain {
82 if !seen.insert(Arc::clone(¤t_key_name)) {
83 return ValidationResult::Invalid(TrustError::ChainCycle {
84 name: current_key_name.to_string(),
85 });
86 }
87
88 if let Some(anchor) = self.trust_anchors.get(¤t_key_name) {
90 if !anchor.is_valid_at(now) {
91 return ValidationResult::Invalid(TrustError::CertNotFound {
92 name: format!("expired trust anchor: {}", current_key_name),
93 });
94 }
95 return match self
96 .verifier
97 .verify(current_signed_region, current_sig_value, &anchor.public_key)
98 .await
99 {
100 Ok(VerifyOutcome::Valid) => {
101 chain_names.push(current_key_name.as_ref().clone());
102 let safe = SafeData {
103 inner: Data::decode(data.raw().clone()).unwrap(),
104 trust_path: crate::safe_data::TrustPath::CertChain(chain_names),
105 verified_at: now,
106 };
107 ValidationResult::Valid(Box::new(safe))
108 }
109 Ok(VerifyOutcome::Invalid) => {
110 ValidationResult::Invalid(TrustError::InvalidSignature)
111 }
112 Err(e) => ValidationResult::Invalid(e),
113 };
114 }
115
116 let cert = match self.resolve_cert(¤t_key_name).await {
118 Some(c) => c,
119 None => return ValidationResult::Pending,
120 };
121
122 if !cert.is_valid_at(now) {
123 return ValidationResult::Invalid(TrustError::CertNotFound {
124 name: format!("expired or not-yet-valid: {}", current_key_name),
125 });
126 }
127
128 match self
130 .verifier
131 .verify(current_signed_region, current_sig_value, &cert.public_key)
132 .await
133 {
134 Ok(VerifyOutcome::Valid) => {}
135 Ok(VerifyOutcome::Invalid) => {
136 return ValidationResult::Invalid(TrustError::InvalidSignature);
137 }
138 Err(e) => return ValidationResult::Invalid(e),
139 }
140
141 chain_names.push(current_key_name.as_ref().clone());
142
143 let Some(issuer) = &cert.issuer else {
145 return ValidationResult::Invalid(TrustError::CertNotFound {
146 name: format!("cert has no issuer: {}", cert.name),
147 });
148 };
149 let Some(sr) = &cert.signed_region else {
150 return ValidationResult::Invalid(TrustError::CertNotFound {
151 name: format!("cert missing signed region: {}", cert.name),
152 });
153 };
154 let Some(sv) = &cert.sig_value else {
155 return ValidationResult::Invalid(TrustError::CertNotFound {
156 name: format!("cert missing sig value: {}", cert.name),
157 });
158 };
159
160 owned_signed_region = sr.clone();
161 owned_sig_value = sv.clone();
162 current_signed_region = &owned_signed_region;
163 current_sig_value = &owned_sig_value;
164 current_key_name = Arc::clone(issuer);
165 }
166
167 ValidationResult::Invalid(TrustError::ChainTooDeep {
168 limit: self.max_chain,
169 })
170 }
171
172 async fn resolve_cert(&self, name: &Arc<Name>) -> Option<Certificate> {
174 if let Some(cert) = self.cert_cache.get(name) {
175 return Some(cert);
176 }
177 if let Some(fetcher) = &self.cert_fetcher {
178 fetcher.fetch(name).await.ok()
179 } else {
180 None
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::TrustSchema;
189 use crate::cert_cache::Certificate;
190 use crate::signer::{Ed25519Signer, Signer};
191 use crate::trust_schema::{NamePattern, PatternComponent};
192 use bytes::Bytes;
193 use ndn_packet::{Name, NameComponent};
194 use std::sync::Arc;
195
196 fn comp(s: &'static str) -> NameComponent {
197 NameComponent::generic(Bytes::from_static(s.as_bytes()))
198 }
199 fn name1(c: &'static str) -> Name {
200 Name::from_components([comp(c)])
201 }
202
203 async fn make_signed_data(
205 signer: &Ed25519Signer,
206 data_comp: &'static str,
207 key_comp: &'static str,
208 ) -> Bytes {
209 use ndn_tlv::TlvWriter;
210
211 let nc = {
212 let mut w = TlvWriter::new();
213 w.write_tlv(0x08, data_comp.as_bytes());
214 w.finish()
215 };
216 let name_tlv = {
217 let mut w = TlvWriter::new();
218 w.write_tlv(0x07, &nc);
219 w.finish()
220 };
221
222 let knc = {
223 let mut w = TlvWriter::new();
224 w.write_tlv(0x08, key_comp.as_bytes());
225 w.finish()
226 };
227 let kname_tlv = {
228 let mut w = TlvWriter::new();
229 w.write_tlv(0x07, &knc);
230 w.finish()
231 };
232 let kloc_tlv = {
233 let mut w = TlvWriter::new();
234 w.write_tlv(0x1c, &kname_tlv);
235 w.finish()
236 };
237 let stype_tlv = {
238 let mut w = TlvWriter::new();
239 w.write_tlv(0x1b, &[7u8]);
240 w.finish()
241 };
242 let sinfo_inner: Vec<u8> = stype_tlv.iter().chain(kloc_tlv.iter()).copied().collect();
243 let sinfo_tlv = {
244 let mut w = TlvWriter::new();
245 w.write_tlv(0x16, &sinfo_inner);
246 w.finish()
247 };
248
249 let signed_region: Vec<u8> = name_tlv.iter().chain(sinfo_tlv.iter()).copied().collect();
250 let sig = signer.sign(&signed_region).await.unwrap();
251
252 let sval_tlv = {
253 let mut w = TlvWriter::new();
254 w.write_tlv(0x17, &sig);
255 w.finish()
256 };
257 let inner: Vec<u8> = signed_region
258 .iter()
259 .chain(sval_tlv.iter())
260 .copied()
261 .collect();
262 let mut w = TlvWriter::new();
263 w.write_tlv(0x06, &inner);
264 w.finish()
265 }
266
267 async fn make_cert_data_packet(
270 cert_name: &Name,
271 subject_pk: &[u8],
272 issuer_signer: &Ed25519Signer,
273 ) -> Bytes {
274 use ndn_tlv::TlvWriter;
275
276 let name_inner = {
277 let mut w = TlvWriter::new();
278 for c in cert_name.components() {
279 w.write_tlv(c.typ, &c.value);
280 }
281 w.finish()
282 };
283 let name_tlv = {
284 let mut w = TlvWriter::new();
285 w.write_tlv(0x07, &name_inner);
286 w.finish()
287 };
288
289 let content_tlv = {
290 let mut w = TlvWriter::new();
291 w.write_nested(0x15, |w| {
292 w.write_tlv(0x00, subject_pk);
293 });
294 w.finish()
295 };
296
297 let issuer_name_inner = {
298 let mut w = TlvWriter::new();
299 for c in issuer_signer.key_name().components() {
300 w.write_tlv(c.typ, &c.value);
301 }
302 w.finish()
303 };
304 let sinfo_tlv = {
305 let mut w = TlvWriter::new();
306 w.write_nested(0x16, |w| {
307 w.write_tlv(0x1b, &[7u8]);
308 w.write_nested(0x1c, |w| {
309 w.write_tlv(0x07, &issuer_name_inner);
310 });
311 });
312 w.finish()
313 };
314
315 let signed_region: Vec<u8> = name_tlv
316 .iter()
317 .chain(content_tlv.iter())
318 .chain(sinfo_tlv.iter())
319 .copied()
320 .collect();
321 let sig = issuer_signer.sign(&signed_region).await.unwrap();
322
323 let sval_tlv = {
324 let mut w = TlvWriter::new();
325 w.write_tlv(0x17, &sig);
326 w.finish()
327 };
328 let inner: Vec<u8> = signed_region
329 .iter()
330 .chain(sval_tlv.iter())
331 .copied()
332 .collect();
333 let mut w = TlvWriter::new();
334 w.write_tlv(0x06, &inner);
335 w.finish()
336 }
337
338 fn wildcard_schema() -> TrustSchema {
340 use crate::trust_schema::SchemaRule;
341 let mut schema = TrustSchema::new();
342 schema.add_rule(SchemaRule {
343 data_pattern: NamePattern(vec![PatternComponent::MultiCapture("_".into())]),
344 key_pattern: NamePattern(vec![PatternComponent::MultiCapture("_".into())]),
345 });
346 schema
347 }
348
349 #[tokio::test]
350 async fn chain_walk_data_to_anchor() {
351 let anchor_seed = [20u8; 32];
353 let anchor_name = name1("anchor");
354 let anchor_signer = Ed25519Signer::from_seed(&anchor_seed, anchor_name.clone());
355 let anchor_pk = ed25519_dalek::SigningKey::from_bytes(&anchor_seed)
356 .verifying_key()
357 .to_bytes();
358
359 let key_seed = [21u8; 32];
360 let key_name = name1("key");
361 let key_signer = Ed25519Signer::from_seed(&key_seed, key_name.clone());
362 let key_pk = ed25519_dalek::SigningKey::from_bytes(&key_seed)
363 .verifying_key()
364 .to_bytes();
365
366 let cert_wire = make_cert_data_packet(&key_name, &key_pk, &anchor_signer).await;
367 let cert_data = Data::decode(cert_wire).unwrap();
368 let cert = Certificate::decode(&cert_data).unwrap();
369
370 let data_bytes = make_signed_data(&key_signer, "data", "key").await;
371 let data = Data::decode(data_bytes).unwrap();
372
373 let validator = Validator::new(wildcard_schema());
374 validator.add_trust_anchor(Certificate {
375 name: Arc::new(anchor_name),
376 public_key: Bytes::copy_from_slice(&anchor_pk),
377 valid_from: 0,
378 valid_until: u64::MAX,
379 issuer: None,
380 signed_region: None,
381 sig_value: None,
382 });
383 validator.cert_cache().insert(cert);
384
385 match validator.validate_chain(&data).await {
386 ValidationResult::Valid(safe) => {
387 assert_eq!(safe.inner.name, data.name);
388 }
389 ValidationResult::Invalid(e) => panic!("expected Valid, got Invalid: {e}"),
390 ValidationResult::Pending => panic!("expected Valid, got Pending"),
391 }
392 }
393
394 #[tokio::test]
395 async fn chain_walk_missing_cert_returns_pending() {
396 let key_seed = [22u8; 32];
397 let key_name = name1("key");
398 let key_signer = Ed25519Signer::from_seed(&key_seed, key_name);
399
400 let data_bytes = make_signed_data(&key_signer, "data", "key").await;
401 let data = Data::decode(data_bytes).unwrap();
402
403 let validator = Validator::new(wildcard_schema());
404 assert!(matches!(
405 validator.validate_chain(&data).await,
406 ValidationResult::Pending
407 ));
408 }
409
410 async fn make_signed_data_with_key_digest(
415 signer: &Ed25519Signer,
416 signer_pk: &[u8],
417 data_comp: &'static str,
418 ) -> Bytes {
419 use ndn_tlv::TlvWriter;
420
421 let nc = {
422 let mut w = TlvWriter::new();
423 w.write_tlv(0x08, data_comp.as_bytes());
424 w.finish()
425 };
426 let name_tlv = {
427 let mut w = TlvWriter::new();
428 w.write_tlv(0x07, &nc);
429 w.finish()
430 };
431
432 let digest = {
434 use sha2::{Digest, Sha256};
435 Sha256::digest(signer_pk)
436 };
437 let kloc_tlv = {
438 let mut w = TlvWriter::new();
439 w.write_nested(0x1c, |w| {
440 w.write_tlv(0x1d, digest.as_slice());
441 });
442 w.finish()
443 };
444 let stype_tlv = {
445 let mut w = TlvWriter::new();
446 w.write_tlv(0x1b, &[7u8]); w.finish()
448 };
449 let sinfo_inner: Vec<u8> = stype_tlv.iter().chain(kloc_tlv.iter()).copied().collect();
450 let sinfo_tlv = {
451 let mut w = TlvWriter::new();
452 w.write_tlv(0x16, &sinfo_inner);
453 w.finish()
454 };
455
456 let signed_region: Vec<u8> = name_tlv.iter().chain(sinfo_tlv.iter()).copied().collect();
457 let sig = signer.sign(&signed_region).await.unwrap();
458
459 let sval_tlv = {
460 let mut w = TlvWriter::new();
461 w.write_tlv(0x17, &sig);
462 w.finish()
463 };
464 let inner: Vec<u8> = signed_region
465 .iter()
466 .chain(sval_tlv.iter())
467 .copied()
468 .collect();
469 let mut w = TlvWriter::new();
470 w.write_tlv(0x06, &inner);
471 w.finish()
472 }
473
474 #[tokio::test]
475 async fn chain_walk_resolves_key_digest_via_cache() {
476 let anchor_seed = [30u8; 32];
481 let anchor_name = name1("anchor");
482 let anchor_signer = Ed25519Signer::from_seed(&anchor_seed, anchor_name.clone());
483 let anchor_pk = ed25519_dalek::SigningKey::from_bytes(&anchor_seed)
484 .verifying_key()
485 .to_bytes();
486
487 let key_seed = [31u8; 32];
488 let key_name = name1("key");
489 let key_signer = Ed25519Signer::from_seed(&key_seed, key_name.clone());
490 let key_pk = ed25519_dalek::SigningKey::from_bytes(&key_seed)
491 .verifying_key()
492 .to_bytes();
493
494 let cert_wire = make_cert_data_packet(&key_name, &key_pk, &anchor_signer).await;
495 let cert_data = Data::decode(cert_wire).unwrap();
496 let cert = Certificate::decode(&cert_data).unwrap();
497
498 let data_bytes = make_signed_data_with_key_digest(&key_signer, &key_pk, "data").await;
499 let data = Data::decode(data_bytes).unwrap();
500
501 let validator = Validator::new(wildcard_schema());
502 validator.add_trust_anchor(Certificate {
503 name: Arc::new(anchor_name),
504 public_key: Bytes::copy_from_slice(&anchor_pk),
505 valid_from: 0,
506 valid_until: u64::MAX,
507 issuer: None,
508 signed_region: None,
509 sig_value: None,
510 });
511 validator.cert_cache().insert(cert);
512
513 match validator.validate_chain(&data).await {
514 ValidationResult::Valid(safe) => {
515 assert_eq!(safe.inner.name, data.name);
516 }
517 ValidationResult::Invalid(e) => {
518 panic!("expected Valid, got Invalid: {e}")
519 }
520 ValidationResult::Pending => panic!("expected Valid, got Pending"),
521 }
522 }
523
524 #[tokio::test]
525 async fn chain_walk_key_digest_uncached_returns_invalid() {
526 let key_seed = [32u8; 32];
529 let key_name = name1("key");
530 let key_signer = Ed25519Signer::from_seed(&key_seed, key_name);
531 let key_pk = ed25519_dalek::SigningKey::from_bytes(&key_seed)
532 .verifying_key()
533 .to_bytes();
534
535 let data_bytes = make_signed_data_with_key_digest(&key_signer, &key_pk, "data").await;
536 let data = Data::decode(data_bytes).unwrap();
537
538 let validator = Validator::new(wildcard_schema());
539 match validator.validate_chain(&data).await {
540 ValidationResult::Invalid(TrustError::InvalidSignature) => {}
541 other => panic!("expected Invalid(InvalidSignature), got: {other:?}"),
542 }
543 }
544
545 #[tokio::test]
546 async fn chain_walk_depth_limit() {
547 let seed = [23u8; 32];
548 let key_name = name1("key");
549 let signer = Ed25519Signer::from_seed(&seed, key_name.clone());
550 let pk = ed25519_dalek::SigningKey::from_bytes(&seed)
551 .verifying_key()
552 .to_bytes();
553
554 let cert_wire = make_cert_data_packet(&key_name, &pk, &signer).await;
555 let cert_data = Data::decode(cert_wire).unwrap();
556 let cert = Certificate::decode(&cert_data).unwrap();
557
558 let data_bytes = make_signed_data(&signer, "data", "key").await;
559 let data = Data::decode(data_bytes).unwrap();
560
561 let validator = Validator::new(wildcard_schema());
562 validator.cert_cache().insert(cert);
563
564 match validator.validate_chain(&data).await {
565 ValidationResult::Invalid(TrustError::ChainCycle { .. }) => {}
566 other => panic!("expected ChainCycle, got: {other:?}"),
567 }
568 }
569}