diff --git a/examples/tlsclient.rs b/examples/tlsclient.rs index ec88111865..004345cf4c 100644 --- a/examples/tlsclient.rs +++ b/examples/tlsclient.rs @@ -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 Allow connections to sites without certs. --verbose Emit log output. --mtu MTU Limit outgoing messages to MTU bytes. --version, -v Show tool version. @@ -324,6 +325,7 @@ struct Args { flag_auth_key: Option, flag_auth_certs: Option, arg_hostname: String, + flag_insecure: bool, } // TODO: um, well, it turns out that openssl s_client/s_server @@ -415,6 +417,10 @@ fn make_config(args: &Args) -> Arc { 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); diff --git a/src/client.rs b/src/client.rs index 9d6c818b67..1cc43ca918 100644 --- a/src/client.rs +++ b/src/client.rs @@ -188,6 +188,11 @@ pub struct ClientConfig { /// Supported versions, in no particular order. The default /// is all supported versions. pub versions: Vec, + + /// 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 { @@ -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, } } @@ -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 { diff --git a/src/client_hs.rs b/src/client_hs.rs index 3475ebf42f..37286f991b 100644 --- a/src/client_hs.rs +++ b/src/client_hs.rs @@ -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], @@ -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: @@ -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. diff --git a/src/verify.rs b/src/verify.rs index 332c73b999..f550bc719e 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -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, TLSError> { if presented_certs.is_empty() { return Err(TLSError::NoCertificatesPresented); @@ -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); } @@ -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(()); } @@ -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,