| use std::fs; |
| use std::io::{Read, Write}; |
| use std::net::{TcpListener, TcpStream}; |
| use std::process::{Command, Stdio}; |
| use std::string::String; |
| use std::thread; |
| |
| use super::*; |
| |
| macro_rules! p { |
| ($e:expr) => { |
| match $e { |
| Ok(r) => r, |
| Err(e) => panic!("{:?}", e), |
| } |
| }; |
| } |
| |
| #[test] |
| fn connect_google() { |
| let builder = p!(TlsConnector::new()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| let mut socket = p!(builder.connect("google.com", s)); |
| |
| p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n")); |
| let mut result = vec![]; |
| p!(socket.read_to_end(&mut result)); |
| |
| println!("{}", String::from_utf8_lossy(&result)); |
| assert!(result.starts_with(b"HTTP/1.0")); |
| assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>")); |
| } |
| |
| #[test] |
| fn connect_bad_hostname() { |
| let builder = p!(TlsConnector::new()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| builder.connect("goggle.com", s).unwrap_err(); |
| } |
| |
| #[test] |
| fn connect_bad_hostname_ignored() { |
| let builder = p!(TlsConnector::builder() |
| .danger_accept_invalid_hostnames(true) |
| .build()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| builder.connect("goggle.com", s).unwrap(); |
| } |
| |
| #[test] |
| fn connect_no_root_certs() { |
| let builder = p!(TlsConnector::builder().disable_built_in_roots(true).build()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| assert!(builder.connect("google.com", s).is_err()); |
| } |
| |
| #[test] |
| fn server_no_root_certs() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .disable_built_in_roots(true) |
| .add_root_certificate(root_ca) |
| .build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn server() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .add_root_certificate(root_ca) |
| .build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn certificate_from_pem() { |
| let dir = tempfile::tempdir().unwrap(); |
| let keys = test_cert_gen::keys(); |
| |
| let der_path = dir.path().join("cert.der"); |
| fs::write(&der_path, &keys.client.ca.get_der()).unwrap(); |
| let output = Command::new("openssl") |
| .arg("x509") |
| .arg("-in") |
| .arg(der_path) |
| .arg("-inform") |
| .arg("der") |
| .stderr(Stdio::piped()) |
| .output() |
| .unwrap(); |
| |
| assert!(output.status.success()); |
| |
| let cert = Certificate::from_pem(&output.stdout).unwrap(); |
| assert_eq!(cert.to_der().unwrap(), keys.client.ca.get_der()); |
| } |
| |
| #[test] |
| fn peer_certificate() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let socket = p!(builder.accept(socket)); |
| assert!(socket.peer_certificate().unwrap().is_none()); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .add_root_certificate(root_ca) |
| .build()); |
| let socket = p!(builder.connect("localhost", socket)); |
| |
| let cert = socket.peer_certificate().unwrap().unwrap(); |
| assert_eq!( |
| cert.to_der().unwrap(), |
| keys.server.cert_and_key.cert.get_der() |
| ); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn server_tls11_only() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::builder(identity) |
| .min_protocol_version(Some(Protocol::Tlsv12)) |
| .max_protocol_version(Some(Protocol::Tlsv12)) |
| .build()); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .add_root_certificate(root_ca) |
| .min_protocol_version(Some(Protocol::Tlsv12)) |
| .max_protocol_version(Some(Protocol::Tlsv12)) |
| .build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn server_no_shared_protocol() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::builder(identity) |
| .min_protocol_version(Some(Protocol::Tlsv12)) |
| .build()); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| assert!(builder.accept(socket).is_err()); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .add_root_certificate(root_ca) |
| .min_protocol_version(Some(Protocol::Tlsv11)) |
| .max_protocol_version(Some(Protocol::Tlsv11)) |
| .build()); |
| assert!(builder.connect("localhost", socket).is_err()); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn server_untrusted() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| // FIXME should assert error |
| // https://github.com/steffengy/schannel-rs/issues/20 |
| let _ = builder.accept(socket); |
| }); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::new()); |
| builder.connect("localhost", socket).unwrap_err(); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn server_untrusted_unverified() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .danger_accept_invalid_certs(true) |
| .build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn import_same_identity_multiple_times() { |
| let keys = test_cert_gen::keys(); |
| |
| let _ = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let _ = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| |
| let cert = keys.server.cert_and_key.cert.to_pem().into_bytes(); |
| let key = rsa_to_pkcs8(&keys.server.cert_and_key.key.to_pem_incorrect()).into_bytes(); |
| let _ = p!(Identity::from_pkcs8(&cert, &key)); |
| let _ = p!(Identity::from_pkcs8(&cert, &key)); |
| } |
| |
| #[test] |
| fn from_pkcs8_rejects_rsa_key() { |
| let keys = test_cert_gen::keys(); |
| let cert = keys.server.cert_and_key.cert.to_pem().into_bytes(); |
| let rsa_key = keys.server.cert_and_key.key.to_pem_incorrect(); |
| assert!(Identity::from_pkcs8(&cert, rsa_key.as_bytes()).is_err()); |
| let pkcs8_key = rsa_to_pkcs8(&rsa_key); |
| assert!(Identity::from_pkcs8(&cert, pkcs8_key.as_bytes()).is_ok()); |
| } |
| |
| #[test] |
| fn shutdown() { |
| let keys = test_cert_gen::keys(); |
| |
| let identity = p!(Identity::from_pkcs12( |
| &keys.server.cert_and_key_pkcs12.pkcs12.0, |
| &keys.server.cert_and_key_pkcs12.password |
| )); |
| let builder = p!(TlsAcceptor::new(identity)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| assert_eq!(p!(socket.read(&mut buf)), 0); |
| p!(socket.shutdown()); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let builder = p!(TlsConnector::builder() |
| .add_root_certificate(root_ca) |
| .build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| p!(socket.shutdown()); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| #[cfg(feature = "alpn")] |
| fn alpn_google_h2() { |
| let builder = p!(TlsConnector::builder().request_alpns(&["h2"]).build()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| let socket = p!(builder.connect("google.com", s)); |
| let alpn = p!(socket.negotiated_alpn()); |
| assert_eq!(alpn, Some(b"h2".to_vec())); |
| } |
| |
| #[test] |
| #[cfg(feature = "alpn")] |
| fn alpn_google_invalid() { |
| let builder = p!(TlsConnector::builder().request_alpns(&["h2c"]).build()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| let socket = p!(builder.connect("google.com", s)); |
| let alpn = p!(socket.negotiated_alpn()); |
| assert_eq!(alpn, None); |
| } |
| |
| #[test] |
| #[cfg(feature = "alpn")] |
| fn alpn_google_none() { |
| let builder = p!(TlsConnector::new()); |
| let s = p!(TcpStream::connect("google.com:443")); |
| let socket = p!(builder.connect("google.com", s)); |
| let alpn = p!(socket.negotiated_alpn()); |
| assert_eq!(alpn, None); |
| } |
| |
| #[test] |
| fn server_pkcs8() { |
| let keys = test_cert_gen::keys(); |
| let cert = keys.server.cert_and_key.cert.to_pem().into_bytes(); |
| let key = rsa_to_pkcs8(&keys.server.cert_and_key.key.to_pem_incorrect()).into_bytes(); |
| |
| let ident = Identity::from_pkcs8(&cert, &key).unwrap(); |
| let ident2 = ident.clone(); |
| let builder = p!(TlsAcceptor::new(ident)); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let mut builder = TlsConnector::builder(); |
| // FIXME |
| // This checks that we can successfully add a certificate on the client side. |
| // Unfortunately, we can not request client certificates through the API of this library, |
| // otherwise we could check in the server thread that |
| // socket.peer_certificate().unwrap().is_some() |
| builder.identity(ident2); |
| |
| builder.add_root_certificate(root_ca); |
| let builder = p!(builder.build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| } |
| |
| #[test] |
| fn two_servers() { |
| let keys1 = test_cert_gen::gen_keys(); |
| let cert = keys1.server.cert_and_key.cert.to_pem().into_bytes(); |
| let key = rsa_to_pkcs8(&keys1.server.cert_and_key.key.to_pem_incorrect()).into_bytes(); |
| let identity = p!(Identity::from_pkcs8(&cert, &key)); |
| let builder = TlsAcceptor::builder(identity); |
| let builder = p!(builder.build()); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port = p!(listener.local_addr()).port(); |
| |
| let j = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let keys2 = test_cert_gen::gen_keys(); |
| let cert = keys2.server.cert_and_key.cert.to_pem().into_bytes(); |
| let key = rsa_to_pkcs8(&keys2.server.cert_and_key.key.to_pem_incorrect()).into_bytes(); |
| let identity = p!(Identity::from_pkcs8(&cert, &key)); |
| let builder = TlsAcceptor::builder(identity); |
| let builder = p!(builder.build()); |
| |
| let listener = p!(TcpListener::bind("0.0.0.0:0")); |
| let port2 = p!(listener.local_addr()).port(); |
| |
| let j2 = thread::spawn(move || { |
| let socket = p!(listener.accept()).0; |
| let mut socket = p!(builder.accept(socket)); |
| |
| let mut buf = [0; 5]; |
| p!(socket.read_exact(&mut buf)); |
| assert_eq!(&buf, b"hello"); |
| |
| p!(socket.write_all(b"world")); |
| }); |
| |
| let root_ca = Certificate::from_der(keys1.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port))); |
| let mut builder = TlsConnector::builder(); |
| builder.add_root_certificate(root_ca); |
| let builder = p!(builder.build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| let root_ca = Certificate::from_der(keys2.client.ca.get_der()).unwrap(); |
| |
| let socket = p!(TcpStream::connect(("localhost", port2))); |
| let mut builder = TlsConnector::builder(); |
| builder.add_root_certificate(root_ca); |
| let builder = p!(builder.build()); |
| let mut socket = p!(builder.connect("localhost", socket)); |
| |
| p!(socket.write_all(b"hello")); |
| let mut buf = vec![]; |
| p!(socket.read_to_end(&mut buf)); |
| assert_eq!(buf, b"world"); |
| |
| p!(j.join()); |
| p!(j2.join()); |
| } |
| |
| fn rsa_to_pkcs8(pem: &str) -> String { |
| let mut child = Command::new("openssl") |
| .arg("pkcs8") |
| .arg("-topk8") |
| .arg("-nocrypt") |
| .stdin(Stdio::piped()) |
| .stdout(Stdio::piped()) |
| .spawn() |
| .unwrap(); |
| { |
| let child_stdin = child.stdin.as_mut().unwrap(); |
| child_stdin.write_all(pem.as_bytes()).unwrap(); |
| } |
| String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap() |
| } |