Skip to content

Commit 97b77f4

Browse files
authored
Merge pull request #160 from cyang1/no-roots
Implement bindings to only use supplied root certificates for validating the server
2 parents 75e43da + a84af12 commit 97b77f4

File tree

6 files changed

+89
-3
lines changed

6 files changed

+89
-3
lines changed

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ schannel = "0.1.16"
2222

2323
[target.'cfg(not(any(target_os = "windows", target_os = "macos", target_os = "ios")))'.dependencies]
2424
log = "0.4.5"
25-
openssl = "0.10.25"
26-
openssl-sys = "0.9.30"
25+
openssl = "0.10.29"
26+
openssl-sys = "0.9.55"
2727
openssl-probe = "0.1"
2828

2929
[dev-dependencies]

src/imp/openssl.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use self::openssl::ssl::{
1010
self, MidHandshakeSslStream, SslAcceptor, SslConnector, SslContextBuilder, SslMethod,
1111
SslVerifyMode,
1212
};
13-
use self::openssl::x509::{X509, X509VerifyResult};
13+
use self::openssl::x509::{X509, store::X509StoreBuilder, X509VerifyResult};
1414
use std::error;
1515
use std::fmt;
1616
use std::io;
@@ -264,6 +264,10 @@ impl TlsConnector {
264264
}
265265
supported_protocols(builder.min_protocol, builder.max_protocol, &mut connector)?;
266266

267+
if builder.disable_built_in_roots {
268+
connector.set_cert_store(X509StoreBuilder::new()?.build());
269+
}
270+
267271
for cert in &builder.root_certificates {
268272
if let Err(err) = connector.cert_store_mut().add_cert((cert.0).0.clone()) {
269273
debug!("add_cert error: {:?}", err);

src/imp/schannel.rs

+24
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ pub struct TlsConnector {
185185
use_sni: bool,
186186
accept_invalid_hostnames: bool,
187187
accept_invalid_certs: bool,
188+
disable_built_in_roots: bool,
188189
}
189190

190191
impl TlsConnector {
@@ -203,6 +204,7 @@ impl TlsConnector {
203204
use_sni: builder.use_sni,
204205
accept_invalid_hostnames: builder.accept_invalid_hostnames,
205206
accept_invalid_certs: builder.accept_invalid_certs,
207+
disable_built_in_roots: builder.disable_built_in_roots,
206208
})
207209
}
208210

@@ -224,6 +226,28 @@ impl TlsConnector {
224226
.accept_invalid_hostnames(self.accept_invalid_hostnames);
225227
if self.accept_invalid_certs {
226228
builder.verify_callback(|_| Ok(()));
229+
} else if self.disable_built_in_roots {
230+
let roots_copy = self.roots.clone();
231+
builder.verify_callback(move |res| {
232+
if let Err(err) = res.result() {
233+
// Propagate previous error encountered during normal cert validation.
234+
return Err(err);
235+
}
236+
237+
if let Some(chain) = res.chain() {
238+
if chain
239+
.certificates()
240+
.any(|cert| roots_copy.certs().any(|root_cert| root_cert == cert))
241+
{
242+
return Ok(());
243+
}
244+
}
245+
246+
Err(io::Error::new(
247+
io::ErrorKind::Other,
248+
"unable to find any user-specified roots in the final cert chain",
249+
))
250+
});
227251
}
228252
match builder.connect(cred, stream) {
229253
Ok(s) => Ok(TlsStream(s)),

src/imp/security_framework.rs

+3
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ pub struct TlsConnector {
262262
use_sni: bool,
263263
danger_accept_invalid_hostnames: bool,
264264
danger_accept_invalid_certs: bool,
265+
disable_built_in_roots: bool,
265266
}
266267

267268
impl TlsConnector {
@@ -278,6 +279,7 @@ impl TlsConnector {
278279
use_sni: builder.use_sni,
279280
danger_accept_invalid_hostnames: builder.accept_invalid_hostnames,
280281
danger_accept_invalid_certs: builder.accept_invalid_certs,
282+
disable_built_in_roots: builder.disable_built_in_roots,
281283
})
282284
}
283285

@@ -299,6 +301,7 @@ impl TlsConnector {
299301
builder.use_sni(self.use_sni);
300302
builder.danger_accept_invalid_hostnames(self.danger_accept_invalid_hostnames);
301303
builder.danger_accept_invalid_certs(self.danger_accept_invalid_certs);
304+
builder.trust_anchor_certificates_only(self.disable_built_in_roots);
302305

303306
match builder.handshake(domain, stream) {
304307
Ok(stream) => Ok(TlsStream { stream, cert: None }),

src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ pub struct TlsConnectorBuilder {
327327
accept_invalid_certs: bool,
328328
accept_invalid_hostnames: bool,
329329
use_sni: bool,
330+
disable_built_in_roots: bool,
330331
}
331332

332333
impl TlsConnectorBuilder {
@@ -367,6 +368,14 @@ impl TlsConnectorBuilder {
367368
self
368369
}
369370

371+
/// Controls the use of built-in system certificates during certificate validation.
372+
///
373+
/// Defaults to `false` -- built-in system certs will be used.
374+
pub fn disable_built_in_roots(&mut self, disable: bool) -> &mut TlsConnectorBuilder {
375+
self.disable_built_in_roots = disable;
376+
self
377+
}
378+
370379
/// Controls the use of certificate validation.
371380
///
372381
/// Defaults to `false`.
@@ -454,6 +463,7 @@ impl TlsConnector {
454463
use_sni: true,
455464
accept_invalid_certs: false,
456465
accept_invalid_hostnames: false,
466+
disable_built_in_roots: false,
457467
}
458468
}
459469

src/test.rs

+45
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,51 @@ mod tests {
5050
builder.connect("goggle.com", s).unwrap();
5151
}
5252

53+
#[test]
54+
fn connect_no_root_certs() {
55+
let builder = p!(TlsConnector::builder().disable_built_in_roots(true).build());
56+
let s = p!(TcpStream::connect("google.com:443"));
57+
assert!(builder.connect("google.com", s).is_err());
58+
}
59+
60+
#[test]
61+
fn server_no_root_certs() {
62+
let buf = include_bytes!("../test/identity.p12");
63+
let identity = p!(Identity::from_pkcs12(buf, "mypass"));
64+
let builder = p!(TlsAcceptor::new(identity));
65+
66+
let listener = p!(TcpListener::bind("0.0.0.0:0"));
67+
let port = p!(listener.local_addr()).port();
68+
69+
let j = thread::spawn(move || {
70+
let socket = p!(listener.accept()).0;
71+
let mut socket = p!(builder.accept(socket));
72+
73+
let mut buf = [0; 5];
74+
p!(socket.read_exact(&mut buf));
75+
assert_eq!(&buf, b"hello");
76+
77+
p!(socket.write_all(b"world"));
78+
});
79+
80+
let root_ca = include_bytes!("../test/root-ca.der");
81+
let root_ca = Certificate::from_der(root_ca).unwrap();
82+
83+
let socket = p!(TcpStream::connect(("localhost", port)));
84+
let builder = p!(TlsConnector::builder()
85+
.disable_built_in_roots(true)
86+
.add_root_certificate(root_ca)
87+
.build());
88+
let mut socket = p!(builder.connect("foobar.com", socket));
89+
90+
p!(socket.write_all(b"hello"));
91+
let mut buf = vec![];
92+
p!(socket.read_to_end(&mut buf));
93+
assert_eq!(buf, b"world");
94+
95+
p!(j.join());
96+
}
97+
5398
#[test]
5499
fn server() {
55100
let buf = include_bytes!("../test/identity.p12");

0 commit comments

Comments
 (0)