Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows disabling of hostname verification. #64

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion admin/capture-certdata
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,6 @@ if __name__ == '__main__':
print ' anchors.add_trust_anchors(&webpki_roots::ROOTS);'
print ' bench(100, "verify_server_cert(%s)", ' % name
print ' || (),'
print ' |_| verify::verify_server_cert(&anchors, &chain[..], "%s").unwrap());' % hostname
print ' |_| verify::verify_server_cert(&anchors, &chain[..], "%s", false).unwrap());' % hostname
print '}'
print
6 changes: 6 additions & 0 deletions examples/tlsclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ Options:
May be used multiple times to offer serveral protocols.
--cache CACHE Save session cache to file CACHE.
--no-tickets Disable session ticket support.
--insecure Do not do hostname verification on presented server certificates.
--verbose Emit log output.
--mtu MTU Limit outgoing messages to MTU bytes.
--version, -v Show tool version.
Expand All @@ -324,6 +325,7 @@ struct Args {
flag_auth_key: Option<String>,
flag_auth_certs: Option<String>,
arg_hostname: String,
flag_insecure: bool,
}

// TODO: um, well, it turns out that openssl s_client/s_server
Expand Down Expand Up @@ -415,6 +417,10 @@ fn make_config(args: &Args) -> Arc<rustls::ClientConfig> {
config.enable_tickets = false;
}

if args.flag_insecure {
config.danger_disable_host_name_verification();
}

let persist = Box::new(PersistCache::new(&args.flag_cache));

config.set_protocols(&args.flag_proto);
Expand Down
25 changes: 25 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ pub struct ClientConfig {
/// Supported versions, in no particular order. The default
/// is all supported versions.
pub versions: Vec<ProtocolVersion>,

/// Whether to do host name verification or not. WARNING: turning
/// this off is *insecure* as the host will not be verified to be
/// who it says it is.
host_verification: bool,
}

impl ClientConfig {
Expand All @@ -204,6 +209,7 @@ impl ClientConfig {
client_auth_cert_resolver: Box::new(FailResolveClientCert {}),
enable_tickets: true,
versions: vec![ProtocolVersion::TLSv1_3, ProtocolVersion::TLSv1_2],
host_verification: true,
}
}

Expand Down Expand Up @@ -249,6 +255,25 @@ impl ClientConfig {
self.client_auth_cert_resolver = Box::new(AlwaysResolvesClientCert::new_rsa(cert_chain,
&key_der));
}

/// Allow creation of a TLS stream without verification of host
/// names. WARNING: This is a dangerous option to enable, as it
/// will allow any valid certificate for any site to be trusted
/// for any other site. This opens up a major risk of
/// man-in-the-middle attaks.
pub fn danger_disable_host_name_verification(&mut self) {
self.host_verification = false;
}

/// Enable host name verification.
pub fn enable_host_name_verification(&mut self) {
self.host_verification = true;
}

/// Should this connection do host name verification
pub fn do_host_name_verification(&self) -> bool {
self.host_verification
}
}

pub struct ClientHandshakeData {
Expand Down
10 changes: 6 additions & 4 deletions src/client_hs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -839,11 +839,12 @@ fn handle_certificate_verify(sess: &mut ClientSessionImpl,

info!("Server cert is {:?}", sess.handshake_data.server_cert_chain);

// 1. Verify the certificate chain.
// 1. Verify the certificate chain. (unless configured not to)
// 2. Verify their signature on the handshake.
try!(verify::verify_server_cert(&sess.config.root_store,
&sess.handshake_data.server_cert_chain,
&sess.handshake_data.dns_name));
&sess.handshake_data.dns_name,
!sess.config.do_host_name_verification()));

let handshake_hash = sess.handshake_data.transcript.get_current_hash();
try!(verify::verify_tls13(&sess.handshake_data.server_cert_chain[0],
Expand Down Expand Up @@ -1076,7 +1077,7 @@ fn handle_server_hello_done(sess: &mut ClientSessionImpl,
info!("Server cert is {:?}", sess.handshake_data.server_cert_chain);
info!("Server DNS name is {:?}", sess.handshake_data.dns_name);

// 1. Verify the cert chain.
// 1. Verify the cert chain. (unless configured not to)
// 2. Verify that the top certificate signed their kx.
// 3. If doing client auth, send our Certificate.
// 4. Complete the key exchange:
Expand All @@ -1090,7 +1091,8 @@ fn handle_server_hello_done(sess: &mut ClientSessionImpl,
// 1.
try!(verify::verify_server_cert(&sess.config.root_store,
&sess.handshake_data.server_cert_chain,
&sess.handshake_data.dns_name));
&sess.handshake_data.dns_name,
!sess.config.do_host_name_verification()));

// 2.
// Build up the contents of the signed message.
Expand Down
14 changes: 8 additions & 6 deletions src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ impl RootCertStore {
/// Return the `webpki::EndEntityCert` for the top certificate
/// in `presented_certs`.
fn verify_common_cert<'a>(roots: &RootCertStore,
presented_certs: &'a [ASN1Cert])
presented_certs: &'a [ASN1Cert],
skip_verify: bool)
-> Result<webpki::EndEntityCert<'a>, TLSError> {
if presented_certs.is_empty() {
return Err(TLSError::NoCertificatesPresented);
Expand All @@ -176,7 +177,7 @@ fn verify_common_cert<'a>(roots: &RootCertStore,
.map(|x| x.to_trust_anchor())
.collect();

if DANGEROUS_DISABLE_VERIFY {
if DANGEROUS_DISABLE_VERIFY || skip_verify {
warn!("DANGEROUS_DISABLE_VERIFY is turned on, skipping certificate verification");
return Ok(cert);
}
Expand All @@ -191,11 +192,12 @@ fn verify_common_cert<'a>(roots: &RootCertStore,
/// the top certificate in the chain.
pub fn verify_server_cert(roots: &RootCertStore,
presented_certs: &[ASN1Cert],
dns_name: &str)
dns_name: &str,
skip_host_name_verify: bool)
-> Result<(), TLSError> {
let cert = try!(verify_common_cert(roots, presented_certs));
let cert = try!(verify_common_cert(roots, presented_certs, skip_host_name_verify));

if DANGEROUS_DISABLE_VERIFY {
if DANGEROUS_DISABLE_VERIFY || skip_host_name_verify {
warn!("DANGEROUS_DISABLE_VERIFY is turned on, skipping server name verification");
return Ok(());
}
Expand All @@ -209,7 +211,7 @@ pub fn verify_server_cert(roots: &RootCertStore,
pub fn verify_client_cert(roots: &RootCertStore,
presented_certs: &[ASN1Cert])
-> Result<(), TLSError> {
verify_common_cert(roots, presented_certs).map(|_| ())
verify_common_cert(roots, presented_certs, false).map(|_| ())
}

static ECDSA_SHA256: SignatureAlgorithms = &[&webpki::ECDSA_P256_SHA256,
Expand Down
35 changes: 23 additions & 12 deletions src/verifybench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn test_reddit_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(reddit)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "reddit.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "reddit.com", false).unwrap());
}

#[test]
Expand All @@ -54,7 +54,7 @@ fn test_github_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(github)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "github.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "github.com", false).unwrap());
}

#[test]
Expand All @@ -67,7 +67,7 @@ fn test_arstechnica_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(arstechnica)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "arstechnica.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "arstechnica.com", false).unwrap());
}

#[test]
Expand All @@ -80,7 +80,7 @@ fn test_servo_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(servo)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "servo.org").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "servo.org", false).unwrap());
}

#[test]
Expand All @@ -92,7 +92,7 @@ fn test_twitter_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(twitter)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "twitter.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "twitter.com", false).unwrap());
}

#[test]
Expand All @@ -104,7 +104,7 @@ fn test_wikipedia_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(wikipedia)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "wikipedia.org").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "wikipedia.org", false).unwrap());
}

#[test]
Expand All @@ -117,7 +117,7 @@ fn test_google_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(google)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "www.google.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "www.google.com", false).unwrap());
}

#[test]
Expand All @@ -130,7 +130,7 @@ fn test_hn_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(hn)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "news.ycombinator.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "news.ycombinator.com", false).unwrap());
}

#[test]
Expand All @@ -142,7 +142,7 @@ fn test_stackoverflow_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(stackoverflow)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "stackoverflow.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "stackoverflow.com", false).unwrap());
}

#[test]
Expand All @@ -154,7 +154,7 @@ fn test_duckduckgo_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(duckduckgo)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "duckduckgo.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "duckduckgo.com", false).unwrap());
}

#[test]
Expand All @@ -167,7 +167,7 @@ fn test_rustlang_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(rustlang)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "www.rust-lang.org").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "www.rust-lang.org", false).unwrap());
}

#[test]
Expand All @@ -180,6 +180,17 @@ fn test_wapo_cert() {
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(wapo)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "www.washingtonpost.com").unwrap());
|_| verify::verify_server_cert(&anchors, &chain[..], "www.washingtonpost.com", false).unwrap());
}

#[test]
fn test_no_hostname_verification() {
let cert0 = key::Certificate(include_bytes!("testdata/cert-stackoverflow.0.der").to_vec());
let cert1 = key::Certificate(include_bytes!("testdata/cert-stackoverflow.1.der").to_vec());
let chain = [ cert0, cert1 ];
let mut anchors = verify::RootCertStore::empty();
anchors.add_trust_anchors(&webpki_roots::ROOTS);
bench(100, "verify_server_cert(no_hostname_verification)",
|| (),
|_| verify::verify_server_cert(&anchors, &chain[..], "NOTstackoverflow.com", true).unwrap());
}