Merge pull request #472 from sfackler/alpn-test

Fix test_alpn_server_select_none
This commit is contained in:
Steven Fackler 2016-10-14 22:26:32 -07:00 committed by GitHub
commit 1fe16382e0
3 changed files with 100 additions and 54 deletions

View File

@ -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) 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 { extern {
pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; 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; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;

View File

@ -76,39 +76,79 @@ impl Error {
} }
/// Returns the raw OpenSSL error code for this 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 self.0
} }
/// Returns the name of the library reporting the error. /// Returns the name of the library reporting the error, if available.
pub fn library(&self) -> &'static str { pub fn library(&self) -> Option<&'static str> {
get_lib(self.0) 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. /// Returns the name of the function reporting the error.
pub fn function(&self) -> &'static str { pub fn function(&self) -> Option<&'static str> {
get_func(self.0) 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. /// Returns the reason for the error.
pub fn reason(&self) -> &'static str { pub fn reason(&self) -> Option<&'static str> {
get_reason(self.0) 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 { impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Error") let mut builder = fmt.debug_struct("Error");
.field("library", &self.library()) builder.field("code", &self.code());
.field("function", &self.function()) if let Some(library) = self.library() {
.field("reason", &self.reason()) builder.field("library", &library);
.finish() }
if let Some(function) = self.function() {
builder.field("function", &function);
}
if let Some(reason) = self.reason() {
builder.field("reason", &reason);
}
builder.finish()
} }
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(&self.reason()) 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)),
}
} }
} }
@ -117,31 +157,3 @@ impl error::Error for Error {
"An OpenSSL error" "An OpenSSL error"
} }
} }
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()
}
}
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()
}
}

View File

@ -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 /// Test that Servers supporting ALPN don't report a protocol when none of their protocols match
/// the client's reported protocol. /// the client's reported protocol.
#[test] #[test]
#[cfg(feature = "openssl-102")] #[cfg(all(feature = "openssl-102", ossl102))]
// 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)]
fn test_alpn_server_select_none() { fn test_alpn_server_select_none() {
let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let localhost = listener.local_addr().unwrap(); let localhost = listener.local_addr().unwrap();
@ -753,21 +750,46 @@ fn test_alpn_server_select_none() {
let mut ctx = SslContext::new(Tls).unwrap(); let mut ctx = SslContext::new(Tls).unwrap();
ctx.set_verify(SSL_VERIFY_PEER); ctx.set_verify(SSL_VERIFY_PEER);
ctx.set_alpn_protocols(&[b"http/2"]); ctx.set_alpn_protocols(&[b"http/2"]);
match ctx.set_CA_file(&Path::new("test/root-ca.pem")) { ctx.set_CA_file(&Path::new("test/root-ca.pem")).unwrap();
Ok(_) => {}
Err(err) => panic!("Unexpected error {:?}", err),
}
// Now connect to the socket and make sure the protocol negotiation works... // Now connect to the socket and make sure the protocol negotiation works...
let stream = TcpStream::connect(localhost).unwrap(); let stream = TcpStream::connect(localhost).unwrap();
let stream = match SslStream::connect(&ctx, stream) { let stream = SslStream::connect(&ctx, stream).unwrap();
Ok(stream) => stream,
Err(err) => panic!("Expected success, got {:?}", err),
};
// Since the protocols from the server and client don't overlap at all, no protocol is selected // 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()); 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)] #[cfg(test)]
mod dtlsv1 { mod dtlsv1 {