Loading appveyor.yml +2 −0 Original line number Diff line number Diff line environment: SSL_CERT_FILE: "C:\\OpenSSL\\cacert.pem" matrix: # 1.1.0, 64/32 bit - TARGET: i686-pc-windows-gnu Loading @@ -23,6 +24,7 @@ install: # install OpenSSL - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe" - Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - ps: Start-FileDownload "https://curl.haxx.se/ca/cacert.pem" -FileName "C:\OpenSSL\cacert.pem" # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ Loading openssl/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ pub mod ssl; pub mod symm; pub mod version; pub mod x509; #[cfg(any(ossl102, ossl110))] mod verify; pub fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Loading openssl/src/pkey.rs +65 −44 Original line number Diff line number Diff line use libc::{c_void, c_char, c_int}; use std::ptr; use std::mem; use std::ops::Deref; use ffi; use {cvt, cvt_p}; Loading @@ -9,13 +10,66 @@ use dsa::Dsa; use rsa::Rsa; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb}; use opaque::Opaque; /// A borrowed `PKey`. pub struct PKeyRef(Opaque); impl PKeyRef { pub unsafe fn from_ptr<'a>(ptr: *mut ffi::EVP_PKEY) -> &'a PKeyRef { &*(ptr as *mut _) } pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY { self as *const _ as *mut _ } /// Get a reference to the interal RSA key for direct access to the key components pub fn rsa(&self) -> Result<Rsa, ErrorStack> { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))); // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), self.as_ptr(), ptr::null(), ptr::null_mut(), -1, None, ptr::null_mut()))); } Ok(mem_bio.get_buf().to_owned()) } /// Stores public key as a PEM pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); } Ok(mem_bio.get_buf().to_owned()) } pub fn public_eq(&self, other: &PKeyRef) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } } /// Represents a public key, optionally with a private key attached. pub struct PKey(*mut ffi::EVP_PKEY); unsafe impl Send for PKey {} unsafe impl Sync for PKey {} /// Represents a public key, optionally with a private key attached. impl PKey { /// Create a new `PKey` containing an RSA key. pub fn from_rsa(rsa: Rsa) -> Result<PKey, ErrorStack> { Loading Loading @@ -101,7 +155,7 @@ impl PKey { } } /// assign RSA key to this pkey /// Assign an RSA key to this pkey. pub fn set_rsa(&mut self, rsa: &Rsa) -> Result<(), ErrorStack> { unsafe { // this needs to be a reference as the set1_RSA ups the reference count Loading @@ -110,55 +164,22 @@ impl PKey { Ok(()) } } /// Get a reference to the interal RSA key for direct access to the key components pub fn rsa(&self) -> Result<Rsa, ErrorStack> { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.0))); // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), self.0, ptr::null(), ptr::null_mut(), -1, None, ptr::null_mut()))); } Ok(mem_bio.get_buf().to_owned()) } /// Stores public key as a PEM pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); impl Drop for PKey { fn drop(&mut self) { unsafe { try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0))); ffi::EVP_PKEY_free(self.0); } Ok(mem_bio.get_buf().to_owned()) } pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY { return self.0; } pub fn public_eq(&self, other: &PKey) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 } } } impl Deref for PKey { type Target = PKeyRef; impl Drop for PKey { fn drop(&mut self) { fn deref(&self) -> &PKeyRef { unsafe { ffi::EVP_PKEY_free(self.0); PKeyRef::from_ptr(self.0) } } } Loading openssl/src/ssl/connector.rs 0 → 100644 +359 −0 Original line number Diff line number Diff line use std::io::{Read, Write}; use dh::Dh; use error::ErrorStack; use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, SslStream, HandshakeError}; use pkey::PKeyRef; use x509::X509Ref; // apps/dh2048.pem const DHPARAM_PEM: &'static str = r#" -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq 5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg== -----END DH PARAMETERS----- These are the 2048-bit DH parameters from "More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": https://tools.ietf.org/html/rfc3526 See https://tools.ietf.org/html/rfc2412 for how they were generated."#; fn ctx(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> { let mut ctx = try!(SslContextBuilder::new(method)); // options to enable and cipher list lifted from libcurl let mut opts = ssl::SSL_OP_ALL; opts |= ssl::SSL_OP_NO_TICKET; opts |= ssl::SSL_OP_NO_COMPRESSION; opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; opts |= ssl::SSL_OP_NO_SSLV2; opts |= ssl::SSL_OP_NO_SSLV3; ctx.set_options(opts); Ok(ctx) } /// A builder for `ClientConnector`s. pub struct ClientConnectorBuilder(SslContextBuilder); impl ClientConnectorBuilder { /// Creates a new builder for TLS connections. /// /// The default configuration is based off of libcurl's and is subject to change. pub fn tls() -> Result<ClientConnectorBuilder, ErrorStack> { ClientConnectorBuilder::new(SslMethod::tls()) } fn new(method: SslMethod) -> Result<ClientConnectorBuilder, ErrorStack> { let mut ctx = try!(ctx(method)); try!(ctx.set_default_verify_paths()); try!(ctx.set_cipher_list("ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH")); Ok(ClientConnectorBuilder(ctx)) } /// Returns a shared reference to the inner `SslContextBuilder`. pub fn context(&self) -> &SslContextBuilder { &self.0 } /// Returns a mutable reference to the inner `SslContextBuilder`. pub fn context_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } /// Consumes the builder, returning a `ClientConnector`. pub fn build(self) -> ClientConnector { ClientConnector(self.0.build()) } } /// A type which wraps client-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, hostname verification, and more. /// /// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, /// and a custom implementation is used when linking against OpenSSL 1.0.1. pub struct ClientConnector(SslContext); impl ClientConnector { /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification. pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { let mut ssl = try!(Ssl::new(&self.0)); try!(ssl.set_hostname(domain)); try!(setup_verify(&mut ssl, domain)); ssl.connect(stream) } } /// A builder for `ServerConnector`s. pub struct ServerConnectorBuilder(SslContextBuilder); impl ServerConnectorBuilder { /// Creates a new builder for server-side TLS connections. /// /// The default configuration is based off of the intermediate profile of Mozilla's SSL /// Configuration Generator, and is subject to change. pub fn tls<I, T>(private_key: &PKeyRef, certificate: &X509Ref, chain: I) -> Result<ServerConnectorBuilder, ErrorStack> where I: IntoIterator<Item = T>, T: AsRef<X509Ref> { ServerConnectorBuilder::new(SslMethod::tls(), private_key, certificate, chain) } fn new<I, T>(method: SslMethod, private_key: &PKeyRef, certificate: &X509Ref, chain: I) -> Result<ServerConnectorBuilder, ErrorStack> where I: IntoIterator<Item = T>, T: AsRef<X509Ref> { let mut ctx = try!(ctx(method)); ctx.set_options(ssl::SSL_OP_SINGLE_DH_USE | ssl::SSL_OP_CIPHER_SERVER_PREFERENCE); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); try!(ctx.set_cipher_list( "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\ ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:\ ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\ ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:\ DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:\ AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS")); try!(ctx.set_private_key(private_key)); try!(ctx.set_certificate(certificate)); try!(ctx.check_private_key()); for cert in chain { try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned())); } Ok(ServerConnectorBuilder(ctx)) } /// Returns a shared reference to the inner `SslContextBuilder`. pub fn context(&self) -> &SslContextBuilder { &self.0 } /// Returns a mutable reference to the inner `SslContextBuilder`. pub fn context_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } /// Consumes the builder, returning a `ServerConnector`. pub fn build(self) -> ServerConnector { ServerConnector(self.0.build()) } } /// A type which wraps server-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, and more. pub struct ServerConnector(SslContext); impl ServerConnector { /// Initiates a server-side TLS session on a stream. pub fn connect<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { let ssl = try!(Ssl::new(&self.0)); ssl.accept(stream) } } #[cfg(any(ossl102, ossl110))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { ssl.set_verify(SSL_VERIFY_PEER); let param = ssl._param_mut(); param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); param.set_host(domain) } #[cfg(not(any(ossl102, ossl110)))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { let domain = domain.to_owned(); ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify::verify_callback(&domain, p, x)); Ok(()) } #[cfg(not(any(ossl102, ossl110)))] mod verify { use std::net::IpAddr; use nid; use x509::{X509StoreContextRef, X509Ref, GeneralNames, X509NameRef}; pub fn verify_callback(domain: &str, preverify_ok: bool, x509_ctx: &X509StoreContextRef) -> bool { if !preverify_ok || x509_ctx.error_depth() != 0 { return preverify_ok; } match x509_ctx.current_cert() { Some(x509) => verify_hostname(domain, &x509), None => true, } } fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { match cert.subject_alt_names() { Some(names) => verify_subject_alt_names(domain, &names), None => verify_subject_name(domain, &cert.subject_name()), } } fn verify_subject_alt_names(domain: &str, names: &GeneralNames) -> bool { let ip = domain.parse(); for name in names { match ip { Ok(ip) => { if let Some(actual) = name.ipaddress() { if matches_ip(&ip, actual) { return true; } } } Err(_) => { if let Some(pattern) = name.dnsname() { if matches_dns(pattern, domain, false) { return true; } } } } } false } fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { if let Some(pattern) = subject_name.text_by_nid(nid::COMMONNAME) { // Unlike with SANs, IP addresses in the subject name don't have a // different encoding. We need to pass this down to matches_dns to // disallow wildcard matches with bogus patterns like *.0.0.1 let is_ip = domain.parse::<IpAddr>().is_ok(); if matches_dns(&pattern, domain, is_ip) { return true; } } false } fn matches_dns(mut pattern: &str, mut hostname: &str, is_ip: bool) -> bool { // first strip trailing . off of pattern and hostname to normalize if pattern.ends_with('.') { pattern = &pattern[..pattern.len() - 1]; } if hostname.ends_with('.') { hostname = &hostname[..hostname.len() - 1]; } matches_wildcard(pattern, hostname, is_ip).unwrap_or_else(|| pattern == hostname) } fn matches_wildcard(pattern: &str, hostname: &str, is_ip: bool) -> Option<bool> { // IP addresses and internationalized domains can't involved in wildcards if is_ip || pattern.starts_with("xn--") { return None; } let wildcard_location = match pattern.find('*') { Some(l) => l, None => return None, }; let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); let wildcard_end = match dot_idxs.next() { Some(l) => l, None => return None, }; // Never match wildcards if the pattern has less than 2 '.'s (no *.com) // // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. // Chrome has a black- and white-list for this, but Firefox (via NSS) does // the same thing we do here. // // The Public Suffix (https://www.publicsuffix.org/) list could // potentically be used here, but it's both huge and updated frequently // enough that management would be a PITA. if dot_idxs.next().is_none() { return None; } // Wildcards can only be in the first component if wildcard_location > wildcard_end { return None; } let hostname_label_end = match hostname.find('.') { Some(l) => l, None => return None, }; // check that the non-wildcard parts are identical if pattern[wildcard_end..] != hostname[hostname_label_end..] { return Some(false); } let wildcard_prefix = &pattern[..wildcard_location]; let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; let hostname_label = &hostname[..hostname_label_end]; // check the prefix of the first label if !hostname_label.starts_with(wildcard_prefix) { return Some(false); } // and the suffix if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { return Some(false); } Some(true) } fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { match (expected, actual.len()) { (&IpAddr::V4(ref addr), 4) => actual == addr.octets(), (&IpAddr::V6(ref addr), 16) => { let segments = [((actual[0] as u16) << 8) | actual[1] as u16, ((actual[2] as u16) << 8) | actual[3] as u16, ((actual[4] as u16) << 8) | actual[5] as u16, ((actual[6] as u16) << 8) | actual[7] as u16, ((actual[8] as u16) << 8) | actual[9] as u16, ((actual[10] as u16) << 8) | actual[11] as u16, ((actual[12] as u16) << 8) | actual[13] as u16, ((actual[14] as u16) << 8) | actual[15] as u16]; segments == addr.segments() } _ => false, } } } openssl/src/ssl/mod.rs +104 −4 Original line number Diff line number Diff line //! SSL/TLS support. //! //! The `ClientConnector` and `ServerConnector` should be used in most cases - they handle //! configuration of the OpenSSL primitives for you. //! //! # Examples //! //! To connect as a client to a remote server: //! //! ``` //! use openssl::ssl::ClientConnectorBuilder; //! use std::io::{Read, Write}; //! use std::net::TcpStream; //! //! let connector = ClientConnectorBuilder::tls().unwrap().build(); //! //! let stream = TcpStream::connect("google.com:443").unwrap(); //! let mut stream = connector.connect("google.com", stream).unwrap(); //! //! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); //! let mut res = vec![]; //! stream.read_to_end(&mut res).unwrap(); //! println!("{}", String::from_utf8_lossy(&res)); //! ``` //! //! To accept connections as a server from remote clients: //! //! ```no_run //! use openssl::pkcs12::Pkcs12; //! use openssl::ssl::{ServerConnectorBuilder, SslStream}; //! use std::fs::File; //! use std::io::{Read, Write}; //! use std::net::{TcpListener, TcpStream}; //! use std::sync::Arc; //! use std::thread; //! //! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive, //! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted //! // files. See the documentation for the `PKey` and `X509` types for more details. //! let mut file = File::open("identity.pfx").unwrap(); //! let mut pkcs12 = vec![]; //! file.read_to_end(&mut pkcs12).unwrap(); //! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap(); //! let identity = pkcs12.parse("password123").unwrap(); //! //! let connector = ServerConnectorBuilder::tls(&identity.pkey, &identity.cert, &identity.chain) //! .unwrap() //! .build(); //! let connector = Arc::new(connector); //! //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); //! //! fn handle_client(stream: SslStream<TcpStream>) { //! // ... //! } //! //! for stream in listener.incoming() { //! match stream { //! Ok(stream) => { //! let connector = connector.clone(); //! thread::spawn(move || { //! let stream = connector.connect(stream).unwrap(); //! handle_client(stream); //! }); //! } //! Err(e) => { /* connection failed */ } //! } //! } //! ``` use libc::{c_int, c_void, c_long, c_ulong}; use std::any::Any; use std::any::TypeId; Loading @@ -22,19 +91,22 @@ use ffi; use {init, cvt, cvt_p}; use dh::Dh; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509VerifyParamRef; use pkey::PKey; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; use opaque::Opaque; pub mod error; mod connector; mod bio; #[cfg(test)] mod tests; use self::bio::BioMethod; pub use ssl::connector::{ClientConnectorBuilder, ClientConnector, ServerConnectorBuilder, ServerConnector}; #[doc(inline)] pub use ssl::error::Error; Loading Loading @@ -339,6 +411,7 @@ pub enum SniError { NoAck, } /// A builder for `SslContext`s. pub struct SslContextBuilder(*mut ffi::SSL_CTX); impl Drop for SslContextBuilder { Loading Loading @@ -529,7 +602,7 @@ impl SslContextBuilder { } /// Specifies the private key pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> { pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } Loading Loading @@ -790,6 +863,7 @@ impl SslCipherRef { } } /// A reference to an `Ssl`. pub struct SslRef(Opaque); unsafe impl Send for SslRef {} Loading Loading @@ -1030,6 +1104,11 @@ impl SslRef { /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { self._param_mut() } #[cfg(any(ossl102, ossl110))] fn _param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } Loading Loading @@ -1096,6 +1175,11 @@ impl Ssl { } /// Creates an SSL/TLS client operating over the provided stream. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `ClientConnector` rather than `Ssl` directly, as it manages that configuration. pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { Loading Loading @@ -1123,6 +1207,11 @@ impl Ssl { } /// Creates an SSL/TLS server operating over the provided stream. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `ServerConnector` rather than `Ssl` directly, as it manages that configuration. pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { Loading Loading @@ -1153,6 +1242,8 @@ impl Ssl { /// An error or intermediate state after a TLS handshake attempt. #[derive(Debug)] pub enum HandshakeError<S> { /// Setup failed. SetupFailure(ErrorStack), /// The handshake failed. Failure(MidHandshakeSslStream<S>), /// The handshake was interrupted midway through. Loading @@ -1162,6 +1253,7 @@ pub enum HandshakeError<S> { impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> { fn description(&self) -> &str { match *self { HandshakeError::SetupFailure(_) => "stream setup failed", HandshakeError::Failure(_) => "the handshake failed", HandshakeError::Interrupted(_) => "the handshake was interrupted", } Loading @@ -1169,6 +1261,7 @@ impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> { fn cause(&self) -> Option<&stderror::Error> { match *self { HandshakeError::SetupFailure(ref e) => Some(e), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => Some(s.error()), } } Loading @@ -1178,6 +1271,7 @@ impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(f.write_str(stderror::Error::description(self))); match *self { HandshakeError::SetupFailure(ref e) => try!(write!(f, ": {}", e)), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => { try!(write!(f, ": {}", s.error())); if let Some(err) = s.ssl().verify_result() { Loading @@ -1189,6 +1283,12 @@ impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> { } } impl<S> From<ErrorStack> for HandshakeError<S> { fn from(e: ErrorStack) -> HandshakeError<S> { HandshakeError::SetupFailure(e) } } /// An SSL stream midway through the handshake process. #[derive(Debug)] pub struct MidHandshakeSslStream<S> { Loading Loading
appveyor.yml +2 −0 Original line number Diff line number Diff line environment: SSL_CERT_FILE: "C:\\OpenSSL\\cacert.pem" matrix: # 1.1.0, 64/32 bit - TARGET: i686-pc-windows-gnu Loading @@ -23,6 +24,7 @@ install: # install OpenSSL - ps: Start-FileDownload "http://slproweb.com/download/Win${env:BITS}OpenSSL-${env:OPENSSL_VERSION}.exe" - Win%BITS%OpenSSL-%OPENSSL_VERSION%.exe /SILENT /VERYSILENT /SP- /DIR="C:\OpenSSL" - ps: Start-FileDownload "https://curl.haxx.se/ca/cacert.pem" -FileName "C:\OpenSSL\cacert.pem" # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ Loading
openssl/src/lib.rs +2 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,8 @@ pub mod ssl; pub mod symm; pub mod version; pub mod x509; #[cfg(any(ossl102, ossl110))] mod verify; pub fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Loading
openssl/src/pkey.rs +65 −44 Original line number Diff line number Diff line use libc::{c_void, c_char, c_int}; use std::ptr; use std::mem; use std::ops::Deref; use ffi; use {cvt, cvt_p}; Loading @@ -9,13 +10,66 @@ use dsa::Dsa; use rsa::Rsa; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb}; use opaque::Opaque; /// A borrowed `PKey`. pub struct PKeyRef(Opaque); impl PKeyRef { pub unsafe fn from_ptr<'a>(ptr: *mut ffi::EVP_PKEY) -> &'a PKeyRef { &*(ptr as *mut _) } pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY { self as *const _ as *mut _ } /// Get a reference to the interal RSA key for direct access to the key components pub fn rsa(&self) -> Result<Rsa, ErrorStack> { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))); // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), self.as_ptr(), ptr::null(), ptr::null_mut(), -1, None, ptr::null_mut()))); } Ok(mem_bio.get_buf().to_owned()) } /// Stores public key as a PEM pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); } Ok(mem_bio.get_buf().to_owned()) } pub fn public_eq(&self, other: &PKeyRef) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } } /// Represents a public key, optionally with a private key attached. pub struct PKey(*mut ffi::EVP_PKEY); unsafe impl Send for PKey {} unsafe impl Sync for PKey {} /// Represents a public key, optionally with a private key attached. impl PKey { /// Create a new `PKey` containing an RSA key. pub fn from_rsa(rsa: Rsa) -> Result<PKey, ErrorStack> { Loading Loading @@ -101,7 +155,7 @@ impl PKey { } } /// assign RSA key to this pkey /// Assign an RSA key to this pkey. pub fn set_rsa(&mut self, rsa: &Rsa) -> Result<(), ErrorStack> { unsafe { // this needs to be a reference as the set1_RSA ups the reference count Loading @@ -110,55 +164,22 @@ impl PKey { Ok(()) } } /// Get a reference to the interal RSA key for direct access to the key components pub fn rsa(&self) -> Result<Rsa, ErrorStack> { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.0))); // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), self.0, ptr::null(), ptr::null_mut(), -1, None, ptr::null_mut()))); } Ok(mem_bio.get_buf().to_owned()) } /// Stores public key as a PEM pub fn public_key_to_pem(&self) -> Result<Vec<u8>, ErrorStack> { let mem_bio = try!(MemBio::new()); impl Drop for PKey { fn drop(&mut self) { unsafe { try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.0))); ffi::EVP_PKEY_free(self.0); } Ok(mem_bio.get_buf().to_owned()) } pub fn as_ptr(&self) -> *mut ffi::EVP_PKEY { return self.0; } pub fn public_eq(&self, other: &PKey) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.0, other.0) == 1 } } } impl Deref for PKey { type Target = PKeyRef; impl Drop for PKey { fn drop(&mut self) { fn deref(&self) -> &PKeyRef { unsafe { ffi::EVP_PKEY_free(self.0); PKeyRef::from_ptr(self.0) } } } Loading
openssl/src/ssl/connector.rs 0 → 100644 +359 −0 Original line number Diff line number Diff line use std::io::{Read, Write}; use dh::Dh; use error::ErrorStack; use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, SslStream, HandshakeError}; use pkey::PKeyRef; use x509::X509Ref; // apps/dh2048.pem const DHPARAM_PEM: &'static str = r#" -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq 5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg== -----END DH PARAMETERS----- These are the 2048-bit DH parameters from "More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)": https://tools.ietf.org/html/rfc3526 See https://tools.ietf.org/html/rfc2412 for how they were generated."#; fn ctx(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> { let mut ctx = try!(SslContextBuilder::new(method)); // options to enable and cipher list lifted from libcurl let mut opts = ssl::SSL_OP_ALL; opts |= ssl::SSL_OP_NO_TICKET; opts |= ssl::SSL_OP_NO_COMPRESSION; opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; opts |= ssl::SSL_OP_NO_SSLV2; opts |= ssl::SSL_OP_NO_SSLV3; ctx.set_options(opts); Ok(ctx) } /// A builder for `ClientConnector`s. pub struct ClientConnectorBuilder(SslContextBuilder); impl ClientConnectorBuilder { /// Creates a new builder for TLS connections. /// /// The default configuration is based off of libcurl's and is subject to change. pub fn tls() -> Result<ClientConnectorBuilder, ErrorStack> { ClientConnectorBuilder::new(SslMethod::tls()) } fn new(method: SslMethod) -> Result<ClientConnectorBuilder, ErrorStack> { let mut ctx = try!(ctx(method)); try!(ctx.set_default_verify_paths()); try!(ctx.set_cipher_list("ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH")); Ok(ClientConnectorBuilder(ctx)) } /// Returns a shared reference to the inner `SslContextBuilder`. pub fn context(&self) -> &SslContextBuilder { &self.0 } /// Returns a mutable reference to the inner `SslContextBuilder`. pub fn context_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } /// Consumes the builder, returning a `ClientConnector`. pub fn build(self) -> ClientConnector { ClientConnector(self.0.build()) } } /// A type which wraps client-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, hostname verification, and more. /// /// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, /// and a custom implementation is used when linking against OpenSSL 1.0.1. pub struct ClientConnector(SslContext); impl ClientConnector { /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification. pub fn connect<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { let mut ssl = try!(Ssl::new(&self.0)); try!(ssl.set_hostname(domain)); try!(setup_verify(&mut ssl, domain)); ssl.connect(stream) } } /// A builder for `ServerConnector`s. pub struct ServerConnectorBuilder(SslContextBuilder); impl ServerConnectorBuilder { /// Creates a new builder for server-side TLS connections. /// /// The default configuration is based off of the intermediate profile of Mozilla's SSL /// Configuration Generator, and is subject to change. pub fn tls<I, T>(private_key: &PKeyRef, certificate: &X509Ref, chain: I) -> Result<ServerConnectorBuilder, ErrorStack> where I: IntoIterator<Item = T>, T: AsRef<X509Ref> { ServerConnectorBuilder::new(SslMethod::tls(), private_key, certificate, chain) } fn new<I, T>(method: SslMethod, private_key: &PKeyRef, certificate: &X509Ref, chain: I) -> Result<ServerConnectorBuilder, ErrorStack> where I: IntoIterator<Item = T>, T: AsRef<X509Ref> { let mut ctx = try!(ctx(method)); ctx.set_options(ssl::SSL_OP_SINGLE_DH_USE | ssl::SSL_OP_CIPHER_SERVER_PREFERENCE); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); try!(ctx.set_cipher_list( "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:\ ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:\ ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:\ ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:\ DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:\ AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS")); try!(ctx.set_private_key(private_key)); try!(ctx.set_certificate(certificate)); try!(ctx.check_private_key()); for cert in chain { try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned())); } Ok(ServerConnectorBuilder(ctx)) } /// Returns a shared reference to the inner `SslContextBuilder`. pub fn context(&self) -> &SslContextBuilder { &self.0 } /// Returns a mutable reference to the inner `SslContextBuilder`. pub fn context_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } /// Consumes the builder, returning a `ServerConnector`. pub fn build(self) -> ServerConnector { ServerConnector(self.0.build()) } } /// A type which wraps server-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, and more. pub struct ServerConnector(SslContext); impl ServerConnector { /// Initiates a server-side TLS session on a stream. pub fn connect<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { let ssl = try!(Ssl::new(&self.0)); ssl.accept(stream) } } #[cfg(any(ossl102, ossl110))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { ssl.set_verify(SSL_VERIFY_PEER); let param = ssl._param_mut(); param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); param.set_host(domain) } #[cfg(not(any(ossl102, ossl110)))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { let domain = domain.to_owned(); ssl.set_verify_callback(SSL_VERIFY_PEER, move |p, x| verify::verify_callback(&domain, p, x)); Ok(()) } #[cfg(not(any(ossl102, ossl110)))] mod verify { use std::net::IpAddr; use nid; use x509::{X509StoreContextRef, X509Ref, GeneralNames, X509NameRef}; pub fn verify_callback(domain: &str, preverify_ok: bool, x509_ctx: &X509StoreContextRef) -> bool { if !preverify_ok || x509_ctx.error_depth() != 0 { return preverify_ok; } match x509_ctx.current_cert() { Some(x509) => verify_hostname(domain, &x509), None => true, } } fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { match cert.subject_alt_names() { Some(names) => verify_subject_alt_names(domain, &names), None => verify_subject_name(domain, &cert.subject_name()), } } fn verify_subject_alt_names(domain: &str, names: &GeneralNames) -> bool { let ip = domain.parse(); for name in names { match ip { Ok(ip) => { if let Some(actual) = name.ipaddress() { if matches_ip(&ip, actual) { return true; } } } Err(_) => { if let Some(pattern) = name.dnsname() { if matches_dns(pattern, domain, false) { return true; } } } } } false } fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { if let Some(pattern) = subject_name.text_by_nid(nid::COMMONNAME) { // Unlike with SANs, IP addresses in the subject name don't have a // different encoding. We need to pass this down to matches_dns to // disallow wildcard matches with bogus patterns like *.0.0.1 let is_ip = domain.parse::<IpAddr>().is_ok(); if matches_dns(&pattern, domain, is_ip) { return true; } } false } fn matches_dns(mut pattern: &str, mut hostname: &str, is_ip: bool) -> bool { // first strip trailing . off of pattern and hostname to normalize if pattern.ends_with('.') { pattern = &pattern[..pattern.len() - 1]; } if hostname.ends_with('.') { hostname = &hostname[..hostname.len() - 1]; } matches_wildcard(pattern, hostname, is_ip).unwrap_or_else(|| pattern == hostname) } fn matches_wildcard(pattern: &str, hostname: &str, is_ip: bool) -> Option<bool> { // IP addresses and internationalized domains can't involved in wildcards if is_ip || pattern.starts_with("xn--") { return None; } let wildcard_location = match pattern.find('*') { Some(l) => l, None => return None, }; let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); let wildcard_end = match dot_idxs.next() { Some(l) => l, None => return None, }; // Never match wildcards if the pattern has less than 2 '.'s (no *.com) // // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. // Chrome has a black- and white-list for this, but Firefox (via NSS) does // the same thing we do here. // // The Public Suffix (https://www.publicsuffix.org/) list could // potentically be used here, but it's both huge and updated frequently // enough that management would be a PITA. if dot_idxs.next().is_none() { return None; } // Wildcards can only be in the first component if wildcard_location > wildcard_end { return None; } let hostname_label_end = match hostname.find('.') { Some(l) => l, None => return None, }; // check that the non-wildcard parts are identical if pattern[wildcard_end..] != hostname[hostname_label_end..] { return Some(false); } let wildcard_prefix = &pattern[..wildcard_location]; let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; let hostname_label = &hostname[..hostname_label_end]; // check the prefix of the first label if !hostname_label.starts_with(wildcard_prefix) { return Some(false); } // and the suffix if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { return Some(false); } Some(true) } fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { match (expected, actual.len()) { (&IpAddr::V4(ref addr), 4) => actual == addr.octets(), (&IpAddr::V6(ref addr), 16) => { let segments = [((actual[0] as u16) << 8) | actual[1] as u16, ((actual[2] as u16) << 8) | actual[3] as u16, ((actual[4] as u16) << 8) | actual[5] as u16, ((actual[6] as u16) << 8) | actual[7] as u16, ((actual[8] as u16) << 8) | actual[9] as u16, ((actual[10] as u16) << 8) | actual[11] as u16, ((actual[12] as u16) << 8) | actual[13] as u16, ((actual[14] as u16) << 8) | actual[15] as u16]; segments == addr.segments() } _ => false, } } }
openssl/src/ssl/mod.rs +104 −4 Original line number Diff line number Diff line //! SSL/TLS support. //! //! The `ClientConnector` and `ServerConnector` should be used in most cases - they handle //! configuration of the OpenSSL primitives for you. //! //! # Examples //! //! To connect as a client to a remote server: //! //! ``` //! use openssl::ssl::ClientConnectorBuilder; //! use std::io::{Read, Write}; //! use std::net::TcpStream; //! //! let connector = ClientConnectorBuilder::tls().unwrap().build(); //! //! let stream = TcpStream::connect("google.com:443").unwrap(); //! let mut stream = connector.connect("google.com", stream).unwrap(); //! //! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); //! let mut res = vec![]; //! stream.read_to_end(&mut res).unwrap(); //! println!("{}", String::from_utf8_lossy(&res)); //! ``` //! //! To accept connections as a server from remote clients: //! //! ```no_run //! use openssl::pkcs12::Pkcs12; //! use openssl::ssl::{ServerConnectorBuilder, SslStream}; //! use std::fs::File; //! use std::io::{Read, Write}; //! use std::net::{TcpListener, TcpStream}; //! use std::sync::Arc; //! use std::thread; //! //! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive, //! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted //! // files. See the documentation for the `PKey` and `X509` types for more details. //! let mut file = File::open("identity.pfx").unwrap(); //! let mut pkcs12 = vec![]; //! file.read_to_end(&mut pkcs12).unwrap(); //! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap(); //! let identity = pkcs12.parse("password123").unwrap(); //! //! let connector = ServerConnectorBuilder::tls(&identity.pkey, &identity.cert, &identity.chain) //! .unwrap() //! .build(); //! let connector = Arc::new(connector); //! //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); //! //! fn handle_client(stream: SslStream<TcpStream>) { //! // ... //! } //! //! for stream in listener.incoming() { //! match stream { //! Ok(stream) => { //! let connector = connector.clone(); //! thread::spawn(move || { //! let stream = connector.connect(stream).unwrap(); //! handle_client(stream); //! }); //! } //! Err(e) => { /* connection failed */ } //! } //! } //! ``` use libc::{c_int, c_void, c_long, c_ulong}; use std::any::Any; use std::any::TypeId; Loading @@ -22,19 +91,22 @@ use ffi; use {init, cvt, cvt_p}; use dh::Dh; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509VerifyParamRef; use pkey::PKey; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; use opaque::Opaque; pub mod error; mod connector; mod bio; #[cfg(test)] mod tests; use self::bio::BioMethod; pub use ssl::connector::{ClientConnectorBuilder, ClientConnector, ServerConnectorBuilder, ServerConnector}; #[doc(inline)] pub use ssl::error::Error; Loading Loading @@ -339,6 +411,7 @@ pub enum SniError { NoAck, } /// A builder for `SslContext`s. pub struct SslContextBuilder(*mut ffi::SSL_CTX); impl Drop for SslContextBuilder { Loading Loading @@ -529,7 +602,7 @@ impl SslContextBuilder { } /// Specifies the private key pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> { pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } Loading Loading @@ -790,6 +863,7 @@ impl SslCipherRef { } } /// A reference to an `Ssl`. pub struct SslRef(Opaque); unsafe impl Send for SslRef {} Loading Loading @@ -1030,6 +1104,11 @@ impl SslRef { /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0. #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { self._param_mut() } #[cfg(any(ossl102, ossl110))] fn _param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } Loading Loading @@ -1096,6 +1175,11 @@ impl Ssl { } /// Creates an SSL/TLS client operating over the provided stream. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `ClientConnector` rather than `Ssl` directly, as it manages that configuration. pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { Loading Loading @@ -1123,6 +1207,11 @@ impl Ssl { } /// Creates an SSL/TLS server operating over the provided stream. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `ServerConnector` rather than `Ssl` directly, as it manages that configuration. pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write { Loading Loading @@ -1153,6 +1242,8 @@ impl Ssl { /// An error or intermediate state after a TLS handshake attempt. #[derive(Debug)] pub enum HandshakeError<S> { /// Setup failed. SetupFailure(ErrorStack), /// The handshake failed. Failure(MidHandshakeSslStream<S>), /// The handshake was interrupted midway through. Loading @@ -1162,6 +1253,7 @@ pub enum HandshakeError<S> { impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> { fn description(&self) -> &str { match *self { HandshakeError::SetupFailure(_) => "stream setup failed", HandshakeError::Failure(_) => "the handshake failed", HandshakeError::Interrupted(_) => "the handshake was interrupted", } Loading @@ -1169,6 +1261,7 @@ impl<S: Any + fmt::Debug> stderror::Error for HandshakeError<S> { fn cause(&self) -> Option<&stderror::Error> { match *self { HandshakeError::SetupFailure(ref e) => Some(e), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => Some(s.error()), } } Loading @@ -1178,6 +1271,7 @@ impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(f.write_str(stderror::Error::description(self))); match *self { HandshakeError::SetupFailure(ref e) => try!(write!(f, ": {}", e)), HandshakeError::Failure(ref s) | HandshakeError::Interrupted(ref s) => { try!(write!(f, ": {}", s.error())); if let Some(err) = s.ssl().verify_result() { Loading @@ -1189,6 +1283,12 @@ impl<S: Any + fmt::Debug> fmt::Display for HandshakeError<S> { } } impl<S> From<ErrorStack> for HandshakeError<S> { fn from(e: ErrorStack) -> HandshakeError<S> { HandshakeError::SetupFailure(e) } } /// An SSL stream midway through the handshake process. #[derive(Debug)] pub struct MidHandshakeSslStream<S> { Loading