From d0b769c93c623d308c02cb5d86726f4c9607f5f4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 15:11:11 -0700 Subject: Move macro replicas into C shim --- openssl/src/bio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') diff --git a/openssl/src/bio/mod.rs b/openssl/src/bio/mod.rs index e81694a4..e0a7d0c9 100644 --- a/openssl/src/bio/mod.rs +++ b/openssl/src/bio/mod.rs @@ -73,7 +73,7 @@ impl Read for MemBio { if ret <= 0 { let is_eof = unsafe { ffi::BIO_eof(self.bio) }; - if is_eof { + if is_eof != 0 { Ok(0) } else { Err(io::Error::new(io::ErrorKind::Other, -- cgit v1.2.3 From cb7248d8cb1596f48cb916fe36aa3be2d7b91164 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 15:23:19 -0700 Subject: Import shim'd HMAC stuff with the original name --- openssl/src/crypto/hmac.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/crypto/hmac.rs b/openssl/src/crypto/hmac.rs index a59cb929..5c9f7576 100644 --- a/openssl/src/crypto/hmac.rs +++ b/openssl/src/crypto/hmac.rs @@ -88,9 +88,9 @@ impl HMAC { #[inline] fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) { unsafe { - let r = ffi::HMAC_Init_ex_shim(&mut self.ctx, - key.as_ptr(), key.len() as c_int, - md, 0 as *const _); + let r = ffi::HMAC_Init_ex(&mut self.ctx, + key.as_ptr(), key.len() as c_int, + md, 0 as *const _); assert_eq!(r, 1); } self.state = Reset; @@ -106,9 +106,9 @@ impl HMAC { // If the key and/or md is not supplied it's reused from the last time // avoiding redundant initializations unsafe { - let r = ffi::HMAC_Init_ex_shim(&mut self.ctx, - 0 as *const _, 0, - 0 as *const _, 0 as *const _); + let r = ffi::HMAC_Init_ex(&mut self.ctx, + 0 as *const _, 0, + 0 as *const _, 0 as *const _); assert_eq!(r, 1); } self.state = Reset; @@ -120,7 +120,7 @@ impl HMAC { self.init(); } unsafe { - let r = ffi::HMAC_Update_shim(&mut self.ctx, data.as_ptr(), data.len() as c_uint); + let r = ffi::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint); assert_eq!(r, 1); } self.state = Updated; @@ -135,7 +135,7 @@ impl HMAC { let mut res: Vec = repeat(0).take(md_len).collect(); unsafe { let mut len = 0; - let r = ffi::HMAC_Final_shim(&mut self.ctx, res.as_mut_ptr(), &mut len); + let r = ffi::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len); self.state = Finalized; assert_eq!(len as usize, md_len); assert_eq!(r, 1); @@ -181,7 +181,7 @@ impl Drop for HMAC { if self.state != Finalized { let mut buf: Vec = repeat(0).take(self.type_.md_len()).collect(); let mut len = 0; - ffi::HMAC_Final_shim(&mut self.ctx, buf.as_mut_ptr(), &mut len); + ffi::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len); } ffi::HMAC_CTX_cleanup(&mut self.ctx); } -- cgit v1.2.3 From 9d0acfe6155e1f432a80d0bfa99efbbdf0b07100 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 19:37:45 -0700 Subject: Fix set_hostname It was previously failing to null terminate the hostname string (was anyone actually using this?). Also move the macro expansion to the C shim. --- openssl/src/ssl/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index a0f97b17..57635523 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -655,16 +655,8 @@ impl Ssl { /// Set the host name to be used with SNI (Server Name Indication). pub fn set_hostname(&self, hostname: &str) -> Result<(), SslError> { - let ret = unsafe { - // This is defined as a macro: - // #define SSL_set_tlsext_host_name(s,name) \ - // SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name) - - let hostname = CString::new(hostname.as_bytes()).unwrap(); - ffi::SSL_ctrl(self.ssl, ffi::SSL_CTRL_SET_TLSEXT_HOSTNAME, - ffi::TLSEXT_NAMETYPE_host_name, - hostname.as_ptr() as *mut c_void) - }; + let cstr = CString::new(hostname).unwrap(); + let ret = unsafe { ffi::SSL_set_tlsext_host_name(self.ssl, cstr.as_ptr()) }; // For this case, 0 indicates failure. if ret == 0 { -- cgit v1.2.3 From a80a77bbb8b6c969c053cdbd56d83faa6de15e0f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 19:42:13 -0700 Subject: Initialize stream buffer --- openssl/src/ssl/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 57635523..fbad7dcc 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -5,6 +5,7 @@ use std::ffi::{CStr, CString}; use std::fmt; use std::io; use std::io::prelude::*; +use std::iter; use std::mem; use std::net; use std::path::Path; @@ -770,14 +771,7 @@ impl SslStream { stream: stream, ssl: Arc::new(ssl), // Maximum TLS record size is 16k - // We're just using this as a buffer, so there's no reason to pay - // to memset it - buf: { - const CAP: usize = 16 * 1024; - let mut v = Vec::with_capacity(CAP); - unsafe { v.set_len(CAP); } - v - } + buf: iter::repeat(0).take(16 * 1024).collect(), } } -- cgit v1.2.3 From 0cff370f1d4e46145bc9047508a7e63402b10adc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 21:40:00 -0700 Subject: Reduce SslStream constructor duplication --- openssl/src/bio/mod.rs | 6 ++--- openssl/src/ssl/mod.rs | 57 +++++++++++++++++++++++++++++++++--------------- openssl/src/ssl/tests.rs | 46 +++++++++++++++++++------------------- 3 files changed, 64 insertions(+), 45 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/bio/mod.rs b/openssl/src/bio/mod.rs index e0a7d0c9..7eea16d8 100644 --- a/openssl/src/bio/mod.rs +++ b/openssl/src/bio/mod.rs @@ -76,8 +76,7 @@ impl Read for MemBio { if is_eof != 0 { Ok(0) } else { - Err(io::Error::new(io::ErrorKind::Other, - SslError::get())) + Err(io::Error::new(io::ErrorKind::Other, SslError::get())) } } else { Ok(ret as usize) @@ -93,8 +92,7 @@ impl Write for MemBio { }; if ret < 0 { - Err(io::Error::new(io::ErrorKind::Other, - SslError::get())) + Err(io::Error::new(io::ErrorKind::Other, SslError::get())) } else { Ok(ret as usize) } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index fbad7dcc..0768fead 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -496,7 +496,7 @@ impl SslContext { pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(),SslError> { wrap_ssl_result( unsafe { - let cipher_list = CString::new(cipher_list.as_bytes()).unwrap(); + let cipher_list = CString::new(cipher_list).unwrap(); ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr()) }) } @@ -766,36 +766,41 @@ impl fmt::Debug for SslStream where S: fmt::Debug { } impl SslStream { - fn new_base(ssl:Ssl, stream: S) -> SslStream { - SslStream { + fn new_base(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); + Ok(SslStream { stream: stream, ssl: Arc::new(ssl), // Maximum TLS record size is 16k buf: iter::repeat(0).take(16 * 1024).collect(), - } + }) + } + + pub fn new_client(ssl: T, stream: S) -> Result, SslError> { + let mut ssl = try!(SslStream::new_base(ssl, stream)); + try!(ssl.in_retry_wrapper(|ssl| ssl.connect())); + Ok(ssl) } + pub fn new_server(ssl: T, stream: S) -> Result, SslError> { + let mut ssl = try!(SslStream::new_base(ssl, stream)); + try!(ssl.in_retry_wrapper(|ssl| ssl.accept())); + Ok(ssl) + } + + /// # Deprecated pub fn new_server_from(ssl: Ssl, stream: S) -> Result, SslError> { - let mut ssl = SslStream::new_base(ssl, stream); - ssl.in_retry_wrapper(|ssl| { ssl.accept() }).and(Ok(ssl)) + SslStream::new_server(ssl, stream) } - /// Attempts to create a new SSL stream from a given `Ssl` instance. + /// # Deprecated pub fn new_from(ssl: Ssl, stream: S) -> Result, SslError> { - let mut ssl = SslStream::new_base(ssl, stream); - ssl.in_retry_wrapper(|ssl| { ssl.connect() }).and(Ok(ssl)) + SslStream::new_client(ssl, stream) } - /// Creates a new SSL stream + /// # Deprecated pub fn new(ctx: &SslContext, stream: S) -> Result, SslError> { - let ssl = try!(Ssl::new(ctx)); - SslStream::new_from(ssl, stream) - } - - /// Creates a new SSL server stream - pub fn new_server(ctx: &SslContext, stream: S) -> Result, SslError> { - let ssl = try!(Ssl::new(ctx)); - SslStream::new_server_from(ssl, stream) + SslStream::new_client(ctx, stream) } #[doc(hidden)] @@ -920,6 +925,22 @@ impl Write for SslStream { } } +pub trait IntoSsl { + fn into_ssl(self) -> Result; +} + +impl IntoSsl for Ssl { + fn into_ssl(self) -> Result { + Ok(self) + } +} + +impl<'a> IntoSsl for &'a SslContext { + fn into_ssl(self) -> Result { + Ssl::new(self) + } +} + /// A utility type to help in cases where the use of SSL is decided at runtime. #[derive(Debug)] pub enum MaybeSslStream where S: Read+Write { diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index dcaee215..a0e4a9d6 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -83,14 +83,14 @@ run_test!(new_ctx, |method, _| { }); run_test!(new_sslstream, |method, stream| { - SslStream::new(&SslContext::new(method).unwrap(), stream).unwrap(); + SslStream::new_client(&SslContext::new(method).unwrap(), stream).unwrap(); }); run_test!(verify_untrusted, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, None); - match SslStream::new(&ctx, stream) { + match SslStream::new_client(&ctx, stream) { Ok(_) => panic!("expected failure"), Err(err) => println!("error {:?}", err) } @@ -104,7 +104,7 @@ run_test!(verify_trusted, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::new(&ctx, stream) { + match SslStream::new_client(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -118,7 +118,7 @@ run_test!(verify_untrusted_callback_override_ok, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - match SslStream::new(&ctx, stream) { + match SslStream::new_client(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -132,7 +132,7 @@ run_test!(verify_untrusted_callback_override_bad, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new(&ctx, stream).is_err()); + assert!(SslStream::new_client(&ctx, stream).is_err()); }); run_test!(verify_trusted_callback_override_ok, |method, stream| { @@ -147,7 +147,7 @@ run_test!(verify_trusted_callback_override_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::new(&ctx, stream) { + match SslStream::new_client(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -165,7 +165,7 @@ run_test!(verify_trusted_callback_override_bad, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::new(&ctx, stream).is_err()); + assert!(SslStream::new_client(&ctx, stream).is_err()); }); run_test!(verify_callback_load_certs, |method, stream| { @@ -177,7 +177,7 @@ run_test!(verify_callback_load_certs, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new(&ctx, stream).is_ok()); + assert!(SslStream::new_client(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_ok, |method, stream| { @@ -193,7 +193,7 @@ run_test!(verify_trusted_get_error_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::new(&ctx, stream).is_ok()); + assert!(SslStream::new_client(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_err, |method, stream| { @@ -205,7 +205,7 @@ run_test!(verify_trusted_get_error_err, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new(&ctx, stream).is_err()); + assert!(SslStream::new_client(&ctx, stream).is_err()); }); run_test!(verify_callback_data, |method, stream| { @@ -230,7 +230,7 @@ run_test!(verify_callback_data, |method, stream| { ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id); ctx.set_verify_depth(1); - match SslStream::new(&ctx, stream) { + match SslStream::new_client(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -245,7 +245,7 @@ fn test_write_hits_stream() { let guard = thread::spawn(move || { let ctx = SslContext::new(Sslv23).unwrap(); let stream = TcpStream::connect(addr).unwrap(); - let mut stream = SslStream::new(&ctx, stream).unwrap(); + let mut stream = SslStream::new_client(&ctx, stream).unwrap(); stream.write_all(b"hello").unwrap(); stream @@ -310,7 +310,7 @@ run_test!(clear_ctx_options, |method, _| { #[test] fn test_write() { let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -319,7 +319,7 @@ fn test_write() { run_test!(get_peer_certificate, |method, stream| { //let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let stream = SslStream::new(&SslContext::new(method).unwrap(), stream).unwrap(); + let stream = SslStream::new_client(&SslContext::new(method).unwrap(), stream).unwrap(); let cert = stream.get_peer_certificate().unwrap(); let fingerprint = cert.fingerprint(SHA256).unwrap(); let node_hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; @@ -333,7 +333,7 @@ fn test_write_dtlsv1() { let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); let stream = sock.connect("127.0.0.1:15410").unwrap(); - let mut stream = SslStream::new(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::new_client(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -343,7 +343,7 @@ fn test_write_dtlsv1() { #[test] fn test_read() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -353,7 +353,7 @@ fn test_read() { #[test] fn test_pending() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); @@ -386,7 +386,7 @@ fn test_connect_with_unilateral_npn() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new(&ctx, stream) { + let stream = match SslStream::new_client(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -410,7 +410,7 @@ fn test_connect_with_npn_successful_multiple_matching() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new(&ctx, stream) { + let stream = match SslStream::new_client(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -435,7 +435,7 @@ fn test_connect_with_npn_successful_single_match() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new(&ctx, stream) { + let stream = match SslStream::new_client(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -477,7 +477,7 @@ fn test_npn_server_advertise_multiple() { } // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); - let stream = match SslStream::new(&ctx, stream) { + let stream = match SslStream::new_client(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -514,7 +514,7 @@ fn test_read_dtlsv1() { let server = udp::next_server(); let stream = sock.connect(&server[..]).unwrap(); - let mut stream = SslStream::new(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::new_client(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); let mut buf = [0u8;100]; assert!(stream.read(&mut buf).is_ok()); } @@ -523,5 +523,5 @@ fn test_read_dtlsv1() { #[cfg(feature = "sslv2")] fn test_sslv2_connect_failure() { let tcp = TcpStream::connect("127.0.0.1:15420").unwrap(); - SslStream::new(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); + SslStream::new_client(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); } -- cgit v1.2.3 From c722f889c1e4962dc7793a881d37b07aedc6f02f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 21:40:55 -0700 Subject: Docs tweak --- openssl/src/ssl/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0768fead..cb4448b8 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -803,6 +803,7 @@ impl SslStream { SslStream::new_client(ctx, stream) } + /// # Deprecated #[doc(hidden)] pub fn get_inner(&mut self) -> &mut S { self.get_mut() @@ -823,7 +824,7 @@ impl SslStream { /// ## Warning /// /// It is inadvisable to read from or write to the underlying stream as it - /// will most likely desynchronize the SSL session. + /// will most likely corrupt the SSL session. pub fn get_mut(&mut self) -> &mut S { &mut self.stream } -- cgit v1.2.3 From 9b235a7b9121613780810b0bc7b4d1f30dc861c9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 27 Jun 2015 22:37:10 -0700 Subject: Prepare for direct stream support --- openssl/src/ssl/mod.rs | 243 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 165 insertions(+), 78 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cb4448b8..18acf7f8 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -5,7 +5,6 @@ use std::ffi::{CStr, CString}; use std::fmt; use std::io; use std::io::prelude::*; -use std::iter; use std::mem; use std::net; use std::path::Path; @@ -740,52 +739,181 @@ make_LibSslError! { ErrorWantAccept = SSL_ERROR_WANT_ACCEPT } +struct IndirectStream { + stream: S, + ssl: Arc, + // Max TLS record size is 16k + buf: Box<[u8; 16 * 1024]>, +} + +impl Clone for IndirectStream { + fn clone(&self) -> IndirectStream { + IndirectStream { + stream: self.stream.clone(), + ssl: self.ssl.clone(), + buf: Box::new(*self.buf) + } + } +} + +impl IndirectStream { + fn try_clone(&self) -> io::Result> { + Ok(IndirectStream { + stream: try!(self.stream.try_clone()), + ssl: self.ssl.clone(), + buf: Box::new(*self.buf) + }) + } +} + +impl IndirectStream { + fn new_base(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); + Ok(IndirectStream { + stream: stream, + ssl: Arc::new(ssl), + buf: Box::new([0; 16 * 1024]), + }) + } + + fn new_client(ssl: T, stream: S) -> Result, SslError> { + let mut ssl = try!(IndirectStream::new_base(ssl, stream)); + try!(ssl.in_retry_wrapper(|ssl| ssl.connect())); + Ok(ssl) + } + + fn new_server(ssl: T, stream: S) -> Result, SslError> { + let mut ssl = try!(IndirectStream::new_base(ssl, stream)); + try!(ssl.in_retry_wrapper(|ssl| ssl.accept())); + Ok(ssl) + } + + fn in_retry_wrapper(&mut self, mut blk: F) -> Result + where F: FnMut(&Ssl) -> c_int { + loop { + let ret = blk(&self.ssl); + if ret > 0 { + return Ok(ret); + } + + let e = self.ssl.get_error(ret); + match e { + LibSslError::ErrorWantRead => { + try_ssl_stream!(self.flush()); + let len = try_ssl_stream!(self.stream.read(&mut self.buf[..])); + if len == 0 { + self.ssl.get_rbio().set_eof(true); + } else { + try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len])); + } + } + LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) } + LibSslError::ErrorZeroReturn => return Err(SslSessionClosed), + LibSslError::ErrorSsl => return Err(SslError::get()), + LibSslError::ErrorSyscall if ret == 0 => return Ok(0), + err => panic!("unexpected error {:?} with ret {}", err, ret), + } + } + } + + fn write_through(&mut self) -> io::Result<()> { + io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ()) + } +} + +impl Read for IndirectStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) { + Ok(len) => Ok(len as usize), + Err(SslSessionClosed) => Ok(0), + Err(StreamError(e)) => Err(e), + Err(e @ OpenSslErrors(_)) => { + Err(io::Error::new(io::ErrorKind::Other, e)) + } + } + } +} + +impl Write for IndirectStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) { + Ok(len) => len as usize, + Err(SslSessionClosed) => 0, + Err(StreamError(e)) => return Err(e), + Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)), + }; + try!(self.write_through()); + Ok(count) + } + + fn flush(&mut self) -> io::Result<()> { + try!(self.write_through()); + self.stream.flush() + } +} + +#[derive(Clone)] +enum StreamKind { + Indirect(IndirectStream), +} + +impl StreamKind { + fn stream(&self) -> &S { + match *self { + StreamKind::Indirect(ref s) => &s.stream + } + } + + fn mut_stream(&mut self) -> &mut S { + match *self { + StreamKind::Indirect(ref mut s) => &mut s.stream + } + } + + fn ssl(&self) -> &Ssl { + match *self { + StreamKind::Indirect(ref s) => &s.ssl + } + } +} + /// A stream wrapper which handles SSL encryption for an underlying stream. #[derive(Clone)] pub struct SslStream { - stream: S, - ssl: Arc, - buf: Vec + kind: StreamKind, } impl SslStream { /// Create a new independently owned handle to the underlying socket. pub fn try_clone(&self) -> io::Result> { + let kind = match self.kind { + StreamKind::Indirect(ref s) => StreamKind::Indirect(try!(s.try_clone())) + }; Ok(SslStream { - stream: try!(self.stream.try_clone()), - ssl: self.ssl.clone(), - buf: self.buf.clone(), + kind: kind }) } } impl fmt::Debug for SslStream where S: fmt::Debug { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "SslStream {{ stream: {:?}, ssl: {:?} }}", self.stream, self.ssl) + write!(fmt, "SslStream {{ stream: {:?}, ssl: {:?} }}", self.kind.stream(), self.kind.ssl()) } } impl SslStream { - fn new_base(ssl: T, stream: S) -> Result, SslError> { - let ssl = try!(ssl.into_ssl()); + pub fn new_client(ssl: T, stream: S) -> Result, SslError> { + let stream = try!(IndirectStream::new_client(ssl, stream)); Ok(SslStream { - stream: stream, - ssl: Arc::new(ssl), - // Maximum TLS record size is 16k - buf: iter::repeat(0).take(16 * 1024).collect(), + kind: StreamKind::Indirect(stream) }) } - pub fn new_client(ssl: T, stream: S) -> Result, SslError> { - let mut ssl = try!(SslStream::new_base(ssl, stream)); - try!(ssl.in_retry_wrapper(|ssl| ssl.connect())); - Ok(ssl) - } - pub fn new_server(ssl: T, stream: S) -> Result, SslError> { - let mut ssl = try!(SslStream::new_base(ssl, stream)); - try!(ssl.in_retry_wrapper(|ssl| ssl.accept())); - Ok(ssl) + let stream = try!(IndirectStream::new_server(ssl, stream)); + Ok(SslStream { + kind: StreamKind::Indirect(stream) + }) } /// # Deprecated @@ -811,12 +939,12 @@ impl SslStream { /// Returns a reference to the underlying stream. pub fn get_ref(&self) -> &S { - &self.stream + self.kind.stream() } /// Return the certificate of the peer pub fn get_peer_certificate(&self) -> Option { - self.ssl.get_peer_certificate() + self.kind.ssl().get_peer_certificate() } /// Returns a mutable reference to the underlying stream. @@ -826,46 +954,14 @@ impl SslStream { /// It is inadvisable to read from or write to the underlying stream as it /// will most likely corrupt the SSL session. pub fn get_mut(&mut self) -> &mut S { - &mut self.stream - } - - fn in_retry_wrapper(&mut self, mut blk: F) - -> Result where F: FnMut(&Ssl) -> c_int { - loop { - let ret = blk(&self.ssl); - if ret > 0 { - return Ok(ret); - } - - let e = self.ssl.get_error(ret); - match e { - LibSslError::ErrorWantRead => { - try_ssl_stream!(self.flush()); - let len = try_ssl_stream!(self.stream.read(&mut self.buf[..])); - if len == 0 { - self.ssl.get_rbio().set_eof(true); - } else { - try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len])); - } - } - LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) } - LibSslError::ErrorZeroReturn => return Err(SslSessionClosed), - LibSslError::ErrorSsl => return Err(SslError::get()), - LibSslError::ErrorSyscall if ret == 0 => return Ok(0), - err => panic!("unexpected error {:?} with ret {}", err, ret), - } - } - } - - fn write_through(&mut self) -> io::Result<()> { - io::copy(&mut *self.ssl.get_wbio(), &mut self.stream).map(|_| ()) + self.kind.mut_stream() } /// Get the compression currently in use. The result will be /// either None, indicating no compression is in use, or a string /// with the compression name. pub fn get_compression(&self) -> Option { - let ptr = unsafe { ffi::SSL_get_current_compression(self.ssl.ssl) }; + let ptr = unsafe { ffi::SSL_get_current_compression(self.kind.ssl().ssl) }; if ptr == ptr::null() { return None; } @@ -886,43 +982,34 @@ impl SslStream { /// This method needs the `npn` feature. #[cfg(feature = "npn")] pub fn get_selected_npn_protocol(&self) -> Option<&[u8]> { - self.ssl.get_selected_npn_protocol() + self.kind.ssl().get_selected_npn_protocol() } /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). pub fn pending(&self) -> usize { - self.ssl.pending() + self.kind.ssl().pending() } } impl Read for SslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { - match self.in_retry_wrapper(|ssl| { ssl.read(buf) }) { - Ok(len) => Ok(len as usize), - Err(SslSessionClosed) => Ok(0), - Err(StreamError(e)) => Err(e), - Err(e @ OpenSslErrors(_)) => { - Err(io::Error::new(io::ErrorKind::Other, e)) - } + match self.kind { + StreamKind::Indirect(ref mut s) => s.read(buf) } } } impl Write for SslStream { fn write(&mut self, buf: &[u8]) -> io::Result { - let count = match self.in_retry_wrapper(|ssl| ssl.write(buf)) { - Ok(len) => len as usize, - Err(SslSessionClosed) => 0, - Err(StreamError(e)) => return Err(e), - Err(e @ OpenSslErrors(_)) => return Err(io::Error::new(io::ErrorKind::Other, e)), - }; - try!(self.write_through()); - Ok(count) + match self.kind { + StreamKind::Indirect(ref mut s) => s.write(buf) + } } fn flush(&mut self) -> io::Result<()> { - try!(self.write_through()); - self.stream.flush() + match self.kind { + StreamKind::Indirect(ref mut s) => s.flush() + } } } -- cgit v1.2.3 From 1373a76ce12d6a856b6caae7457ceb3eb5ad4122 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 00:06:14 -0700 Subject: Implement direct IO support --- openssl/src/ssl/mod.rs | 181 +++++++++++++++++++++++++++++++++++++++++++---- openssl/src/ssl/tests.rs | 19 ++++- 2 files changed, 187 insertions(+), 13 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 18acf7f8..0e1e5b30 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -603,11 +603,6 @@ impl Ssl { return Err(SslError::get()); } let ssl = Ssl { ssl: ssl }; - - let rbio = try!(MemBio::new()); - let wbio = try!(MemBio::new()); - - unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) } Ok(ssl) } @@ -769,6 +764,12 @@ impl IndirectStream { impl IndirectStream { fn new_base(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); + + let rbio = try!(MemBio::new()); + let wbio = try!(MemBio::new()); + + unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) } + Ok(IndirectStream { stream: stream, ssl: Arc::new(ssl), @@ -852,27 +853,139 @@ impl Write for IndirectStream { } } +#[derive(Clone)] +struct DirectStream { + stream: S, + ssl: Arc, +} + +impl DirectStream { + fn try_clone(&self) -> io::Result> { + Ok(DirectStream { + stream: try!(self.stream.try_clone()), + ssl: self.ssl.clone(), + }) + } +} + +impl DirectStream { + fn new_base(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { + unsafe { + let bio = ffi::BIO_new_socket(sock, 0); + if bio == ptr::null_mut() { + return Err(SslError::get()); + } + ffi::SSL_set_bio(ssl.ssl, bio, bio); + } + + Ok(DirectStream { + stream: stream, + ssl: Arc::new(ssl), + }) + } + + fn new_client(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { + let ssl = try!(DirectStream::new_base(ssl, stream, sock)); + let ret = ssl.ssl.connect(); + if ret > 0 { + Ok(ssl) + } else { + Err(ssl.make_error(ret)) + } + } + + fn new_server(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { + let ssl = try!(DirectStream::new_base(ssl, stream, sock)); + let ret = ssl.ssl.accept(); + if ret > 0 { + Ok(ssl) + } else { + Err(ssl.make_error(ret)) + } + } + + fn make_error(&self, ret: c_int) -> SslError { + match self.ssl.get_error(ret) { + LibSslError::ErrorSsl => SslError::get(), + LibSslError::ErrorSyscall => { + let err = SslError::get(); + let count = match err { + SslError::OpenSslErrors(ref v) => v.len(), + _ => unreachable!(), + }; + if count == 0 { + if ret == 0 { + SslError::StreamError(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } else { + SslError::StreamError(io::Error::last_os_error()) + } + } else { + err + } + } + err => panic!("unexpected error {:?} with ret {}", err, ret), + } + } +} + +impl Read for DirectStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let ret = self.ssl.read(buf); + if ret >= 0 { + return Ok(ret as usize); + } + + match self.make_error(ret) { + SslError::StreamError(e) => Err(e), + e => Err(io::Error::new(io::ErrorKind::Other, e)), + } + } +} + +impl Write for DirectStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + let ret = self.ssl.write(buf); + if ret > 0 { + return Ok(ret as usize); + } + + match self.make_error(ret) { + SslError::StreamError(e) => Err(e), + e => Err(io::Error::new(io::ErrorKind::Other, e)), + } + } + + fn flush(&mut self) -> io::Result<()> { + self.stream.flush() + } +} + #[derive(Clone)] enum StreamKind { Indirect(IndirectStream), + Direct(DirectStream), } impl StreamKind { fn stream(&self) -> &S { match *self { - StreamKind::Indirect(ref s) => &s.stream + StreamKind::Indirect(ref s) => &s.stream, + StreamKind::Direct(ref s) => &s.stream, } } fn mut_stream(&mut self) -> &mut S { match *self { - StreamKind::Indirect(ref mut s) => &mut s.stream + StreamKind::Indirect(ref mut s) => &mut s.stream, + StreamKind::Direct(ref mut s) => &mut s.stream, } } fn ssl(&self) -> &Ssl { match *self { - StreamKind::Indirect(ref s) => &s.ssl + StreamKind::Indirect(ref s) => &s.ssl, + StreamKind::Direct(ref s) => &s.ssl, } } } @@ -887,7 +1000,8 @@ impl SslStream { /// Create a new independently owned handle to the underlying socket. pub fn try_clone(&self) -> io::Result> { let kind = match self.kind { - StreamKind::Indirect(ref s) => StreamKind::Indirect(try!(s.try_clone())) + StreamKind::Indirect(ref s) => StreamKind::Indirect(try!(s.try_clone())), + StreamKind::Direct(ref s) => StreamKind::Direct(try!(s.try_clone())) }; Ok(SslStream { kind: kind @@ -901,6 +1015,46 @@ impl fmt::Debug for SslStream where S: fmt::Debug { } } +#[cfg(unix)] +impl SslStream { + pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); + let fd = stream.as_raw_fd() as c_int; + let stream = try!(DirectStream::new_client(ssl, stream, fd)); + Ok(SslStream { + kind: StreamKind::Direct(stream) + }) + } + + pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); + let fd = stream.as_raw_fd() as c_int; + let stream = try!(DirectStream::new_server(ssl, stream, fd)); + Ok(SslStream { + kind: StreamKind::Direct(stream) + }) + } +} + +#[cfg(windows)] +impl SslStream { + pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { + let fd = stream.as_raw_socket() as c_int; + let stream = try!(DirectStream::new_client(ssl, stream, fd)); + Ok(SslStream { + kind: StreamKind::Direct(stream) + }) + } + + pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { + let fd = stream.as_raw_socket() as c_int; + let stream = try!(DirectStream::new_server(ssl, stream, fd)); + Ok(SslStream { + kind: StreamKind::Direct(stream) + }) + } +} + impl SslStream { pub fn new_client(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::new_client(ssl, stream)); @@ -994,7 +1148,8 @@ impl SslStream { impl Read for SslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { match self.kind { - StreamKind::Indirect(ref mut s) => s.read(buf) + StreamKind::Indirect(ref mut s) => s.read(buf), + StreamKind::Direct(ref mut s) => s.read(buf), } } } @@ -1002,13 +1157,15 @@ impl Read for SslStream { impl Write for SslStream { fn write(&mut self, buf: &[u8]) -> io::Result { match self.kind { - StreamKind::Indirect(ref mut s) => s.write(buf) + StreamKind::Indirect(ref mut s) => s.write(buf), + StreamKind::Direct(ref mut s) => s.write(buf), } } fn flush(&mut self) -> io::Result<()> { match self.kind { - StreamKind::Indirect(ref mut s) => s.flush() + StreamKind::Indirect(ref mut s) => s.flush(), + StreamKind::Direct(ref mut s) => s.flush(), } } } diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index a0e4a9d6..2ba940ab 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -317,8 +317,17 @@ fn test_write() { stream.flush().unwrap(); } +#[test] +fn test_write_direct() { + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); + let mut stream = SslStream::new_client_direct(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + stream.write_all("hello".as_bytes()).unwrap(); + stream.flush().unwrap(); + stream.write_all(" there".as_bytes()).unwrap(); + stream.flush().unwrap(); +} + run_test!(get_peer_certificate, |method, stream| { - //let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let stream = SslStream::new_client(&SslContext::new(method).unwrap(), stream).unwrap(); let cert = stream.get_peer_certificate().unwrap(); let fingerprint = cert.fingerprint(SHA256).unwrap(); @@ -349,6 +358,14 @@ fn test_read() { io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); } +#[test] +fn test_read_direct() { + let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); + let mut stream = SslStream::new_client_direct(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); + stream.flush().unwrap(); + io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); +} #[test] fn test_pending() { -- cgit v1.2.3 From b1a30ce4ba13cc6e673fb3b71ca9aa7249529c31 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 00:12:47 -0700 Subject: Rename new_client to connect and new_server to accept --- openssl/src/ssl/mod.rs | 39 +++++++++++++++++++--------------- openssl/src/ssl/tests.rs | 54 ++++++++++++++++++++++++------------------------ 2 files changed, 49 insertions(+), 44 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0e1e5b30..5d770c19 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -777,13 +777,13 @@ impl IndirectStream { }) } - fn new_client(ssl: T, stream: S) -> Result, SslError> { + fn connect(ssl: T, stream: S) -> Result, SslError> { let mut ssl = try!(IndirectStream::new_base(ssl, stream)); try!(ssl.in_retry_wrapper(|ssl| ssl.connect())); Ok(ssl) } - fn new_server(ssl: T, stream: S) -> Result, SslError> { + fn accept(ssl: T, stream: S) -> Result, SslError> { let mut ssl = try!(IndirectStream::new_base(ssl, stream)); try!(ssl.in_retry_wrapper(|ssl| ssl.accept())); Ok(ssl) @@ -884,7 +884,7 @@ impl DirectStream { }) } - fn new_client(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { + fn connect(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { let ssl = try!(DirectStream::new_base(ssl, stream, sock)); let ret = ssl.ssl.connect(); if ret > 0 { @@ -894,7 +894,7 @@ impl DirectStream { } } - fn new_server(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { + fn accept(ssl: Ssl, stream: S, sock: c_int) -> Result, SslError> { let ssl = try!(DirectStream::new_base(ssl, stream, sock)); let ret = ssl.ssl.accept(); if ret > 0 { @@ -1017,19 +1017,19 @@ impl fmt::Debug for SslStream where S: fmt::Debug { #[cfg(unix)] impl SslStream { - pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn connect_direct(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; - let stream = try!(DirectStream::new_client(ssl, stream, fd)); + let stream = try!(DirectStream::connect(ssl, stream, fd)); Ok(SslStream { kind: StreamKind::Direct(stream) }) } - pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn accept_direct(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; - let stream = try!(DirectStream::new_server(ssl, stream, fd)); + let stream = try!(DirectStream::accept(ssl, stream, fd)); Ok(SslStream { kind: StreamKind::Direct(stream) }) @@ -1040,7 +1040,7 @@ impl SslStream { impl SslStream { pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; - let stream = try!(DirectStream::new_client(ssl, stream, fd)); + let stream = try!(DirectStream::connect(ssl, stream, fd)); Ok(SslStream { kind: StreamKind::Direct(stream) }) @@ -1048,7 +1048,7 @@ impl SslStream { pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; - let stream = try!(DirectStream::new_server(ssl, stream, fd)); + let stream = try!(DirectStream::accept(ssl, stream, fd)); Ok(SslStream { kind: StreamKind::Direct(stream) }) @@ -1056,33 +1056,38 @@ impl SslStream { } impl SslStream { - pub fn new_client(ssl: T, stream: S) -> Result, SslError> { - let stream = try!(IndirectStream::new_client(ssl, stream)); + pub fn connect(ssl: T, stream: S) -> Result, SslError> { + let stream = try!(IndirectStream::connect(ssl, stream)); Ok(SslStream { kind: StreamKind::Indirect(stream) }) } - pub fn new_server(ssl: T, stream: S) -> Result, SslError> { - let stream = try!(IndirectStream::new_server(ssl, stream)); + pub fn accept(ssl: T, stream: S) -> Result, SslError> { + let stream = try!(IndirectStream::accept(ssl, stream)); Ok(SslStream { kind: StreamKind::Indirect(stream) }) } + /// # Deprecated + pub fn new_server(ssl: Ssl, stream: S) -> Result, SslError> { + SslStream::accept(ssl, stream) + } + /// # Deprecated pub fn new_server_from(ssl: Ssl, stream: S) -> Result, SslError> { - SslStream::new_server(ssl, stream) + SslStream::accept(ssl, stream) } /// # Deprecated pub fn new_from(ssl: Ssl, stream: S) -> Result, SslError> { - SslStream::new_client(ssl, stream) + SslStream::connect(ssl, stream) } /// # Deprecated pub fn new(ctx: &SslContext, stream: S) -> Result, SslError> { - SslStream::new_client(ctx, stream) + SslStream::connect(ctx, stream) } /// # Deprecated diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index 2ba940ab..02f962d6 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -83,14 +83,14 @@ run_test!(new_ctx, |method, _| { }); run_test!(new_sslstream, |method, stream| { - SslStream::new_client(&SslContext::new(method).unwrap(), stream).unwrap(); + SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); }); run_test!(verify_untrusted, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, None); - match SslStream::new_client(&ctx, stream) { + match SslStream::connect(&ctx, stream) { Ok(_) => panic!("expected failure"), Err(err) => println!("error {:?}", err) } @@ -104,7 +104,7 @@ run_test!(verify_trusted, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::new_client(&ctx, stream) { + match SslStream::connect(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -118,7 +118,7 @@ run_test!(verify_untrusted_callback_override_ok, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - match SslStream::new_client(&ctx, stream) { + match SslStream::connect(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -132,7 +132,7 @@ run_test!(verify_untrusted_callback_override_bad, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new_client(&ctx, stream).is_err()); + assert!(SslStream::connect(&ctx, stream).is_err()); }); run_test!(verify_trusted_callback_override_ok, |method, stream| { @@ -147,7 +147,7 @@ run_test!(verify_trusted_callback_override_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::new_client(&ctx, stream) { + match SslStream::connect(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -165,7 +165,7 @@ run_test!(verify_trusted_callback_override_bad, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::new_client(&ctx, stream).is_err()); + assert!(SslStream::connect(&ctx, stream).is_err()); }); run_test!(verify_callback_load_certs, |method, stream| { @@ -177,7 +177,7 @@ run_test!(verify_callback_load_certs, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new_client(&ctx, stream).is_ok()); + assert!(SslStream::connect(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_ok, |method, stream| { @@ -193,7 +193,7 @@ run_test!(verify_trusted_get_error_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::new_client(&ctx, stream).is_ok()); + assert!(SslStream::connect(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_err, |method, stream| { @@ -205,7 +205,7 @@ run_test!(verify_trusted_get_error_err, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::new_client(&ctx, stream).is_err()); + assert!(SslStream::connect(&ctx, stream).is_err()); }); run_test!(verify_callback_data, |method, stream| { @@ -230,7 +230,7 @@ run_test!(verify_callback_data, |method, stream| { ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id); ctx.set_verify_depth(1); - match SslStream::new_client(&ctx, stream) { + match SslStream::connect(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -245,7 +245,7 @@ fn test_write_hits_stream() { let guard = thread::spawn(move || { let ctx = SslContext::new(Sslv23).unwrap(); let stream = TcpStream::connect(addr).unwrap(); - let mut stream = SslStream::new_client(&ctx, stream).unwrap(); + let mut stream = SslStream::connect(&ctx, stream).unwrap(); stream.write_all(b"hello").unwrap(); stream @@ -256,7 +256,7 @@ fn test_write_hits_stream() { ctx.set_certificate_file(&Path::new("test/cert.pem"), X509FileType::PEM).unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), X509FileType::PEM).unwrap(); let stream = listener.accept().unwrap().0; - let mut stream = SslStream::new_server(&ctx, stream).unwrap(); + let mut stream = SslStream::accept(&ctx, stream).unwrap(); let mut buf = [0; 5]; assert_eq!(5, stream.read(&mut buf).unwrap()); @@ -310,7 +310,7 @@ run_test!(clear_ctx_options, |method, _| { #[test] fn test_write() { let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -320,7 +320,7 @@ fn test_write() { #[test] fn test_write_direct() { let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new_client_direct(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect_direct(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -328,7 +328,7 @@ fn test_write_direct() { } run_test!(get_peer_certificate, |method, stream| { - let stream = SslStream::new_client(&SslContext::new(method).unwrap(), stream).unwrap(); + let stream = SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); let cert = stream.get_peer_certificate().unwrap(); let fingerprint = cert.fingerprint(SHA256).unwrap(); let node_hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; @@ -342,7 +342,7 @@ fn test_write_dtlsv1() { let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); let stream = sock.connect("127.0.0.1:15410").unwrap(); - let mut stream = SslStream::new_client(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -352,7 +352,7 @@ fn test_write_dtlsv1() { #[test] fn test_read() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -361,7 +361,7 @@ fn test_read() { #[test] fn test_read_direct() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new_client_direct(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect_direct(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -370,7 +370,7 @@ fn test_read_direct() { #[test] fn test_pending() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::new_client(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); @@ -403,7 +403,7 @@ fn test_connect_with_unilateral_npn() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new_client(&ctx, stream) { + let stream = match SslStream::connect(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -427,7 +427,7 @@ fn test_connect_with_npn_successful_multiple_matching() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new_client(&ctx, stream) { + let stream = match SslStream::connect(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -452,7 +452,7 @@ fn test_connect_with_npn_successful_single_match() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::new_client(&ctx, stream) { + let stream = match SslStream::connect(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -482,7 +482,7 @@ fn test_npn_server_advertise_multiple() { // Have the listener wait on the connection in a different thread. thread::spawn(move || { let (stream, _) = listener.accept().unwrap(); - let _ = SslStream::new_server(&listener_ctx, stream).unwrap(); + let _ = SslStream::accept(&listener_ctx, stream).unwrap(); }); let mut ctx = SslContext::new(Sslv23).unwrap(); @@ -494,7 +494,7 @@ fn test_npn_server_advertise_multiple() { } // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); - let stream = match SslStream::new_client(&ctx, stream) { + let stream = match SslStream::connect(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -531,7 +531,7 @@ fn test_read_dtlsv1() { let server = udp::next_server(); let stream = sock.connect(&server[..]).unwrap(); - let mut stream = SslStream::new_client(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); let mut buf = [0u8;100]; assert!(stream.read(&mut buf).is_ok()); } @@ -540,5 +540,5 @@ fn test_read_dtlsv1() { #[cfg(feature = "sslv2")] fn test_sslv2_connect_failure() { let tcp = TcpStream::connect("127.0.0.1:15420").unwrap(); - SslStream::new_client(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); + SslStream::connect(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); } -- cgit v1.2.3 From 797488dd091ce74e9b36c1c131406b4a9e9962ad Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 00:21:41 -0700 Subject: Add docs for accept and connect --- openssl/src/ssl/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 5d770c19..d0f1644b 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1017,6 +1017,11 @@ impl fmt::Debug for SslStream where S: fmt::Debug { #[cfg(unix)] impl SslStream { + /// Creates an SSL/TLS client operating over the provided stream. + /// + /// `connect_direct` creates a more efficient `SslStream` than `connect` + /// does, but requires that the stream implement `AsRawFd` on Unix and + /// `AsRawSocket` on Windows. pub fn connect_direct(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1026,6 +1031,11 @@ impl SslStream { }) } + /// Creates an SSL/TLS server operating over the provided stream. + /// + /// `accept_direct` creates a more efficient `SslStream` than `accept` + /// does, but requires that the stream implement `AsRawFd` on Unix and + /// `AsRawSocket` on Windows. pub fn accept_direct(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1038,6 +1048,11 @@ impl SslStream { #[cfg(windows)] impl SslStream { + /// Creates an SSL/TLS client operating over the provided stream. + /// + /// `connect_direct` creates a more efficient `SslStream` than `connect` + /// does, but requires that the stream implement `AsRawFd` on Unix and + /// `AsRawSocket` on Windows. pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::connect(ssl, stream, fd)); @@ -1046,6 +1061,11 @@ impl SslStream { }) } + /// Creates an SSL/TLS server operating over the provided stream. + /// + /// `accept_direct` creates a more efficient `SslStream` than `accept` + /// does, but requires that the stream implement `AsRawFd` on Unix and + /// `AsRawSocket` on Windows. pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::accept(ssl, stream, fd)); @@ -1056,6 +1076,7 @@ impl SslStream { } impl SslStream { + /// Creates an SSL/TLS client operating over the provided stream. pub fn connect(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::connect(ssl, stream)); Ok(SslStream { @@ -1063,6 +1084,7 @@ impl SslStream { }) } + /// Creates an SSL/TLS server operating over the provided stream. pub fn accept(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::accept(ssl, stream)); Ok(SslStream { -- cgit v1.2.3 From 3325e6b4748b76367c06987e1288579b485b3016 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 10:06:42 -0700 Subject: Make the direct constructors the defaults --- openssl/src/ssl/mod.rs | 20 +++++++++---------- openssl/src/ssl/tests.rs | 50 ++++++++++++++++++++++++------------------------ 2 files changed, 35 insertions(+), 35 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index d0f1644b..500e9aa4 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1022,7 +1022,7 @@ impl SslStream { /// `connect_direct` creates a more efficient `SslStream` than `connect` /// does, but requires that the stream implement `AsRawFd` on Unix and /// `AsRawSocket` on Windows. - pub fn connect_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn connect(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; let stream = try!(DirectStream::connect(ssl, stream, fd)); @@ -1036,7 +1036,7 @@ impl SslStream { /// `accept_direct` creates a more efficient `SslStream` than `accept` /// does, but requires that the stream implement `AsRawFd` on Unix and /// `AsRawSocket` on Windows. - pub fn accept_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn accept(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; let stream = try!(DirectStream::accept(ssl, stream, fd)); @@ -1053,7 +1053,7 @@ impl SslStream { /// `connect_direct` creates a more efficient `SslStream` than `connect` /// does, but requires that the stream implement `AsRawFd` on Unix and /// `AsRawSocket` on Windows. - pub fn new_client_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn connect(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::connect(ssl, stream, fd)); Ok(SslStream { @@ -1066,7 +1066,7 @@ impl SslStream { /// `accept_direct` creates a more efficient `SslStream` than `accept` /// does, but requires that the stream implement `AsRawFd` on Unix and /// `AsRawSocket` on Windows. - pub fn new_server_direct(ssl: T, stream: S) -> Result, SslError> { + pub fn accept(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::accept(ssl, stream, fd)); Ok(SslStream { @@ -1077,7 +1077,7 @@ impl SslStream { impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. - pub fn connect(ssl: T, stream: S) -> Result, SslError> { + pub fn connect_generic(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::connect(ssl, stream)); Ok(SslStream { kind: StreamKind::Indirect(stream) @@ -1085,7 +1085,7 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. - pub fn accept(ssl: T, stream: S) -> Result, SslError> { + pub fn accept_generic(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::accept(ssl, stream)); Ok(SslStream { kind: StreamKind::Indirect(stream) @@ -1094,22 +1094,22 @@ impl SslStream { /// # Deprecated pub fn new_server(ssl: Ssl, stream: S) -> Result, SslError> { - SslStream::accept(ssl, stream) + SslStream::accept_generic(ssl, stream) } /// # Deprecated pub fn new_server_from(ssl: Ssl, stream: S) -> Result, SslError> { - SslStream::accept(ssl, stream) + SslStream::accept_generic(ssl, stream) } /// # Deprecated pub fn new_from(ssl: Ssl, stream: S) -> Result, SslError> { - SslStream::connect(ssl, stream) + SslStream::connect_generic(ssl, stream) } /// # Deprecated pub fn new(ctx: &SslContext, stream: S) -> Result, SslError> { - SslStream::connect(ctx, stream) + SslStream::connect_generic(ctx, stream) } /// # Deprecated diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index 02f962d6..c4673edc 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -83,14 +83,14 @@ run_test!(new_ctx, |method, _| { }); run_test!(new_sslstream, |method, stream| { - SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); + SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap(); }); run_test!(verify_untrusted, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, None); - match SslStream::connect(&ctx, stream) { + match SslStream::connect_generic(&ctx, stream) { Ok(_) => panic!("expected failure"), Err(err) => println!("error {:?}", err) } @@ -104,7 +104,7 @@ run_test!(verify_trusted, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::connect(&ctx, stream) { + match SslStream::connect_generic(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -118,7 +118,7 @@ run_test!(verify_untrusted_callback_override_ok, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - match SslStream::connect(&ctx, stream) { + match SslStream::connect_generic(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -132,7 +132,7 @@ run_test!(verify_untrusted_callback_override_bad, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::connect(&ctx, stream).is_err()); + assert!(SslStream::connect_generic(&ctx, stream).is_err()); }); run_test!(verify_trusted_callback_override_ok, |method, stream| { @@ -147,7 +147,7 @@ run_test!(verify_trusted_callback_override_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - match SslStream::connect(&ctx, stream) { + match SslStream::connect_generic(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -165,7 +165,7 @@ run_test!(verify_trusted_callback_override_bad, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::connect(&ctx, stream).is_err()); + assert!(SslStream::connect_generic(&ctx, stream).is_err()); }); run_test!(verify_callback_load_certs, |method, stream| { @@ -177,7 +177,7 @@ run_test!(verify_callback_load_certs, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::connect(&ctx, stream).is_ok()); + assert!(SslStream::connect_generic(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_ok, |method, stream| { @@ -193,7 +193,7 @@ run_test!(verify_trusted_get_error_ok, |method, stream| { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - assert!(SslStream::connect(&ctx, stream).is_ok()); + assert!(SslStream::connect_generic(&ctx, stream).is_ok()); }); run_test!(verify_trusted_get_error_err, |method, stream| { @@ -205,7 +205,7 @@ run_test!(verify_trusted_get_error_err, |method, stream| { let mut ctx = SslContext::new(method).unwrap(); ctx.set_verify(SSL_VERIFY_PEER, Some(callback as VerifyCallback)); - assert!(SslStream::connect(&ctx, stream).is_err()); + assert!(SslStream::connect_generic(&ctx, stream).is_err()); }); run_test!(verify_callback_data, |method, stream| { @@ -230,7 +230,7 @@ run_test!(verify_callback_data, |method, stream| { ctx.set_verify_with_data(SSL_VERIFY_PEER, callback, node_id); ctx.set_verify_depth(1); - match SslStream::connect(&ctx, stream) { + match SslStream::connect_generic(&ctx, stream) { Ok(_) => (), Err(err) => panic!("Expected success, got {:?}", err) } @@ -245,7 +245,7 @@ fn test_write_hits_stream() { let guard = thread::spawn(move || { let ctx = SslContext::new(Sslv23).unwrap(); let stream = TcpStream::connect(addr).unwrap(); - let mut stream = SslStream::connect(&ctx, stream).unwrap(); + let mut stream = SslStream::connect_generic(&ctx, stream).unwrap(); stream.write_all(b"hello").unwrap(); stream @@ -310,7 +310,7 @@ run_test!(clear_ctx_options, |method, _| { #[test] fn test_write() { let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -320,7 +320,7 @@ fn test_write() { #[test] fn test_write_direct() { let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::connect_direct(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -328,7 +328,7 @@ fn test_write_direct() { } run_test!(get_peer_certificate, |method, stream| { - let stream = SslStream::connect(&SslContext::new(method).unwrap(), stream).unwrap(); + let stream = SslStream::connect_generic(&SslContext::new(method).unwrap(), stream).unwrap(); let cert = stream.get_peer_certificate().unwrap(); let fingerprint = cert.fingerprint(SHA256).unwrap(); let node_hash_str = "db400bb62f1b1f29c3b8f323b8f7d9dea724fdcd67104ef549c772ae3749655b"; @@ -342,7 +342,7 @@ fn test_write_dtlsv1() { let sock = UdpSocket::bind("127.0.0.1:0").unwrap(); let stream = sock.connect("127.0.0.1:15410").unwrap(); - let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); stream.write_all("hello".as_bytes()).unwrap(); stream.flush().unwrap(); stream.write_all(" there".as_bytes()).unwrap(); @@ -352,7 +352,7 @@ fn test_write_dtlsv1() { #[test] fn test_read() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -361,7 +361,7 @@ fn test_read() { #[test] fn test_read_direct() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::connect_direct(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); io::copy(&mut stream, &mut io::sink()).ok().expect("read error"); @@ -370,7 +370,7 @@ fn test_read_direct() { #[test] fn test_pending() { let tcp = TcpStream::connect("127.0.0.1:15418").unwrap(); - let mut stream = SslStream::connect(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); + let mut stream = SslStream::connect_generic(&SslContext::new(Sslv23).unwrap(), tcp).unwrap(); stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); @@ -403,7 +403,7 @@ fn test_connect_with_unilateral_npn() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::connect(&ctx, stream) { + let stream = match SslStream::connect_generic(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -427,7 +427,7 @@ fn test_connect_with_npn_successful_multiple_matching() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::connect(&ctx, stream) { + let stream = match SslStream::connect_generic(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -452,7 +452,7 @@ fn test_connect_with_npn_successful_single_match() { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err) } - let stream = match SslStream::connect(&ctx, stream) { + let stream = match SslStream::connect_generic(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -494,7 +494,7 @@ fn test_npn_server_advertise_multiple() { } // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); - let stream = match SslStream::connect(&ctx, stream) { + let stream = match SslStream::connect_generic(&ctx, stream) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err) }; @@ -531,7 +531,7 @@ fn test_read_dtlsv1() { let server = udp::next_server(); let stream = sock.connect(&server[..]).unwrap(); - let mut stream = SslStream::connect(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); + let mut stream = SslStream::connect_generic(&SslContext::new(Dtlsv1).unwrap(), stream).unwrap(); let mut buf = [0u8;100]; assert!(stream.read(&mut buf).is_ok()); } @@ -540,5 +540,5 @@ fn test_read_dtlsv1() { #[cfg(feature = "sslv2")] fn test_sslv2_connect_failure() { let tcp = TcpStream::connect("127.0.0.1:15420").unwrap(); - SslStream::connect(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); + SslStream::connect_generic(&SslContext::new(Sslv2).unwrap(), tcp).err().unwrap(); } -- cgit v1.2.3 From b1dd46ae6a9f873e809ddc5aea8ea01ab7c39349 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 10:15:33 -0700 Subject: Docs --- openssl/src/ssl/mod.rs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 500e9aa4..0bbba4c8 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1016,12 +1016,8 @@ impl fmt::Debug for SslStream where S: fmt::Debug { } #[cfg(unix)] -impl SslStream { +impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. - /// - /// `connect_direct` creates a more efficient `SslStream` than `connect` - /// does, but requires that the stream implement `AsRawFd` on Unix and - /// `AsRawSocket` on Windows. pub fn connect(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1032,10 +1028,6 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. - /// - /// `accept_direct` creates a more efficient `SslStream` than `accept` - /// does, but requires that the stream implement `AsRawFd` on Unix and - /// `AsRawSocket` on Windows. pub fn accept(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1047,12 +1039,8 @@ impl SslStream { } #[cfg(windows)] -impl SslStream { +impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. - /// - /// `connect_direct` creates a more efficient `SslStream` than `connect` - /// does, but requires that the stream implement `AsRawFd` on Unix and - /// `AsRawSocket` on Windows. pub fn connect(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::connect(ssl, stream, fd)); @@ -1062,10 +1050,6 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. - /// - /// `accept_direct` creates a more efficient `SslStream` than `accept` - /// does, but requires that the stream implement `AsRawFd` on Unix and - /// `AsRawSocket` on Windows. pub fn accept(ssl: T, stream: S) -> Result, SslError> { let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::accept(ssl, stream, fd)); @@ -1077,6 +1061,10 @@ impl SslStream { impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. + /// + /// `SslStream`s returned by this method will be less efficient than ones + /// returned by `connect`, so this method should only be used for streams + /// that do not implement `AsRawFd` and `AsRawSocket`. pub fn connect_generic(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::connect(ssl, stream)); Ok(SslStream { @@ -1085,6 +1073,10 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. + /// + /// `SslStream`s returned by this method will be less efficient than ones + /// returned by `accept`, so this method should only be used for streams + /// that do not implement `AsRawFd` and `AsRawSocket`. pub fn accept_generic(ssl: T, stream: S) -> Result, SslError> { let stream = try!(IndirectStream::accept(ssl, stream)); Ok(SslStream { -- cgit v1.2.3 From 94b0f26c10e6a5862264d578e7cd47c05d252e3d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 10:21:06 -0700 Subject: Fix windows build --- openssl/src/ssl/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0bbba4c8..6d4b1f81 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1042,6 +1042,7 @@ impl SslStream { impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. pub fn connect(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::connect(ssl, stream, fd)); Ok(SslStream { @@ -1051,6 +1052,7 @@ impl SslStream { /// Creates an SSL/TLS server operating over the provided stream. pub fn accept(ssl: T, stream: S) -> Result, SslError> { + let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_socket() as c_int; let stream = try!(DirectStream::accept(ssl, stream, fd)); Ok(SslStream { -- cgit v1.2.3 From 8fdd0e2ec1e0457215cb0550714e0e6024ac6192 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Jun 2015 11:30:49 -0700 Subject: More docs --- openssl/src/ssl/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6d4b1f81..2163891d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1018,6 +1018,10 @@ impl fmt::Debug for SslStream where S: fmt::Debug { #[cfg(unix)] impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. + /// + /// Streams passed to this method must implement `AsRawFd` on Unixy + /// platforms and `AsRawSocket` on Windows. Use `connect_generic` for + /// streams that do not. pub fn connect(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1028,6 +1032,10 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. + /// + /// Streams passed to this method must implement `AsRawFd` on Unixy + /// platforms and `AsRawSocket` on Windows. Use `accept_generic` for + /// streams that do not. pub fn accept(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_fd() as c_int; @@ -1041,6 +1049,10 @@ impl SslStream { #[cfg(windows)] impl SslStream { /// Creates an SSL/TLS client operating over the provided stream. + /// + /// Streams passed to this method must implement `AsRawFd` on Unixy + /// platforms and `AsRawSocket` on Windows. Use `connect_generic` for + /// streams that do not. pub fn connect(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_socket() as c_int; @@ -1051,6 +1063,10 @@ impl SslStream { } /// Creates an SSL/TLS server operating over the provided stream. + /// + /// Streams passed to this method must implement `AsRawFd` on Unixy + /// platforms and `AsRawSocket` on Windows. Use `accept_generic` for + /// streams that do not. pub fn accept(ssl: T, stream: S) -> Result, SslError> { let ssl = try!(ssl.into_ssl()); let fd = stream.as_raw_socket() as c_int; -- cgit v1.2.3 From a94ea78d8a4b8beafa539ab817a1f110c8c2ed3e Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 24 Jun 2015 15:15:17 -0400 Subject: ssl: use a common helper to generate new ex data indexes, switch NPN to a lazyref Rather than having the verification data idx generation and NPN use there own (similar) impls to generate indexes with destructors, unify them. Make NPNs use of indexes more idomatic by storing the index in a lazyref rather than having a function with static data members. --- openssl/src/ssl/mod.rs | 50 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 33 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2163891d..1123b3d0 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -170,49 +170,33 @@ lazy_static! { // Registers a destructor for the data which will be called // when context is freed fn get_verify_data_idx() -> c_int { - extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void, - _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int, - _argl: c_long, _argp: *mut c_void) { - if ptr != 0 as *mut _ { - let _: Box = unsafe { mem::transmute(ptr) }; - } - } - *INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| { - unsafe { - let f: ffi::CRYPTO_EX_free = free_data_box::; - let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, Some(f)); - assert!(idx >= 0); - idx - } + get_new_idx::() }) } -/// Creates a static index for the list of NPN protocols. -/// Registers a destructor for the data which will be called -/// when the context is freed. #[cfg(feature = "npn")] -fn get_npn_protos_idx() -> c_int { - static mut NPN_PROTOS_IDX: c_int = -1; - static mut INIT: Once = ONCE_INIT; +lazy_static! { + static ref NPN_PROTOS_IDX: c_int = get_new_idx::>(); +} - extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void, +/// Determine a new index to use for SSL CTX ex data. +/// Registers a destruct for the data which will be called by openssl when the context is freed. +fn get_new_idx() -> c_int { + extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void, _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int, _argl: c_long, _argp: *mut c_void) { if !ptr.is_null() { - let _: Box> = unsafe { mem::transmute(ptr) }; + let _: Box = unsafe { mem::transmute(ptr) }; } } unsafe { - INIT.call_once(|| { - let f: ffi::CRYPTO_EX_free = free_data_box; - let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, - None, Some(f)); - assert!(idx >= 0); - NPN_PROTOS_IDX = idx; - }); - NPN_PROTOS_IDX + let f: ffi::CRYPTO_EX_free = free_data_box::; + let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, + None, Some(f)); + assert!(idx >= 0); + idx } } @@ -279,7 +263,7 @@ extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, // First, get the list of protocols (that the client should support) saved in the context // extra data. let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx()); + let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, *NPN_PROTOS_IDX); let protocols: &Vec = mem::transmute(protocols); // Prepare the client list parameters to be passed to the OpenSSL function... let client = protocols.as_ptr(); @@ -306,7 +290,7 @@ extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, unsafe { // First, get the list of (supported) protocols saved in the context extra data. let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_npn_protos_idx()); + let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, *NPN_PROTOS_IDX); if protocols.is_null() { *out = b"".as_ptr(); *outlen = 0; @@ -543,7 +527,7 @@ impl SslContext { unsafe { // Attach the protocol list to the OpenSSL context structure, // so that we can refer to it within the callback. - ffi::SSL_CTX_set_ex_data(self.ctx, get_npn_protos_idx(), + ffi::SSL_CTX_set_ex_data(self.ctx, *NPN_PROTOS_IDX, mem::transmute(protocols)); // Now register the callback that performs the default protocol // matching based on the client-supported list of protocols that -- cgit v1.2.3 From 539ae2eebf723e935fee2e342f0ce4799d2733fc Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 24 Jun 2015 15:18:19 -0400 Subject: ssl/NPN: factor out encoding of the protocol list The intention is to allow the encoding to be reused by the ALPN support code. --- openssl/src/ssl/mod.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 1123b3d0..67ecd302 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -306,6 +306,24 @@ extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, ffi::SSL_TLSEXT_ERR_OK } +/// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte +/// containing the length followed by the string. +#[cfg(feature = "npn")] +fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec +{ + let mut enc = Vec::new(); + for string in strings { + let len = string.len() as u8; + if len as usize != string.len() { + // If the item does not fit, discard it + continue; + } + enc.push(len); + enc.extend(string[..len as usize].to_vec()); + } + enc +} + /// The signature of functions that can be used to manually verify certificates pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool; @@ -515,14 +533,7 @@ impl SslContext { pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) { // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL // APIs -- a list of length-prefixed strings. - let mut npn_protocols = Vec::new(); - for protocol in protocols { - let len = protocol.len() as u8; - npn_protocols.push(len); - // If the length is greater than the max `u8`, this truncates the protocol name. - npn_protocols.extend(protocol[..len as usize].to_vec()); - } - let protocols: Box> = Box::new(npn_protocols); + let protocols: Box> = Box::new(ssl_encode_byte_strings(protocols)); unsafe { // Attach the protocol list to the OpenSSL context structure, -- cgit v1.2.3 From 01e01e3747dd0dbd46486c4f9406c29488a28c19 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Wed, 24 Jun 2015 17:17:43 -0400 Subject: ssl: support ALPN Heavily based on the existing NPN wrapping code. Naming of public functions is identical to the NPN ones with `s/npn/alpn/` applied to prevent devs from needing to remember 2 names (and to let my copy the npn tests and perform the subistution to generate the apln tests). It might make sense to (at some point) use macros or a trait to cut down the duplication. --- openssl/src/ssl/mod.rs | 115 ++++++++++++++++++++++++++++++++++++++++------- openssl/src/ssl/tests.rs | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+), 15 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 67ecd302..d67dc1a2 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -13,9 +13,9 @@ use std::sync::{Once, ONCE_INIT, Arc, Mutex}; use std::ops::{Deref, DerefMut}; use std::cmp; use std::any::Any; -#[cfg(feature = "npn")] +#[cfg(any(feature = "npn", feature = "alpn"))] use libc::{c_uchar, c_uint}; -#[cfg(feature = "npn")] +#[cfg(any(feature = "npn", feature = "alpn"))] use std::slice; use bio::{MemBio}; @@ -179,6 +179,10 @@ fn get_verify_data_idx() -> c_int { lazy_static! { static ref NPN_PROTOS_IDX: c_int = get_new_idx::>(); } +#[cfg(feature = "alpn")] +lazy_static! { + static ref ALPN_PROTOS_IDX: c_int = get_new_idx::>(); +} /// Determine a new index to use for SSL CTX ex data. /// Registers a destruct for the data which will be called by openssl when the context is freed. @@ -248,6 +252,26 @@ extern fn raw_verify_with_data(preverify_ok: c_int, } } +#[cfg(any(feature = "npn", feature = "alpn"))] +unsafe fn select_proto_using(ssl: *mut ffi::SSL, + out: *mut *mut c_uchar, outlen: *mut c_uchar, + inbuf: *const c_uchar, inlen: c_uint, + ex_data: c_int) -> c_int { + + // First, get the list of protocols (that the client should support) saved in the context + // extra data. + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, ex_data); + let protocols: &Vec = mem::transmute(protocols); + // Prepare the client list parameters to be passed to the OpenSSL function... + let client = protocols.as_ptr(); + let client_len = protocols.len() as c_uint; + // Finally, let OpenSSL find a protocol to be used, by matching the given server and + // client lists. + ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len); + ffi::SSL_TLSEXT_ERR_OK +} + /// The function is given as the callback to `SSL_CTX_set_next_proto_select_cb`. /// /// It chooses the protocol that the client wishes to use, out of the given list of protocols @@ -260,20 +284,18 @@ extern fn raw_next_proto_select_cb(ssl: *mut ffi::SSL, inbuf: *const c_uchar, inlen: c_uint, _arg: *mut c_void) -> c_int { unsafe { - // First, get the list of protocols (that the client should support) saved in the context - // extra data. - let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let protocols = ffi::SSL_CTX_get_ex_data(ssl_ctx, *NPN_PROTOS_IDX); - let protocols: &Vec = mem::transmute(protocols); - // Prepare the client list parameters to be passed to the OpenSSL function... - let client = protocols.as_ptr(); - let client_len = protocols.len() as c_uint; - // Finally, let OpenSSL find a protocol to be used, by matching the given server and - // client lists. - ffi::SSL_select_next_proto(out, outlen, inbuf, inlen, client, client_len); + select_proto_using(ssl, out, outlen, inbuf, inlen, *NPN_PROTOS_IDX) } +} - ffi::SSL_TLSEXT_ERR_OK +#[cfg(feature = "alpn")] +extern fn raw_alpn_select_cb(ssl: *mut ffi::SSL, + out: *mut *mut c_uchar, outlen: *mut c_uchar, + inbuf: *const c_uchar, inlen: c_uint, + _arg: *mut c_void) -> c_int { + unsafe { + select_proto_using(ssl, out, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) + } } /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. @@ -308,7 +330,7 @@ extern fn raw_next_protos_advertise_cb(ssl: *mut ffi::SSL, /// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte /// containing the length followed by the string. -#[cfg(feature = "npn")] +#[cfg(any(feature = "npn", feature = "alpn"))] fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec { let mut enc = Vec::new(); @@ -549,6 +571,35 @@ impl SslContext { ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx, raw_next_protos_advertise_cb, ptr::null_mut()); } } + + /// Set the protocols to be used during ALPN (application layer protocol negotiation). + /// If this is a server, these are the protocols we report to the client. + /// If this is a client, these are the protocols we try to match with those reported by the + /// server. + /// + /// Note that ordering of the protocols controls the priority with which they are chosen. + /// + /// This method needs the `alpn` feature. + #[cfg(feature = "alpn")] + pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) { + let protocols: Box> = Box::new(ssl_encode_byte_strings(protocols)); + unsafe { + // Set the context's internal protocol list for use if we are a server + ffi::SSL_CTX_set_alpn_protos(self.ctx, protocols.as_ptr(), protocols.len() as c_uint); + + // Rather than use the argument to the callback to contain our data, store it in the + // ssl ctx's ex_data so that we can configure a function to free it later. In the + // future, it might make sense to pull this into our internal struct Ssl instead of + // leaning on openssl and using function pointers. + ffi::SSL_CTX_set_ex_data(self.ctx, *ALPN_PROTOS_IDX, + mem::transmute(protocols)); + + // Now register the callback that performs the default protocol + // matching based on the client-supported list of protocols that + // has been saved. + ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut()); + } + } } #[allow(dead_code)] @@ -690,6 +741,29 @@ impl Ssl { } } + /// Returns the protocol selected by performing ALPN, if any. + /// + /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client + /// to interpret it. + /// + /// This method needs the `alpn` feature. + #[cfg(feature = "alpn")] + pub fn get_selected_alpn_protocol(&self) -> Option<&[u8]> { + unsafe { + let mut data: *const c_uchar = ptr::null(); + let mut len: c_uint = 0; + // Get the negotiated protocol from the SSL instance. + // `data` will point at a `c_uchar` array; `len` will contain the length of this array. + ffi::SSL_get0_alpn_selected(self.ssl, &mut data, &mut len); + + if data.is_null() { + None + } else { + Some(slice::from_raw_parts(data, len as usize)) + } + } + } + /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). pub fn pending(&self) -> usize { unsafe { @@ -1171,6 +1245,17 @@ impl SslStream { self.kind.ssl().get_selected_npn_protocol() } + /// Returns the protocol selected by performing ALPN, if any. + /// + /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client + /// to interpret it. + /// + /// This method needs the `alpn` feature. + #[cfg(feature = "alpn")] + pub fn get_selected_alpn_protocol(&self) -> Option<&[u8]> { + self.ssl.get_selected_alpn_protocol() + } + /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). pub fn pending(&self) -> usize { self.kind.ssl().pending() diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index c4673edc..b44b9c35 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -390,6 +390,28 @@ fn test_pending() { assert_eq!(pending, len); } +/// Tests that connecting with the client using NPN, but the server not does not +/// break the existing connection behavior. +#[test] +#[cfg(feature = "alpn")] +fn test_connect_with_unilateral_alpn() { + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); + match ctx.set_CA_file(&Path::new("test/cert.pem")) { + Ok(_) => {} + Err(err) => panic!("Unexpected error {:?}", err) + } + let stream = match SslStream::new(&ctx, stream) { + Ok(stream) => stream, + Err(err) => panic!("Expected success, got {:?}", err) + }; + // Since the socket to which we connected is not configured to use NPN, + // there should be no selected protocol... + assert!(stream.get_selected_alpn_protocol().is_none()); +} + /// Tests that connecting with the client using NPN, but the server not does not /// break the existing connection behavior. #[test] @@ -412,6 +434,30 @@ fn test_connect_with_unilateral_npn() { assert!(stream.get_selected_npn_protocol().is_none()); } +/// Tests that when both the client as well as the server use ALPN and their +/// lists of supported protocols have an overlap, the correct protocol is chosen. +#[test] +#[cfg(feature = "alpn")] +fn test_connect_with_alpn_successful_multiple_matching() { + // A different port than the other tests: an `openssl` process that has + // NPN enabled. + let stream = TcpStream::connect("127.0.0.1:15419").unwrap(); + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + ctx.set_alpn_protocols(&[b"spdy/3.1", b"http/1.1"]); + match ctx.set_CA_file(&Path::new("test/cert.pem")) { + Ok(_) => {} + Err(err) => panic!("Unexpected error {:?}", err) + } + let stream = match SslStream::new(&ctx, stream) { + Ok(stream) => stream, + Err(err) => panic!("Expected success, got {:?}", err) + }; + // The server prefers "http/1.1", so that is chosen, even though the client + // would prefer "spdy/3.1" + assert_eq!(b"http/1.1", stream.get_selected_alpn_protocol().unwrap()); +} + /// Tests that when both the client as well as the server use NPN and their /// lists of supported protocols have an overlap, the correct protocol is chosen. #[test] @@ -436,6 +482,32 @@ fn test_connect_with_npn_successful_multiple_matching() { assert_eq!(b"http/1.1", stream.get_selected_npn_protocol().unwrap()); } +/// Tests that when both the client as well as the server use ALPN and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +#[cfg(feature = "alpn")] +fn test_connect_with_alpn_successful_single_match() { + // A different port than the other tests: an `openssl` process that has + // ALPN enabled. + let stream = TcpStream::connect("127.0.0.1:15419").unwrap(); + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + ctx.set_alpn_protocols(&[b"spdy/3.1"]); + match ctx.set_CA_file(&Path::new("test/cert.pem")) { + Ok(_) => {} + Err(err) => panic!("Unexpected error {:?}", err) + } + let stream = match SslStream::new(&ctx, stream) { + Ok(stream) => stream, + Err(err) => panic!("Expected success, got {:?}", err) + }; + // The client now only supports one of the server's protocols, so that one + // is used. + assert_eq!(b"spdy/3.1", stream.get_selected_alpn_protocol().unwrap()); +} + + /// Tests that when both the client as well as the server use NPN and their /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. @@ -502,6 +574,47 @@ fn test_npn_server_advertise_multiple() { assert_eq!(b"spdy/3.1", stream.get_selected_npn_protocol().unwrap()); } +/// Tests that when the `SslStream` is created as a server stream, the protocols +/// are correctly advertised to the client. +#[test] +#[cfg(feature = "alpn")] +fn test_alpn_server_advertise_multiple() { + let localhost = "127.0.0.1:15420"; + let listener = TcpListener::bind(localhost).unwrap(); + // We create a different context instance for the server... + let listener_ctx = { + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + ctx.set_alpn_protocols(&[b"http/1.1", b"spdy/3.1"]); + assert!(ctx.set_certificate_file( + &Path::new("test/cert.pem"), X509FileType::PEM).is_ok()); + ctx.set_private_key_file( + &Path::new("test/key.pem"), X509FileType::PEM).unwrap(); + ctx + }; + // Have the listener wait on the connection in a different thread. + thread::spawn(move || { + let (stream, _) = listener.accept().unwrap(); + let _ = SslStream::new_server(&listener_ctx, stream).unwrap(); + }); + + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_verify(SSL_VERIFY_PEER, None); + ctx.set_alpn_protocols(&[b"spdy/3.1"]); + match ctx.set_CA_file(&Path::new("test/cert.pem")) { + Ok(_) => {} + Err(err) => panic!("Unexpected error {:?}", err) + } + // Now connect to the socket and make sure the protocol negotiation works... + let stream = TcpStream::connect(localhost).unwrap(); + let stream = match SslStream::new(&ctx, stream) { + Ok(stream) => stream, + Err(err) => panic!("Expected success, got {:?}", err) + }; + // SPDY is selected since that's the only thing the client supports. + assert_eq!(b"spdy/3.1", stream.get_selected_alpn_protocol().unwrap()); +} + #[cfg(feature="dtlsv1")] #[cfg(test)] mod dtlsv1 { -- cgit v1.2.3 From dfacea1df693e9c3ec3eadafa9c96a0e1ddd3839 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 29 Jun 2015 21:58:54 -0700 Subject: Fix build with alpn feature --- openssl/src/ssl/mod.rs | 2 +- openssl/src/ssl/tests.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index d67dc1a2..cf885201 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1253,7 +1253,7 @@ impl SslStream { /// This method needs the `alpn` feature. #[cfg(feature = "alpn")] pub fn get_selected_alpn_protocol(&self) -> Option<&[u8]> { - self.ssl.get_selected_alpn_protocol() + self.kind.ssl().get_selected_alpn_protocol() } /// pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index b44b9c35..8401836d 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -579,7 +579,7 @@ fn test_npn_server_advertise_multiple() { #[test] #[cfg(feature = "alpn")] fn test_alpn_server_advertise_multiple() { - let localhost = "127.0.0.1:15420"; + let localhost = "127.0.0.1:15421"; let listener = TcpListener::bind(localhost).unwrap(); // We create a different context instance for the server... let listener_ctx = { @@ -595,7 +595,7 @@ fn test_alpn_server_advertise_multiple() { // Have the listener wait on the connection in a different thread. thread::spawn(move || { let (stream, _) = listener.accept().unwrap(); - let _ = SslStream::new_server(&listener_ctx, stream).unwrap(); + let _ = SslStream::accept(&listener_ctx, stream).unwrap(); }); let mut ctx = SslContext::new(Sslv23).unwrap(); -- cgit v1.2.3 From 61e61bbae4a7d25291c48c1bd1d7504310a96c16 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 29 Jun 2015 22:04:31 -0700 Subject: Fix backcompat method --- openssl/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index cf885201..88ba9af4 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1172,7 +1172,7 @@ impl SslStream { } /// # Deprecated - pub fn new_server(ssl: Ssl, stream: S) -> Result, SslError> { + pub fn new_server(ssl: &SslContext, stream: S) -> Result, SslError> { SslStream::accept_generic(ssl, stream) } -- cgit v1.2.3 From 1d214bce61e461f7aa57808e9c650eee27971ddb Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 30 Jun 2015 18:45:17 -0700 Subject: Fix NID definitions to match OpenSSL. The previous numbers were introduced incorrectly in #213 --- openssl/src/nid.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'openssl/src') diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 08424ae8..c5b9e277 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -37,6 +37,7 @@ pub enum Nid { DES_EDE, DES_EDE3, IDEA_CBC, + IDEA_CFB, IDEA_ECB, RC2_CBC, RC2_ECB, @@ -55,6 +56,7 @@ pub enum Nid { MessageDigest, SigningTime, CounterSignature, + ChallengePassword, UnstructuredAddress, ExtendedCertificateAttributes, Netscape, @@ -93,6 +95,7 @@ pub enum Nid { AuthorityKeyIdentifier, BF_CBC, BF_ECB, + BF_CFB, BF_OFB, MDC2, RSA_MDC2, @@ -117,7 +120,8 @@ pub enum Nid { RSA_SHA1_2, DSA, RIPEMD160, - RSA_RIPEMD160, + /* 118 missing */ + RSA_RIPEMD160=119, RC5_CBC, RC5_ECB, RC5_CFB, @@ -142,7 +146,6 @@ pub enum Nid { CRLReason, InvalidityDate, SXNetID, - Pkcs12, PBE_SHA1_RC4_128, PBE_SHA1_RC4_40, PBE_SHA1_3DES, -- cgit v1.2.3 From 9074af5bdd0d88521979174e287748b0422c12e2 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Tue, 30 Jun 2015 23:51:54 -0700 Subject: Add a test that checks whether 3 known subject attributes can be retrieved by NID --- openssl/src/x509/tests.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'openssl/src') diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 6d95b966..4e1c4f15 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -69,3 +69,32 @@ fn test_subject_read_cn() { assert_eq!(&cn as &str, "test_cert") } + +#[test] +fn test_nid_values() { + let cert_path = Path::new("test/nid_test_cert.pem"); + let mut file = File::open(&cert_path) + .ok() + .expect("Failed to open `test/nid_test_cert.pem`"); + + let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); + let subject = cert.subject_name(); + + let cn = match subject.text_by_nid(Nid::CN) { + Some(x) => x, + None => panic!("Failed to read CN from cert") + }; + assert_eq!(&cn as &str, "example.com"); + + let email = match subject.text_by_nid(Nid::Email) { + Some(x) => x, + None => panic!("Failed to read subject email address from cert") + }; + assert_eq!(&email as &str, "test@example.com"); + + let friendly = match subject.text_by_nid(Nid::FriendlyName) { + Some(x) => x, + None => panic!("Failed to read subject friendly name from cert") + }; + assert_eq!(&friendly as &str, "Example"); +} -- cgit v1.2.3 From cc497b47686d1dd03f96e2c2a99f214b9bc97eb9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 6 Jul 2015 11:09:03 -0700 Subject: Release v0.6.4 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 06c514a1..62d18dce 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.3")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.6.4")] #[macro_use] extern crate bitflags; -- cgit v1.2.3