Loading openssl-sys/src/lib.rs +12 −0 Original line number Diff line number Diff line Loading @@ -318,6 +318,18 @@ pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long name as *mut c_void) } pub fn ERR_GET_LIB(l: c_ulong) -> c_int { ((l >> 24) & 0x0FF) as c_int } pub fn ERR_GET_FUNC(l: c_ulong) -> c_int { ((l >> 12) & 0xFFF) as c_int } pub fn ERR_GET_REASON(l: c_ulong) -> c_int { (l & 0xFFF) as c_int } extern { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; Loading openssl/src/error.rs +54 −42 Original line number Diff line number Diff line Loading @@ -76,72 +76,84 @@ impl Error { } /// Returns the raw OpenSSL error code for this error. pub fn error_code(&self) -> c_ulong { pub fn code(&self) -> c_ulong { self.0 } /// Returns the name of the library reporting the error. pub fn library(&self) -> &'static str { get_lib(self.0) /// Returns the name of the library reporting the error, if available. pub fn library(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_lib_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the name of the function reporting the error. pub fn function(&self) -> &'static str { get_func(self.0) pub fn function(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_func_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the reason for the error. pub fn reason(&self) -> &'static str { get_reason(self.0) pub fn reason(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_reason_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } impl fmt::Debug for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Error") .field("library", &self.library()) .field("function", &self.function()) .field("reason", &self.reason()) .finish() } } impl fmt::Display for Error { impl fmt::Debug for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(&self.reason()) let mut builder = fmt.debug_struct("Error"); builder.field("code", &self.code()); if let Some(library) = self.library() { builder.field("library", &library); } if let Some(function) = self.function() { builder.field("function", &function); } impl error::Error for Error { fn description(&self) -> &str { "An OpenSSL error" if let Some(reason) = self.reason() { builder.field("reason", &reason); } builder.finish() } } fn get_lib(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_lib_error_string(err); assert!(!cstr.is_null(), "bad lib: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "error:{:08X}", self.0)); match self.library() { Some(l) => try!(write!(fmt, ":{}", l)), None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))), } match self.function() { Some(f) => try!(write!(fmt, ":{}", f)), None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))), } match self.reason() { Some(r) => write!(fmt, ":{}", r), None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)), } fn get_func(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_func_error_string(err); assert!(!cstr.is_null(), "bad func: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } } fn get_reason(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_reason_error_string(err); assert!(!cstr.is_null(), "bad reason: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() impl error::Error for Error { fn description(&self) -> &str { "An OpenSSL error" } } openssl/src/ssl/tests/mod.rs +34 −12 Original line number Diff line number Diff line Loading @@ -726,10 +726,7 @@ fn test_alpn_server_advertise_multiple() { /// Test that Servers supporting ALPN don't report a protocol when none of their protocols match /// the client's reported protocol. #[test] #[cfg(feature = "openssl-102")] // TODO: not sure why this test is failing on OpenSSL 1.1.0, may be related to // something about SSLv3 though? #[cfg_attr(ossl110, ignore)] #[cfg(all(feature = "openssl-102", ossl102))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); Loading @@ -753,21 +750,46 @@ fn test_alpn_server_select_none() { let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/2"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err), } ctx.set_CA_file(&Path::new("test/root-ca.pem")).unwrap(); // 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) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err), }; let stream = SslStream::connect(&ctx, stream).unwrap(); // Since the protocols from the server and client don't overlap at all, no protocol is selected assert_eq!(None, stream.ssl().selected_alpn_protocol()); } // In 1.1.0, ALPN negotiation failure is a fatal error #[test] #[cfg(all(feature = "openssl-102", ossl110))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); // We create a different context instance for the server... let listener_ctx = { let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); 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(); assert!(SslStream::accept(&listener_ctx, stream).is_err()); }); let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/2"]); ctx.set_CA_file(&Path::new("test/root-ca.pem")).unwrap(); // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); assert!(SslStream::connect(&ctx, stream).is_err()); } #[cfg(test)] mod dtlsv1 { Loading Loading
openssl-sys/src/lib.rs +12 −0 Original line number Diff line number Diff line Loading @@ -318,6 +318,18 @@ pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long name as *mut c_void) } pub fn ERR_GET_LIB(l: c_ulong) -> c_int { ((l >> 24) & 0x0FF) as c_int } pub fn ERR_GET_FUNC(l: c_ulong) -> c_int { ((l >> 12) & 0xFFF) as c_int } pub fn ERR_GET_REASON(l: c_ulong) -> c_int { (l & 0xFFF) as c_int } extern { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; Loading
openssl/src/error.rs +54 −42 Original line number Diff line number Diff line Loading @@ -76,72 +76,84 @@ impl Error { } /// Returns the raw OpenSSL error code for this error. pub fn error_code(&self) -> c_ulong { pub fn code(&self) -> c_ulong { self.0 } /// Returns the name of the library reporting the error. pub fn library(&self) -> &'static str { get_lib(self.0) /// Returns the name of the library reporting the error, if available. pub fn library(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_lib_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the name of the function reporting the error. pub fn function(&self) -> &'static str { get_func(self.0) pub fn function(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_func_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the reason for the error. pub fn reason(&self) -> &'static str { get_reason(self.0) pub fn reason(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_reason_error_string(self.0); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } impl fmt::Debug for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Error") .field("library", &self.library()) .field("function", &self.function()) .field("reason", &self.reason()) .finish() } } impl fmt::Display for Error { impl fmt::Debug for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(&self.reason()) let mut builder = fmt.debug_struct("Error"); builder.field("code", &self.code()); if let Some(library) = self.library() { builder.field("library", &library); } if let Some(function) = self.function() { builder.field("function", &function); } impl error::Error for Error { fn description(&self) -> &str { "An OpenSSL error" if let Some(reason) = self.reason() { builder.field("reason", &reason); } builder.finish() } } fn get_lib(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_lib_error_string(err); assert!(!cstr.is_null(), "bad lib: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "error:{:08X}", self.0)); match self.library() { Some(l) => try!(write!(fmt, ":{}", l)), None => try!(write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.0))), } match self.function() { Some(f) => try!(write!(fmt, ":{}", f)), None => try!(write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.0))), } match self.reason() { Some(r) => write!(fmt, ":{}", r), None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.0)), } fn get_func(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_func_error_string(err); assert!(!cstr.is_null(), "bad func: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } } fn get_reason(err: c_ulong) -> &'static str { unsafe { let cstr = ffi::ERR_reason_error_string(err); assert!(!cstr.is_null(), "bad reason: {}", err); let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); str::from_utf8(bytes).unwrap() impl error::Error for Error { fn description(&self) -> &str { "An OpenSSL error" } }
openssl/src/ssl/tests/mod.rs +34 −12 Original line number Diff line number Diff line Loading @@ -726,10 +726,7 @@ fn test_alpn_server_advertise_multiple() { /// Test that Servers supporting ALPN don't report a protocol when none of their protocols match /// the client's reported protocol. #[test] #[cfg(feature = "openssl-102")] // TODO: not sure why this test is failing on OpenSSL 1.1.0, may be related to // something about SSLv3 though? #[cfg_attr(ossl110, ignore)] #[cfg(all(feature = "openssl-102", ossl102))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); Loading @@ -753,21 +750,46 @@ fn test_alpn_server_select_none() { let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/2"]); match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { Ok(_) => {} Err(err) => panic!("Unexpected error {:?}", err), } ctx.set_CA_file(&Path::new("test/root-ca.pem")).unwrap(); // 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) { Ok(stream) => stream, Err(err) => panic!("Expected success, got {:?}", err), }; let stream = SslStream::connect(&ctx, stream).unwrap(); // Since the protocols from the server and client don't overlap at all, no protocol is selected assert_eq!(None, stream.ssl().selected_alpn_protocol()); } // In 1.1.0, ALPN negotiation failure is a fatal error #[test] #[cfg(all(feature = "openssl-102", ossl110))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); // We create a different context instance for the server... let listener_ctx = { let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); 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(); assert!(SslStream::accept(&listener_ctx, stream).is_err()); }); let mut ctx = SslContext::new(Tls).unwrap(); ctx.set_verify(SSL_VERIFY_PEER); ctx.set_alpn_protocols(&[b"http/2"]); ctx.set_CA_file(&Path::new("test/root-ca.pem")).unwrap(); // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); assert!(SslStream::connect(&ctx, stream).is_err()); } #[cfg(test)] mod dtlsv1 { Loading