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