Loading openssl-sys/src/ssl.rs +49 −1 Original line number Diff line number Diff line Loading @@ -300,7 +300,6 @@ cfg_if! { } } cfg_if! { if #[cfg(ossl101)] { pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; Loading Loading @@ -672,6 +671,8 @@ pub const SSL_ERROR_WANT_READ: c_int = 2; pub const SSL_ERROR_WANT_WRITE: c_int = 3; pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; pub const SSL_ERROR_ZERO_RETURN: c_int = 6; #[cfg(ossl111)] pub const SSL_ERROR_WANT_CLIENT_HELLO_CB: c_int = 11; pub const SSL_VERIFY_NONE: c_int = 0; pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; Loading Loading @@ -942,6 +943,53 @@ extern "C" { #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; } #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1; #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_ERROR: c_int = 0; #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_RETRY: c_int = -1; #[cfg(ossl111)] pub type SSL_client_hello_cb_fn = Option<unsafe extern "C" fn(s: *mut SSL, al: *mut c_int, arg: *mut c_void) -> c_int>; extern "C" { #[cfg(ossl111)] pub fn SSL_CTX_set_client_hello_cb( c: *mut SSL_CTX, cb: SSL_client_hello_cb_fn, arg: *mut c_void, ); #[cfg(ossl111)] pub fn SSL_client_hello_isv2(s: *mut SSL) -> c_int; #[cfg(ossl111)] pub fn SSL_client_hello_get0_legacy_version(s: *mut SSL) -> c_uint; #[cfg(ossl111)] pub fn SSL_client_hello_get0_random(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_session_id(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_ciphers(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_compression_methods( s: *mut SSL, out: *mut *const c_uchar, ) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get1_extensions_present( s: *mut SSL, out: *mut *mut c_int, outlen: *mut size_t, ) -> c_int; #[cfg(ossl111)] pub fn SSL_client_hello_get0_ext( s: *mut SSL, type_: c_uint, out: *mut *const c_uchar, outlen: *mut size_t, ) -> c_int; pub fn SSL_free(ssl: *mut SSL); pub fn SSL_accept(ssl: *mut SSL) -> c_int; Loading openssl/src/ssl/callbacks.rs +28 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ use pkey::Params; #[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] use ssl::ExtensionContext; use ssl::{ExtensionContext, ClientHelloResponse}; use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef}; #[cfg(ossl111)] use x509::X509Ref; Loading Loading @@ -655,3 +655,30 @@ where } } } #[cfg(ossl111)] pub unsafe extern "C" fn raw_client_hello<F>( ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void, ) -> c_int where F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = arg as *const F; let mut alert = SslAlert(*al); let r = (*callback)(ssl, &mut alert); *al = alert.0; match r { Ok(c) => c.0, Err(e) => { e.put(); ffi::SSL_CLIENT_HELLO_ERROR } } } openssl/src/ssl/error.rs +7 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,12 @@ impl ErrorCode { /// An error occurred in the SSL library. pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); /// The client hello callback indicated that it needed to be retried. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); } #[derive(Debug)] Loading Loading @@ -131,6 +137,7 @@ impl error::Error for Error { } /// An error or intermediate state after a TLS handshake attempt. // FIXME overhaul #[derive(Debug)] pub enum HandshakeError<S> { /// Setup failed. Loading openssl/src/ssl/mod.rs +166 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,22 @@ impl AlpnError { pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK); } /// The result of a client hello callback. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ClientHelloResponse(c_int); #[cfg(ossl111)] impl ClientHelloResponse { /// Continue the handshake. pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS); /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error. pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY); } /// An SSL/TLS protocol version. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SslVersion(c_int); Loading Loading @@ -1600,6 +1616,31 @@ impl SslContextBuilder { } } /// Sets a callback which will be invoked just after the client's hello message is received. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_set_client_hello_cb`]. /// /// [`SSL_CTX_set_client_hello_cb`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn set_client_hello_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack> + 'static + Sync + Send, { unsafe { let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback); ffi::SSL_CTX_set_client_hello_cb( self.as_ptr(), Some(callbacks::raw_client_hello::<F>), ptr, ); } } /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 Loading Loading @@ -2934,6 +2975,131 @@ impl SslRef { ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } /// Determines if the client's hello message is in the SSLv2 format. /// /// This can only be used inside of the client hello callback. Otherwise, `false` is returned. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_isv2`]. /// /// [`SSL_client_hello_isv2`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_isv2(&self) -> bool { unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 } } /// Returns the legacy version field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_legacy_version`]. /// /// [`SSL_client_hello_get0_legacy_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_legacy_version(&self) -> Option<SslVersion> { unsafe { let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr()); if version == 0 { None } else { Some(SslVersion(version as c_int)) } } } /// Returns the random field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_random`]. /// /// [`SSL_client_hello_get0_random`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_random(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the session ID field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_session_id`]. /// /// [`SSL_client_hello_get0_session_id`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_session_id(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the ciphers field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_ciphers`]. /// /// [`SSL_client_hello_get0_ciphers`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_ciphers(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the compression methods field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_compression_methods`]. /// /// [`SSL_client_hello_get0_compression_methods`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_compression_methods(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } } /// An SSL stream midway through the handshake process. Loading openssl/src/ssl/test.rs +46 −0 Original line number Diff line number Diff line Loading @@ -1793,3 +1793,49 @@ fn sni_callback_swapped_ctx() { guard.join().unwrap(); } #[test] #[cfg(ossl111)] fn client_hello() { use ssl::ClientHelloResponse; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); 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) .unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) .unwrap(); ctx.set_client_hello_callback(|ssl, _| { assert!(!ssl.client_hello_isv2()); assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); assert!(ssl.client_hello_random().is_some()); assert!(ssl.client_hello_session_id().is_some()); assert!(ssl.client_hello_ciphers().is_some()); assert!(ssl.client_hello_compression_methods().is_some()); CALLED_BACK.store(true, Ordering::SeqCst); Ok(ClientHelloResponse::SUCCESS) }); let ssl = Ssl::new(&ctx.build()).unwrap(); let mut stream = ssl.accept(stream).unwrap(); stream.write_all(&mut [0]).unwrap(); }); let stream = TcpStream::connect(addr).unwrap(); let ctx = SslContext::builder(SslMethod::tls()).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); let mut stream = ssl.connect(stream).unwrap(); stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); guard.join().unwrap(); } Loading
openssl-sys/src/ssl.rs +49 −1 Original line number Diff line number Diff line Loading @@ -300,7 +300,6 @@ cfg_if! { } } cfg_if! { if #[cfg(ossl101)] { pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; Loading Loading @@ -672,6 +671,8 @@ pub const SSL_ERROR_WANT_READ: c_int = 2; pub const SSL_ERROR_WANT_WRITE: c_int = 3; pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; pub const SSL_ERROR_ZERO_RETURN: c_int = 6; #[cfg(ossl111)] pub const SSL_ERROR_WANT_CLIENT_HELLO_CB: c_int = 11; pub const SSL_VERIFY_NONE: c_int = 0; pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; Loading Loading @@ -942,6 +943,53 @@ extern "C" { #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; } #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1; #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_ERROR: c_int = 0; #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_RETRY: c_int = -1; #[cfg(ossl111)] pub type SSL_client_hello_cb_fn = Option<unsafe extern "C" fn(s: *mut SSL, al: *mut c_int, arg: *mut c_void) -> c_int>; extern "C" { #[cfg(ossl111)] pub fn SSL_CTX_set_client_hello_cb( c: *mut SSL_CTX, cb: SSL_client_hello_cb_fn, arg: *mut c_void, ); #[cfg(ossl111)] pub fn SSL_client_hello_isv2(s: *mut SSL) -> c_int; #[cfg(ossl111)] pub fn SSL_client_hello_get0_legacy_version(s: *mut SSL) -> c_uint; #[cfg(ossl111)] pub fn SSL_client_hello_get0_random(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_session_id(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_ciphers(s: *mut SSL, out: *mut *const c_uchar) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get0_compression_methods( s: *mut SSL, out: *mut *const c_uchar, ) -> size_t; #[cfg(ossl111)] pub fn SSL_client_hello_get1_extensions_present( s: *mut SSL, out: *mut *mut c_int, outlen: *mut size_t, ) -> c_int; #[cfg(ossl111)] pub fn SSL_client_hello_get0_ext( s: *mut SSL, type_: c_uint, out: *mut *const c_uchar, outlen: *mut size_t, ) -> c_int; pub fn SSL_free(ssl: *mut SSL); pub fn SSL_accept(ssl: *mut SSL) -> c_int; Loading
openssl/src/ssl/callbacks.rs +28 −1 Original line number Diff line number Diff line Loading @@ -23,7 +23,7 @@ use pkey::Params; #[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] use ssl::ExtensionContext; use ssl::{ExtensionContext, ClientHelloResponse}; use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef}; #[cfg(ossl111)] use x509::X509Ref; Loading Loading @@ -655,3 +655,30 @@ where } } } #[cfg(ossl111)] pub unsafe extern "C" fn raw_client_hello<F>( ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void, ) -> c_int where F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = arg as *const F; let mut alert = SslAlert(*al); let r = (*callback)(ssl, &mut alert); *al = alert.0; match r { Ok(c) => c.0, Err(e) => { e.put(); ffi::SSL_CLIENT_HELLO_ERROR } } }
openssl/src/ssl/error.rs +7 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,12 @@ impl ErrorCode { /// An error occurred in the SSL library. pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); /// The client hello callback indicated that it needed to be retried. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); } #[derive(Debug)] Loading Loading @@ -131,6 +137,7 @@ impl error::Error for Error { } /// An error or intermediate state after a TLS handshake attempt. // FIXME overhaul #[derive(Debug)] pub enum HandshakeError<S> { /// Setup failed. Loading
openssl/src/ssl/mod.rs +166 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,22 @@ impl AlpnError { pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK); } /// The result of a client hello callback. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ClientHelloResponse(c_int); #[cfg(ossl111)] impl ClientHelloResponse { /// Continue the handshake. pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS); /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error. pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY); } /// An SSL/TLS protocol version. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SslVersion(c_int); Loading Loading @@ -1600,6 +1616,31 @@ impl SslContextBuilder { } } /// Sets a callback which will be invoked just after the client's hello message is received. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_set_client_hello_cb`]. /// /// [`SSL_CTX_set_client_hello_cb`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn set_client_hello_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack> + 'static + Sync + Send, { unsafe { let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback); ffi::SSL_CTX_set_client_hello_cb( self.as_ptr(), Some(callbacks::raw_client_hello::<F>), ptr, ); } } /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 Loading Loading @@ -2934,6 +2975,131 @@ impl SslRef { ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } /// Determines if the client's hello message is in the SSLv2 format. /// /// This can only be used inside of the client hello callback. Otherwise, `false` is returned. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_isv2`]. /// /// [`SSL_client_hello_isv2`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_isv2(&self) -> bool { unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 } } /// Returns the legacy version field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_legacy_version`]. /// /// [`SSL_client_hello_get0_legacy_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_legacy_version(&self) -> Option<SslVersion> { unsafe { let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr()); if version == 0 { None } else { Some(SslVersion(version as c_int)) } } } /// Returns the random field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_random`]. /// /// [`SSL_client_hello_get0_random`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_random(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the session ID field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_session_id`]. /// /// [`SSL_client_hello_get0_session_id`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_session_id(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the ciphers field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_ciphers`]. /// /// [`SSL_client_hello_get0_ciphers`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_ciphers(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// Returns the compression methods field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_client_hello_get0_compression_methods`]. /// /// [`SSL_client_hello_get0_compression_methods`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_compression_methods(&self) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } } /// An SSL stream midway through the handshake process. Loading
openssl/src/ssl/test.rs +46 −0 Original line number Diff line number Diff line Loading @@ -1793,3 +1793,49 @@ fn sni_callback_swapped_ctx() { guard.join().unwrap(); } #[test] #[cfg(ossl111)] fn client_hello() { use ssl::ClientHelloResponse; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); 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) .unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) .unwrap(); ctx.set_client_hello_callback(|ssl, _| { assert!(!ssl.client_hello_isv2()); assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); assert!(ssl.client_hello_random().is_some()); assert!(ssl.client_hello_session_id().is_some()); assert!(ssl.client_hello_ciphers().is_some()); assert!(ssl.client_hello_compression_methods().is_some()); CALLED_BACK.store(true, Ordering::SeqCst); Ok(ClientHelloResponse::SUCCESS) }); let ssl = Ssl::new(&ctx.build()).unwrap(); let mut stream = ssl.accept(stream).unwrap(); stream.write_all(&mut [0]).unwrap(); }); let stream = TcpStream::connect(addr).unwrap(); let ctx = SslContext::builder(SslMethod::tls()).unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); let mut stream = ssl.connect(stream).unwrap(); stream.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); guard.join().unwrap(); }