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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::io::BufReader;
use webpki;
use rustls::{ResolvesServerCert, SignatureScheme, PrivateKey};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::internal::pemfile;
use sozu_command::proxy::{CertificateAndKey, CertFingerprint, AddCertificate, RemoveCertificate};
use sozu_command::certificate::calculate_fingerprint_from_der;
use network::trie::TrieNode;
struct TlsData {
pub cert: CertifiedKey,
pub refcount: usize,
}
pub struct CertificateResolver {
domains: TrieNode<CertFingerprint>,
certificates: HashMap<CertFingerprint, TlsData>,
}
impl CertificateResolver {
pub fn new() -> CertificateResolver {
CertificateResolver {
domains: TrieNode::root(),
certificates: HashMap::new(),
}
}
pub fn add_certificate(&mut self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
if let Some(certified_key) = generate_certified_key(add_certificate.certificate) {
if add_certificate.names.is_empty() {
unimplemented!("the rustls proxy cannot extract the names from the certificate");
}
let mut names = add_certificate.names;
let fingerprint = calculate_fingerprint_from_der(&certified_key.cert[0].0);
let data = TlsData {
cert: certified_key,
refcount: 0,
};
let fingerprint = CertFingerprint(fingerprint);
self.certificates.insert(fingerprint.clone(), data);
for name in names.drain(..) {
self.domains.domain_insert(name.into_bytes(), fingerprint.clone());
}
Some(fingerprint)
} else {
None
}
}
pub fn remove_certificate(&mut self, remove_certificate: RemoveCertificate) {
let must_delete = self.certificates.get(&remove_certificate.fingerprint).map(|data| data.refcount == 0).unwrap_or(false);
if let Some(data) = self.certificates.get(&remove_certificate.fingerprint) {
let cert = &data.cert.cert[0];
if remove_certificate.names.is_empty() {
unimplemented!("the rustls proxy cannot extract the names from the certificate");
}
let mut names = remove_certificate.names;
for name in names {
self.domains.domain_remove(&name.into_bytes());
}
}
if must_delete {
self.certificates.remove(&remove_certificate.fingerprint);
}
}
pub fn add_front(&mut self, fingerprint: &CertFingerprint) -> bool {
if self.certificates.contains_key(fingerprint) {
self.certificates.get_mut(fingerprint).map(|data| data.refcount += 1);
true
} else {
false
}
}
pub fn remove_front(&mut self, fingerprint: &CertFingerprint) {
self.certificates.get_mut(fingerprint).map(|data| data.refcount -= 1);
let must_delete = self.certificates.get(fingerprint).map(|data| data.refcount == 0).unwrap_or(false);
if must_delete {
self.certificates.remove(fingerprint);
}
}
}
pub struct CertificateResolverWrapper(Mutex<CertificateResolver>);
impl CertificateResolverWrapper {
pub fn new() -> CertificateResolverWrapper {
CertificateResolverWrapper(Mutex::new(CertificateResolver::new()))
}
pub fn add_certificate(&self, add_certificate: AddCertificate) -> Option<CertFingerprint> {
if let Ok(ref mut resolver) = self.0.try_lock() {
resolver.add_certificate(add_certificate)
} else {
None
}
}
pub fn remove_certificate(&self, remove_certificate: RemoveCertificate) {
if let Ok(ref mut resolver) = self.0.try_lock() {
resolver.remove_certificate(remove_certificate)
}
}
pub fn add_front(&self, fingerprint: &CertFingerprint) -> bool {
if let Ok(ref mut resolver) = self.0.try_lock() {
resolver.add_front(fingerprint)
} else {
false
}
}
pub fn remove_front(&self, fingerprint: &CertFingerprint) {
if let Ok(ref mut resolver) = self.0.try_lock() {
resolver.remove_front(fingerprint)
}
}
}
impl ResolvesServerCert for CertificateResolverWrapper {
fn resolve(
&self,
server_name: Option<webpki::DNSNameRef>,
sigschemes: &[SignatureScheme]
) -> Option<CertifiedKey> {
if server_name.is_none() {
error!("cannot look up certificate: no SNI from session");
return None;
}
let name: &str = server_name.unwrap().into();
trace!("trying to resolve name: {:?} for signature scheme: {:?}", name, sigschemes);
if let Ok(ref mut resolver) = self.0.try_lock() {
if let Some(kv) = resolver.domains.domain_lookup(name.as_bytes()) {
trace!("looking for certificate for {:?} with fingerprint {:?}", name, kv.1);
return resolver.certificates.get(&kv.1).as_ref().map(|data| data.cert.clone());
}
}
error!("could not look up a certificate for server name '{}'", name);
None
}
}
pub fn generate_certified_key(certificate_and_key: CertificateAndKey) -> Option<CertifiedKey> {
let mut chain = Vec::new();
let mut cert_reader = BufReader::new(certificate_and_key.certificate.as_bytes());
let parsed_certs = pemfile::certs(&mut cert_reader);
let fingerprint:Vec<u8> = Vec::new();
if let Ok(certs) = parsed_certs {
for cert in certs {
chain.push(cert);
}
} else {
return None;
}
for ref cert in certificate_and_key.certificate_chain.iter() {
let mut chain_cert_reader = BufReader::new(cert.as_bytes());
if let Ok(parsed_chain_certs) = pemfile::certs(&mut chain_cert_reader) {
for cert in parsed_chain_certs {
chain.push(cert);
}
}
}
let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
let parsed_key = pemfile::rsa_private_keys(&mut key_reader);
if let Ok(keys) = parsed_key {
if !keys.is_empty() {
if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
return Some(certified);
}
} else {
let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
let parsed_key = pemfile::pkcs8_private_keys(&mut key_reader);
if let Ok(keys) = parsed_key {
if !keys.is_empty() {
if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
return Some(certified);
}
}
}
}
} else {
error!("could not parse private key: {:?}", parsed_key);
}
None
}