1use std::borrow::Borrow;
2use std::collections::BTreeMap;
3use std::fmt;
4use std::time::SystemTime;
5use std::ops::Deref;
6
7use sequoia_openpgp as openpgp;
8
9use openpgp::Result;
10use openpgp::cert::prelude::*;
11use openpgp::cert::raw::RawCert;
12use openpgp::Fingerprint;
13use openpgp::packet::UserID;
14use openpgp::policy::Policy;
15
16use sequoia_cert_store as cert_store;
17
18use crate::CertSynopsis;
19use crate::Certification;
20use crate::FULLY_TRUSTED;
21use crate::Path;
22use crate::Paths;
23use crate::RevocationStatus;
24use crate::store::CertStore;
25use crate::store::Store;
26use crate::store::SynopsisSlice;
27
28pub(crate) mod filter;
29use filter::CapCertificateFilter;
30use filter::CapDepthFilter;
31use filter::ChainFilter;
32use filter::SuppressIssuerFilter;
33use filter::SuppressCertificationFilter;
34use filter::TrustedIntroducerFilter;
35mod root;
36pub use root::Root;
37mod roots;
38pub use roots::Roots;
39mod path;
40pub use path::PathError;
41pub use path::CertLints;
42pub use path::CertificationLints;
43pub use path::PathLints;
44mod builder;
45pub use builder::NetworkBuilder;
46
47use super::TRACE;
48
49pub struct Network<S>
51 where S: Store
52{
53 store: S,
54
55 roots: Roots,
57
58 certification_network: bool,
62
63 maximum_depth: Option<usize>,
65}
66
67impl<S> fmt::Debug for Network<S>
68 where S: Store
69{
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 write!(f, "Network {{\n")?;
72 write!(f, " Reference time: {:?}\n", self.reference_time())?;
73 write!(f, " Nodes:\n")?;
74
75 let mut certs: Vec<_> = self.synopses().map(|cert| {
76 (
77 cert.self_signed_and_revoked_userids()
78 .map(|userid| {
79 format!(
80 "{}{}",
81 String::from_utf8_lossy(userid.value()),
82 match userid.revocation_status() {
83 RevocationStatus::NotAsFarAsWeKnow => "",
84 RevocationStatus::Soft(_t) => " (soft revoked)",
85 RevocationStatus::Hard => " (hard revoked)",
86 })
87 })
88 .collect::<Vec<String>>()
89 .join(", "),
90 cert.fingerprint()
91 )
92 }).collect();
93 certs.sort();
94
95 for (userid, fpr) in certs {
96 write!(f, " {}: {}\n", fpr, userid)?;
97 }
98
99 write!(f, " Edges:\n")?;
100
101 let mut certifications: Vec<crate::CertificationSet> = self
102 .iter_fingerprints()
103 .filter_map(|fpr| {
104 if let Ok(cs) = self.certifications_of(&fpr, 0.into()) {
105 if cs.is_empty() {
106 None
107 } else {
108 Some((*cs).clone())
109 }
110 } else {
111 None
112 }
113 })
114 .flatten()
115 .collect::<Vec<_>>();
116 certifications.sort_by_key(|cs| {
117 (cs.issuer().primary_userid().map(|u| u.userid().clone()),
118 cs.issuer().fingerprint(),
119 cs.target().fingerprint())
120 });
121
122 let mut last_issuer_fpr = None;
123 for cs in certifications.into_iter() {
124 let issuer = &cs.issuer();
125 let issuer_fpr = issuer.fingerprint();
126 if Some(&issuer_fpr) != last_issuer_fpr.as_ref() {
127 write!(f, " {} certifies:\n", issuer)?;
128 last_issuer_fpr = Some(issuer_fpr);
129 }
130
131 let target_fpr = cs.target().fingerprint();
132 for c in cs.into_certifications() {
133 write!(f, " {}, {}: {}, {}, {}\n",
134 target_fpr,
135 c.userid().map(|userid| {
136 String::from_utf8_lossy(userid.value()).into_owned()
137 }).unwrap_or_else(|| "<No User ID>".into()),
138 c.depth(), c.amount(),
139 if let Some(re_set) = c.regular_expressions() {
140 if re_set.matches_everything() {
141 "*".into()
142 } else {
143 format!("{:?}", re_set)
144 }
145 } else {
146 "<invalid RE>".into()
147 })?;
148 }
149 }
150
151 write!(f, "}}\n")?;
152
153 Ok(())
154 }
155}
156
157impl<S> Deref for Network<S>
158 where S: Store
159{
160 type Target = S;
161
162 fn deref(&self) -> &Self::Target {
163 &self.store
164 }
165}
166
167impl<S> Network<S>
168 where S: Store
169{
170 pub fn new<R>(store: S, roots: R)
179 -> Result<Self>
180 where R: Into<Roots>,
181 {
182 tracer!(TRACE, "Network::new");
183
184 let roots = roots.into();
185
186 t!("Roots ({}): {}.",
187 roots.iter().count(),
188 roots.iter()
189 .map(|r| format!("{} ({})", r.fingerprint(), r.amount()))
190 .collect::<Vec<_>>()
191 .join(", "));
192
193 Ok(NetworkBuilder::rooted(store, roots).build())
194 }
195
196 pub fn backend(&self) -> &S {
198 &self.store
199 }
200}
201
202impl<'a: 'policy, 'policy> Network<CertStore<'a, 'policy, cert_store::store::Certs<'a>>> {
203 pub fn from_certs<I, C, T, R>(certs: I,
208 policy: &'policy dyn Policy, t: T,
209 roots: R)
210 -> Result<Self>
211 where T: Into<Option<SystemTime>>,
212 I: IntoIterator<Item=C>,
213 C: Into<Cert>,
214 R: Into<Roots>,
215 {
216 tracer!(TRACE, "Network::from_certs");
217
218 let t = t.into().unwrap_or_else(|| crate::now());
219 Network::new(
220 CertStore::from_certs(
221 certs.into_iter().map(|c| c.into()),
222 policy, t)?,
223 roots)
224 }
225
226 pub fn from_cert_refs<I, C, T, R>(certs: I,
231 policy: &'policy dyn Policy, t: T,
232 roots: R)
233 -> Result<Self>
234 where T: Into<Option<SystemTime>>,
235 I: IntoIterator<Item=C>,
236 C: Into<&'a Cert>,
237 R: Into<Roots>,
238 {
239 tracer!(TRACE, "Network::from_certs");
240
241 let t = t.into().unwrap_or_else(|| crate::now());
242 Network::new(
243 CertStore::from_cert_refs(
244 certs.into_iter().map(|c| c.into()),
245 policy, t)?,
246 roots)
247 }
248
249 pub fn from_bytes<T, R>(certs: &'a [u8], policy: &'policy dyn Policy, t: T,
254 roots: R)
255 -> Result<Self>
256 where T: Into<Option<SystemTime>>,
257 R: Into<Roots>,
258 {
259 tracer!(TRACE, "Network::from_bytes");
260
261 let t = t.into().unwrap_or_else(|| crate::now());
262 Network::new(CertStore::from_bytes(certs, policy, t)?, roots)
263 }
264
265 pub fn from_raw_certs<T, R>(certs: impl Iterator<Item=RawCert<'a>>,
270 policy: &'a dyn Policy, t: T,
271 roots: R)
272 -> Result<Self>
273 where T: Into<Option<SystemTime>>,
274 R: Into<Roots>,
275 {
276 tracer!(TRACE, "Network::from_raw_certs");
277
278 let t = t.into().unwrap_or_else(|| crate::now());
279 Network::new(
280 CertStore::from_raw_certs(certs, policy, t)?,
281 roots)
282 }
283}
284
285impl<'a> Network<SynopsisSlice<'a>> {
286 pub fn from_synopses<R>(certs: &'a [CertSynopsis],
291 certifications: &'a [Certification],
292 t: SystemTime,
293 roots: R)
294 -> Result<Self>
295 where R: Into<Roots>
296 {
297 Network::new(
298 SynopsisSlice::new(certs, certifications, t)?,
299 roots)
300 }
301}
302
303impl<S> Network<S>
304 where S: Store
305{
306 pub fn roots(&self) -> &Roots
308 {
309 &self.roots
310 }
311
312 pub fn is_root<F>(&self, fpr: F) -> bool
314 where F: Borrow<Fingerprint>
315 {
316 self.roots.is_root(fpr.borrow())
317 }
318
319 pub fn root<F>(&self, fpr: F) -> Option<&Root>
321 where F: Borrow<Fingerprint>
322 {
323 self.roots.get(fpr.borrow())
324 }
325
326 pub fn certification_network(&self) -> bool {
331 self.certification_network
332 }
333
334 pub fn authentication_network(&self) -> bool {
339 ! self.certification_network
340 }
341
342 pub fn maximum_depth(&mut self) -> Option<usize> {
348 self.maximum_depth
349 }
350
351 fn authenticate_internal<U, F>(&self, target_userid: U, target_fpr: F,
352 target_trust_amount: usize,
353 gossip: bool)
354 -> Paths
355 where U: Borrow<UserID>,
356 F: Borrow<Fingerprint>,
357 {
358 tracer!(TRACE, "Network::authenticate_internal");
359
360 let target_userid = target_userid.borrow();
361 let target_fpr = target_fpr.borrow();
362
363 t!("Authenticating <{}, {}>",
364 target_fpr, String::from_utf8_lossy(target_userid.value()));
365 t!("Roots ({}):", self.roots.iter().count());
366 for (i, r) in self.roots.iter().enumerate() {
367 t!(" {}: {} ({})", i, r.fingerprint(), r.amount());
368 }
369
370 let mut paths = Paths::new();
371
372 let mut filter = ChainFilter::new();
373 if self.certification_network {
374 filter.push(TrustedIntroducerFilter::new());
378 } else {
379 if self.roots.iter().any(|r| r.amount() != FULLY_TRUSTED) {
380 let mut caps = CapCertificateFilter::new();
381 for r in self.roots.iter() {
382 let amount = r.amount();
383 if amount != FULLY_TRUSTED {
384 caps.cap(r.fingerprint().clone(), amount);
385 }
386 }
387 filter.push(caps);
388 };
389 }
390
391 if let Some(limit) = self.maximum_depth {
395 filter.push(CapDepthFilter::new(limit));
396 }
397
398 let mut progress = true;
399 'next_path: while progress
400 && (paths.amount() < target_trust_amount || gossip)
401 {
402 progress = false;
403
404 let mut gossip_paths = Vec::new();
405
406 for self_signed in [true, false] {
407 let auth_paths: BTreeMap<Fingerprint, (Path, usize)>
408 = self.backward_propagate(
409 target_fpr.clone(), target_userid.clone(),
410 self_signed, &filter, gossip);
411
412 if let Some((path, path_amount)) = self.roots.iter()
418 .filter_map(|r| {
420 auth_paths.get(r.fingerprint())
421 })
422 .max_by_key(|(path, path_amount)| {
426 (path_amount,
428 -(path.len() as isize),
430 path.root().fingerprint())
433 })
434 {
435 let path = path.clone();
436
437 if path.len() == 1 {
438 let mut suppress_filter
440 = SuppressIssuerFilter::new();
441 suppress_filter.suppress_issuer(
442 &path.root().fingerprint(), *path_amount);
443 filter.push(suppress_filter);
444 } else {
445 let mut suppress_filter
448 = SuppressCertificationFilter::new();
449 suppress_filter.suppress_path(&path, *path_amount);
450 filter.push(suppress_filter);
451 }
452
453 paths.push(path, *path_amount);
454 progress = true;
455 continue 'next_path;
458 } else if gossip {
459 gossip_paths.extend(auth_paths.into_values());
460 }
461 }
462
463 assert!(! progress);
465
466 if gossip {
467 t!("Adding the remaining paths ({}) as gossip paths",
473 gossip_paths.len());
474
475 gossip_paths.sort_by_key(|(path, _amount)| {
476 -(path.len() as isize)
477 });
478 for (path, _amount) in gossip_paths.into_iter() {
479 if ! paths.has_suffix(&path) {
480 t!("Adding: {:?} (length: {})", path, path.len());
481 paths.push(path, 0);
482 } else {
483 t!("Skipping suffix: {:?}", path);
484 }
485 }
486 }
487 }
488
489 paths
490 }
491
492 pub fn authenticate<U, F>(&self, target_userid: U, target_fpr: F,
499 target_trust_amount: usize)
500 -> Paths
501 where U: Borrow<UserID>,
502 F: Borrow<Fingerprint>,
503 {
504 self.authenticate_internal(target_userid, target_fpr,
505 target_trust_amount, false)
506 }
507
508 pub fn gossip<U, F>(&self, target_fpr: F, target_userid: U)
518 -> Paths
519 where U: Borrow<UserID>,
520 F: Borrow<Fingerprint>,
521 {
522 self.authenticate_internal(target_userid, target_fpr,
523 0, true)
524 }
525}
526
527#[cfg(test)]
528mod test {
529 use super::*;
530
531 use std::slice;
532 use std::time;
533
534 use openpgp::Fingerprint;
535 use openpgp::packet::UserID;
536 use openpgp::parse::Parse;
537 use openpgp::policy::StandardPolicy;
538
539 #[allow(unused)]
540 #[test]
541 fn third_party_certifications_of() -> Result<()> {
542 let p = &StandardPolicy::new();
543
544 let alice_fpr: Fingerprint =
545 "2A2A4A23A7EEC119BC0B46642B3825DC02A05FEA"
546 .parse().expect("valid fingerprint");
547 let alice_uid
548 = UserID::from("<alice@example.org>");
549
550 let bob_fpr: Fingerprint =
551 "03182611B91B1E7E20B848E83DFC151ABFAD85D5"
552 .parse().expect("valid fingerprint");
553 let bob_uid
554 = UserID::from("<bob@other.org>");
555 let bob_some_org_uid
557 = UserID::from("<bob@some.org>");
558 let carol_fpr: Fingerprint =
561 "9CA36907B46FE7B6B9EE9601E78064C12B6D7902"
562 .parse().expect("valid fingerprint");
563 let carol_uid
564 = UserID::from("<carol@example.org>");
565 let dave_fpr: Fingerprint =
568 "C1BC6794A6C6281B968A6A41ACE2055D610CEA03"
569 .parse().expect("valid fingerprint");
570 let dave_uid
571 = UserID::from("<dave@other.org>");
572 let certs: Vec<Cert> = CertParser::from_bytes(
576 &crate::testdata::data("multiple-userids-1.pgp"))?
577 .map(|c| c.expect("Valid certificate"))
578 .collect();
579 let store = CertStore::from_cert_refs(
580 certs.iter().map(|c| c.into()), p, None)?;
581 let n = NetworkBuilder::rootless(store).build();
582
583 eprintln!("{:?}", n);
584
585 assert!(
587 n.third_party_certifications_of(&alice_fpr.clone())
588 .is_empty());
589
590 let mut c = n.third_party_certifications_of(&bob_fpr);
592 assert_eq!(c.len(), 2);
593 c.sort_by_key(|c| (c.issuer().fingerprint(),
594 c.userid().map(Clone::clone)));
595 assert_eq!(&c[0].issuer().fingerprint(), &alice_fpr);
596 assert_eq!(c[0].userid(), Some(&bob_uid));
597 assert_eq!(&c[1].issuer().fingerprint(), &alice_fpr);
598 assert_eq!(c[1].userid(), Some(&bob_some_org_uid));
599
600 Ok(())
601 }
602
603 #[allow(unused)]
604 #[test]
605 fn certified_userids_of() -> Result<()> {
606 let p = &StandardPolicy::new();
607
608 let alice_fpr: Fingerprint =
609 "2A2A4A23A7EEC119BC0B46642B3825DC02A05FEA"
610 .parse().expect("valid fingerprint");
611 let alice_uid
612 = UserID::from("<alice@example.org>");
613
614 let bob_fpr: Fingerprint =
615 "03182611B91B1E7E20B848E83DFC151ABFAD85D5"
616 .parse().expect("valid fingerprint");
617 let bob_uid
618 = UserID::from("<bob@other.org>");
619 let bob_some_org_uid
621 = UserID::from("<bob@some.org>");
622 let carol_fpr: Fingerprint =
625 "9CA36907B46FE7B6B9EE9601E78064C12B6D7902"
626 .parse().expect("valid fingerprint");
627 let carol_uid
628 = UserID::from("<carol@example.org>");
629 let dave_fpr: Fingerprint =
632 "C1BC6794A6C6281B968A6A41ACE2055D610CEA03"
633 .parse().expect("valid fingerprint");
634 let dave_uid
635 = UserID::from("<dave@other.org>");
636 let certs: Vec<Cert> = CertParser::from_bytes(
640 &crate::testdata::data("multiple-userids-1.pgp"))?
641 .map(|c| c.expect("Valid certificate"))
642 .collect();
643 let store = CertStore::from_cert_refs(
644 certs.iter().map(|c| c.into()), p, None)?;
645 let n = NetworkBuilder::rootless(store).build();
646
647 eprintln!("{:?}", n);
648
649 let mut c = n.certified_userids_of(&alice_fpr);
651 assert_eq!(c.len(), 1);
652
653 let mut c = n.certified_userids_of(&bob_fpr);
656 assert_eq!(c.len(), 2);
657 c.sort_unstable();
658 assert_eq!(&c[0], &bob_uid);
659 assert_eq!(&c[1], &bob_some_org_uid);
660
661 Ok(())
662 }
663
664 #[allow(unused)]
665 #[test]
666 fn certified_userids() -> Result<()> {
667 let p = &StandardPolicy::new();
668
669 let alice_fpr: Fingerprint =
670 "2A2A4A23A7EEC119BC0B46642B3825DC02A05FEA"
671 .parse().expect("valid fingerprint");
672 let alice_uid
673 = UserID::from("<alice@example.org>");
674
675 let bob_fpr: Fingerprint =
676 "03182611B91B1E7E20B848E83DFC151ABFAD85D5"
677 .parse().expect("valid fingerprint");
678 let bob_uid
679 = UserID::from("<bob@other.org>");
680 let bob_some_org_uid
682 = UserID::from("<bob@some.org>");
683 let carol_fpr: Fingerprint =
686 "9CA36907B46FE7B6B9EE9601E78064C12B6D7902"
687 .parse().expect("valid fingerprint");
688 let carol_uid
689 = UserID::from("<carol@example.org>");
690 let dave_fpr: Fingerprint =
693 "C1BC6794A6C6281B968A6A41ACE2055D610CEA03"
694 .parse().expect("valid fingerprint");
695 let dave_uid
696 = UserID::from("<dave@other.org>");
697 let certs: Vec<Cert> = CertParser::from_bytes(
701 &crate::testdata::data("multiple-userids-1.pgp"))?
702 .map(|c| c.expect("Valid certificate"))
703 .collect();
704 let store = CertStore::from_cert_refs(
705 certs.iter().map(|c| c.into()), p, None)?;
706 let n = NetworkBuilder::rootless(store).build();
707
708 eprintln!("{:?}", n);
709
710 let mut got = n.certified_userids();
713 assert_eq!(got.len(), 5);
714
715 got.sort_unstable();
716
717 let mut expected = [
718 (alice_fpr.clone(), alice_uid.clone()),
719 (bob_fpr.clone(), bob_uid.clone()),
720 (bob_fpr.clone(), bob_some_org_uid.clone()),
721 (carol_fpr.clone(), carol_uid.clone()),
722 (dave_fpr.clone(), dave_uid.clone()),
723 ];
724 expected.sort_unstable();
725
726 assert_eq!(got, expected);
727
728 Ok(())
729 }
730
731 #[allow(unused)]
732 #[test]
733 fn not_self_signed_revoked_userids() -> Result<()> {
734 let p = &StandardPolicy::new();
735
736 let alice_fpr: Fingerprint =
737 "D74DE22EDAE82EB8AD87A2D9816B56FDF9022248"
738 .parse().expect("valid fingerprint");
739 let alice_uid
740 = UserID::from("<alice@example.org>");
741
742 let bob_fpr: Fingerprint =
743 "3CC2F380C997730543AFCA3830887147FDECD335"
744 .parse().expect("valid fingerprint");
745 let bob_uid
746 = UserID::from("<bob@example.org>");
747 let bob_other_org_uid
748 = UserID::from("<bob@other.org>");
749 let t1 = time::UNIX_EPOCH + time::Duration::new(1580598000, 0);
754 let t2 = time::UNIX_EPOCH + time::Duration::new(1583103600, 0);
757
758 let certs: Vec<Cert> = CertParser::from_bytes(
759 &crate::testdata::data("userid-revoked-2.pgp"))?
760 .map(|c| c.expect("Valid certificate"))
761 .collect();
762
763 let store = CertStore::from_cert_refs(
764 certs.iter().map(|c| c.into()), p, t1)?;
765 let n = NetworkBuilder::rooted(store,
766 Roots::from(slice::from_ref(&alice_fpr)))
767 .build();
768
769 eprintln!("{:?}", n);
770
771 let paths = n.authenticate(&bob_other_org_uid, bob_fpr.clone(),
773 FULLY_TRUSTED);
774 assert_eq!(paths.len(), 1);
775
776 let store = CertStore::from_cert_refs(
777 certs.iter().map(|c| c.into()), p, t2)?;
778 let n = NetworkBuilder::rooted(store,
779 Roots::from(slice::from_ref(&alice_fpr)))
780 .build();
781
782 let paths = n.authenticate(&bob_other_org_uid, bob_fpr.clone(),
786 FULLY_TRUSTED);
787 assert_eq!(paths.len(), 0);
788
789 Ok(())
790 }
791}