diff --git a/openssl-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md index 1113ce8c60..84262e4077 100644 --- a/openssl-sys/CHANGELOG.md +++ b/openssl-sys/CHANGELOG.md @@ -2,6 +2,18 @@ ## [Unreleased] +## [v0.9.96] - 2023-11-22 + +### Changed + +* `EVP_chacha20` is now available on LibreSSL + +### Added + +* Added `EVP_des_ede3_ecb`, `EVP_des_ede3_cfb8`, `EVP_des_ede3_ofb`, `EVP_camellia_128_ofb`, `EVP_camellia_192_ofb`, `EVP_camellia_256_ofb`, `EVP_cast5_ofb`, `EVP_idea_ofb` +* Added `X509_STORE_get1_all_certs` +* Added `SSL_CTRL_GET_PEER_TMP_KEY`, `SSL_CTRL_GET_TMP_KEY`, `SSL_get_peer_tmp_key`, `SSL_get_tmp_key` + ## [v0.9.95] - 2023-11-03 ### Changed @@ -533,7 +545,8 @@ Fixed builds against OpenSSL built with `no-cast`. * Added `X509_verify` and `X509_REQ_verify`. * Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.95..master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.96..master +[v0.9.96]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.95...openssl-sys-v0.9.96 [v0.9.95]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.94...openssl-sys-v0.9.95 [v0.9.94]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.93...openssl-sys-v0.9.94 [v0.9.93]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.92...openssl-sys-v0.9.93 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index fc7e8f3c7a..95d920adb6 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.95" +version = "0.9.96" authors = [ "Alex Crichton ", "Steven Fackler ", diff --git a/openssl-sys/src/handwritten/evp.rs b/openssl-sys/src/handwritten/evp.rs index bf5aa421bd..fabb13383e 100644 --- a/openssl-sys/src/handwritten/evp.rs +++ b/openssl-sys/src/handwritten/evp.rs @@ -312,7 +312,10 @@ extern "C" { pub fn EVP_des_ecb() -> *const EVP_CIPHER; pub fn EVP_des_ede3() -> *const EVP_CIPHER; pub fn EVP_des_ede3_cbc() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_ecb() -> *const EVP_CIPHER; pub fn EVP_des_ede3_cfb64() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_cfb8() -> *const EVP_CIPHER; + pub fn EVP_des_ede3_ofb() -> *const EVP_CIPHER; pub fn EVP_des_cbc() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn EVP_rc4() -> *const EVP_CIPHER; @@ -367,7 +370,7 @@ extern "C" { pub fn EVP_aes_256_wrap() -> *const EVP_CIPHER; #[cfg(ossl110)] pub fn EVP_aes_256_wrap_pad() -> *const EVP_CIPHER; - #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + #[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn EVP_chacha20() -> *const EVP_CIPHER; #[cfg(all(any(ossl110, libressl360), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn EVP_chacha20_poly1305() -> *const EVP_CIPHER; @@ -398,17 +401,23 @@ extern "C" { #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_128_cbc() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn EVP_camellia_128_ofb() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_192_cfb128() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_192_ecb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_192_cbc() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn EVP_camellia_192_ofb() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_256_cfb128() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_256_ecb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn EVP_camellia_256_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn EVP_camellia_256_ofb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn EVP_cast5_cfb64() -> *const EVP_CIPHER; @@ -416,6 +425,8 @@ extern "C" { pub fn EVP_cast5_ecb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn EVP_cast5_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] + pub fn EVP_cast5_ofb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn EVP_idea_cfb64() -> *const EVP_CIPHER; @@ -423,6 +434,8 @@ extern "C" { pub fn EVP_idea_ecb() -> *const EVP_CIPHER; #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn EVP_idea_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] + pub fn EVP_idea_ofb() -> *const EVP_CIPHER; #[cfg(not(ossl110))] pub fn OPENSSL_add_all_algorithms_noconf(); diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index f5e3c24289..c5419ed6eb 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -644,6 +644,8 @@ const_ptr_api! { extern "C" { #[cfg(any(ossl110, libressl270))] pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; + #[cfg(ossl300)] + pub fn X509_STORE_get1_all_certs(ctx: *mut X509_STORE) -> *mut stack_st_X509; } } diff --git a/openssl-sys/src/ssl.rs b/openssl-sys/src/ssl.rs index e812673333..52ea5b2135 100644 --- a/openssl-sys/src/ssl.rs +++ b/openssl-sys/src/ssl.rs @@ -349,6 +349,8 @@ pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; pub const SSL_CTRL_SET_SIGALGS_LIST: c_int = 98; #[cfg(ossl102)] pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; +#[cfg(ossl300)] +pub const SSL_CTRL_GET_PEER_TMP_KEY: c_int = 109; #[cfg(ossl110)] pub const SSL_CTRL_GET_EXTMS_SUPPORT: c_int = 122; #[cfg(any(ossl110, libressl261))] @@ -359,6 +361,8 @@ pub const SSL_CTRL_SET_MAX_PROTO_VERSION: c_int = 124; pub const SSL_CTRL_GET_MIN_PROTO_VERSION: c_int = 130; #[cfg(any(ossl110g, libressl270))] pub const SSL_CTRL_GET_MAX_PROTO_VERSION: c_int = 131; +#[cfg(ossl300)] +pub const SSL_CTRL_GET_TMP_KEY: c_int = 133; pub unsafe fn SSL_CTX_set_tmp_dh(ctx: *mut SSL_CTX, dh: *mut DH) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) @@ -506,6 +510,17 @@ cfg_if! { } } } +cfg_if! { + if #[cfg(ossl300)] { + pub unsafe fn SSL_get_peer_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_GET_PEER_TMP_KEY, 0, key as *mut c_void) + } + + pub unsafe fn SSL_get_tmp_key(ssl: *mut SSL, key: *mut *mut EVP_PKEY) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_GET_TMP_KEY, 0, key as *mut c_void) + } + } +} #[cfg(ossl111)] pub const SSL_CLIENT_HELLO_SUCCESS: c_int = 1; diff --git a/openssl/CHANGELOG.md b/openssl/CHANGELOG.md index f9a433fae8..d616f57fc2 100644 --- a/openssl/CHANGELOG.md +++ b/openssl/CHANGELOG.md @@ -2,6 +2,29 @@ ## [Unreleased] +## [v0.10.60] - 2023-11-22 + +### Deprecated + +* Deprecated `X509StoreRef::objects`. It is unsound. All callers should migrate to using `X509StoreRef::all_certificates` instead. + +### Fixed + +* Fixed a memory leak when calling `SslContextBuilder::set_ex_data` and `SslRef::set_ex_data` multiple times with the same index. + +### Added + +* Added `X509StoreRef::all_certificates` +* Added `cipher::Cipher::{camellia128_cbc,camellia192_cbc,camellia256_cbc,cast5_cbc,idea_cbc}` +* Added `symm::Cipher::{des_ede3_ecb,des_ede3_cfb8,des_ede3_ofb,camellia_128_ecb,camellia_128_ofb,camellia_128_cfb128,camellia_192_ecb,camellia_192_ofb,camellia_192_cfb128,camellia_256_ecb,camellia_256_ofb,camellia_256_cfb128,cast5_ecb,cast5_ofb,cast5_cfb64,idea_ecb,idea_ofb,idea_cfb64}` +* Added `Crypter::update_unchecked` +* Added `SslRef::{peer_tmp_key,tmp_key}` + +### Changed + +* `cipher::Cipher::chacha20` is now available on LibreSSL +* `symm::Cipher::chacha20` is now available on LibreSSL + ## [v0.10.59] - 2023-11-03 ### Added @@ -825,7 +848,8 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.59...master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.60...master +[v0.10.60]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.59...openssl-v0.10.60 [v0.10.59]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.58...openssl-v0.10.59 [v0.10.58]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.57...openssl-v0.10.58 [v0.10.57]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.56...openssl-v0.10.57 diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 6778dcbb0e..aaf48b81a6 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.59" +version = "0.10.60" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -30,7 +30,7 @@ libc = "0.2" once_cell = "1.5.2" openssl-macros = { version = "0.1.0", path = "../openssl-macros" } -ffi = { package = "openssl-sys", version = "0.9.95", path = "../openssl-sys" } +ffi = { package = "openssl-sys", version = "0.9.96", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" diff --git a/openssl/src/cipher.rs b/openssl/src/cipher.rs index 892cae1db7..b5c82e8f68 100644 --- a/openssl/src/cipher.rs +++ b/openssl/src/cipher.rs @@ -388,6 +388,11 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ecb() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia128_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cbc() as *mut _) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia192_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cfb128() as *mut _) } @@ -398,6 +403,11 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ecb() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia192_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cbc() as *mut _) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia256_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cfb128() as *mut _) } @@ -408,6 +418,11 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia256_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cbc() as *mut _) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) } @@ -418,6 +433,11 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] + pub fn cast5_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cbc() as *mut _) } + } + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_idea_cfb64() as *mut _) } @@ -428,7 +448,12 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_idea_ecb() as *mut _) } } - #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] + pub fn idea_cbc() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_idea_cbc() as *mut _) } + } + + #[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_chacha20() as *mut _) } } diff --git a/openssl/src/cipher_ctx.rs b/openssl/src/cipher_ctx.rs index 1769ee9716..abb1f11ef3 100644 --- a/openssl/src/cipher_ctx.rs +++ b/openssl/src/cipher_ctx.rs @@ -581,7 +581,9 @@ impl CipherCtxRef { /// output size check removed. It can be used when the exact /// buffer size control is maintained by the caller. /// - /// SAFETY: The caller is expected to provide `output` buffer + /// # Safety + /// + /// The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer size should be at least as big as /// the input buffer. For block ciphers the size of the output @@ -693,7 +695,9 @@ impl CipherCtxRef { /// This function is the same as [`Self::cipher_final`] but with /// the output buffer size check removed. /// - /// SAFETY: The caller is expected to provide `output` buffer + /// # Safety + /// + /// The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer can be empty, for block ciphers the /// output buffer should be at least as big as the block. diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index bc9d2b3455..5c9ccf7a05 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -119,12 +119,14 @@ //! ``` #![doc(html_root_url = "https://docs.rs/openssl/0.10")] #![warn(rust_2018_idioms)] -#![allow(clippy::uninlined_format_args)] +#![allow(clippy::uninlined_format_args, clippy::needless_doctest_main)] #[doc(inline)] pub use ffi::init; use libc::c_int; +#[cfg(ossl300)] +use libc::c_long; use crate::error::ErrorStack; @@ -212,6 +214,19 @@ fn cvt(r: c_int) -> Result { } } +// cvt_long is currently only used in functions that require openssl >= 3.0.0, +// so this cfg statement is used to avoid "unused function" errors when +// compiling with openssl < 3.0.0 +#[inline] +#[cfg(ossl300)] +fn cvt_long(r: c_long) -> Result { + if r <= 0 { + Err(ErrorStack::get()) + } else { + Ok(r) + } +} + #[inline] fn cvt_n(r: c_int) -> Result { if r < 0 { diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index d147c3c343..fb38bb3e4a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -57,6 +57,8 @@ //! } //! } //! ``` +#[cfg(ossl300)] +use crate::cvt_long; use crate::dh::{Dh, DhRef}; #[cfg(all(ossl101, not(ossl110)))] use crate::ec::EcKey; @@ -68,6 +70,8 @@ use crate::hash::MessageDigest; #[cfg(any(ossl110, libressl270))] use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; +#[cfg(ossl300)] +use crate::pkey::{PKey, Public}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; @@ -1568,16 +1572,34 @@ impl SslContextBuilder { /// /// This can be used to provide data to callbacks registered with the context. Use the /// `SslContext::new_ex_index` method to create an `Index`. + // FIXME should return a result #[corresponds(SSL_CTX_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { self.set_ex_data_inner(index, data); } fn set_ex_data_inner(&mut self, index: Index, data: T) -> *mut c_void { + match self.ex_data_mut(index) { + Some(v) => { + *v = data; + (v as *mut T).cast() + } + _ => unsafe { + let data = Box::into_raw(Box::new(data)) as *mut c_void; + ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data); + data + }, + } + } + + fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { unsafe { - let data = Box::into_raw(Box::new(data)) as *mut c_void; - ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data); - data + let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&mut *data.cast()) + } } } @@ -2961,15 +2983,19 @@ impl SslRef { /// /// This can be used to provide data to callbacks registered with the context. Use the /// `Ssl::new_ex_index` method to create an `Index`. + // FIXME should return a result #[corresponds(SSL_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { - unsafe { - let data = Box::new(data); - ffi::SSL_set_ex_data( - self.as_ptr(), - index.as_raw(), - Box::into_raw(data) as *mut c_void, - ); + match self.ex_data_mut(index) { + Some(v) => *v = data, + None => unsafe { + let data = Box::new(data); + ffi::SSL_set_ex_data( + self.as_ptr(), + index.as_raw(), + Box::into_raw(data) as *mut c_void, + ); + }, } } @@ -3445,6 +3471,38 @@ impl SslRef { pub fn security_level(&self) -> u32 { unsafe { ffi::SSL_get_security_level(self.as_ptr()) as u32 } } + + /// Get the temporary key provided by the peer that is used during key + /// exchange. + // We use an owned value because EVP_KEY free need to be called when it is + // dropped + #[corresponds(SSL_get_peer_tmp_key)] + #[cfg(ossl300)] + pub fn peer_tmp_key(&self) -> Result, ErrorStack> { + unsafe { + let mut key = ptr::null_mut(); + match cvt_long(ffi::SSL_get_peer_tmp_key(self.as_ptr(), &mut key)) { + Ok(_) => Ok(PKey::::from_ptr(key)), + Err(e) => Err(e), + } + } + } + + /// Returns the temporary key from the local end of the connection that is + /// used during key exchange. + // We use an owned value because EVP_KEY free need to be called when it is + // dropped + #[corresponds(SSL_get_tmp_key)] + #[cfg(ossl300)] + pub fn tmp_key(&self) -> Result, ErrorStack> { + unsafe { + let mut key = ptr::null_mut(); + match cvt_long(ffi::SSL_get_tmp_key(self.as_ptr(), &mut key)) { + Ok(_) => Ok(PKey::::from_ptr(key)), + Err(e) => Err(e), + } + } + } } /// An SSL stream midway through the handshake process. diff --git a/openssl/src/ssl/test/mod.rs b/openssl/src/ssl/test/mod.rs index 542656cb04..412c4a5dc6 100644 --- a/openssl/src/ssl/test/mod.rs +++ b/openssl/src/ssl/test/mod.rs @@ -10,7 +10,7 @@ use std::net::UdpSocket; use std::net::{SocketAddr, TcpListener, TcpStream}; use std::path::Path; use std::process::{Child, ChildStdin, Command, Stdio}; -use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::thread; use std::time::Duration; @@ -19,7 +19,7 @@ use crate::error::ErrorStack; use crate::hash::MessageDigest; #[cfg(not(boringssl))] use crate::ocsp::{OcspResponse, OcspResponseStatus}; -use crate::pkey::PKey; +use crate::pkey::{Id, PKey}; use crate::srtp::SrtpProfileId; use crate::ssl::test::server::Server; #[cfg(any(ossl110, ossl111, libressl261))] @@ -322,6 +322,56 @@ fn state() { ); } +// when a connection uses ECDHE P-384 key exchange, then the temp key APIs +// return P-384 keys, and the peer and local keys are different. +#[test] +#[cfg(ossl300)] +fn peer_tmp_key_p384() { + let mut server = Server::builder(); + server.ctx().set_groups_list("P-384").unwrap(); + let server = server.build(); + let s = server.client().connect(); + let peer_temp = s.ssl().peer_tmp_key().unwrap(); + assert_eq!(peer_temp.id(), Id::EC); + assert_eq!(peer_temp.bits(), 384); + + let local_temp = s.ssl().tmp_key().unwrap(); + assert_eq!(local_temp.id(), Id::EC); + assert_eq!(local_temp.bits(), 384); + + assert_ne!( + peer_temp.ec_key().unwrap().public_key_to_der().unwrap(), + local_temp.ec_key().unwrap().public_key_to_der().unwrap(), + ); +} + +// when a connection uses RSA key exchange, then the peer (server) temp key is +// an Error because there is no temp key, and the local (client) temp key is the +// temp key sent in the initial key share. +#[test] +#[cfg(ossl300)] +fn peer_tmp_key_rsa() { + let mut server = Server::builder(); + server.ctx().set_cipher_list("RSA").unwrap(); + // RSA key exchange is not allowed in TLS 1.3, so force the connection + // to negotiate TLS 1.2 + server + .ctx() + .set_max_proto_version(Some(SslVersion::TLS1_2)) + .unwrap(); + let server = server.build(); + let mut client = server.client(); + client.ctx().set_groups_list("P-521").unwrap(); + let s = client.connect(); + let peer_temp = s.ssl().peer_tmp_key(); + assert!(peer_temp.is_err()); + + // this is the temp key that the client sent in the initial key share + let local_temp = s.ssl().tmp_key().unwrap(); + assert_eq!(local_temp.id(), Id::EC); + assert_eq!(local_temp.bits(), 521); +} + /// Tests that when both the client as well as the server use SRTP and their /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. @@ -1588,3 +1638,50 @@ fn set_security_level() { let ssl = ssl; assert_eq!(4, ssl.security_level()); } + +#[test] +fn ssl_ctx_ex_data_leak() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct DropTest; + + impl Drop for DropTest { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } + } + + let idx = SslContext::new_ex_index().unwrap(); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_ex_data(idx, DropTest); + ctx.set_ex_data(idx, DropTest); + assert_eq!(DROPS.load(Ordering::Relaxed), 1); + + drop(ctx); + assert_eq!(DROPS.load(Ordering::Relaxed), 2); +} + +#[test] +fn ssl_ex_data_leak() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct DropTest; + + impl Drop for DropTest { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::Relaxed); + } + } + + let idx = Ssl::new_ex_index().unwrap(); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_ex_data(idx, DropTest); + ssl.set_ex_data(idx, DropTest); + assert_eq!(DROPS.load(Ordering::Relaxed), 1); + + drop(ssl); + assert_eq!(DROPS.load(Ordering::Relaxed), 2); +} diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 7cf152e3c1..0ff9d874e2 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -278,11 +278,25 @@ impl Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cbc()) } } + pub fn des_ede3_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_ecb()) } + } + #[cfg(not(boringssl))] pub fn des_ede3_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } } + #[cfg(not(boringssl))] + pub fn des_ede3_cfb8() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cfb8()) } + } + + #[cfg(not(boringssl))] + pub fn des_ede3_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_ofb()) } + } + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } @@ -293,23 +307,83 @@ impl Cipher { unsafe { Cipher(ffi::EVP_camellia_128_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_128_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_128_ecb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_128_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_128_ofb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_128_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_128_cfb128()) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_192_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_192_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_192_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_192_ecb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_192_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_192_ofb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_192_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_192_cfb128()) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_256_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_256_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_256_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_256_ecb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_256_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_256_ofb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] + pub fn camellia_256_cfb128() -> Cipher { + unsafe { Cipher(ffi::EVP_camellia_256_cfb128()) } + } + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_cast5_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] + pub fn cast5_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_cast5_ecb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] + pub fn cast5_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_cast5_ofb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] + pub fn cast5_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_cast5_cfb64()) } + } + /// Requires OpenSSL 1.1.0 or newer. - #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] + #[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20()) } } @@ -325,6 +399,21 @@ impl Cipher { unsafe { Cipher(ffi::EVP_idea_cbc()) } } + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] + pub fn idea_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_idea_ecb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] + pub fn idea_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_idea_ofb()) } + } + + #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] + pub fn idea_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_idea_cfb64()) } + } + #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_seed_cbc()) } @@ -607,6 +696,27 @@ impl Crypter { self.ctx.cipher_update(input, Some(output)) } + /// Feeds data from `input` through the cipher, writing encrypted/decrypted + /// bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Safety + /// + /// The caller must provide an `output` buffer large enough to contain + /// correct number of bytes. For streaming ciphers the output buffer size + /// should be at least as big as the input buffer. For block ciphers the + /// size of the output buffer depends on the state of partially updated + /// blocks. + pub unsafe fn update_unchecked( + &mut self, + input: &[u8], + output: &mut [u8], + ) -> Result { + self.ctx.cipher_update_unchecked(input, Some(output)) + } + /// Finishes the encryption/decryption process, writing any remaining data /// to `output`. /// @@ -1503,7 +1613,7 @@ mod tests { } #[test] - #[cfg(ossl110)] + #[cfg(any(ossl110, libressl310))] fn test_chacha20() { let key = "0000000000000000000000000000000000000000000000000000000000000000"; let iv = "00000000000000000000000000000000"; diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index a90bf3515f..8619086ebb 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -42,12 +42,14 @@ //! ``` use cfg_if::cfg_if; -use foreign_types::ForeignTypeRef; +use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::ssl::SslFiletype; +#[cfg(ossl300)] +use crate::stack::Stack; use crate::stack::StackRef; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef}; @@ -260,10 +262,24 @@ foreign_type_and_impl_send_sync! { impl X509StoreRef { /// Get a reference to the cache of certificates in this store. + /// + /// This method is deprecated. It is **unsound** and will be removed in a + /// future version of rust-openssl. `X509StoreRef::all_certificates` + /// should be used instead. + #[deprecated( + note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead." + )] #[corresponds(X509_STORE_get0_objects)] pub fn objects(&self) -> &StackRef { unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } } + + /// Returns a stack of all the certificates in this store. + #[corresponds(X509_STORE_get1_all_certs)] + #[cfg(ossl300)] + pub fn all_certificates(&self) -> Stack { + unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) } + } } cfg_if! { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index a4a3de970c..0444a067dd 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1177,3 +1177,18 @@ fn test_dist_point_null() { let cert = X509::from_pem(cert).unwrap(); assert!(cert.crl_distribution_points().is_none()); } + +#[test] +#[cfg(ossl300)] +fn test_store_all_certificates() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let store = { + let mut b = X509StoreBuilder::new().unwrap(); + b.add_cert(cert).unwrap(); + b.build() + }; + + assert_eq!(store.all_certificates().len(), 1); +}