diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e3ce6e8..9168a1a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -91,7 +91,7 @@ macos_job: &MACOS_JOB openssl_111: &OPENSSL_111 LIBRARY: openssl - VERSION: 1.1.1-pre3 + VERSION: 1.1.1-pre7 openssl_110: &OPENSSL_110 LIBRARY: openssl VERSION: 1.1.0h diff --git a/openssl-sys/src/openssl/v111.rs b/openssl-sys/src/openssl/v111.rs index 36682663..1bb56d5a 100644 --- a/openssl-sys/src/openssl/v111.rs +++ b/openssl-sys/src/openssl/v111.rs @@ -1,29 +1,45 @@ -use libc::{c_char, c_uchar, c_int, c_uint, c_ulong, size_t, c_void}; +use libc::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void, size_t}; pub type SSL_CTX_keylog_cb_func = Option; -pub type SSL_custom_ext_add_cb_ex = - Option c_int>; +pub type SSL_custom_ext_add_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + out: *mut *const c_uchar, + outlen: *mut size_t, + x: *mut ::X509, + chainidx: size_t, + al: *mut c_int, + add_arg: *mut c_void, + ) -> c_int, +>; -pub type SSL_custom_ext_free_cb_ex = - Option; +pub type SSL_custom_ext_free_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + out: *mut *const c_uchar, + add_arg: *mut c_void, + ), +>; -pub type SSL_custom_ext_parse_cb_ex = - Option c_int>; +pub type SSL_custom_ext_parse_cb_ex = Option< + unsafe extern "C" fn( + ssl: *mut ::SSL, + ext_type: c_uint, + context: c_uint, + input: *const c_uchar, + inlen: size_t, + x: *mut ::X509, + chainidx: size_t, + al: *mut c_int, + parse_arg: *mut c_void, + ) -> c_int, +>; pub const SSL_COOKIE_LENGTH: c_int = 4096; @@ -61,38 +77,38 @@ pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2; extern "C" { pub fn SSL_CTX_set_keylog_callback(ctx: *mut ::SSL_CTX, cb: SSL_CTX_keylog_cb_func); - pub fn SSL_CTX_add_custom_ext(ctx: *mut ::SSL_CTX, ext_type: c_uint, context: c_uint, - add_cb: SSL_custom_ext_add_cb_ex, - free_cb: SSL_custom_ext_free_cb_ex, - add_arg: *mut c_void, - parse_cb: SSL_custom_ext_parse_cb_ex, - parse_arg: *mut c_void) -> c_int; - pub fn SSL_stateless(s: *mut ::SSL) -> c_int; + pub fn SSL_CTX_add_custom_ext( + ctx: *mut ::SSL_CTX, + ext_type: c_uint, + context: c_uint, + add_cb: SSL_custom_ext_add_cb_ex, + free_cb: SSL_custom_ext_free_cb_ex, + add_arg: *mut c_void, + parse_cb: SSL_custom_ext_parse_cb_ex, + parse_arg: *mut c_void, + ) -> c_int; pub fn SSL_CIPHER_get_handshake_digest(cipher: *const ::SSL_CIPHER) -> *const ::EVP_MD; pub fn SSL_CTX_set_stateless_cookie_generate_cb( s: *mut ::SSL_CTX, - cb: Option c_int> + cb: Option< + unsafe extern "C" fn(ssl: *mut ::SSL, cookie: *mut c_uchar, cookie_len: *mut size_t) + -> c_int, + >, ); pub fn SSL_CTX_set_stateless_cookie_verify_cb( s: *mut ::SSL_CTX, - cb: Option c_int> + cb: Option< + unsafe extern "C" fn(ssl: *mut ::SSL, cookie: *const c_uchar, cookie_len: size_t) + -> c_int, + >, ); - pub fn SSL_CTX_set_max_early_data(ctx: *mut ::SSL_CTX, max_early_data: u32) -> c_int; pub fn SSL_CTX_get_max_early_data(ctx: *const ::SSL_CTX) -> u32; + pub fn SSL_CTX_set_ciphersuites(ctx: *mut ::SSL_CTX, str: *const c_char) -> c_int; + pub fn SSL_set_max_early_data(ctx: *mut ::SSL, max_early_data: u32) -> c_int; pub fn SSL_get_max_early_data(ctx: *const ::SSL) -> u32; - pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int; - pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32; - + pub fn SSL_stateless(s: *mut ::SSL) -> c_int; pub fn SSL_export_keying_material_early( s: *mut ::SSL, out: *mut c_uchar, @@ -102,7 +118,20 @@ extern "C" { context: *const c_uchar, contextlen: size_t, ) -> c_int; + pub fn SSL_write_early_data( + s: *mut ::SSL, + buf: *const c_void, + num: size_t, + written: *mut size_t, + ) -> c_int; + pub fn SSL_read_early_data( + s: *mut ::SSL, + buf: *mut c_void, + num: size_t, + readbytes: *mut size_t, + ) -> c_int; + pub fn SSL_set_ciphersuites(ssl: *mut ::SSL, str: *const c_char) -> c_int; - pub fn SSL_write_early_data(s: *mut ::SSL, buf: *const c_void, num: size_t, written: *mut size_t) -> c_int; - pub fn SSL_read_early_data(s: *mut ::SSL, buf: *mut c_void, num: size_t, readbytes: *mut size_t) -> c_int; + pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int; + pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0f3f9624..5bd04c7f 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -952,7 +952,9 @@ impl SslContextBuilder { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } } - /// Sets the list of supported ciphers. + /// Sets the list of supported ciphers for protocols before TLSv1.3. + /// + /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. /// /// See [`ciphers`] for details on the format. /// @@ -970,6 +972,29 @@ impl SslContextBuilder { } } + /// Sets the list of supported ciphers for the TLSv1.3 protocol. + /// + /// The `set_cipher_list` method controls lthe cipher suites for protocols before TLSv1.3. + /// + /// The format consists of TLSv1.3 ciphersuite names separated by `:` characters in order of + /// preference. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_ciphersuites`]. + /// + /// [`SSL_CTX_set_ciphersuites`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_ciphersuites.html + #[cfg(ossl111)] + pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { + let cipher_list = CString::new(cipher_list).unwrap(); + unsafe { + cvt(ffi::SSL_CTX_set_ciphersuites( + self.as_ptr(), + cipher_list.as_ptr() as *const _, + )).map(|_| ()) + } + } + /// Enables ECDHE key exchange with an automatically chosen curve list. /// /// Requires OpenSSL 1.0.2. diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index f5ec7b29..e516e151 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -567,9 +567,10 @@ fn test_alpn_server_advertise_multiple() { ctx.build() }; // Have the listener wait on the connection in a different thread. - thread::spawn(move || { + let guard = thread::spawn(move || { let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); + let mut stream = Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -581,12 +582,16 @@ fn test_alpn_server_advertise_multiple() { } // Now connect to the socket and make sure the protocol negotiation works... let stream = TcpStream::connect(localhost).unwrap(); - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { + let mut stream = match Ssl::new(&ctx.build()).unwrap().connect(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.ssl().selected_alpn_protocol().unwrap()); + let mut buf = [0]; + stream.read_exact(&mut buf).unwrap(); + + guard.join().unwrap(); } #[test] @@ -643,9 +648,10 @@ fn test_alpn_server_select_none() { ctx.build() }; // Have the listener wait on the connection in a different thread. - thread::spawn(move || { + let guard = thread::spawn(move || { let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); + let mut stream = Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -654,10 +660,15 @@ fn test_alpn_server_select_none() { 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 = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); + let mut stream = Ssl::new(&ctx.build()).unwrap().connect(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()); + + let mut buf = [0]; + stream.read_exact(&mut buf).unwrap(); + + guard.join().unwrap(); } #[test] @@ -972,7 +983,7 @@ fn shutdown() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -999,6 +1010,8 @@ fn shutdown() { assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Sent); assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); + + guard.join().unwrap(); } #[test] @@ -1030,7 +1043,7 @@ fn tmp_dh_callback() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -1043,23 +1056,24 @@ fn tmp_dh_callback() { Dh::params_from_pem(dh) }); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - // TLS 1.3 has no DH suites, and openssl isn't happy if the max version has no suites :( + // TLS 1.3 has no DH suites, so make sure we don't pick that version #[cfg(ossl111)] - { - ctx.set_options(super::SslOptions { - bits: ::ffi::SSL_OP_NO_TLSv1_3, - }); - } + ctx.set_options(super::SslOptions::NO_TLSV1_3); ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); + + guard.join().unwrap(); } #[test] @@ -1073,7 +1087,7 @@ fn tmp_ecdh_callback() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -1085,16 +1099,20 @@ fn tmp_ecdh_callback() { EcKey::from_curve_name(Nid::X9_62_PRIME256V1) }); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); + + guard.join().unwrap(); } #[test] @@ -1104,7 +1122,7 @@ fn tmp_dh_callback_ssl() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -1117,23 +1135,23 @@ fn tmp_dh_callback_ssl() { let dh = include_bytes!("../../test/dhparams.pem"); Dh::params_from_pem(dh) }); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - // TLS 1.3 has no DH suites, and openssl isn't happy if the max version has no suites :( + // TLS 1.3 has no DH suites, so make sure we don't pick that version #[cfg(ossl111)] - { - ctx.set_options(super::SslOptions { - bits: ::ffi::SSL_OP_NO_TLSv1_3, - }); - } + ctx.set_options(super::SslOptions::NO_TLSV1_3); ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); + + guard.join().unwrap(); } #[test] @@ -1147,7 +1165,7 @@ fn tmp_ecdh_callback_ssl() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -1159,16 +1177,20 @@ fn tmp_ecdh_callback_ssl() { CALLED_BACK.store(true, Ordering::SeqCst); EcKey::from_curve_name(Nid::X9_62_PRIME256V1) }); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); + + guard.join().unwrap(); } #[test] @@ -1200,7 +1222,7 @@ fn status_callbacks() { static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT; static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT; - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let listener = TcpListener::bind("127.0.0.1:12345").unwrap(); let port = listener.local_addr().unwrap().port(); let guard = thread::spawn(move || { @@ -1218,7 +1240,8 @@ fn status_callbacks() { Ok(true) }).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); @@ -1231,7 +1254,9 @@ fn status_callbacks() { }).unwrap(); let mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_status_type(StatusType::OCSP).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + let mut buf = [0]; + stream.read_exact(&mut buf).unwrap(); assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); @@ -1246,7 +1271,7 @@ fn new_session_callback() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); - thread::spawn(move || { + let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) @@ -1265,11 +1290,11 @@ fn new_session_callback() { ctx.set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); let ssl = Ssl::new(&ctx.build()).unwrap(); let mut stream = ssl.connect(stream).unwrap(); - // read 1 byte to make sure the session is received for TLSv1.3 - let mut buf = [0]; - stream.read_exact(&mut buf).unwrap(); + stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); + + guard.join().unwrap(); } #[test] @@ -1288,20 +1313,23 @@ fn keying_export() { ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) .unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - let stream = ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); let mut buf = [0; 32]; stream .ssl() .export_keying_material(&mut buf, label, Some(context)) .unwrap(); + + stream.write_all(&[0]).unwrap(); + buf }); let stream = TcpStream::connect(addr).unwrap(); let ctx = SslContext::builder(SslMethod::tls()).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - let stream = ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); let mut buf = [1; 32]; stream @@ -1309,6 +1337,8 @@ fn keying_export() { .export_keying_material(&mut buf, label, Some(context)) .unwrap(); + stream.read_exact(&mut [0]).unwrap(); + let buf2 = guard.join().unwrap(); assert_eq!(buf, buf2); @@ -1374,7 +1404,8 @@ fn custom_extensions() { }, ).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + stream.write_all(&[0]).unwrap(); }); let stream = TcpStream::connect(addr).unwrap(); @@ -1386,7 +1417,8 @@ fn custom_extensions() { |_, _, _, _| unreachable!(), ).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + stream.read_exact(&mut [0]).unwrap(); guard.join().unwrap(); assert!(FOUND_EXTENSION.load(Ordering::SeqCst));