1 use webpki; 2 3 pub use crate::msgs::handshake::{DistinguishedName, DistinguishedNames}; 4 use crate::pemfile; 5 use crate::x509; 6 use crate::key; 7 #[cfg(feature = "logging")] 8 use crate::log::{debug, trace}; 9 use std::io; 10 11 /// This is like a `webpki::TrustAnchor`, except it owns 12 /// rather than borrows its memory. That prevents lifetimes 13 /// leaking up the object tree. 14 #[derive(Debug, Clone)] 15 pub struct OwnedTrustAnchor { 16 subject: Vec<u8>, 17 spki: Vec<u8>, 18 name_constraints: Option<Vec<u8>>, 19 } 20 21 impl OwnedTrustAnchor { from_trust_anchor(t: &webpki::TrustAnchor) -> OwnedTrustAnchor22 fn from_trust_anchor(t: &webpki::TrustAnchor) -> OwnedTrustAnchor { 23 OwnedTrustAnchor { 24 subject: t.subject.to_vec(), 25 spki: t.spki.to_vec(), 26 name_constraints: t.name_constraints.map(|x| x.to_vec()), 27 } 28 } 29 to_trust_anchor(&self) -> webpki::TrustAnchor30 pub fn to_trust_anchor(&self) -> webpki::TrustAnchor { 31 webpki::TrustAnchor { 32 subject: &self.subject, 33 spki: &self.spki, 34 name_constraints: self.name_constraints 35 .as_ref() 36 .map(Vec::as_slice), 37 } 38 } 39 } 40 41 /// A container for root certificates able to provide a root-of-trust 42 /// for connection authentication. 43 #[derive(Debug, Clone)] 44 pub struct RootCertStore { 45 /// The list of roots. 46 pub roots: Vec<OwnedTrustAnchor>, 47 } 48 49 impl RootCertStore { 50 /// Make a new, empty `RootCertStore`. empty() -> RootCertStore51 pub fn empty() -> RootCertStore { 52 RootCertStore { roots: Vec::new() } 53 } 54 55 /// Return true if there are no certificates. is_empty(&self) -> bool56 pub fn is_empty(&self) -> bool { 57 self.len() == 0 58 } 59 60 /// Say how many certificates are in the container. len(&self) -> usize61 pub fn len(&self) -> usize { 62 self.roots.len() 63 } 64 65 /// Return the Subject Names for certificates in the container. get_subjects(&self) -> DistinguishedNames66 pub fn get_subjects(&self) -> DistinguishedNames { 67 let mut r = DistinguishedNames::new(); 68 69 for ota in &self.roots { 70 let mut name = Vec::new(); 71 name.extend_from_slice(&ota.subject); 72 x509::wrap_in_sequence(&mut name); 73 r.push(DistinguishedName::new(name)); 74 } 75 76 r 77 } 78 79 /// Add a single DER-encoded certificate to the store. add(&mut self, der: &key::Certificate) -> Result<(), webpki::Error>80 pub fn add(&mut self, der: &key::Certificate) -> Result<(), webpki::Error> { 81 let ta = webpki::trust_anchor_util::cert_der_as_trust_anchor(&der.0)?; 82 83 let ota = OwnedTrustAnchor::from_trust_anchor(&ta); 84 self.roots.push(ota); 85 Ok(()) 86 } 87 88 /// Adds all the given TrustAnchors `anchors`. This does not 89 /// fail. add_server_trust_anchors(&mut self, &webpki::TLSServerTrustAnchors(anchors): &webpki::TLSServerTrustAnchors)90 pub fn add_server_trust_anchors(&mut self, 91 &webpki::TLSServerTrustAnchors(anchors): 92 &webpki::TLSServerTrustAnchors) { 93 for ta in anchors { 94 self.roots.push(OwnedTrustAnchor::from_trust_anchor(ta)); 95 } 96 } 97 98 /// Parse a PEM file and add all certificates found inside. 99 /// Errors are non-specific; they may be io errors in `rd` and 100 /// PEM format errors, but not certificate validity errors. 101 /// 102 /// This is because large collections of root certificates often 103 /// include ancient or syntactically invalid certificates. CAs 104 /// are competent like that. 105 /// 106 /// Returns the number of certificates added, and the number 107 /// which were extracted from the PEM but ultimately unsuitable. add_pem_file(&mut self, rd: &mut dyn io::BufRead) -> Result<(usize, usize), ()>108 pub fn add_pem_file(&mut self, rd: &mut dyn io::BufRead) -> Result<(usize, usize), ()> { 109 let ders = pemfile::certs(rd)?; 110 let mut valid_count = 0; 111 let mut invalid_count = 0; 112 113 for der in ders { 114 #[cfg_attr(not(feature = "logging"), allow(unused_variables))] 115 match self.add(&der) { 116 Ok(_) => valid_count += 1, 117 Err(err) => { 118 trace!("invalid cert der {:?}", der); 119 debug!("certificate parsing failed: {:?}", err); 120 invalid_count += 1 121 } 122 } 123 } 124 125 debug!("add_pem_file processed {} valid and {} invalid certs", 126 valid_count, 127 invalid_count); 128 129 Ok((valid_count, invalid_count)) 130 } 131 } 132