From 6ca27a7738cbde1b19dd6750041ef0dff0227106 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Mon, 13 Jan 2025 15:37:24 +0100 Subject: [PATCH 01/34] RTG-3333 Support X25519MLKEM768 by default, but don't sent it as client X25519MLKEM768 is the standardised successor of the preliminary X25519Kyber768Draft00. Latest browsers have switched to X25519MLKEM768. Cloudflare supports both on the edge. We've had support for X25519MLKEM768 in this crate for a while, but didn't enable by default. We're now enabling serverside support by default. We also let clients advertise support when set to kx-client-pq-supported. We don't enable support by default yet for clients set to kx-client-pq-preferred, as that would cause an extra round-trip due to HelloRetryRequest if the server doesn't support X25519MLKEM768 yet. BoringSSL against which we build must support X25519MLKEM768, otherwise this will fail. --- boring/src/ssl/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index f0849589..cc6e07f4 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -2748,7 +2748,7 @@ impl SslRef { if cfg!(feature = "kx-client-nist-required") { "P-256:P-384:P-521:P256Kyber768Draft00" } else { - "X25519:P-256:P-384:P-521:X25519Kyber768Draft00:P256Kyber768Draft00" + "X25519:P-256:P-384:P-521:X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00" } } else { if cfg!(feature = "kx-client-nist-required") { @@ -2764,8 +2764,10 @@ impl SslRef { #[cfg(feature = "kx-safe-default")] fn server_set_default_curves_list(&mut self) { - self.set_curves_list("X25519Kyber768Draft00:P256Kyber768Draft00:X25519:P-256:P-384") - .expect("invalid default server curves list"); + self.set_curves_list( + "X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00:X25519:P-256:P-384", + ) + .expect("invalid default server curves list"); } /// Returns the [`SslCurve`] used for this `SslRef`. From af9df3765debe7198eecc0ab0aa93bb61580700c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 22 Jan 2025 15:25:23 +0000 Subject: [PATCH 02/34] replace once_cell with LazyLock We can drop the once_cell dependency since the same functionality is implemented in std now. Requires bumping MSRV to 1.80. --- Cargo.toml | 1 - boring/Cargo.toml | 3 +-- boring/src/ssl/async_callbacks.rs | 23 ++++++++++++----------- boring/src/ssl/mod.rs | 16 +++++++++------- boring/src/ssl/test/private_key_method.rs | 6 ++---- hyper-boring/Cargo.toml | 2 +- hyper-boring/src/lib.rs | 6 +++--- tokio-boring/Cargo.toml | 1 - 8 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e3502707..04a02486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ hyper1 = { package = "hyper", version = "1" } hyper-util = "0.1.6" hyper0 = { package = "hyper", version = "0.14", default-features = false } linked_hash_set = "0.1" -once_cell = "1.0" openssl-macros = "0.1.1" tower = { version = "0.4", default-features = false, features = ["util"] } tower-layer = "0.3" diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 96bfbc92..5e0b1c28 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" keywords = ["crypto", "tls", "ssl", "dtls"] categories = ["cryptography", "api-bindings"] edition = { workspace = true } -rust-version = "1.70" +rust-version = "1.80" [package.metadata.docs.rs] features = ["rpk", "pq-experimental", "underscore-wildcards"] @@ -74,7 +74,6 @@ kx-client-nist-required = ["kx-safe-default"] [dependencies] bitflags = { workspace = true } foreign-types = { workspace = true } -once_cell = { workspace = true } openssl-macros = { workspace = true } libc = { workspace = true } boring-sys = { workspace = true } diff --git a/boring/src/ssl/async_callbacks.rs b/boring/src/ssl/async_callbacks.rs index db674e9a..93226b48 100644 --- a/boring/src/ssl/async_callbacks.rs +++ b/boring/src/ssl/async_callbacks.rs @@ -5,10 +5,10 @@ use super::{ SslVerifyMode, }; use crate::ex_data::Index; -use once_cell::sync::Lazy; use std::convert::identity; use std::future::Future; use std::pin::Pin; +use std::sync::LazyLock; use std::task::{ready, Context, Poll, Waker}; /// The type of futures to pass to [`SslContextBuilderExt::set_async_select_certificate_callback`]. @@ -42,19 +42,20 @@ pub type BoxCustomVerifyFinish = Box Result<(), SslAl /// Public for documentation purposes. pub type ExDataFuture = Pin + Send>>; -pub(crate) static TASK_WAKER_INDEX: Lazy>> = - Lazy::new(|| Ssl::new_ex_index().unwrap()); -pub(crate) static SELECT_CERT_FUTURE_INDEX: Lazy>>> = - Lazy::new(|| Ssl::new_ex_index().unwrap()); -pub(crate) static SELECT_PRIVATE_KEY_METHOD_FUTURE_INDEX: Lazy< +pub(crate) static TASK_WAKER_INDEX: LazyLock>> = + LazyLock::new(|| Ssl::new_ex_index().unwrap()); +pub(crate) static SELECT_CERT_FUTURE_INDEX: LazyLock< + Index>>, +> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); +pub(crate) static SELECT_PRIVATE_KEY_METHOD_FUTURE_INDEX: LazyLock< Index>>, -> = Lazy::new(|| Ssl::new_ex_index().unwrap()); -pub(crate) static SELECT_GET_SESSION_FUTURE_INDEX: Lazy< +> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); +pub(crate) static SELECT_GET_SESSION_FUTURE_INDEX: LazyLock< Index>>, -> = Lazy::new(|| Ssl::new_ex_index().unwrap()); -pub(crate) static SELECT_CUSTOM_VERIFY_FUTURE_INDEX: Lazy< +> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); +pub(crate) static SELECT_CUSTOM_VERIFY_FUTURE_INDEX: LazyLock< Index>>, -> = Lazy::new(|| Ssl::new_ex_index().unwrap()); +> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); impl SslContextBuilder { /// Sets a callback that is called before most [`ClientHello`] processing diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index cc6e07f4..99a2950f 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -59,7 +59,6 @@ //! ``` use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void}; -use once_cell::sync::Lazy; use openssl_macros::corresponds; use std::any::TypeId; use std::collections::HashMap; @@ -76,7 +75,7 @@ use std::path::Path; use std::ptr::{self, NonNull}; use std::slice; use std::str; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, LazyLock, Mutex}; use crate::dh::DhRef; use crate::ec::EcKeyRef; @@ -426,12 +425,15 @@ impl NameType { } } -static INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); -static SSL_INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); -static SESSION_CTX_INDEX: Lazy> = Lazy::new(|| Ssl::new_ex_index().unwrap()); +static INDEXES: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); +static SSL_INDEXES: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); +static SESSION_CTX_INDEX: LazyLock> = + LazyLock::new(|| Ssl::new_ex_index().unwrap()); #[cfg(feature = "rpk")] -static RPK_FLAG_INDEX: Lazy> = - Lazy::new(|| SslContext::new_ex_index().unwrap()); +static RPK_FLAG_INDEX: LazyLock> = + LazyLock::new(|| SslContext::new_ex_index().unwrap()); unsafe extern "C" fn free_data_box( _parent: *mut c_void, diff --git a/boring/src/ssl/test/private_key_method.rs b/boring/src/ssl/test/private_key_method.rs index 019a8c7c..ead0ffeb 100644 --- a/boring/src/ssl/test/private_key_method.rs +++ b/boring/src/ssl/test/private_key_method.rs @@ -1,5 +1,3 @@ -use once_cell::sync::OnceCell; - use super::server::{Builder, Server}; use super::KEY; use crate::hash::MessageDigest; @@ -12,7 +10,7 @@ use crate::ssl::{ }; use std::io::Write; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; #[allow(clippy::type_complexity)] pub(super) struct Method { @@ -233,7 +231,7 @@ fn test_sign_ok() { #[test] fn test_sign_retry_complete_ok() { - let input_cell = Arc::new(OnceCell::new()); + let input_cell = Arc::new(OnceLock::new()); let input_cell_clone = input_cell.clone(); let mut builder = builder_with_private_key_method( diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index f8560ff0..2b706537 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -9,6 +9,7 @@ repository = { workspace = true } documentation = "https://docs.rs/hyper-boring" readme = "README.md" exclude = ["test/*"] +rust-version = "1.80" [package.metadata.docs.rs] features = ["pq-experimental"] @@ -45,7 +46,6 @@ hyper1 = { workspace = true, optional = true } hyper-util = { workspace = true, optional = true, features = ["client", "client-legacy"] } hyper0 = { workspace = true, optional = true, features = ["client"] } linked_hash_set = { workspace = true } -once_cell = { workspace = true } boring = { workspace = true } tokio = { workspace = true } tokio-boring = { workspace = true } diff --git a/hyper-boring/src/lib.rs b/hyper-boring/src/lib.rs index f51dfaac..e66aa955 100644 --- a/hyper-boring/src/lib.rs +++ b/hyper-boring/src/lib.rs @@ -6,8 +6,8 @@ use crate::cache::SessionKey; use boring::error::ErrorStack; use boring::ex_data::Index; use boring::ssl::Ssl; -use once_cell::sync::OnceCell; use std::fmt; +use std::sync::LazyLock; use tokio_boring::SslStream; mod cache; @@ -21,8 +21,8 @@ mod v1; pub use self::v1::*; fn key_index() -> Result, ErrorStack> { - static IDX: OnceCell> = OnceCell::new(); - IDX.get_or_try_init(Ssl::new_ex_index).copied() + static IDX: LazyLock> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); + Ok(*IDX) } /// Settings for [`HttpsLayer`] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 1d5a3847..8a475515 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -31,7 +31,6 @@ rpk = ["boring/rpk"] [dependencies] boring = { workspace = true } boring-sys = { workspace = true } -once_cell = { workspace = true } tokio = { workspace = true } [dev-dependencies] From 76b592673f716dca49dbe532f97f7e430c36ed9c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Wed, 22 Jan 2025 15:53:45 +0000 Subject: [PATCH 03/34] fix manual_c_str_literals clippy warning --- boring/src/ssl/bio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring/src/ssl/bio.rs b/boring/src/ssl/bio.rs index 37e2866b..f3b83672 100644 --- a/boring/src/ssl/bio.rs +++ b/boring/src/ssl/bio.rs @@ -219,7 +219,7 @@ struct BIO_METHOD(*mut ffi::BIO_METHOD); impl BIO_METHOD { fn new() -> BIO_METHOD { unsafe { - let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr().cast()); + let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, c"rust".as_ptr().cast()); assert!(!ptr.is_null()); let ret = BIO_METHOD(ptr); assert!(ffi::BIO_meth_set_write(ptr, Some(bwrite::)) != 0); From 3355ccca678875ab4ad7c136e443f7522cfe7403 Mon Sep 17 00:00:00 2001 From: Evan Rittenhouse Date: Tue, 4 Feb 2025 07:57:15 -0600 Subject: [PATCH 04/34] chore: Fix docs on SslRef::replace_ex_data --- boring/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 99a2950f..d4d317a5 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -3496,7 +3496,7 @@ 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`. /// - /// Any previous value will be dropped and replaced by the new one. + /// The previous value, if any, will be returned. #[corresponds(SSL_set_ex_data)] pub fn replace_ex_data(&mut self, index: Index, data: T) -> Option { if let Some(old) = self.ex_data_mut(index) { From 3b36cb6c7879128f7d05c01f1bd5c05d4e51399d Mon Sep 17 00:00:00 2001 From: Kornel Date: Wed, 27 Nov 2024 16:50:07 +0000 Subject: [PATCH 05/34] Detailed error codes --- boring/src/error.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/boring/src/error.rs b/boring/src/error.rs index fdc3ba9e..9cdc878b 100644 --- a/boring/src/error.rs +++ b/boring/src/error.rs @@ -182,6 +182,12 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the library reporting the + /// error. + pub fn library_code(&self) -> libc::c_int { + ffi::ERR_GET_LIB(self.code) + } + /// Returns the name of the function reporting the error. pub fn function(&self) -> Option<&'static str> { unsafe { @@ -206,6 +212,11 @@ impl Error { } } + /// Returns the raw OpenSSL error constant for the reason for the error. + pub fn reason_code(&self) -> libc::c_int { + ffi::ERR_GET_REASON(self.code) + } + /// Returns the name of the source file which encountered the error. pub fn file(&self) -> &'static str { unsafe { @@ -235,12 +246,14 @@ impl fmt::Debug for Error { if let Some(library) = self.library() { builder.field("library", &library); } + builder.field("library_code", &self.library_code()); if let Some(function) = self.function() { builder.field("function", &function); } if let Some(reason) = self.reason() { builder.field("reason", &reason); } + builder.field("reason_code", &self.reason_code()); builder.field("file", &self.file()); builder.field("line", &self.line()); if let Some(data) = self.data() { From a613d4b510b726a21ee542cc74db91701b5ceb20 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Mon, 10 Feb 2025 14:07:49 -0800 Subject: [PATCH 06/34] Clean up boring_sys::init() We don't need the workaround that was initially introduced for a bug in openssl, and OPENSSL_init_ssl always calls into CRYPTO_library_init on boringssl, so just call it explicitly. --- boring-sys/src/lib.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/boring-sys/src/lib.rs b/boring-sys/src/lib.rs index c821b3e5..094221ff 100644 --- a/boring-sys/src/lib.rs +++ b/boring-sys/src/lib.rs @@ -48,18 +48,7 @@ pub const fn ERR_GET_REASON(l: c_uint) -> c_int { } pub fn init() { - use std::ptr; - use std::sync::Once; - - // explicitly initialize to work around https://github.com/openssl/openssl/issues/3505 - static INIT: Once = Once::new(); - - let init_options = OPENSSL_INIT_LOAD_SSL_STRINGS; - - INIT.call_once(|| { - assert_eq!( - unsafe { OPENSSL_init_ssl(init_options.try_into().unwrap(), ptr::null_mut()) }, - 1 - ) - }); + unsafe { + CRYPTO_library_init(); + } } From 2561bdf64d1e2ea1b2f9de30c3fc805953413e20 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Mon, 10 Feb 2025 13:50:50 -0800 Subject: [PATCH 07/34] Expose EVP_HPKE_KEY --- boring/src/hpke.rs | 31 +++++++++++++++++++++++++++++++ boring/src/lib.rs | 1 + 2 files changed, 32 insertions(+) create mode 100644 boring/src/hpke.rs diff --git a/boring/src/hpke.rs b/boring/src/hpke.rs new file mode 100644 index 00000000..7f788224 --- /dev/null +++ b/boring/src/hpke.rs @@ -0,0 +1,31 @@ +use crate::error::ErrorStack; +use crate::{cvt_0i, cvt_p, ffi}; + +use foreign_types::ForeignType; + +foreign_type_and_impl_send_sync! { + type CType = ffi::EVP_HPKE_KEY; + fn drop = ffi::EVP_HPKE_KEY_free; + + pub struct HpkeKey; +} + +impl HpkeKey { + /// Allocates and initializes a key with the `EVP_HPKE_KEY` type using the + /// `EVP_hpke_x25519_hkdf_sha256` KEM algorithm. + pub fn dhkem_p256_sha256(pkey: &[u8]) -> Result { + unsafe { + ffi::init(); + let hpke = cvt_p(ffi::EVP_HPKE_KEY_new()).map(|p| HpkeKey::from_ptr(p))?; + + cvt_0i(ffi::EVP_HPKE_KEY_init( + hpke.as_ptr(), + ffi::EVP_hpke_x25519_hkdf_sha256(), + pkey.as_ptr(), + pkey.len(), + ))?; + + Ok(hpke) + } + } +} diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 6779586a..93d56943 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -128,6 +128,7 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; +pub mod hpke; pub mod memcmp; pub mod nid; pub mod pkcs12; From 5af82912dff26fe3fd2c684df012685eacd3708b Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Mon, 10 Feb 2025 13:58:42 -0800 Subject: [PATCH 08/34] Expose client/server-side ECH Resolves https://github.com/cloudflare/boring/issues/282 --- boring/src/lib.rs | 1 + boring/src/ssl/ech.rs | 43 ++++++++++++++++++ boring/src/ssl/mod.rs | 85 ++++++++++++++++++++++++++++++++++++ boring/src/ssl/test/ech.rs | 67 ++++++++++++++++++++++++++++ boring/src/ssl/test/mod.rs | 2 + boring/test/echconfig | Bin 0 -> 62 bytes boring/test/echconfig-2 | Bin 0 -> 62 bytes boring/test/echconfiglist | Bin 0 -> 64 bytes boring/test/echconfiglist-2 | Bin 0 -> 64 bytes boring/test/echkey | Bin 0 -> 32 bytes boring/test/echkey-2 | 1 + 11 files changed, 199 insertions(+) create mode 100644 boring/src/ssl/ech.rs create mode 100644 boring/src/ssl/test/ech.rs create mode 100644 boring/test/echconfig create mode 100644 boring/test/echconfig-2 create mode 100644 boring/test/echconfiglist create mode 100644 boring/test/echconfiglist-2 create mode 100644 boring/test/echkey create mode 100644 boring/test/echkey-2 diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 93d56943..1b23edac 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -128,6 +128,7 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; +#[cfg(not(feature = "fips"))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/ech.rs b/boring/src/ssl/ech.rs new file mode 100644 index 00000000..d7b49328 --- /dev/null +++ b/boring/src/ssl/ech.rs @@ -0,0 +1,43 @@ +use crate::ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; + +use crate::error::ErrorStack; +use crate::hpke::HpkeKey; +use crate::{cvt_0i, cvt_p}; + +foreign_type_and_impl_send_sync! { + type CType = ffi::SSL_ECH_KEYS; + fn drop = ffi::SSL_ECH_KEYS_free; + + pub struct SslEchKeys; +} + +impl SslEchKeys { + pub fn new() -> Result { + unsafe { + ffi::init(); + cvt_p(ffi::SSL_ECH_KEYS_new()).map(|p| SslEchKeys::from_ptr(p)) + } + } +} + +impl SslEchKeysRef { + pub fn add_key( + &mut self, + is_retry_config: bool, + ech_config: &[u8], + key: HpkeKey, + ) -> Result<(), ErrorStack> { + unsafe { + cvt_0i(ffi::SSL_ECH_KEYS_add( + self.as_ptr(), + is_retry_config as c_int, + ech_config.as_ptr(), + ech_config.len(), + key.as_ptr(), + )) + .map(|_| ()) + } + } +} diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index d4d317a5..01f9c962 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -87,6 +87,8 @@ use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; +#[cfg(not(feature = "fips"))] +use crate::ssl::ech::SslEchKeys; use crate::ssl::error::InnerError; use crate::stack::{Stack, StackRef, Stackable}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; @@ -110,6 +112,8 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; +#[cfg(not(feature = "fips"))] +mod ech; mod error; mod mut_only; #[cfg(test)] @@ -1956,6 +1960,16 @@ impl SslContextBuilder { } } + /// Registers a list of ECH keys on the context. This list should contain new and old + /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function + /// is safe to call even after the `SSL_CTX` has been associated with connections on various + /// threads. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_CTX_set1_ech_keys)] + pub fn set_ech_keys(&mut self, keys: SslEchKeys) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.ctx @@ -3623,6 +3637,77 @@ impl SslRef { pub fn add_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_add1_chain_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } + + /// Configures `ech_config_list` on `SSL` for offering ECH during handshakes. If the server + /// cannot decrypt the encrypted ClientHello, `SSL` will instead handshake using + /// the cleartext parameters of the ClientHelloOuter. + /// + /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH + /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh + /// set of ECHConfigs. If the retry also fails, clients should report a connection failure. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_set1_ech_config_list)] + pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> { + unsafe { + cvt_0i(ffi::SSL_set1_ech_config_list( + self.as_ptr(), + ech_config_list.as_ptr(), + ech_config_list.len(), + )) + .map(|_| ()) + } + } + + /// This function returns a serialized `ECHConfigList` as provided by the + /// server, if one exists. + /// + /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to + /// recover from potential key mismatches. If the result is `Some`, the client should retry the + /// connection using the returned `ECHConfigList`. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_get0_ech_retry_configs)] + pub fn get_ech_retry_configs(&self) -> Option<&[u8]> { + unsafe { + let mut data = ptr::null(); + let mut len: usize = 0; + ffi::SSL_get0_ech_retry_configs(self.as_ptr(), &mut data, &mut len); + + if data.is_null() { + None + } else { + Some(slice::from_raw_parts(data, len)) + } + } + } + + /// If `SSL` is a client and the server rejects ECH, this function returns the public name + /// associated with the ECHConfig that was used to attempt ECH. + /// + /// Clients should call this function during the certificate verification callback to + /// ensure the server's certificate is valid for the public name, which is required to + /// authenticate retry configs. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_get0_ech_name_override)] + pub fn get_ech_name_override(&self) -> Option<&[u8]> { + unsafe { + let mut data: *const c_char = ptr::null(); + let mut len: usize = 0; + ffi::SSL_get0_ech_name_override(self.as_ptr(), &mut data, &mut len); + + if data.is_null() { + None + } else { + Some(slice::from_raw_parts(data as *const u8, len)) + } + } + } + + // Whether or not `SSL` negotiated ECH. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_ech_accepted)] + pub fn ech_accepted(&self) -> bool { + unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 } + } } /// An SSL stream midway through the handshake process. diff --git a/boring/src/ssl/test/ech.rs b/boring/src/ssl/test/ech.rs new file mode 100644 index 00000000..7413240e --- /dev/null +++ b/boring/src/ssl/test/ech.rs @@ -0,0 +1,67 @@ +use crate::hpke::HpkeKey; +use crate::ssl::ech::SslEchKeys; +use crate::ssl::test::Server; +use crate::ssl::HandshakeError; + +// For future reference, these configs are generated by building the bssl tool (the binary is built +// alongside boringssl) and running the following command: +// +// ./bssl generate-ech -out-ech-config-list ./list -out-ech-config ./config -out-private-key ./key +// -public-name ech.com -config-id 1 +static ECH_CONFIG_LIST: &[u8] = include_bytes!("../../../test/echconfiglist"); +static ECH_CONFIG: &[u8] = include_bytes!("../../../test/echconfig"); +static ECH_KEY: &[u8] = include_bytes!("../../../test/echkey"); + +static ECH_CONFIG_2: &[u8] = include_bytes!("../../../test/echconfig-2"); +static ECH_KEY_2: &[u8] = include_bytes!("../../../test/echkey-2"); + +#[test] +fn ech() { + let server = { + let key = HpkeKey::dhkem_p256_sha256(ECH_KEY).unwrap(); + let mut ech_keys = SslEchKeys::new().unwrap(); + ech_keys.add_key(true, ECH_CONFIG, key).unwrap(); + + let mut builder = Server::builder(); + builder.ctx().set_ech_keys(ech_keys).unwrap(); + + builder.build() + }; + + let mut client = server.client_with_root_ca().build().builder(); + client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); + client.ssl().set_hostname("foobar.com").unwrap(); + + let ssl_stream = client.connect(); + assert!(ssl_stream.ssl().ech_accepted()) +} + +#[test] +fn ech_rejection() { + let server = { + let key = HpkeKey::dhkem_p256_sha256(ECH_KEY_2).unwrap(); + let mut ech_keys = SslEchKeys::new().unwrap(); + ech_keys.add_key(true, ECH_CONFIG_2, key).unwrap(); + + let mut builder = Server::builder(); + builder.ctx().set_ech_keys(ech_keys).unwrap(); + + builder.build() + }; + + let mut client = server.client_with_root_ca().build().builder(); + // Server is initialized using `ECH_CONFIG_2`, so using `ECH_CONFIG_LIST` instead of + // `ECH_CONFIG_LIST_2` should trigger rejection. + client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); + client.ssl().set_hostname("foobar.com").unwrap(); + let HandshakeError::Failure(failed_ssl_stream) = client.connect_err() else { + panic!("wrong HandshakeError failure variant!"); + }; + + assert_eq!( + failed_ssl_stream.ssl().get_ech_name_override(), + Some(b"ech.com".to_vec().as_ref()) + ); + assert!(failed_ssl_stream.ssl().get_ech_retry_configs().is_some()); + assert!(!failed_ssl_stream.ssl().ech_accepted()) +} diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 6010cf98..ab11780e 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -26,6 +26,8 @@ use super::CompliancePolicy; mod cert_verify; mod custom_verify; +#[cfg(not(feature = "fips"))] +mod ech; mod private_key_method; mod server; mod session; diff --git a/boring/test/echconfig b/boring/test/echconfig new file mode 100644 index 0000000000000000000000000000000000000000..cd0649cea7d5b603c9d771afcefc68b8faaa31f4 GIT binary patch literal 62 zcmeyz%V5R8punK8TVM0>W7awr$*cNDzc@;i=l5=tdF6k_U<5;E P2KLnC487$1Tm}XJHN+N1 literal 0 HcmV?d00001 diff --git a/boring/test/echconfiglist b/boring/test/echconfiglist new file mode 100644 index 0000000000000000000000000000000000000000..c055475e08ef0f2681f19a9119a6edf4b0549d6b GIT binary patch literal 64 zcmZRu`^U>*#lWDzps-tC^YLTWIu^;R`bWPwN|fjKZj*WCf4_`<_T+?|s3Z>t4hBXr RWM*JbP0r9u&d+6F005gY65Rj* literal 0 HcmV?d00001 diff --git a/boring/test/echconfiglist-2 b/boring/test/echconfiglist-2 new file mode 100644 index 0000000000000000000000000000000000000000..58f0f2241add164da92369ef554629617ace7fb0 GIT binary patch literal 64 zcmZRu`^U>*#mJz*piuWa{@tQQC7b{M%M6_N>)|iYoJ0Qf2nHUIzs literal 0 HcmV?d00001 diff --git a/boring/test/echkey-2 b/boring/test/echkey-2 new file mode 100644 index 00000000..3222ee5e --- /dev/null +++ b/boring/test/echkey-2 @@ -0,0 +1 @@ +§5D$lþ°SLb~Ê.V<À.j¢ç¯:}´rˆ¶… \ No newline at end of file From 24003a04e895447e4ac7cdf070054b6382f8dd7b Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Wed, 12 Feb 2025 10:11:06 -0800 Subject: [PATCH 09/34] Clean up ECH tests --- boring/src/ssl/test/ech.rs | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/boring/src/ssl/test/ech.rs b/boring/src/ssl/test/ech.rs index 7413240e..54926524 100644 --- a/boring/src/ssl/test/ech.rs +++ b/boring/src/ssl/test/ech.rs @@ -1,6 +1,6 @@ use crate::hpke::HpkeKey; use crate::ssl::ech::SslEchKeys; -use crate::ssl::test::Server; +use crate::ssl::test::server::{ClientSslBuilder, Server}; use crate::ssl::HandshakeError; // For future reference, these configs are generated by building the bssl tool (the binary is built @@ -15,12 +15,11 @@ static ECH_KEY: &[u8] = include_bytes!("../../../test/echkey"); static ECH_CONFIG_2: &[u8] = include_bytes!("../../../test/echconfig-2"); static ECH_KEY_2: &[u8] = include_bytes!("../../../test/echkey-2"); -#[test] -fn ech() { +fn bootstrap_ech(config: &[u8], key: &[u8], list: &[u8]) -> (Server, ClientSslBuilder) { let server = { - let key = HpkeKey::dhkem_p256_sha256(ECH_KEY).unwrap(); + let key = HpkeKey::dhkem_p256_sha256(key).unwrap(); let mut ech_keys = SslEchKeys::new().unwrap(); - ech_keys.add_key(true, ECH_CONFIG, key).unwrap(); + ech_keys.add_key(true, config, key).unwrap(); let mut builder = Server::builder(); builder.ctx().set_ech_keys(ech_keys).unwrap(); @@ -29,35 +28,29 @@ fn ech() { }; let mut client = server.client_with_root_ca().build().builder(); - client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); + client.ssl().set_ech_config_list(list).unwrap(); client.ssl().set_hostname("foobar.com").unwrap(); + (server, client) +} + +#[test] +fn ech() { + let (_server, client) = bootstrap_ech(ECH_CONFIG, ECH_KEY, ECH_CONFIG_LIST); + let ssl_stream = client.connect(); assert!(ssl_stream.ssl().ech_accepted()) } #[test] fn ech_rejection() { - let server = { - let key = HpkeKey::dhkem_p256_sha256(ECH_KEY_2).unwrap(); - let mut ech_keys = SslEchKeys::new().unwrap(); - ech_keys.add_key(true, ECH_CONFIG_2, key).unwrap(); - - let mut builder = Server::builder(); - builder.ctx().set_ech_keys(ech_keys).unwrap(); - - builder.build() - }; - - let mut client = server.client_with_root_ca().build().builder(); // Server is initialized using `ECH_CONFIG_2`, so using `ECH_CONFIG_LIST` instead of // `ECH_CONFIG_LIST_2` should trigger rejection. - client.ssl().set_ech_config_list(ECH_CONFIG_LIST).unwrap(); - client.ssl().set_hostname("foobar.com").unwrap(); + let (_server, client) = bootstrap_ech(ECH_CONFIG_2, ECH_KEY_2, ECH_CONFIG_LIST); + let HandshakeError::Failure(failed_ssl_stream) = client.connect_err() else { panic!("wrong HandshakeError failure variant!"); }; - assert_eq!( failed_ssl_stream.ssl().get_ech_name_override(), Some(b"ech.com".to_vec().as_ref()) From 05270fa100a840f766ffd0cb72d9e69cbe5ad21d Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Wed, 12 Feb 2025 09:18:17 -0800 Subject: [PATCH 10/34] Expose SSL_set_enable_ech_grease --- boring/src/ssl/mod.rs | 11 +++++++++++ boring/src/ssl/test/ech.rs | 12 ++++++++++++ 2 files changed, 23 insertions(+) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 01f9c962..726bc339 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -3708,6 +3708,17 @@ impl SslRef { pub fn ech_accepted(&self) -> bool { unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 } } + + // Whether or not to enable ECH grease on `SSL`. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_set_enable_ech_grease)] + pub fn set_enable_ech_grease(&self, enable: bool) { + let enable = if enable { 1 } else { 0 }; + + unsafe { + ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable); + } + } } /// An SSL stream midway through the handshake process. diff --git a/boring/src/ssl/test/ech.rs b/boring/src/ssl/test/ech.rs index 54926524..c94a842d 100644 --- a/boring/src/ssl/test/ech.rs +++ b/boring/src/ssl/test/ech.rs @@ -58,3 +58,15 @@ fn ech_rejection() { assert!(failed_ssl_stream.ssl().get_ech_retry_configs().is_some()); assert!(!failed_ssl_stream.ssl().ech_accepted()) } + +#[test] +fn ech_grease() { + let server = Server::builder().build(); + + let mut client = server.client_with_root_ca().build().builder(); + // Verified with a pcap locally that the ECH extension gets sent due to GREASE + client.ssl().set_enable_ech_grease(true); + + let ssl_stream = client.connect(); + assert!(!ssl_stream.ssl().ech_accepted()) +} From bf0e21cec8f7bfd95996d4112cd4a5a36620682e Mon Sep 17 00:00:00 2001 From: Kornel Date: Sat, 30 Nov 2024 00:12:44 +0000 Subject: [PATCH 11/34] Use corresponds macro --- boring/src/derive.rs | 21 ++---- boring/src/dh.rs | 21 ++---- boring/src/dsa.rs | 36 ++------- boring/src/ec.rs | 158 ++++++++------------------------------- boring/src/ecdsa.rs | 36 ++------- boring/src/fips.rs | 4 +- boring/src/hash.rs | 6 +- boring/src/nid.rs | 12 +-- boring/src/pkcs12.rs | 11 +-- boring/src/pkey.rs | 106 ++++++-------------------- boring/src/rsa.rs | 154 ++++++++------------------------------ boring/src/sign.rs | 92 +++++------------------ boring/src/ssl/mod.rs | 33 ++------ boring/src/symm.rs | 6 +- boring/src/x509/mod.rs | 90 +++++----------------- boring/src/x509/store.rs | 5 +- 16 files changed, 171 insertions(+), 620 deletions(-) diff --git a/boring/src/derive.rs b/boring/src/derive.rs index 66df434f..701d48a3 100644 --- a/boring/src/derive.rs +++ b/boring/src/derive.rs @@ -1,6 +1,7 @@ //! Shared secret derivation. use crate::ffi; use foreign_types::ForeignTypeRef; +use openssl_macros::corresponds; use std::marker::PhantomData; use std::ptr; @@ -25,10 +26,7 @@ impl Drop for Deriver<'_> { #[allow(clippy::len_without_is_empty)] impl<'a> Deriver<'a> { /// Creates a new `Deriver` using the provided private key. - /// - /// This corresponds to [`EVP_PKEY_derive_init`]. - /// - /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + #[corresponds(EVP_PKEY_derive_init)] pub fn new(key: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, @@ -41,10 +39,7 @@ impl<'a> Deriver<'a> { } /// Sets the peer key used for secret derivation. - /// - /// This corresponds to [`EVP_PKEY_derive_set_peer`]: - /// - /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + #[corresponds(EVP_PKEY_derive_set_peer)] pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -55,10 +50,7 @@ impl<'a> Deriver<'a> { /// Returns the size of the shared secret. /// /// It can be used to size the buffer passed to [`Deriver::derive`]. - /// - /// This corresponds to [`EVP_PKEY_derive`]. - /// - /// [`Deriver::derive`]: #method.derive + #[corresponds(EVP_PKEY_derive)] /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html pub fn len(&mut self) -> Result { unsafe { @@ -70,10 +62,7 @@ impl<'a> Deriver<'a> { /// Derives a shared secret between the two keys, writing it into the buffer. /// /// Returns the number of bytes written. - /// - /// This corresponds to [`EVP_PKEY_derive`]. - /// - /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html + #[corresponds(EVP_PKEY_derive)] pub fn derive(&mut self, buf: &mut [u8]) -> Result { let mut len = buf.len(); unsafe { diff --git a/boring/src/dh.rs b/boring/src/dh.rs index 96a8c63d..c8449d86 100644 --- a/boring/src/dh.rs +++ b/boring/src/dh.rs @@ -1,6 +1,7 @@ use crate::error::ErrorStack; use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; +use openssl_macros::corresponds; use std::mem; use std::ptr; @@ -25,20 +26,14 @@ where /// Serializes the parameters into a PEM-encoded PKCS#3 DHparameter structure. /// /// The output will have a header of `-----BEGIN DH PARAMETERS-----`. - /// - /// This corresponds to [`PEM_write_bio_DHparams`]. - /// - /// [`PEM_write_bio_DHparams`]: https://www.openssl.org/docs/manmaster/man3/PEM_write_bio_DHparams.html + #[corresponds(PEM_write_bio_DHparams)] params_to_pem, ffi::PEM_write_bio_DHparams } to_der! { /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. - /// - /// This corresponds to [`i2d_DHparams`]. - /// - /// [`i2d_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DHparams.html + #[corresponds(i2d_DHparams)] params_to_der, ffi::i2d_DHparams } @@ -58,10 +53,7 @@ impl Dh { /// Deserializes a PEM-encoded PKCS#3 DHpararameters structure. /// /// The input should have a header of `-----BEGIN DH PARAMETERS-----`. - /// - /// This corresponds to [`PEM_read_bio_DHparams`]. - /// - /// [`PEM_read_bio_DHparams`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DHparams.html + #[corresponds(PEM_read_bio_DHparams)] params_from_pem, Dh, ffi::PEM_read_bio_DHparams @@ -69,10 +61,7 @@ impl Dh { from_der! { /// Deserializes a DER-encoded PKCS#3 DHparameters structure. - /// - /// This corresponds to [`d2i_DHparams`]. - /// - /// [`d2i_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_DHparams.html + #[corresponds(d2i_DHparams)] params_from_der, Dh, ffi::d2i_DHparams, diff --git a/boring/src/dsa.rs b/boring/src/dsa.rs index d9c35505..72d6947e 100644 --- a/boring/src/dsa.rs +++ b/boring/src/dsa.rs @@ -8,6 +8,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_uint; +use openssl_macros::corresponds; use std::fmt; use std::mem; use std::ptr; @@ -84,20 +85,14 @@ where /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_DSA_PUBKEY`]. - /// - /// [`PEM_write_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSA_PUBKEY.html + #[corresponds(PEM_write_bio_DSA_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_DSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. - /// - /// This corresponds to [`i2d_DSA_PUBKEY`]. - /// - /// [`i2d_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DSA_PUBKEY.html + #[corresponds(i2d_DSA_PUBKEY)] public_key_to_der, ffi::i2d_DSA_PUBKEY } @@ -120,18 +115,12 @@ where /// Serializes the private key to a PEM-encoded DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_DSAPrivateKey`]. - /// - /// [`PEM_write_bio_DSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSAPrivateKey.html + #[corresponds(PEM_write_bio_DSAPrivateKey)] private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_DSAPrivateKey`]. - /// - /// [`PEM_write_bio_DSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSAPrivateKey.html + #[corresponds(PEM_write_bio_DSAPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_DSAPrivateKey } @@ -151,10 +140,7 @@ where T: HasParams, { /// Returns the maximum size of the signature output by `self` in bytes. - /// - /// OpenSSL documentation at [`DSA_size`] - /// - /// [`DSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_size.html + #[corresponds(DSA_size)] pub fn size(&self) -> u32 { unsafe { ffi::DSA_size(self.as_ptr()) as u32 } } @@ -244,10 +230,7 @@ impl Dsa { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_read_bio_DSA_PUBKEY`]. - /// - /// [`PEM_read_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DSA_PUBKEY.html + #[corresponds(PEM_read_bio_DSA_PUBKEY)] public_key_from_pem, Dsa, ffi::PEM_read_bio_DSA_PUBKEY @@ -255,10 +238,7 @@ impl Dsa { from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. - /// - /// This corresponds to [`d2i_DSA_PUBKEY`]. - /// - /// [`d2i_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_DSA_PUBKEY.html + #[corresponds(d2i_DSA_PUBKEY)] public_key_from_der, Dsa, ffi::d2i_DSA_PUBKEY, diff --git a/boring/src/ec.rs b/boring/src/ec.rs index bbc6638d..8008927a 100644 --- a/boring/src/ec.rs +++ b/boring/src/ec.rs @@ -18,6 +18,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; +use openssl_macros::corresponds; use std::fmt; use std::ptr; @@ -111,10 +112,7 @@ foreign_type_and_impl_send_sync! { impl EcGroup { /// Returns the group of a standard named curve. - /// - /// OpenSSL documentation at [`EC_GROUP_new`]. - /// - /// [`EC_GROUP_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_new.html + #[corresponds(EC_GROUP_new)] pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); @@ -150,10 +148,7 @@ impl EcGroupRef { } /// Places the cofactor of the group in the provided `BigNum`. - /// - /// OpenSSL documentation at [`EC_GROUP_get_cofactor`] - /// - /// [`EC_GROUP_get_cofactor`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_cofactor.html + #[corresponds(EC_GROUP_get_cofactor)] pub fn cofactor( &self, cofactor: &mut BigNumRef, @@ -170,29 +165,20 @@ impl EcGroupRef { } /// Returns the degree of the curve. - /// - /// OpenSSL documentation at [`EC_GROUP_get_degree`] - /// - /// [`EC_GROUP_get_degree`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_degree.html + #[corresponds(EC_GROUP_get_degree)] #[allow(clippy::unnecessary_cast)] pub fn degree(&self) -> u32 { unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } } /// Returns the number of bits in the group order. - /// - /// OpenSSL documentation at [`EC_GROUP_order_bits`] - /// - /// [`EC_GROUP_order_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_order_bits.html + #[corresponds(EC_GROUP_order_bits)] pub fn order_bits(&self) -> u32 { unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } } /// Returns the generator for the given curve as a [`EcPoint`]. - /// - /// OpenSSL documentation at [`EC_GROUP_get0_generator`] - /// - /// [`EC_GROUP_get0_generator`]: https://www.openssl.org/docs/man1.1.0/man3/EC_GROUP_get0_generator.html + #[corresponds(EC_GROUP_get0_generator)] pub fn generator(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); @@ -201,10 +187,7 @@ impl EcGroupRef { } /// Places the order of the curve in the provided `BigNum`. - /// - /// OpenSSL documentation at [`EC_GROUP_get_order`] - /// - /// [`EC_GROUP_get_order`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_order.html + #[corresponds(EC_GROUP_get_order)] pub fn order( &self, order: &mut BigNumRef, @@ -232,10 +215,7 @@ impl EcGroupRef { } /// Returns the name of the curve, if a name is associated. - /// - /// OpenSSL documentation at [`EC_GROUP_get_curve_name`] - /// - /// [`EC_GROUP_get_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_name.html + #[corresponds(EC_GROUP_get_curve_name)] pub fn curve_name(&self) -> Option { let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; if nid > 0 { @@ -260,10 +240,7 @@ foreign_type_and_impl_send_sync! { impl EcPointRef { /// Computes `a + b`, storing the result in `self`. - /// - /// OpenSSL documentation at [`EC_POINT_add`] - /// - /// [`EC_POINT_add`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_add.html + #[corresponds(EC_POINT_add)] pub fn add( &mut self, group: &EcGroupRef, @@ -284,10 +261,7 @@ impl EcPointRef { } /// Computes `q * m`, storing the result in `self`. - /// - /// OpenSSL documentation at [`EC_POINT_mul`] - /// - /// [`EC_POINT_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_mul.html + #[corresponds(EC_POINT_mul)] pub fn mul( &mut self, group: &EcGroupRef, @@ -353,10 +327,7 @@ impl EcPointRef { } /// Inverts `self`. - /// - /// OpenSSL documentation at [`EC_POINT_invert`] - /// - /// [`EC_POINT_invert`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_invert.html + #[corresponds(EC_POINT_invert)] pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_invert( @@ -369,10 +340,7 @@ impl EcPointRef { } /// Serializes the point to a binary representation. - /// - /// OpenSSL documentation at [`EC_POINT_point2oct`] - /// - /// [`EC_POINT_point2oct`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_point2oct.html + #[corresponds(EC_POINT_point2oct)] pub fn to_bytes( &self, group: &EcGroupRef, @@ -409,10 +377,7 @@ impl EcPointRef { } /// Creates a new point on the specified curve with the same value. - /// - /// OpenSSL documentation at [`EC_POINT_dup`] - /// - /// [`EC_POINT_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_dup.html + #[corresponds(EC_POINT_dup)] pub fn to_owned(&self, group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(|p| EcPoint::from_ptr(p)) @@ -443,10 +408,7 @@ impl EcPointRef { /// Place affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s - /// - /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GFp`] - /// - /// [`EC_POINT_get_affine_coordinates_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GFp.html + #[corresponds(EC_POINT_get_affine_coordinates_GFp)] pub fn affine_coordinates_gfp( &self, group: &EcGroupRef, @@ -469,19 +431,13 @@ impl EcPointRef { impl EcPoint { /// Creates a new point on the specified curve. - /// - /// OpenSSL documentation at [`EC_POINT_new`] - /// - /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html + #[corresponds(EC_POINT_new)] pub fn new(group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(|p| EcPoint::from_ptr(p)) } } /// Creates point from a binary representation - /// - /// OpenSSL documentation at [`EC_POINT_oct2point`] - /// - /// [`EC_POINT_oct2point`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_oct2point.html + #[corresponds(EC_POINT_oct2point)] pub fn from_bytes( group: &EcGroupRef, buf: &[u8], @@ -507,9 +463,6 @@ generic_foreign_type_and_impl_send_sync! { /// Public and optional Private key on the given curve /// - /// OpenSSL documentation at [`EC_KEY_new`] - /// - /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html pub struct EcKey; /// Reference to [`EcKey`] @@ -526,37 +479,25 @@ where /// Serializes the private key to a PEM-encoded ECPrivateKey structure. /// /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. - /// - /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html + #[corresponds(PEM_write_bio_ECPrivateKey)] private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. /// /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. - /// - /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html + #[corresponds(PEM_write_bio_ECPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_ECPrivateKey } to_der! { /// Serializes the private key into a DER-encoded ECPrivateKey structure. - /// - /// This corresponds to [`i2d_ECPrivateKey`]. - /// - /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html + #[corresponds(i2d_ECPrivateKey)] private_key_to_der, ffi::i2d_ECPrivateKey } /// Return [`EcPoint`] associated with the private key - /// - /// OpenSSL documentation at [`EC_KEY_get0_private_key`] - /// - /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html + #[corresponds(EC_KEY_get0_private_key)] pub fn private_key(&self) -> &BigNumRef { unsafe { let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); @@ -570,10 +511,7 @@ where T: HasPublic, { /// Returns the public key. - /// - /// OpenSSL documentation at [`EC_KEY_get0_public_key`] - /// - /// [`EC_KEY_get0_public_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html + #[corresponds(EC_KEY_get0_public_key)] pub fn public_key(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); @@ -585,20 +523,14 @@ where /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_EC_PUBKEY`]. - /// - /// [`PEM_write_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_EC_PUBKEY.html + #[corresponds(PEM_write_bio_EC_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_EC_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. - /// - /// This corresponds to [`i2d_EC_PUBKEY`]. - /// - /// [`i2d_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_EC_PUBKEY.html + #[corresponds(i2d_EC_PUBKEY)] public_key_to_der, ffi::i2d_EC_PUBKEY } @@ -609,10 +541,7 @@ where T: HasParams, { /// Return [`EcGroup`] of the `EcKey` - /// - /// OpenSSL documentation at [`EC_KEY_get0_group`] - /// - /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html + #[corresponds(EC_KEY_get0_group)] pub fn group(&self) -> &EcGroupRef { unsafe { let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); @@ -621,10 +550,7 @@ where } /// Checks the key for validity. - /// - /// OpenSSL documentation at [`EC_KEY_check_key`] - /// - /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html + #[corresponds(EC_KEY_check_key)] pub fn check_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } } @@ -647,10 +573,7 @@ impl EcKey { /// /// It will not have an associated public or private key. This kind of key is primarily useful /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. - /// - /// OpenSSL documentation at [`EC_KEY_new_by_curve_name`] - /// - /// [`EC_KEY_new_by_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new_by_curve_name.html + #[corresponds(EC_KEY_new_by_curve_name)] pub fn from_curve_name(nid: Nid) -> Result, ErrorStack> { unsafe { init(); @@ -659,10 +582,7 @@ impl EcKey { } /// Constructs an `EcKey` corresponding to a curve. - /// - /// This corresponds to [`EC_KEY_set_group`]. - /// - /// [`EC_KEY_set_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html + #[corresponds(EC_KEY_set_group)] pub fn from_group(group: &EcGroupRef) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) @@ -743,10 +663,7 @@ impl EcKey { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_read_bio_EC_PUBKEY`]. - /// - /// [`PEM_read_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_EC_PUBKEY.html + #[corresponds(PEM_read_bio_EC_PUBKEY)] public_key_from_pem, EcKey, ffi::PEM_read_bio_EC_PUBKEY @@ -754,10 +671,7 @@ impl EcKey { from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. - /// - /// This corresponds to [`d2i_EC_PUBKEY`]. - /// - /// [`d2i_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_EC_PUBKEY.html + #[corresponds(d2i_EC_PUBKEY)] public_key_from_der, EcKey, ffi::d2i_EC_PUBKEY, @@ -811,15 +725,13 @@ impl EcKey { /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. - /// - /// This corresponds to `PEM_read_bio_ECPrivateKey`. + #[corresponds(PEM_read_bio_ECPrivateKey)] private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. - /// - /// This corresponds to `PEM_read_bio_ECPrivateKey`. + #[corresponds(PEM_read_bio_ECPrivateKey)] private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. @@ -827,8 +739,7 @@ impl EcKey { /// The callback should fill the password into the provided buffer and return its length. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. - /// - /// This corresponds to `PEM_read_bio_ECPrivateKey`. + #[corresponds(PEM_read_bio_ECPrivateKey)] private_key_from_pem_callback, EcKey, ffi::PEM_read_bio_ECPrivateKey @@ -836,10 +747,7 @@ impl EcKey { from_der! { /// Decodes a DER-encoded elliptic curve private key structure. - /// - /// This corresponds to [`d2i_ECPrivateKey`]. - /// - /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html + #[corresponds(d2i_ECPrivateKey)] private_key_from_der, EcKey, ffi::d2i_ECPrivateKey, diff --git a/boring/src/ecdsa.rs b/boring/src/ecdsa.rs index 782dbf20..a56f7b68 100644 --- a/boring/src/ecdsa.rs +++ b/boring/src/ecdsa.rs @@ -3,6 +3,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, size_t}; +use openssl_macros::corresponds; use std::mem; use std::ptr; @@ -26,10 +27,7 @@ foreign_type_and_impl_send_sync! { impl EcdsaSig { /// Computes a digital signature of the hash value `data` using the private EC key eckey. - /// - /// OpenSSL documentation at [`ECDSA_do_sign`] - /// - /// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html + #[corresponds(ECDSA_do_sign)] pub fn sign(data: &[u8], eckey: &EcKeyRef) -> Result where T: HasPrivate, @@ -47,10 +45,7 @@ impl EcdsaSig { /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a /// ECDSA signature. - /// - /// OpenSSL documentation at [`ECDSA_SIG_set0`] - /// - /// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html + #[corresponds(ECDSA_SIG_set0)] pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::ECDSA_SIG_new())?; @@ -62,10 +57,7 @@ impl EcdsaSig { from_der! { /// Decodes a DER-encoded ECDSA signature. - /// - /// This corresponds to [`d2i_ECDSA_SIG`]. - /// - /// [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html + #[corresponds(d2i_ECDSA_SIG)] from_der, EcdsaSig, ffi::d2i_ECDSA_SIG, @@ -76,19 +68,13 @@ impl EcdsaSig { impl EcdsaSigRef { to_der! { /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. - /// - /// This corresponds to [`i2d_ECDSA_SIG`]. - /// - /// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html + #[corresponds(i2d_ECDSA_SIG)] to_der, ffi::i2d_ECDSA_SIG } /// Verifies if the signature is a valid ECDSA signature using the given public key. - /// - /// OpenSSL documentation at [`ECDSA_do_verify`] - /// - /// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html + #[corresponds(ECDSA_do_verify)] pub fn verify(&self, data: &[u8], eckey: &EcKeyRef) -> Result where T: HasPublic, @@ -106,10 +92,7 @@ impl EcdsaSigRef { } /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) - /// - /// OpenSSL documentation at [`ECDSA_SIG_get0`] - /// - /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html + #[corresponds(ECDSA_SIG_get0)] pub fn r(&self) -> &BigNumRef { unsafe { let mut r = ptr::null(); @@ -119,10 +102,7 @@ impl EcdsaSigRef { } /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) - /// - /// OpenSSL documentation at [`ECDSA_SIG_get0`] - /// - /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html + #[corresponds(ECDSA_SIG_get0)] pub fn s(&self) -> &BigNumRef { unsafe { let mut s = ptr::null(); diff --git a/boring/src/fips.rs b/boring/src/fips.rs index e578ae75..de28f260 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -4,10 +4,10 @@ //! //! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf use crate::ffi; +use openssl_macros::corresponds; /// Determines if the library is running in the FIPS 140-2 mode of operation. -/// -/// This corresponds to `FIPS_mode`. +#[corresponds(FIPS_mode)] pub fn enabled() -> bool { unsafe { ffi::FIPS_mode() != 0 } } diff --git a/boring/src/hash.rs b/boring/src/hash.rs index 76167723..ba5d7bab 100644 --- a/boring/src/hash.rs +++ b/boring/src/hash.rs @@ -1,4 +1,5 @@ use crate::ffi; +use openssl_macros::corresponds; use std::convert::TryInto; use std::ffi::{c_uint, c_void}; use std::fmt; @@ -26,10 +27,7 @@ impl MessageDigest { } /// Returns the `MessageDigest` corresponding to an `Nid`. - /// - /// This corresponds to [`EVP_get_digestbynid`]. - /// - /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + #[corresponds(EVP_get_digestbynid)] pub fn from_nid(type_: Nid) -> Option { unsafe { let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); diff --git a/boring/src/nid.rs b/boring/src/nid.rs index a3b0f11a..11607626 100644 --- a/boring/src/nid.rs +++ b/boring/src/nid.rs @@ -1,6 +1,7 @@ //! A collection of numerical identifiers for OpenSSL objects. use crate::ffi; use libc::{c_char, c_int}; +use openssl_macros::corresponds; use std::ffi::CStr; use std::str; @@ -61,8 +62,7 @@ impl Nid { } /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. - /// - /// This corresponds to `OBJ_find_sigid_algs`. + #[corresponds(OBJ_find_sigid_algs)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn signature_algorithms(&self) -> Option { unsafe { @@ -80,9 +80,7 @@ impl Nid { } /// Return the string representation of a `Nid` (long) - /// This corresponds to [`OBJ_nid2ln`] - /// - /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html + #[corresponds(OBJ_nid2ln)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn long_name(&self) -> Result<&'static str, ErrorStack> { unsafe { @@ -92,9 +90,7 @@ impl Nid { } /// Return the string representation of a `Nid` (short) - /// This corresponds to [`OBJ_nid2sn`] - /// - /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html + #[corresponds(OBJ_nid2sn)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn short_name(&self) -> Result<&'static str, ErrorStack> { unsafe { diff --git a/boring/src/pkcs12.rs b/boring/src/pkcs12.rs index 4caec029..8604f6d1 100644 --- a/boring/src/pkcs12.rs +++ b/boring/src/pkcs12.rs @@ -3,6 +3,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; +use openssl_macros::corresponds; use std::ffi::CString; use std::ptr; @@ -25,10 +26,7 @@ foreign_type_and_impl_send_sync! { impl Pkcs12Ref { to_der! { /// Serializes the `Pkcs12` to its standard DER encoding. - /// - /// This corresponds to [`i2d_PKCS12`]. - /// - /// [`i2d_PKCS12`]: https://www.openssl.org/docs/manmaster/man3/i2d_PKCS12.html + #[corresponds(i2d_PKCS12)] to_der, ffi::i2d_PKCS12 } @@ -67,10 +65,7 @@ impl Pkcs12Ref { impl Pkcs12 { from_der! { /// Deserializes a DER-encoded PKCS#12 archive. - /// - /// This corresponds to [`d2i_PKCS12`]. - /// - /// [`d2i_PKCS12`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PKCS12.html + #[corresponds(d2i_PKCS12)] from_der, Pkcs12, ffi::d2i_PKCS12, diff --git a/boring/src/pkey.rs b/boring/src/pkey.rs index 9897635e..1c4012ca 100644 --- a/boring/src/pkey.rs +++ b/boring/src/pkey.rs @@ -43,6 +43,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; +use openssl_macros::corresponds; use std::ffi::CString; use std::fmt; use std::mem; @@ -138,10 +139,7 @@ impl ToOwned for PKeyRef { impl PKeyRef { /// Returns a copy of the internal RSA key. - /// - /// This corresponds to [`EVP_PKEY_get1_RSA`]. - /// - /// [`EVP_PKEY_get1_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_RSA.html + #[corresponds(EVP_PKEY_get1_RSA)] pub fn rsa(&self) -> Result, ErrorStack> { unsafe { let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?; @@ -150,10 +148,7 @@ impl PKeyRef { } /// Returns a copy of the internal DSA key. - /// - /// This corresponds to [`EVP_PKEY_get1_DSA`]. - /// - /// [`EVP_PKEY_get1_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DSA.html + #[corresponds(EVP_PKEY_get1_DSA)] pub fn dsa(&self) -> Result, ErrorStack> { unsafe { let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?; @@ -162,10 +157,7 @@ impl PKeyRef { } /// Returns a copy of the internal DH key. - /// - /// This corresponds to [`EVP_PKEY_get1_DH`]. - /// - /// [`EVP_PKEY_get1_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DH.html + #[corresponds(EVP_PKEY_get1_DH)] pub fn dh(&self) -> Result, ErrorStack> { unsafe { let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?; @@ -174,10 +166,7 @@ impl PKeyRef { } /// Returns a copy of the internal elliptic curve key. - /// - /// This corresponds to [`EVP_PKEY_get1_EC_KEY`]. - /// - /// [`EVP_PKEY_get1_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_EC_KEY.html + #[corresponds(EVP_PKEY_get1_EC_KEY)] pub fn ec_key(&self) -> Result, ErrorStack> { unsafe { let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?; @@ -186,19 +175,13 @@ impl PKeyRef { } /// Returns the `Id` that represents the type of this key. - /// - /// This corresponds to [`EVP_PKEY_id`]. - /// - /// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html + #[corresponds(EVP_PKEY_id)] pub fn id(&self) -> Id { unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) } } /// Returns the maximum size of a signature in bytes. - /// - /// This corresponds to [`EVP_PKEY_size`]. - /// - /// [`EVP_PKEY_size`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_size.html + #[corresponds(EVP_PKEY_size)] pub fn size(&self) -> usize { unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize } } @@ -212,20 +195,14 @@ where /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_PUBKEY`]. - /// - /// [`PEM_write_bio_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PUBKEY.html + #[corresponds(PEM_write_bio_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. - /// - /// This corresponds to [`i2d_PUBKEY`]. - /// - /// [`i2d_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_PUBKEY.html + #[corresponds(i2d_PUBKEY)] public_key_to_der, ffi::i2d_PUBKEY } @@ -255,28 +232,19 @@ where /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure. /// /// The output will have a header of `-----BEGIN PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. - /// - /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html + #[corresponds(PEM_write_bio_PKCS8PrivateKey)] private_key_to_pem_pkcs8, /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure. /// /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. - /// - /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html + #[corresponds(PEM_write_bio_PKCS8PrivateKey)] private_key_to_pem_pkcs8_passphrase, ffi::PEM_write_bio_PKCS8PrivateKey } to_der! { /// Serializes the private key to a DER-encoded key type specific format. - /// - /// This corresponds to [`i2d_PrivateKey`]. - /// - /// [`i2d_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_PrivateKey.html + #[corresponds(i2d_PrivateKey)] private_key_to_der, ffi::i2d_PrivateKey } @@ -285,16 +253,10 @@ where // "identical to the corresponding PEM function", and it's declared in pem.h. private_key_to_pem! { /// Serializes the private key to a DER-encoded PKCS#8 PrivateKeyInfo structure. - /// - /// This corresponds to [`i2d_PKCS8PrivateKey_bio`]. - /// - /// [`i2d_PKCS8PrivateKey_bio`]: https://www.openssl.org/docs/man1.1.1/man3/i2d_PKCS8PrivateKey_bio.html + #[corresponds(i2d_PKCS8PrivateKey_bio)] private_key_to_der_pkcs8, /// Serializes the private key to a DER-encoded PKCS#8 EncryptedPrivateKeyInfo structure. - /// - /// This corresponds to [`i2d_PKCS8PrivateKey_bio`]. - /// - /// [`i2d_PKCS8PrivateKey_bio`]: https://www.openssl.org/docs/man1.1.1/man3/i2d_PKCS8PrivateKey_bio.html + #[corresponds(i2d_PKCS8PrivateKey_bio)] private_key_to_der_pkcs8_passphrase, ffi::i2d_PKCS8PrivateKey_bio } @@ -325,10 +287,7 @@ impl Clone for PKey { impl PKey { /// Creates a new `PKey` containing an RSA key. - /// - /// This corresponds to [`EVP_PKEY_assign_RSA`]. - /// - /// [`EVP_PKEY_assign_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_RSA.html + #[corresponds(EVP_PKEY_assign_RSA)] pub fn from_rsa(rsa: Rsa) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; @@ -344,10 +303,7 @@ impl PKey { } /// Creates a new `PKey` containing an elliptic curve key. - /// - /// This corresponds to [`EVP_PKEY_assign_EC_KEY`]. - /// - /// [`EVP_PKEY_assign_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_EC_KEY.html + #[corresponds(EVP_PKEY_assign_EC_KEY)] pub fn from_ec_key(ec_key: EcKey) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; @@ -366,26 +322,17 @@ impl PKey { impl PKey { private_key_from_pem! { /// Deserializes a private key from a PEM-encoded key type specific format. - /// - /// This corresponds to [`PEM_read_bio_PrivateKey`]. - /// - /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + #[corresponds(PEM_read_bio_PrivateKey)] private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted key type specific format. - /// - /// This corresponds to [`PEM_read_bio_PrivateKey`]. - /// - /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + #[corresponds(PEM_read_bio_PrivateKey)] private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted key type specific format. /// /// The callback should fill the password into the provided buffer and return its length. - /// - /// This corresponds to [`PEM_read_bio_PrivateKey`]. - /// - /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html + #[corresponds(PEM_read_bio_PrivateKey)] private_key_from_pem_callback, PKey, ffi::PEM_read_bio_PrivateKey @@ -397,10 +344,7 @@ impl PKey { /// This function will automatically attempt to detect the underlying key format, and /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific /// formats. - /// - /// This corresponds to [`d2i_AutoPrivateKey`]. - /// - /// [`d2i_AutoPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_AutoPrivateKey.html + #[corresponds(d2i_AutoPrivateKey)] private_key_from_der, PKey, ffi::d2i_AutoPrivateKey, @@ -481,10 +425,7 @@ impl PKey { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_read_bio_PUBKEY`]. - /// - /// [`PEM_read_bio_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PUBKEY.html + #[corresponds(PEM_read_bio_PUBKEY)] public_key_from_pem, PKey, ffi::PEM_read_bio_PUBKEY @@ -492,10 +433,7 @@ impl PKey { from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure. - /// - /// This corresponds to [`d2i_PUBKEY`]. - /// - /// [`d2i_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PUBKEY.html + #[corresponds(d2i_PUBKEY)] public_key_from_der, PKey, ffi::d2i_PUBKEY, diff --git a/boring/src/rsa.rs b/boring/src/rsa.rs index 5b85e9e1..7bb641fb 100644 --- a/boring/src/rsa.rs +++ b/boring/src/rsa.rs @@ -26,6 +26,7 @@ use crate::ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; +use openssl_macros::corresponds; use std::fmt; use std::mem; use std::ptr; @@ -113,28 +114,19 @@ where /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. - /// - /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html + #[corresponds(PEM_write_bio_RSAPrivateKey)] private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. - /// - /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html + #[corresponds(PEM_write_bio_RSAPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_RSAPrivateKey } to_der! { /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure. - /// - /// This corresponds to [`i2d_RSAPrivateKey`]. - /// - /// [`i2d_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPrivateKey.html + #[corresponds(i2d_RSAPrivateKey)] private_key_to_der, ffi::i2d_RSAPrivateKey } @@ -194,10 +186,7 @@ where } /// Returns a reference to the private exponent of the key. - /// - /// This corresponds to [`RSA_get0_key`]. - /// - /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_key)] pub fn d(&self) -> &BigNumRef { unsafe { let mut d = ptr::null(); @@ -207,10 +196,7 @@ where } /// Returns a reference to the first factor of the exponent of the key. - /// - /// This corresponds to [`RSA_get0_factors`]. - /// - /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_factors)] pub fn p(&self) -> Option<&BigNumRef> { unsafe { let mut p = ptr::null(); @@ -224,10 +210,7 @@ where } /// Returns a reference to the second factor of the exponent of the key. - /// - /// This corresponds to [`RSA_get0_factors`]. - /// - /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_factors)] pub fn q(&self) -> Option<&BigNumRef> { unsafe { let mut q = ptr::null(); @@ -241,10 +224,7 @@ where } /// Returns a reference to the first exponent used for CRT calculations. - /// - /// This corresponds to [`RSA_get0_crt_params`]. - /// - /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_crt_params)] pub fn dmp1(&self) -> Option<&BigNumRef> { unsafe { let mut dp = ptr::null(); @@ -258,10 +238,7 @@ where } /// Returns a reference to the second exponent used for CRT calculations. - /// - /// This corresponds to [`RSA_get0_crt_params`]. - /// - /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_crt_params)] pub fn dmq1(&self) -> Option<&BigNumRef> { unsafe { let mut dq = ptr::null(); @@ -275,10 +252,7 @@ where } /// Returns a reference to the coefficient used for CRT calculations. - /// - /// This corresponds to [`RSA_get0_crt_params`]. - /// - /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_crt_params)] pub fn iqmp(&self) -> Option<&BigNumRef> { unsafe { let mut qi = ptr::null(); @@ -292,10 +266,7 @@ where } /// Validates RSA parameters for correctness - /// - /// This corresponds to [`RSA_check_key`]. - /// - /// [`RSA_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_check_key.html + #[corresponds(RSA_check_key)] #[allow(clippy::unnecessary_cast)] pub fn check_key(&self) -> Result { unsafe { @@ -317,20 +288,14 @@ where /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_RSA_PUBKEY`]. - /// - /// [`PEM_write_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html + #[corresponds(PEM_write_bio_RSA_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_RSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. - /// - /// This corresponds to [`i2d_RSA_PUBKEY`]. - /// - /// [`i2d_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSA_PUBKEY.html + #[corresponds(i2d_RSA_PUBKEY)] public_key_to_der, ffi::i2d_RSA_PUBKEY } @@ -339,29 +304,20 @@ where /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure. /// /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_write_bio_RSAPublicKey`]. - /// - /// [`PEM_write_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html + #[corresponds(PEM_write_bio_RSAPublicKey)] public_key_to_pem_pkcs1, ffi::PEM_write_bio_RSAPublicKey } to_der! { /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure. - /// - /// This corresponds to [`i2d_RSAPublicKey`]. - /// - /// [`i2d_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPublicKey.html + #[corresponds(i2d_RSAPublicKey)] public_key_to_der_pkcs1, ffi::i2d_RSAPublicKey } /// Returns the size of the modulus in bytes. - /// - /// This corresponds to [`RSA_size`]. - /// - /// [`RSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_size.html + #[corresponds(RSA_size)] #[allow(clippy::unnecessary_cast)] pub fn size(&self) -> u32 { unsafe { ffi::RSA_size(self.as_ptr()) as u32 } @@ -420,10 +376,7 @@ where } /// Returns a reference to the modulus of the key. - /// - /// This corresponds to [`RSA_get0_key`]. - /// - /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_key)] pub fn n(&self) -> &BigNumRef { unsafe { let mut n = ptr::null(); @@ -433,10 +386,7 @@ where } /// Returns a reference to the public exponent of the key. - /// - /// This corresponds to [`RSA_get0_key`]. - /// - /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html + #[corresponds(RSA_get0_key)] pub fn e(&self) -> &BigNumRef { unsafe { let mut e = ptr::null(); @@ -451,10 +401,7 @@ impl Rsa { /// /// `n` is the modulus common to both public and private key. /// `e` is the public exponent. - /// - /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. - /// - /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html + #[corresponds(RSA_new)] /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { unsafe { @@ -469,10 +416,7 @@ impl Rsa { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_read_bio_RSA_PUBKEY`]. - /// - /// [`PEM_read_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSA_PUBKEY.html + #[corresponds(PEM_read_bio_RSA_PUBKEY)] public_key_from_pem, Rsa, ffi::PEM_read_bio_RSA_PUBKEY @@ -482,10 +426,7 @@ impl Rsa { /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure. /// /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`. - /// - /// This corresponds to [`PEM_read_bio_RSAPublicKey`]. - /// - /// [`PEM_read_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSAPublicKey.html + #[corresponds(PEM_read_bio_RSAPublicKey)] public_key_from_pem_pkcs1, Rsa, ffi::PEM_read_bio_RSAPublicKey @@ -493,10 +434,7 @@ impl Rsa { from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key. - /// - /// This corresponds to [`d2i_RSA_PUBKEY`]. - /// - /// [`d2i_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + #[corresponds(d2i_RSA_PUBKEY)] public_key_from_der, Rsa, ffi::d2i_RSA_PUBKEY, @@ -505,10 +443,7 @@ impl Rsa { from_der! { /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure. - /// - /// This corresponds to [`d2i_RSAPublicKey`]. - /// - /// [`d2i_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + #[corresponds(d2i_RSAPublicKey)] public_key_from_der_pkcs1, Rsa, ffi::d2i_RSAPublicKey, @@ -525,10 +460,7 @@ impl RsaPrivateKeyBuilder { /// /// `n` is the modulus common to both public and private key. /// `e` is the public exponent and `d` is the private exponent. - /// - /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. - /// - /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html + #[corresponds(RSA_new)] /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { unsafe { @@ -545,10 +477,8 @@ impl RsaPrivateKeyBuilder { /// /// `p` and `q` are the first and second factors of `n`. /// - /// This correspond to [`RSA_set0_factors`]. - /// - /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html // FIXME should be infallible + #[corresponds(RSA_set0_factors)] pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { unsafe { RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); @@ -562,10 +492,8 @@ impl RsaPrivateKeyBuilder { /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for /// CRT calculations which is used to speed up RSA operations. /// - /// This correspond to [`RSA_set0_crt_params`]. - /// - /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html // FIXME should be infallible + #[corresponds(RSA_set0_crt_params)] pub fn set_crt_params( self, dmp1: BigNum, @@ -615,10 +543,7 @@ impl Rsa { /// Generates a public/private key pair with the specified size. /// /// The public exponent will be 65537. - /// - /// This corresponds to [`RSA_generate_key_ex`]. - /// - /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html + #[corresponds(RSA_generate_key_ex)] pub fn generate(bits: u32) -> Result, ErrorStack> { let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; Rsa::generate_with_e(bits, &e) @@ -627,10 +552,7 @@ impl Rsa { /// Generates a public/private key pair with the specified size and a custom exponent. /// /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead. - /// - /// This corresponds to [`RSA_generate_key_ex`]. - /// - /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html + #[corresponds(RSA_generate_key_ex)] pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result, ErrorStack> { unsafe { let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); @@ -647,26 +569,17 @@ impl Rsa { // FIXME these need to identify input formats private_key_from_pem! { /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure. - /// - /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. - /// - /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + #[corresponds(PEM_read_bio_RSAPrivateKey)] private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. - /// - /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. - /// - /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + #[corresponds(PEM_read_bio_RSAPrivateKey)] private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. /// /// The callback should fill the password into the provided buffer and return its length. - /// - /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. - /// - /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html + #[corresponds(PEM_read_bio_RSAPrivateKey)] private_key_from_pem_callback, Rsa, ffi::PEM_read_bio_RSAPrivateKey @@ -674,10 +587,7 @@ impl Rsa { from_der! { /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure. - /// - /// This corresponds to [`d2i_RSAPrivateKey`]. - /// - /// [`d2i_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html + #[corresponds(d2i_RSAPrivateKey)] private_key_from_der, Rsa, ffi::d2i_RSAPrivateKey, diff --git a/boring/src/sign.rs b/boring/src/sign.rs index ee68bc7d..89e7ba1c 100644 --- a/boring/src/sign.rs +++ b/boring/src/sign.rs @@ -37,6 +37,7 @@ use crate::ffi; use foreign_types::ForeignTypeRef; use libc::c_int; +use openssl_macros::corresponds; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; @@ -96,10 +97,7 @@ impl<'a> Signer<'a> { /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to /// `new_without_digest`. - /// - /// OpenSSL documentation at [`EVP_DigestSignInit`]. - /// - /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html + #[corresponds(EVP_DigestSignInit)] pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, @@ -111,10 +109,7 @@ impl<'a> Signer<'a> { /// /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. /// It can also be used to create a CMAC. - /// - /// OpenSSL documentation at [`EVP_DigestSignInit`]. - /// - /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html + #[corresponds(EVP_DigestSignInit)] pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, @@ -159,8 +154,7 @@ impl<'a> Signer<'a> { /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. - /// - /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + #[corresponds(EVP_PKEY_CTX_get_rsa_padding)] pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; @@ -172,10 +166,7 @@ impl<'a> Signer<'a> { /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + #[corresponds(EVP_PKEY_CTX_set_rsa_padding)] pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( @@ -189,10 +180,7 @@ impl<'a> Signer<'a> { /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)] pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( @@ -206,10 +194,7 @@ impl<'a> Signer<'a> { /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)] pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( @@ -224,10 +209,7 @@ impl<'a> Signer<'a> { /// /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. /// Use `sign_oneshot` instead. - /// - /// OpenSSL documentation at [`EVP_DigestUpdate`]. - /// - /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html + #[corresponds(EVP_DigestUpdate)] pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate( @@ -243,10 +225,7 @@ impl<'a> Signer<'a> { /// /// The actual signature may be shorter than this value. Check the return value of /// `sign` to get the exact length. - /// - /// OpenSSL documentation at [`EVP_DigestSignFinal`]. - /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + #[corresponds(EVP_DigestSignFinal)] pub fn len(&self) -> Result { self.len_intern() } @@ -269,10 +248,7 @@ impl<'a> Signer<'a> { /// /// This method will fail if the buffer is not large enough for the signature. Use the `len` /// method to get an upper bound on the required size. - /// - /// OpenSSL documentation at [`EVP_DigestSignFinal`]. - /// - /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html + #[corresponds(EVP_DigestSignFinal)] pub fn sign(&self, buf: &mut [u8]) -> Result { unsafe { let mut len = buf.len(); @@ -303,10 +279,7 @@ impl<'a> Signer<'a> { /// /// This method will fail if the buffer is not large enough for the signature. Use the `len` /// method to get an upper bound on the required size. - /// - /// OpenSSL documentation at [`EVP_DigestSign`]. - /// - /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html + #[corresponds(EVP_DigestSign)] pub fn sign_oneshot( &mut self, sig_buf: &mut [u8], @@ -372,10 +345,7 @@ impl<'a> Verifier<'a> { /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to /// `new_without_digest`. - /// - /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. - /// - /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html + #[corresponds(EVP_DigestVerifyInit)] pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, @@ -386,10 +356,7 @@ impl<'a> Verifier<'a> { /// Creates a new `Verifier` without a digest. /// /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. - /// - /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. - /// - /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html + #[corresponds(EVP_DigestVerifyInit)] pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, @@ -434,8 +401,7 @@ impl<'a> Verifier<'a> { /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. - /// - /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. + #[corresponds(EVP_PKEY_CTX_get_rsa_padding)] pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; @@ -447,10 +413,7 @@ impl<'a> Verifier<'a> { /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html + #[corresponds(EVP_PKEY_CTX_set_rsa_padding)] pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( @@ -464,10 +427,7 @@ impl<'a> Verifier<'a> { /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html + #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)] pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( @@ -481,10 +441,7 @@ impl<'a> Verifier<'a> { /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. - /// - /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. - /// - /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html + #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)] pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( @@ -499,10 +456,7 @@ impl<'a> Verifier<'a> { /// /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. /// Use `verify_oneshot` instead. - /// - /// OpenSSL documentation at [`EVP_DigestUpdate`]. - /// - /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html + #[corresponds(EVP_DigestUpdate)] pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate( @@ -515,10 +469,7 @@ impl<'a> Verifier<'a> { } /// Determines if the data fed into the `Verifier` matches the provided signature. - /// - /// OpenSSL documentation at [`EVP_DigestVerifyFinal`]. - /// - /// [`EVP_DigestVerifyFinal`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyFinal.html + #[corresponds(EVP_DigestVerifyFinal)] pub fn verify(&self, signature: &[u8]) -> Result { unsafe { let r = @@ -535,10 +486,7 @@ impl<'a> Verifier<'a> { } /// Determines if the data given in buf matches the provided signature. - /// - /// OpenSSL documentation at [`EVP_DigestVerify`]. - /// - /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html + #[corresponds(EVP_DigestVerify)] pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result { unsafe { let r = ffi::EVP_DigestVerify( diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 726bc339..9ee3b960 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -730,10 +730,6 @@ impl SslCurve { pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); /// Returns the curve name - /// - /// This corresponds to [`SSL_get_curve_name`] - /// - /// [`SSL_get_curve_name`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_get_curve_name #[corresponds(SSL_get_curve_name)] pub fn name(&self) -> Option<&'static str> { unsafe { @@ -808,10 +804,8 @@ impl CompliancePolicy { /// /// It will select the first protocol supported by the server which is also supported by the client. /// -/// This corresponds to [`SSL_select_next_proto`]. -/// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos -/// [`SSL_select_next_proto`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html +#[corresponds(SSL_select_next_proto)] pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> { if server.is_empty() || client.is_empty() { return None; @@ -2244,10 +2238,7 @@ pub struct ClientHello<'ssl>(&'ssl ffi::SSL_CLIENT_HELLO); impl ClientHello<'_> { /// Returns the data of a given extension, if present. - /// - /// This corresponds to [`SSL_early_callback_ctx_extension_get`]. - /// - /// [`SSL_early_callback_ctx_extension_get`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_early_callback_ctx_extension_get + #[corresponds(SSL_early_callback_ctx_extension_get)] pub fn get_extension(&self, ext_type: ExtensionType) -> Option<&[u8]> { unsafe { let mut ptr = ptr::null(); @@ -2466,10 +2457,7 @@ impl Clone for SslSession { impl SslSession { from_der! { /// Deserializes a DER-encoded session structure. - /// - /// This corresponds to [`d2i_SSL_SESSION`]. - /// - /// [`d2i_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/d2i_SSL_SESSION.html + #[corresponds(d2i_SSL_SESSION)] from_der, SslSession, ffi::d2i_SSL_SESSION, @@ -2540,10 +2528,7 @@ impl SslSessionRef { to_der! { /// Serializes the session into a DER-encoded structure. - /// - /// This corresponds to [`i2d_SSL_SESSION`]. - /// - /// [`i2d_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/i2d_SSL_SESSION.html + #[corresponds(i2d_SSL_SESSION)] to_der, ffi::i2d_SSL_SESSION } @@ -2942,10 +2927,7 @@ impl SslRef { } /// Configures whether ClientHello extensions should be permuted. - /// - /// This corresponds to [`SSL_set_permute_extensions`]. - /// - /// [`SSL_set_permute_extensions`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_permute_extensions + #[corresponds(SSL_set_permute_extensions)] /// /// Note: This is gated to non-fips because the fips feature builds with a separate /// version of BoringSSL which doesn't yet include these APIs. @@ -3770,10 +3752,7 @@ impl MidHandshakeSslStream { } /// Restarts the handshake process. - /// - /// This corresponds to [`SSL_do_handshake`]. - /// - /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + #[corresponds(SSL_do_handshake)] pub fn handshake(mut self) -> Result, HandshakeError> { let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) }; if ret > 0 { diff --git a/boring/src/symm.rs b/boring/src/symm.rs index 6e230f0d..1df9a77c 100644 --- a/boring/src/symm.rs +++ b/boring/src/symm.rs @@ -54,6 +54,7 @@ use crate::ffi; use libc::{c_int, c_uint}; +use openssl_macros::corresponds; use std::cmp; use std::ptr; @@ -77,10 +78,7 @@ pub struct Cipher(*const ffi::EVP_CIPHER); impl Cipher { /// Looks up the cipher for a certain nid. - /// - /// This corresponds to [`EVP_get_cipherbynid`] - /// - /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_get_cipherbyname.html + #[corresponds(EVP_get_cipherbynid)] pub fn from_nid(nid: Nid) -> Option { let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; if ptr.is_null() { diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index c09f4df8..f4a44ee5 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -864,10 +864,7 @@ impl X509NameBuilder { } /// Add a field entry by str. - /// - /// This corresponds to [`X509_NAME_add_entry_by_txt`]. - /// - /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html + #[corresponds(X509_NAME_add_entry_by_txt)] pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); @@ -886,10 +883,7 @@ impl X509NameBuilder { } /// Add a field entry by str with a specific type. - /// - /// This corresponds to [`X509_NAME_add_entry_by_txt`]. - /// - /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html + #[corresponds(X509_NAME_add_entry_by_txt)] pub fn append_entry_by_text_with_type( &mut self, field: &str, @@ -913,10 +907,7 @@ impl X509NameBuilder { } /// Add a field entry by NID. - /// - /// This corresponds to [`X509_NAME_add_entry_by_NID`]. - /// - /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html + #[corresponds(X509_NAME_add_entry_by_NID)] pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { unsafe { assert!(value.len() <= ValueLen::MAX as usize); @@ -934,10 +925,7 @@ impl X509NameBuilder { } /// Add a field entry by NID with a specific type. - /// - /// This corresponds to [`X509_NAME_add_entry_by_NID`]. - /// - /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html + #[corresponds(X509_NAME_add_entry_by_NID)] pub fn append_entry_by_nid_with_type( &mut self, field: Nid, @@ -997,10 +985,7 @@ impl X509Name { from_der! { /// Deserializes a DER-encoded X509 name structure. - /// - /// This corresponds to [`d2i_X509_NAME`]. - /// - /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html + #[corresponds(d2i_X509_NAME)] from_der, X509Name, ffi::d2i_X509_NAME, @@ -1047,10 +1032,7 @@ impl X509NameRef { to_der! { /// Serializes the certificate into a DER-encoded X509 name structure. - /// - /// This corresponds to [`i2d_X509_NAME`]. - /// - /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509_NAME.html + #[corresponds(i2d_X509_NAME)] to_der, ffi::i2d_X509_NAME } @@ -1110,10 +1092,7 @@ foreign_type_and_impl_send_sync! { impl X509NameEntryRef { /// Returns the field value of an `X509NameEntry`. - /// - /// This corresponds to [`X509_NAME_ENTRY_get_data`]. - /// - /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html + #[corresponds(X509_NAME_ENTRY_get_data)] pub fn data(&self) -> &Asn1StringRef { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); @@ -1123,10 +1102,7 @@ impl X509NameEntryRef { /// Returns the `Asn1Object` value of an `X509NameEntry`. /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. - /// - /// This corresponds to [`X509_NAME_ENTRY_get_object`]. - /// - /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html + #[corresponds(X509_NAME_ENTRY_get_object)] pub fn object(&self) -> &Asn1ObjectRef { unsafe { let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); @@ -1167,10 +1143,7 @@ impl X509ReqBuilder { } /// Set the issuer name. - /// - /// This corresponds to [`X509_REQ_set_subject_name`]. - /// - /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html + #[corresponds(X509_REQ_set_subject_name)] pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_subject_name( @@ -1182,10 +1155,7 @@ impl X509ReqBuilder { } /// Set the public key. - /// - /// This corresponds to [`X509_REQ_set_pubkey`]. - /// - /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html + #[corresponds(X509_REQ_set_pubkey)] pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -1232,10 +1202,7 @@ impl X509ReqBuilder { } /// Sign the request using a private key. - /// - /// This corresponds to [`X509_REQ_sign`]. - /// - /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html + #[corresponds(X509_REQ_sign)] pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate, @@ -1274,10 +1241,7 @@ impl X509Req { /// Deserializes a PEM-encoded PKCS#10 certificate request structure. /// /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. - /// - /// This corresponds to [`PEM_read_bio_X509_REQ`]. - /// - /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html + #[corresponds(PEM_read_bio_X509_REQ)] from_pem, X509Req, ffi::PEM_read_bio_X509_REQ @@ -1285,10 +1249,7 @@ impl X509Req { from_der! { /// Deserializes a DER-encoded PKCS#10 certificate request structure. - /// - /// This corresponds to [`d2i_X509_REQ`]. - /// - /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html + #[corresponds(d2i_X509_REQ)] from_der, X509Req, ffi::d2i_X509_REQ, @@ -1301,38 +1262,26 @@ impl X509ReqRef { /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. /// /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. - /// - /// This corresponds to [`PEM_write_bio_X509_REQ`]. - /// - /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html + #[corresponds(PEM_write_bio_X509_REQ)] to_pem, ffi::PEM_write_bio_X509_REQ } to_der! { /// Serializes the certificate request to a DER-encoded PKCS#10 structure. - /// - /// This corresponds to [`i2d_X509_REQ`]. - /// - /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html + #[corresponds(i2d_X509_REQ)] to_der, ffi::i2d_X509_REQ } /// Returns the numerical value of the version field of the certificate request. - /// - /// This corresponds to [`X509_REQ_get_version`] - /// - /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html + #[corresponds(X509_REQ_get_version)] pub fn version(&self) -> i32 { unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } /// Returns the subject name of the certificate request. - /// - /// This corresponds to [`X509_REQ_get_subject_name`] - /// - /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html + #[corresponds(X509_REQ_get_subject_name)] pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = X509_REQ_get_subject_name(self.as_ptr()); @@ -1423,10 +1372,7 @@ impl X509VerifyError { } /// Return a human readable error string from the verification error. - /// - /// This corresponds to [`X509_verify_cert_error_string`]. - /// - /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html + #[corresponds(X509_verify_cert_error_string)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn error_string(&self) -> &'static str { ffi::init(); diff --git a/boring/src/x509/store.rs b/boring/src/x509/store.rs index 068c759c..0f626838 100644 --- a/boring/src/x509/store.rs +++ b/boring/src/x509/store.rs @@ -105,10 +105,7 @@ impl X509StoreBuilderRef { } /// Returns a mutable reference to the X509 verification configuration. - /// - /// This corresponds to [`X509_STORE_get0_param`]. - /// - /// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_get0_param.html + #[corresponds(X509_STORE_get0_param)] pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_get0_param(self.as_ptr())) } } From c95d764cdd87ec2ee95d43cea3604a5d26507d94 Mon Sep 17 00:00:00 2001 From: 0x676e67 Date: Fri, 14 Feb 2025 10:54:39 +0800 Subject: [PATCH 12/34] build: Fix the build for 32-bit Linux platform (#312) build: Fix the build for 32-bit Linux platform --- boring-sys/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index 36327950..c0a45aec 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -19,6 +19,7 @@ include = [ "/LICENSE-MIT", "/cmake/*.cmake", # boringssl (non-FIPS) + "/deps/boringssl/src/util/32-bit-toolchain.cmake", "/deps/boringssl/**/*.[chS]", "/deps/boringssl/**/*.asm", "/deps/boringssl/sources.json", @@ -30,6 +31,7 @@ include = [ "/deps/boringssl/**/sources.cmake", "/deps/boringssl/LICENSE", # boringssl (FIPS) + "/deps/boringssl-fips/src/util/32-bit-toolchain.cmake", "/deps/boringssl-fips/**/*.[chS]", "/deps/boringssl-fips/**/*.asm", "/deps/boringssl-fips/**/*.pl", From e6833b0074086422b065edec2839ec9800c73885 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Fri, 26 Jan 2024 16:57:08 -0800 Subject: [PATCH 13/34] Set CMAKE_BUILD_PARALLEL_LEVEL to available_parallelism cmake-rs' jobserver doesn't work reliably, if at all. One workaround is to set CMAKE_BUILD_PARALLEL_LEVEL to available_parallelism(). On my machine it shaves ~35 seconds off of boring-sys builds. --- boring-sys/build/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 4e32431c..5af2df76 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -576,6 +576,10 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { let mut cfg = get_boringssl_cmake_config(config); + if let Ok(threads) = std::thread::available_parallelism() { + cfg.env("CMAKE_BUILD_PARALLEL_LEVEL", threads.to_string()); + } + if config.features.fips { let (clang, clangxx) = verify_fips_clang_version(); cfg.define("CMAKE_C_COMPILER", clang) From 3b5fa6586019facb2dc15fd80af989930245fb23 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Tue, 18 Feb 2025 21:33:39 -0800 Subject: [PATCH 14/34] Expose SSL_CTX_set1_ech_keys from SslContextRef We currently expose this method on `SslContextBuilder`, which is fine for bootstrapping an `SSL_CTX`, but subsequent attempts to set ECH keys (like during key rotation) can only happen via `SslContextRef`. Also update the method on the builder to take an immutable reference to self because the API is thread safe. --- boring/src/ssl/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9ee3b960..a153612d 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -1960,7 +1960,7 @@ impl SslContextBuilder { /// threads. #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] - pub fn set_ech_keys(&mut self, keys: SslEchKeys) -> Result<(), ErrorStack> { + pub fn set_ech_keys(&self, keys: SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } } @@ -2210,6 +2210,16 @@ impl SslContextRef { pub fn is_rpk(&self) -> bool { self.ex_data(*RPK_FLAG_INDEX).copied().unwrap_or_default() } + + /// Registers a list of ECH keys on the context. This list should contain new and old + /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function + /// is safe to call even after the `SSL_CTX` has been associated with connections on various + /// threads. + #[cfg(not(feature = "fips"))] + #[corresponds(SSL_CTX_set1_ech_keys)] + pub fn set_ech_keys(&self, keys: SslEchKeys) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } + } } /// Error returned by the callback to get a session when operation From c3c7e16b9dad98c67702f37352fb7658079f621d Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Tue, 18 Feb 2025 22:46:04 -0800 Subject: [PATCH 15/34] Bump cmake-rs to improve Mac OS build parallelism There's a bug on OSX that prevents the CMake jobserver from working properly, and so CMake defaults to a single-threaded build. It's not clear when this is actually going to get fixed, so recent versions of cmake-rs just disable the jobserver and have CMake fall back to the number of available cores: https://github.com/rust-lang/cmake-rs/pull/229 This means we don't need e6833b0074086422b065edec2839ec9800c73885 --- Cargo.toml | 2 +- boring-sys/build/main.rs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04a02486..b66c15b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ tokio-boring = { version = "4.13.0", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" -cmake = "0.1.18" +cmake = "0.1.54" fs_extra = "1.3.0" fslock = "0.2" bitflags = "2.4" diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 5af2df76..4e32431c 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -576,10 +576,6 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { let mut cfg = get_boringssl_cmake_config(config); - if let Ok(threads) = std::thread::available_parallelism() { - cfg.env("CMAKE_BUILD_PARALLEL_LEVEL", threads.to_string()); - } - if config.features.fips { let (clang, clangxx) = verify_fips_clang_version(); cfg.define("CMAKE_C_COMPILER", clang) From 156cf04c43c18e46f3d49ffe011bd2e8b5369677 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Wed, 19 Feb 2025 03:46:15 -0800 Subject: [PATCH 16/34] Release 4.14.0 (#317) --- Cargo.toml | 8 ++++---- RELEASE_NOTES | 27 +++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b66c15b8..801afb5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.13.0" +version = "4.14.0" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.13.0", path = "./boring-sys" } -boring = { version = "4.13.0", path = "./boring" } -tokio-boring = { version = "4.13.0", path = "./tokio-boring" } +boring-sys = { version = "4.14.0", path = "./boring-sys" } +boring = { version = "4.14.0", path = "./boring" } +tokio-boring = { version = "4.14.0", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" diff --git a/RELEASE_NOTES b/RELEASE_NOTES index e59bc8e1..6cd154c4 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,25 @@ + +4.14.0 +- 2024-01-27 Set CMAKE_BUILD_PARALLEL_LEVEL to available_parallelism +- 2025-02-14 build: Fix the build for 32-bit Linux platform (#312) +- 2024-11-30 Use corresponds macro +- 2025-02-12 Expose SSL_set_enable_ech_grease +- 2025-02-12 Clean up ECH tests +- 2025-02-10 Expose client/server-side ECH +- 2025-02-10 Expose EVP_HPKE_KEY +- 2025-02-10 Clean up boring_sys::init() +- 2024-11-27 Detailed error codes +- 2025-02-04 chore: Fix docs on SslRef::replace_ex_data +- 2025-01-22 fix manual_c_str_literals clippy warning +- 2025-01-22 replace once_cell with LazyLock +- 2025-01-13 RTG-3333 Support X25519MLKEM768 by default, but don't sent it as client +- 2024-07-31 Allow dead_code instead of disabling clippy entirely for bindgen +- 2024-11-12 Remove INVALID_CALL from mid-handshake error message +- 2024-08-16 Fix bug with accessing memzero'd X509StoreContext in tests +- 2024-08-16 Support linking with a runtime cpp library +- 2024-12-06 Refactor!: Introduce a Cargo feature for optional Hyper 0 support +- 2024-12-06 Refactor!: Remove strict `TokioIo` response requirement from `hyper_boring::v1::HttpsConnector` + 4.13.0 - 2024-11-26 Sync X509StoreBuilder with openssl - 2024-11-26 Sync X509VerifyFlags with openssl @@ -6,7 +28,7 @@ - 2024-11-28 Clippy - 2024-03-11 Fix Windows build -4.12.0 +4.12.0 - 2024-11-20 Add bindings for SSL_CB_ACCEPT_EXIT and SSL_CB_CONNECT_EXIT - 2024-10-22 (ci): brew link x86 toolchain for macos13 runner - 2024-10-22 Skip bindgen 0.70's layout tests before Rust 1.77 @@ -14,7 +36,7 @@ 4.11.0 - 2024-10-17 boring-sys: include HPKE header file for bindgen -- 2024-10-17 Add "fips-compat" feature +- 2024-10-17 Add "fips-compat" feature (#286) - 2024-09-25 Create semgrep.yml 4.10.3 @@ -47,6 +69,7 @@ - 2024-08-04 Properly handle `Option` in `SslRef::set_curves` 4.9.0 +- 2024-08-02 Actually Release 4.9.0 - 2024-08-02 Guard against empty strings given to select_next_proto (#252) - 2024-08-01 Document `SslCurve::nid()` - 2024-08-01 Add SslCurve::to_nid() and remove SslCurveId From cbdf9634643060382bbc2ae5e270ccd156bbf9fb Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 20 Feb 2025 22:51:48 -0800 Subject: [PATCH 17/34] Actually expose SslEchKeys --- boring/src/ssl/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index a153612d..37bcf85e 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -87,8 +87,6 @@ use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; -#[cfg(not(feature = "fips"))] -use crate::ssl::ech::SslEchKeys; use crate::ssl::error::InnerError; use crate::stack::{Stack, StackRef, Stackable}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; @@ -106,6 +104,8 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; +#[cfg(not(feature = "fips"))] +pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; mod async_callbacks; From bc17a06df73d26873ce11b68ae965c6ef6809a0c Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 20 Feb 2025 22:58:21 -0800 Subject: [PATCH 18/34] Address clippy lints --- boring-sys/build/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 1671981f..28a43ccc 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -165,7 +165,7 @@ impl Env { opt_level: target_var("OPT_LEVEL"), android_ndk_home: target_var("ANDROID_NDK_HOME").map(Into::into), cmake_toolchain_file: target_var("CMAKE_TOOLCHAIN_FILE").map(Into::into), - cpp_runtime_lib: target_var("BORING_BSSL_RUST_CPPLIB").map(Into::into), + cpp_runtime_lib: target_var("BORING_BSSL_RUST_CPPLIB"), } } } From 7b4bfcbbeead1fc304f4827e9afd1edabad2fd0b Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 20 Feb 2025 22:53:20 -0800 Subject: [PATCH 19/34] Revert "Refactor!: Introduce a Cargo feature for optional Hyper 0 support" This reverts commit 49d5a611637fc76c59c60577cfbee29e52941070. --- .github/workflows/ci.yml | 4 +--- Cargo.toml | 8 ++++---- hyper-boring/Cargo.toml | 26 ++++++++++---------------- hyper-boring/src/lib.rs | 10 ++++------ hyper-boring/src/v0.rs | 10 +++++----- hyper-boring/src/v1.rs | 12 ++++++------ hyper-boring/tests/v0.rs | 12 +++++------- hyper-boring/tests/v1.rs | 8 ++++---- 8 files changed, 39 insertions(+), 51 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad50806e..d587a4a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -366,7 +366,5 @@ jobs: name: Run `rpk,underscore-wildcards` tests - run: cargo test --features pq-experimental,rpk,underscore-wildcards name: Run `pq-experimental,rpk,underscore-wildcards` tests - - run: cargo test -p hyper-boring --features hyper1-runtime + - run: cargo test -p hyper-boring --features hyper1 name: Run hyper 1.0 tests for hyper-boring - - run: cargo test -p hyper-boring --features hyper0-runtime - name: Run hyper 0. tests for hyper-boring diff --git a/Cargo.toml b/Cargo.toml index 801afb5b..bbc550cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,12 +37,12 @@ futures = "0.3" tokio = "1" anyhow = "1" antidote = "1.0.0" -http1 = { package = "http", version = "1" } +http = "1" http-body-util = "0.1.2" -http0 = { package = "http", version = "0.2" } -hyper1 = { package = "hyper", version = "1" } +http_old = { package = "http", version = "0.2" } +hyper = "1" hyper-util = "0.1.6" -hyper0 = { package = "hyper", version = "0.14", default-features = false } +hyper_old = { package = "hyper", version = "0.14", default-features = false } linked_hash_set = "0.1" openssl-macros = "0.1.1" tower = { version = "0.4", default-features = false, features = ["util"] } diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index 2b706537..f34f8923 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -16,13 +16,9 @@ features = ["pq-experimental"] rustdoc-args = ["--cfg", "docsrs"] [features] -default = ["runtime", "hyper1-runtime"] +default = ["runtime"] -runtime = [] -# `hyper1` + `runtime`. -hyper1-runtime = ["hyper1", "dep:tower"] -# `hyper0` + `runtime`. -hyper0-runtime = ["hyper0", "hyper0/runtime"] +runtime = ["hyper_old/runtime", "dep:tower"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] @@ -33,18 +29,16 @@ fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] # Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) pq-experimental = ["tokio-boring/pq-experimental"] -# Enable Hyper 1 support. -hyper1 = ["dep:hyper1", "dep:http1", "dep:hyper-util", "dep:tower-service"] -# Enable Hyper 0 support. -hyper0 = ["dep:hyper0", "dep:http0"] +# Enable Hyper 1 support +hyper1 = ["dep:http", "dep:hyper", "dep:hyper-util", "dep:tower-service"] [dependencies] antidote = { workspace = true } -http1 = { workspace = true, optional = true } -http0 = { workspace = true, optional = true } -hyper1 = { workspace = true, optional = true } +http = { workspace = true, optional = true } +http_old = { workspace = true } +hyper = { workspace = true, optional = true } hyper-util = { workspace = true, optional = true, features = ["client", "client-legacy"] } -hyper0 = { workspace = true, optional = true, features = ["client"] } +hyper_old = { workspace = true, features = ["client"] } linked_hash_set = { workspace = true } boring = { workspace = true } tokio = { workspace = true } @@ -57,8 +51,8 @@ tower-service = { workspace = true, optional = true } bytes = { workspace = true } http-body-util = { workspace = true } hyper-util = { workspace = true, features = ["http1", "http2", "service", "tokio"] } -hyper1 = { workspace = true, features = ["server"] } -hyper0 = { workspace = true, features = [ "full" ] } +hyper = { workspace = true, features = ["server"] } +hyper_old = { workspace = true, features = [ "full" ] } tokio = { workspace = true, features = [ "full" ] } tower = { workspace = true, features = ["util"] } futures = { workspace = true } diff --git a/hyper-boring/src/lib.rs b/hyper-boring/src/lib.rs index e66aa955..0daa3f6a 100644 --- a/hyper-boring/src/lib.rs +++ b/hyper-boring/src/lib.rs @@ -11,14 +11,12 @@ use std::sync::LazyLock; use tokio_boring::SslStream; mod cache; -/// Hyper 0 support. -#[cfg(feature = "hyper0")] -pub mod v0; +mod v0; +/// Hyper 1 support. #[cfg(feature = "hyper1")] -mod v1; +pub mod v1; -#[cfg(feature = "hyper1")] -pub use self::v1::*; +pub use self::v0::*; fn key_index() -> Result, ErrorStack> { static IDX: LazyLock> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); diff --git a/hyper-boring/src/v0.rs b/hyper-boring/src/v0.rs index dcb9f9ac..172d1640 100644 --- a/hyper-boring/src/v0.rs +++ b/hyper-boring/src/v0.rs @@ -6,11 +6,11 @@ use boring::ssl::{ ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, SslSessionCacheMode, }; -use http0::uri::Scheme; -use hyper0::client::connect::{Connected, Connection}; -use hyper0::client::HttpConnector; -use hyper0::service::Service; -use hyper0::Uri; +use http_old::uri::Scheme; +use hyper_old::client::connect::{Connected, Connection}; +use hyper_old::client::HttpConnector; +use hyper_old::service::Service; +use hyper_old::Uri; use std::error::Error; use std::future::Future; use std::net; diff --git a/hyper-boring/src/v1.rs b/hyper-boring/src/v1.rs index 45654c51..a2c65eb6 100644 --- a/hyper-boring/src/v1.rs +++ b/hyper-boring/src/v1.rs @@ -6,9 +6,9 @@ use boring::ssl::{ ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, SslSessionCacheMode, }; -use http1::uri::Scheme; -use http1::Uri; -use hyper1::rt::{Read, ReadBufCursor, Write}; +use http::uri::Scheme; +use http::Uri; +use hyper::rt::{Read, ReadBufCursor, Write}; use hyper_util::client::legacy::connect::{Connected, Connection, HttpConnector}; use hyper_util::rt::TokioIo; use std::error::Error; @@ -20,9 +20,9 @@ use std::task::{Context, Poll}; use std::{io, net}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::TcpStream; -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] +#[cfg(feature = "runtime")] use tower::util::MapResponse; -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] +#[cfg(feature = "runtime")] use tower::ServiceExt; use tower_layer::Layer; use tower_service::Service; @@ -39,7 +39,7 @@ pub struct HttpsConnector { pub type TokioHttpConnector = MapResponse) -> TokioIo>>; -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] +#[cfg(feature = "runtime")] impl HttpsConnector { /// Creates a a new `HttpsConnector` using default settings. /// diff --git a/hyper-boring/tests/v0.rs b/hyper-boring/tests/v0.rs index 0a681e55..08cfce12 100644 --- a/hyper-boring/tests/v0.rs +++ b/hyper-boring/tests/v0.rs @@ -1,12 +1,10 @@ -#![cfg(feature = "hyper0")] - use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; use futures::StreamExt; -use hyper0::client::HttpConnector; -use hyper0::server::conn::Http; -use hyper0::{service, Response}; -use hyper0::{Body, Client}; -use hyper_boring::v0::HttpsConnector; +use hyper_boring::HttpsConnector; +use hyper_old::client::HttpConnector; +use hyper_old::server::conn::Http; +use hyper_old::{service, Response}; +use hyper_old::{Body, Client}; use std::convert::Infallible; use std::{io, iter}; use tokio::net::TcpListener; diff --git a/hyper-boring/tests/v1.rs b/hyper-boring/tests/v1.rs index 3e8273dd..8e84c92b 100644 --- a/hyper-boring/tests/v1.rs +++ b/hyper-boring/tests/v1.rs @@ -4,8 +4,8 @@ use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; use bytes::Bytes; use futures::StreamExt; use http_body_util::{BodyStream, Empty}; -use hyper1::{service, Response}; -use hyper_boring::HttpsConnector; +use hyper::{service, Response}; +use hyper_boring::v1::HttpsConnector; use hyper_util::client::legacy::connect::HttpConnector; use hyper_util::client::legacy::Client; use hyper_util::rt::{TokioExecutor, TokioIo}; @@ -56,7 +56,7 @@ async fn localhost() { Ok::<_, io::Error>(Response::new(>::new())) }); - hyper1::server::conn::http1::Builder::new() + hyper::server::conn::http1::Builder::new() .keep_alive(false) .serve_connection(TokioIo::new(stream), service) .await @@ -127,7 +127,7 @@ async fn alpn_h2() { Ok::<_, io::Error>(Response::new(>::new())) }); - hyper1::server::conn::http2::Builder::new(TokioExecutor::new()) + hyper::server::conn::http2::Builder::new(TokioExecutor::new()) .serve_connection(TokioIo::new(stream), service) .await .unwrap(); From f439f92564ec876de0253a14f296b87645a59ec9 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 20 Feb 2025 22:53:34 -0800 Subject: [PATCH 20/34] Revert "Refactor!: Remove strict `TokioIo` response requirement from `hyper_boring::v1::HttpsConnector`" This reverts commit e518c2444a8dffa20d747b57e0d4829c096e865f. --- Cargo.toml | 2 +- hyper-boring/Cargo.toml | 3 +-- hyper-boring/src/v1.rs | 26 ++++++-------------------- hyper-boring/tests/v1.rs | 6 ++---- 4 files changed, 10 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbc550cb..b33b8a43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ hyper-util = "0.1.6" hyper_old = { package = "hyper", version = "0.14", default-features = false } linked_hash_set = "0.1" openssl-macros = "0.1.1" -tower = { version = "0.4", default-features = false, features = ["util"] } +tower = "0.4" tower-layer = "0.3" tower-service = "0.3" autocfg = "1.3.0" diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index f34f8923..a6ed3180 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -18,7 +18,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["runtime"] -runtime = ["hyper_old/runtime", "dep:tower"] +runtime = ["hyper_old/runtime"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] @@ -43,7 +43,6 @@ linked_hash_set = { workspace = true } boring = { workspace = true } tokio = { workspace = true } tokio-boring = { workspace = true } -tower = { workspace = true, optional = true } tower-layer = { workspace = true } tower-service = { workspace = true, optional = true } diff --git a/hyper-boring/src/v1.rs b/hyper-boring/src/v1.rs index a2c65eb6..e1f9a43d 100644 --- a/hyper-boring/src/v1.rs +++ b/hyper-boring/src/v1.rs @@ -19,11 +19,6 @@ use std::sync::Arc; use std::task::{Context, Poll}; use std::{io, net}; use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::net::TcpStream; -#[cfg(feature = "runtime")] -use tower::util::MapResponse; -#[cfg(feature = "runtime")] -use tower::ServiceExt; use tower_layer::Layer; use tower_service::Service; @@ -34,30 +29,25 @@ pub struct HttpsConnector { inner: Inner, } -/// Specialized version of [`HttpConnector`] with responses wrapped with -/// [`TokioIo::new`] in order to bring back compatibility with Tokio traits. -pub type TokioHttpConnector = - MapResponse) -> TokioIo>>; - #[cfg(feature = "runtime")] -impl HttpsConnector { +impl HttpsConnector { /// Creates a a new `HttpsConnector` using default settings. /// /// The Hyper `HttpConnector` is used to perform the TCP socket connection. ALPN is configured to support both /// HTTP/2 and HTTP/1.1. /// /// Requires the `runtime` Cargo feature. - pub fn new() -> Result { + pub fn new() -> Result, ErrorStack> { let mut http = HttpConnector::new(); http.enforce_http(false); - HttpsLayer::new().map(|l| l.layer(http.map_response(TokioIo::new as _))) + HttpsLayer::new().map(|l| l.layer(http)) } } impl HttpsConnector where - S: Service + Send, + S: Service> + Send, S::Error: Into>, S::Future: Unpin + Send + 'static, T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, @@ -65,10 +55,6 @@ where /// Creates a new `HttpsConnector`. /// /// The session cache configuration of `ssl` will be overwritten. - /// - /// If the provided service's response type does not fit the trait - /// requirements because it is closer to the Hyper ecosystem than the Tokio - /// one, wrapping your responses with [`TokioIo`] should work. pub fn with_connector( http: S, ssl: SslConnectorBuilder, @@ -229,7 +215,7 @@ impl Inner { impl Service for HttpsConnector where - S: Service + Send, + S: Service> + Send, S::Error: Into>, S::Future: Unpin + Send + 'static, T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, @@ -258,7 +244,7 @@ where let connect = self.http.call(uri); let f = async { - let conn = connect.await.map_err(Into::into)?; + let conn = connect.await.map_err(Into::into)?.into_inner(); let (inner, uri) = match tls_setup { Some((inner, uri)) => (inner, uri), diff --git a/hyper-boring/tests/v1.rs b/hyper-boring/tests/v1.rs index 8e84c92b..441caea6 100644 --- a/hyper-boring/tests/v1.rs +++ b/hyper-boring/tests/v1.rs @@ -12,7 +12,6 @@ use hyper_util::rt::{TokioExecutor, TokioIo}; use std::convert::Infallible; use std::{io, iter}; use tokio::net::TcpListener; -use tower::ServiceExt; #[tokio::test] async fn google() { @@ -84,7 +83,7 @@ async fn localhost() { let _ = writeln!(&file, "{}", line); }); - let ssl = HttpsConnector::with_connector(connector.map_response(TokioIo::new), ssl).unwrap(); + let ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); let client = Client::builder(TokioExecutor::new()).build::<_, Empty>(ssl); for _ in 0..3 { @@ -145,8 +144,7 @@ async fn alpn_h2() { ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); - let mut ssl = - HttpsConnector::with_connector(connector.map_response(TokioIo::new), ssl).unwrap(); + let mut ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); ssl.set_ssl_callback(|ssl, _| ssl.set_alpn_protos(b"\x02h2\x08http/1.1")); From abaf06731bc0f7d8ee3c0d135060d6b0e357ddc2 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Fri, 21 Feb 2025 14:33:59 -0800 Subject: [PATCH 21/34] Introduce a builder pattern for SslEchKeys + make set_ech_keys take a reference (#320) Previously, set_ech_keys would consume the SslEchKeys struct to enforce the requirement that the struct is immutable after initializing it on a SSL_CTX. The problem with this is that it requires applications to needlessly reallocate the SslEchKeys struct if they want to initialize keys on multiple SSL_CTXs, which is a pretty common pattern. To work around this, we introduce a builder (SslEchKeysBuilder) that requires mutable access to add keys to the underlying struct. set_ech_keys takes in a reference to SslEchKeys, which can only be made via consuming the builder. --- boring/src/ssl/ech.rs | 72 ++++++++++++++++++++++++-------------- boring/src/ssl/mod.rs | 4 +-- boring/src/ssl/test/ech.rs | 7 ++-- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/boring/src/ssl/ech.rs b/boring/src/ssl/ech.rs index d7b49328..27ccc5b5 100644 --- a/boring/src/ssl/ech.rs +++ b/boring/src/ssl/ech.rs @@ -1,11 +1,54 @@ use crate::ffi; -use foreign_types::{ForeignType, ForeignTypeRef}; +use foreign_types::ForeignType; use libc::c_int; use crate::error::ErrorStack; use crate::hpke::HpkeKey; use crate::{cvt_0i, cvt_p}; +pub struct SslEchKeysBuilder { + keys: SslEchKeys, +} + +impl SslEchKeysBuilder { + pub fn new() -> Result { + unsafe { + ffi::init(); + let keys = cvt_p(ffi::SSL_ECH_KEYS_new())?; + + Ok(SslEchKeysBuilder::from_ptr(keys)) + } + } + + pub unsafe fn from_ptr(keys: *mut ffi::SSL_ECH_KEYS) -> Self { + Self { + keys: SslEchKeys::from_ptr(keys), + } + } + + pub fn add_key( + &mut self, + is_retry_config: bool, + ech_config: &[u8], + key: HpkeKey, + ) -> Result<(), ErrorStack> { + unsafe { + cvt_0i(ffi::SSL_ECH_KEYS_add( + self.keys.as_ptr(), + is_retry_config as c_int, + ech_config.as_ptr(), + ech_config.len(), + key.as_ptr(), + )) + .map(|_| ()) + } + } + + pub fn build(self) -> SslEchKeys { + self.keys + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::SSL_ECH_KEYS; fn drop = ffi::SSL_ECH_KEYS_free; @@ -14,30 +57,7 @@ foreign_type_and_impl_send_sync! { } impl SslEchKeys { - pub fn new() -> Result { - unsafe { - ffi::init(); - cvt_p(ffi::SSL_ECH_KEYS_new()).map(|p| SslEchKeys::from_ptr(p)) - } - } -} - -impl SslEchKeysRef { - pub fn add_key( - &mut self, - is_retry_config: bool, - ech_config: &[u8], - key: HpkeKey, - ) -> Result<(), ErrorStack> { - unsafe { - cvt_0i(ffi::SSL_ECH_KEYS_add( - self.as_ptr(), - is_retry_config as c_int, - ech_config.as_ptr(), - ech_config.len(), - key.as_ptr(), - )) - .map(|_| ()) - } + pub fn builder() -> Result { + SslEchKeysBuilder::new() } } diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 37bcf85e..9a1060d4 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -1960,7 +1960,7 @@ impl SslContextBuilder { /// threads. #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] - pub fn set_ech_keys(&self, keys: SslEchKeys) -> Result<(), ErrorStack> { + pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } } @@ -2217,7 +2217,7 @@ impl SslContextRef { /// threads. #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] - pub fn set_ech_keys(&self, keys: SslEchKeys) -> Result<(), ErrorStack> { + pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } } } diff --git a/boring/src/ssl/test/ech.rs b/boring/src/ssl/test/ech.rs index c94a842d..d2797d42 100644 --- a/boring/src/ssl/test/ech.rs +++ b/boring/src/ssl/test/ech.rs @@ -18,11 +18,12 @@ static ECH_KEY_2: &[u8] = include_bytes!("../../../test/echkey-2"); fn bootstrap_ech(config: &[u8], key: &[u8], list: &[u8]) -> (Server, ClientSslBuilder) { let server = { let key = HpkeKey::dhkem_p256_sha256(key).unwrap(); - let mut ech_keys = SslEchKeys::new().unwrap(); - ech_keys.add_key(true, config, key).unwrap(); + let mut ech_keys_builder = SslEchKeys::builder().unwrap(); + ech_keys_builder.add_key(true, config, key).unwrap(); + let ech_keys = ech_keys_builder.build(); let mut builder = Server::builder(); - builder.ctx().set_ech_keys(ech_keys).unwrap(); + builder.ctx().set_ech_keys(&ech_keys).unwrap(); builder.build() }; From 7ba322560fab82bc8aefb8d0490e396f15dbc0e8 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Sat, 22 Feb 2025 17:16:53 -0800 Subject: [PATCH 22/34] Revert cmake bump (for now) as it is overly restrictive (#321) Some users of boring have issues with newer versions of cmake. Because we have an alternative solution, we can hold off on the bump for now. --- Cargo.toml | 2 +- boring-sys/build/main.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b33b8a43..f991597d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ tokio-boring = { version = "4.14.0", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" -cmake = "0.1.54" +cmake = "0.1.18" fs_extra = "1.3.0" fslock = "0.2" bitflags = "2.4" diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 4e32431c..5af2df76 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -576,6 +576,10 @@ fn built_boring_source_path(config: &Config) -> &PathBuf { let mut cfg = get_boringssl_cmake_config(config); + if let Ok(threads) = std::thread::available_parallelism() { + cfg.env("CMAKE_BUILD_PARALLEL_LEVEL", threads.to_string()); + } + if config.features.fips { let (clang, clangxx) = verify_fips_clang_version(); cfg.define("CMAKE_C_COMPILER", clang) From 9ba00ea58641b708c143926c6bdead27886f8c86 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Sun, 23 Feb 2025 09:52:52 -0800 Subject: [PATCH 23/34] Fix lifetimes in ssl::select_next_proto See https://github.com/sfackler/rust-openssl/pull/2360 and https://nvd.nist.gov/vuln/detail/CVE-2025-24898. From the rust-openssl PR: `SSL_select_next_proto` can return a pointer into either the client or server buffers, but the type signature of the function previously only bound the output buffer to the client buffer. This can result in a UAF in situations where the server slice does not point to a long-lived allocation. Thanks to Matt Mastracci for reporting this issue. --- boring/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9a1060d4..530c4a20 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -806,7 +806,7 @@ impl CompliancePolicy { /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos #[corresponds(SSL_select_next_proto)] -pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> { +pub fn select_next_proto<'a>(server: &'a [u8], client: &'a [u8]) -> Option<&'a [u8]> { if server.is_empty() || client.is_empty() { return None; } From 5e0002bfa8f6f605ebc03dbb1351f10936da3793 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Sun, 23 Feb 2025 12:26:55 -0800 Subject: [PATCH 24/34] Release 4.15.0 --- Cargo.toml | 8 ++++---- RELEASE_NOTES | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f991597d..ac764ff5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.14.0" +version = "4.15.0" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.14.0", path = "./boring-sys" } -boring = { version = "4.14.0", path = "./boring" } -tokio-boring = { version = "4.14.0", path = "./tokio-boring" } +boring-sys = { version = "4.15.0", path = "./boring-sys" } +boring = { version = "4.15.0", path = "./boring" } +tokio-boring = { version = "4.15.0", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 6cd154c4..dab8569b 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,16 @@ +4.15.0 +- 2025-02-23 Fix lifetimes in ssl::select_next_proto +- 2025-02-23 Revert cmake bump (for now) as it is overly restrictive (#321) +- 2025-02-21 Introduce a builder pattern for SslEchKeys + make set_ech_keys take a reference (#320) +- 2025-02-21 Revert "Refactor!: Remove strict `TokioIo` response requirement from `hyper_boring::v1::HttpsConnector`" +- 2025-02-21 Revert "Refactor!: Introduce a Cargo feature for optional Hyper 0 support" +- 2025-02-21 Address clippy lints +- 2025-02-21 Actually expose SslEchKeys + 4.14.0 +- 2025-02-19 Bump cmake-rs to improve Mac OS build parallelism +- 2025-02-19 Expose SSL_CTX_set1_ech_keys from SslContextRef - 2024-01-27 Set CMAKE_BUILD_PARALLEL_LEVEL to available_parallelism - 2025-02-14 build: Fix the build for 32-bit Linux platform (#312) - 2024-11-30 Use corresponds macro From 5268f63a77610b08a87d105dfad7cd87af5a406c Mon Sep 17 00:00:00 2001 From: Yury Yarashevich Date: Thu, 27 Feb 2025 16:09:07 +0100 Subject: [PATCH 25/34] Expose API to enable certificate compression. (#241) --- Cargo.toml | 1 + boring/Cargo.toml | 1 + boring/src/ssl/callbacks.rs | 151 ++++++++++++++++++++++++- boring/src/ssl/mod.rs | 82 ++++++++++++++ boring/src/ssl/test/cert_compressor.rs | 102 +++++++++++++++++ boring/src/ssl/test/mod.rs | 1 + 6 files changed, 334 insertions(+), 4 deletions(-) create mode 100644 boring/src/ssl/test/cert_compressor.rs diff --git a/Cargo.toml b/Cargo.toml index ac764ff5..719505ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,3 +49,4 @@ tower = "0.4" tower-layer = "0.3" tower-service = "0.3" autocfg = "1.3.0" +brotli = "6.0" diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 5e0b1c28..5bd25bc1 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -81,3 +81,4 @@ boring-sys = { workspace = true } [dev-dependencies] hex = { workspace = true } rusty-hook = { workspace = true } +brotli = { workspace = true } diff --git a/boring/src/ssl/callbacks.rs b/boring/src/ssl/callbacks.rs index f41108d5..8ab17b98 100644 --- a/boring/src/ssl/callbacks.rs +++ b/boring/src/ssl/callbacks.rs @@ -1,10 +1,10 @@ #![forbid(unsafe_op_in_unsafe_fn)] use super::{ - AlpnError, ClientHello, GetSessionPendingError, PrivateKeyMethod, PrivateKeyMethodError, - SelectCertError, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslInfoCallbackAlert, - SslInfoCallbackMode, SslInfoCallbackValue, SslRef, SslSession, SslSessionRef, - SslSignatureAlgorithm, SslVerifyError, SESSION_CTX_INDEX, + AlpnError, CertificateCompressor, ClientHello, GetSessionPendingError, PrivateKeyMethod, + PrivateKeyMethodError, SelectCertError, SniError, Ssl, SslAlert, SslContext, SslContextRef, + SslInfoCallbackAlert, SslInfoCallbackMode, SslInfoCallbackValue, SslRef, SslSession, + SslSessionRef, SslSignatureAlgorithm, SslVerifyError, SESSION_CTX_INDEX, }; use crate::error::ErrorStack; use crate::ffi; @@ -579,3 +579,146 @@ pub(super) unsafe extern "C" fn raw_info_callback( callback(ssl, SslInfoCallbackMode(mode), value); } + +pub(super) unsafe extern "C" fn raw_ssl_cert_compress( + ssl: *mut ffi::SSL, + out: *mut ffi::CBB, + input: *const u8, + input_len: usize, +) -> ::std::os::raw::c_int +where + C: CertificateCompressor, +{ + const { + assert!(C::CAN_COMPRESS); + } + + // SAFETY: boring provides valid inputs. + let ssl = unsafe { SslRef::from_ptr_mut(ssl) }; + + let ssl_context = ssl.ssl_context(); + let compressor = ssl_context + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: certificate compression missed"); + + let input_slice = unsafe { std::slice::from_raw_parts(input, input_len) }; + let mut writer = CryptoByteBuilder::from_ptr(out); + if compressor.compress(input_slice, &mut writer).is_err() { + return 0; + } + + 1 +} + +pub(super) unsafe extern "C" fn raw_ssl_cert_decompress( + ssl: *mut ffi::SSL, + out: *mut *mut ffi::CRYPTO_BUFFER, + uncompressed_len: usize, + input: *const u8, + input_len: usize, +) -> ::std::os::raw::c_int +where + C: CertificateCompressor, +{ + const { + assert!(C::CAN_DECOMPRESS); + } + + // SAFETY: boring provides valid inputs. + let ssl = unsafe { SslRef::from_ptr_mut(ssl) }; + + let ssl_context = ssl.ssl_context(); + let compressor = ssl_context + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: certificate compression missed"); + + let Ok(mut decompression_buffer) = CryptoBufferBuilder::with_capacity(uncompressed_len) else { + return 0; + }; + + let input_slice = unsafe { std::slice::from_raw_parts(input, input_len) }; + + if compressor + .decompress(input_slice, decompression_buffer.as_writer()) + .is_err() + { + return 0; + } + + let Ok(crypto_buffer) = decompression_buffer.build() else { + return 0; + }; + + unsafe { *out = crypto_buffer }; + 1 +} + +struct CryptoByteBuilder<'a>(*mut ffi::CBB, std::marker::PhantomData<&'a [u8]>); + +impl CryptoByteBuilder<'_> { + fn from_ptr(ptr: *mut ffi::CBB) -> Self { + Self(ptr, Default::default()) + } +} + +impl std::io::Write for CryptoByteBuilder<'_> { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + let success = unsafe { ffi::CBB_add_bytes(self.0, buf.as_ptr(), buf.len()) == 1 }; + if !success { + return Err(std::io::Error::other("CBB_add_bytes failed")); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + let success = unsafe { ffi::CBB_flush(self.0) == 1 }; + if !success { + return Err(std::io::Error::other("CBB_flush failed")); + } + Ok(()) + } +} + +struct CryptoBufferBuilder<'a> { + buffer: *mut ffi::CRYPTO_BUFFER, + cursor: std::io::Cursor<&'a mut [u8]>, +} + +impl<'a> CryptoBufferBuilder<'a> { + fn with_capacity(capacity: usize) -> Result, ErrorStack> { + let mut data: *mut u8 = std::ptr::null_mut(); + let buffer = unsafe { crate::cvt_p(ffi::CRYPTO_BUFFER_alloc(&mut data, capacity))? }; + Ok(CryptoBufferBuilder { + buffer, + cursor: std::io::Cursor::new(unsafe { std::slice::from_raw_parts_mut(data, capacity) }), + }) + } + + fn as_writer(&mut self) -> &mut (impl std::io::Write + 'a) { + &mut self.cursor + } + + fn build(mut self) -> Result<*mut ffi::CRYPTO_BUFFER, ErrorStack> { + let buffer_capacity = unsafe { ffi::CRYPTO_BUFFER_len(self.buffer) }; + if self.cursor.position() != buffer_capacity as u64 { + // Make sure all bytes in buffer initialized as required by Boring SSL. + return Err(ErrorStack::get()); + } + unsafe { + let mut result = ptr::null_mut(); + ptr::swap(&mut self.buffer, &mut result); + std::mem::forget(self); + Ok(result) + } + } +} + +impl Drop for CryptoBufferBuilder<'_> { + fn drop(&mut self) { + if !self.buffer.is_null() { + unsafe { + boring_sys::CRYPTO_BUFFER_free(self.buffer); + } + } + } +} diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 530c4a20..9be3e590 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -795,6 +795,16 @@ impl CompliancePolicy { Self(ffi::ssl_compliance_policy_t::ssl_compliance_policy_wpa3_192_202304); } +// IANA assigned identifier of compression algorithm. See https://www.rfc-editor.org/rfc/rfc8879.html#name-compression-algorithms +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct CertificateCompressionAlgorithm(u16); + +impl CertificateCompressionAlgorithm { + pub const ZLIB: Self = Self(ffi::TLSEXT_cert_compression_zlib as u16); + + pub const BROTLI: Self = Self(ffi::TLSEXT_cert_compression_brotli as u16); +} + /// A standard implementation of protocol selection for Application Layer Protocol Negotiation /// (ALPN). /// @@ -1594,6 +1604,48 @@ impl SslContextBuilder { } } + /// Registers a certificate compression algorithm. + /// + /// Corresponds to [`SSL_CTX_add_cert_compression_alg`]. + /// + /// [`SSL_CTX_add_cert_compression_alg`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_add_cert_compression_alg + pub fn add_certificate_compression_algorithm( + &mut self, + compressor: C, + ) -> Result<(), ErrorStack> + where + C: CertificateCompressor, + { + const { + assert!(C::CAN_COMPRESS || C::CAN_DECOMPRESS, "Either compression or decompression must be supported for algorithm to be registered") + }; + let success = unsafe { + ffi::SSL_CTX_add_cert_compression_alg( + self.as_ptr(), + C::ALGORITHM.0, + const { + if C::CAN_COMPRESS { + Some(callbacks::raw_ssl_cert_compress::) + } else { + None + } + }, + const { + if C::CAN_DECOMPRESS { + Some(callbacks::raw_ssl_cert_decompress::) + } else { + None + } + }, + ) == 1 + }; + if !success { + return Err(ErrorStack::get()); + } + self.replace_ex_data(SslContext::cached_ex_index::(), compressor); + Ok(()) + } + /// Configures a custom private key method on the context. /// /// See [`PrivateKeyMethod`] for more details. @@ -4349,6 +4401,36 @@ impl PrivateKeyMethodError { pub const RETRY: Self = Self(ffi::ssl_private_key_result_t::ssl_private_key_retry); } +/// Describes certificate compression algorithm. Implementation MUST implement transformation at least in one direction. +pub trait CertificateCompressor: Send + Sync + 'static { + /// An IANA assigned identifier of compression algorithm + const ALGORITHM: CertificateCompressionAlgorithm; + + /// Indicates if compressor support compression + const CAN_COMPRESS: bool; + + /// Indicates if compressor support decompression + const CAN_DECOMPRESS: bool; + + /// Perform compression of `input` buffer and write compressed data to `output`. + #[allow(unused_variables)] + fn compress(&self, input: &[u8], output: &mut W) -> std::io::Result<()> + where + W: std::io::Write, + { + Err(std::io::Error::other("not implemented")) + } + + /// Perform decompression of `input` buffer and write compressed data to `output`. + #[allow(unused_variables)] + fn decompress(&self, input: &[u8], output: &mut W) -> std::io::Result<()> + where + W: std::io::Write, + { + Err(std::io::Error::other("not implemented")) + } +} + use crate::ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server}; use crate::ffi::{DTLS_method, TLS_client_method, TLS_method, TLS_server_method}; diff --git a/boring/src/ssl/test/cert_compressor.rs b/boring/src/ssl/test/cert_compressor.rs new file mode 100644 index 00000000..d62ffa87 --- /dev/null +++ b/boring/src/ssl/test/cert_compressor.rs @@ -0,0 +1,102 @@ +use std::io::Write as _; + +use super::server::Server; +use crate::ssl::CertificateCompressor; +use crate::x509::store::X509StoreBuilder; +use crate::x509::X509; + +struct BrotliCompressor { + q: u32, + lgwin: u32, +} + +impl Default for BrotliCompressor { + fn default() -> Self { + Self { q: 11, lgwin: 32 } + } +} + +impl CertificateCompressor for BrotliCompressor { + const ALGORITHM: crate::ssl::CertificateCompressionAlgorithm = + crate::ssl::CertificateCompressionAlgorithm(1234); + + const CAN_COMPRESS: bool = true; + + const CAN_DECOMPRESS: bool = true; + + fn compress(&self, input: &[u8], output: &mut W) -> std::io::Result<()> + where + W: std::io::Write, + { + let mut writer = brotli::CompressorWriter::new(output, 1024, self.q, self.lgwin); + writer.write_all(input)?; + Ok(()) + } + + fn decompress(&self, input: &[u8], output: &mut W) -> std::io::Result<()> + where + W: std::io::Write, + { + brotli::BrotliDecompress(&mut std::io::Cursor::new(input), output)?; + Ok(()) + } +} + +#[test] +fn server_only_cert_compression() { + let mut server_builder = Server::builder(); + server_builder + .ctx() + .add_certificate_compression_algorithm(BrotliCompressor::default()) + .unwrap(); + + let server = server_builder.build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(super::ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let client = server.client(); + + client.connect(); +} + +#[test] +fn client_only_cert_compression() { + let server_builder = Server::builder().build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(super::ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let mut client = server_builder.client(); + client + .ctx() + .add_certificate_compression_algorithm(BrotliCompressor::default()) + .unwrap(); + + client.connect(); +} + +#[test] +fn client_and_server_cert_compression() { + let mut server = Server::builder(); + server + .ctx() + .add_certificate_compression_algorithm(BrotliCompressor::default()) + .unwrap(); + + let server = server.build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(super::ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let mut client = server.client(); + client + .ctx() + .add_certificate_compression_algorithm(BrotliCompressor::default()) + .unwrap(); + + client.connect(); +} diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index ab11780e..4566b73c 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -24,6 +24,7 @@ use crate::x509::{X509Name, X509}; #[cfg(not(feature = "fips"))] use super::CompliancePolicy; +mod cert_compressor; mod cert_verify; mod custom_verify; #[cfg(not(feature = "fips"))] From ae1851ba0312bef6feb2955d304b0224cfc721d7 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Fri, 28 Feb 2025 10:54:55 -0800 Subject: [PATCH 26/34] Add missing release notes entry (#324) v4.15.0 was tagged a few days ago but wasn't released until today, where a new commit made it to master and snuck into the publish. I updated the v4.15.0 tag to point to the right commit hash as well. --- RELEASE_NOTES | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index dab8569b..c1ea9cf1 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,6 @@ 4.15.0 +- 2025-02-27 Expose API to enable certificate compression. (#241) - 2025-02-23 Fix lifetimes in ssl::select_next_proto - 2025-02-23 Revert cmake bump (for now) as it is overly restrictive (#321) - 2025-02-21 Introduce a builder pattern for SslEchKeys + make set_ech_keys take a reference (#320) From 221efdfea9c62797ebee8f99264452902582aaf5 Mon Sep 17 00:00:00 2001 From: andrew-signal Date: Mon, 10 Mar 2025 13:03:32 -0400 Subject: [PATCH 27/34] Update to actions/cache@v4 (#328) --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d587a4a7..0910a482 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: id: rust-version run: echo "::set-output name=version::$(rustc --version)" - name: Cache cargo index - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} @@ -45,14 +45,14 @@ jobs: - name: Create lockfile run: cargo generate-lockfile - name: Cache cargo registry - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - name: Fetch dependencies run: cargo fetch - name: Cache target directory - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: target key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} From dde4b9ccde9549d2825b675d3692f2ee0b46155b Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Mon, 10 Mar 2025 11:30:56 -0700 Subject: [PATCH 28/34] Advertise X25519MLKEM768 with "kx-client-pq-preferred" (#329) This algorithm is advertised with "kx-client-pq-supported" but not with "preferred". However the algorithm is wide spread enough that preferring it is not a significant risk. --- boring/src/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9be3e590..c4979f97 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -2805,7 +2805,7 @@ impl SslRef { if cfg!(feature = "kx-client-nist-required") { "P256Kyber768Draft00:P-256:P-384:P-521" } else { - "X25519Kyber768Draft00:X25519:P256Kyber768Draft00:P-256:P-384:P-521" + "X25519MLKEM768:X25519Kyber768Draft00:X25519:P256Kyber768Draft00:P-256:P-384:P-521" } } else if cfg!(feature = "kx-client-pq-supported") { if cfg!(feature = "kx-client-nist-required") { From c774afc85921a911562d15cd6ad1ee19fdcf15d9 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Fri, 14 Mar 2025 10:57:02 -0700 Subject: [PATCH 29/34] Add feature "fips-no-compat" As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, which means the "fips-compat" feature is no longer needed for "fips" users. Currently "fips" implies "fips-compat". To allow users to upgrade without breaking API compatibility with boring version 4, add a new feature, "fips-no-compat", that does not imply "fips-compat". In boring 5, we should remove "fips-no-compat" and decouple "fips-compat" from "fips". --- boring-sys/build/main.rs | 2 +- boring/Cargo.toml | 12 +++++++++++- boring/src/fips.rs | 12 ++++++++++-- boring/src/lib.rs | 2 +- boring/src/ssl/mod.rs | 12 ++++++------ boring/src/ssl/test/mod.rs | 6 +++--- hyper-boring/Cargo.toml | 10 ++++++++++ tokio-boring/Cargo.toml | 10 ++++++++++ 8 files changed, 52 insertions(+), 14 deletions(-) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 5af2df76..06756a7d 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -760,7 +760,7 @@ fn main() { "des.h", "dtls1.h", "hkdf.h", - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] "hpke.h", "hmac.h", "hrss.h", diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 5bd25bc1..491b1702 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -19,9 +19,19 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Controlling the build -# Use a FIPS-validated version of boringssl. +# Use a FIPS-validated version of BoringSSL. This feature sets "fips-compat". fips = ["fips-compat", "boring-sys/fips"] +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["boring-sys/fips"] + # Build with compatibility for the BoringSSL FIPS version, without enabling the # `fips` feature itself (useful e.g. if `fips-link-precompiled` is used with an # older BoringSSL version). diff --git a/boring/src/fips.rs b/boring/src/fips.rs index de28f260..29dbfae0 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -14,8 +14,16 @@ pub fn enabled() -> bool { #[test] fn is_enabled() { - #[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] + #[cfg(any( + feature = "fips", + feature = "fips-no-compat", + feature = "fips-link-precompiled" + ))] assert!(enabled()); - #[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] + #[cfg(not(any( + feature = "fips", + feature = "fips-no-compat", + feature = "fips-link-precompiled" + )))] assert!(!enabled()); } diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 1b23edac..7c870c5d 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -128,7 +128,7 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index c4979f97..250c4d08 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -104,7 +104,7 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; @@ -112,7 +112,7 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] mod ech; mod error; mod mut_only; @@ -714,7 +714,7 @@ impl SslCurve { pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _); - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub const X25519_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); @@ -759,7 +759,7 @@ impl SslCurve { ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1), ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1), ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), #[cfg(feature = "pq-experimental")] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), @@ -2010,7 +2010,7 @@ impl SslContextBuilder { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2267,7 +2267,7 @@ impl SslContextRef { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 4566b73c..69d0dbf6 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,13 +21,13 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] use super::CompliancePolicy; mod cert_compressor; mod cert_verify; mod custom_verify; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] mod ech; mod private_key_method; mod server; @@ -990,7 +990,7 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index a6ed3180..7c9921f2 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -23,6 +23,16 @@ runtime = ["hyper_old/runtime"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["tokio-boring/fips-no-compat"] + # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 8a475515..2aed8fb5 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -19,6 +19,16 @@ rustdoc-args = ["--cfg", "docsrs"] # Use a FIPS-validated version of boringssl. fips = ["boring/fips", "boring-sys/fips"] +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["boring/fips-no-compat"] + # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"] From 57307d739e0699454effccc0dd3015287fab398e Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Thu, 13 Mar 2025 09:47:56 -0700 Subject: [PATCH 30/34] Remove "fips-no-compat", decouple "fips-compat" from "fips" Modify the "fips" feature so that it no longer implies "fips-compat". The latter is no longer needed for recent builds of boringSSL; users who need older builds will need to enable "fips-compat" explicitly. Also, remove the "fipps-no-compat" feature, as it's now equivalent to "fips". --- .github/workflows/ci.yml | 4 ++-- boring-sys/build/main.rs | 2 +- boring/Cargo.toml | 21 ++++++--------------- boring/src/fips.rs | 12 ++---------- boring/src/lib.rs | 2 +- boring/src/ssl/mod.rs | 12 ++++++------ boring/src/ssl/test/mod.rs | 6 +++--- hyper-boring/Cargo.toml | 10 ---------- tokio-boring/Cargo.toml | 10 ---------- 9 files changed, 21 insertions(+), 58 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0910a482..f798c632 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -263,7 +263,7 @@ jobs: working-directory: ${{ runner.temp }}/llvm/bin run: ln -s clang clang++-12 - name: Run tests - run: cargo test --features fips + run: cargo test --features fips,fips-compat - name: Test boring-sys cargo publish (FIPS) # Running `cargo publish --dry-run` tests two things: # @@ -338,7 +338,7 @@ jobs: - name: Set CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER run: echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=${{ matrix.target }}-gcc" >> $GITHUB_ENV - name: Build for ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} --all-targets --features fips + run: cargo build --target ${{ matrix.target }} --all-targets --features fips,fips-compat test-features: name: Test features diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 06756a7d..5af2df76 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -760,7 +760,7 @@ fn main() { "des.h", "dtls1.h", "hkdf.h", - #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] + #[cfg(not(feature = "fips"))] "hpke.h", "hmac.h", "hrss.h", diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 491b1702..52de7814 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -19,22 +19,13 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Controlling the build -# Use a FIPS-validated version of BoringSSL. This feature sets "fips-compat". -fips = ["fips-compat", "boring-sys/fips"] +# Use a FIPS-validated version of BoringSSL. Note that depending on how old the +# version you're using, is, you may also need `fips-compat`. +fips = ["boring-sys/fips"] -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-no-compat = ["boring-sys/fips"] - -# Build with compatibility for the BoringSSL FIPS version, without enabling the -# `fips` feature itself (useful e.g. if `fips-link-precompiled` is used with an -# older BoringSSL version). +# Build with compatibility for older versions of boringSSL, primarily +# fips-20220613. This feature doesn't enable `fips` itself, which is useful if, +# e.g., you use `fips-link-precompiled`. fips-compat = [] # Link with precompiled FIPS-validated `bcm.o` module. diff --git a/boring/src/fips.rs b/boring/src/fips.rs index 29dbfae0..de28f260 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -14,16 +14,8 @@ pub fn enabled() -> bool { #[test] fn is_enabled() { - #[cfg(any( - feature = "fips", - feature = "fips-no-compat", - feature = "fips-link-precompiled" - ))] + #[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] assert!(enabled()); - #[cfg(not(any( - feature = "fips", - feature = "fips-no-compat", - feature = "fips-link-precompiled" - )))] + #[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] assert!(!enabled()); } diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 7c870c5d..1b23edac 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -128,7 +128,7 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 250c4d08..c4979f97 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -104,7 +104,7 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; @@ -112,7 +112,7 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] mod ech; mod error; mod mut_only; @@ -714,7 +714,7 @@ impl SslCurve { pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _); - #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] + #[cfg(not(feature = "fips"))] pub const X25519_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); @@ -759,7 +759,7 @@ impl SslCurve { ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1), ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1), ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), - #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] + #[cfg(not(feature = "fips"))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), #[cfg(feature = "pq-experimental")] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), @@ -2010,7 +2010,7 @@ impl SslContextBuilder { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] + #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2267,7 +2267,7 @@ impl SslContextRef { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] + #[cfg(not(feature = "fips"))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 69d0dbf6..4566b73c 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,13 +21,13 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] use super::CompliancePolicy; mod cert_compressor; mod cert_verify; mod custom_verify; -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] mod ech; mod private_key_method; mod server; @@ -990,7 +990,7 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] +#[cfg(not(feature = "fips"))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index 7c9921f2..a6ed3180 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -23,16 +23,6 @@ runtime = ["hyper_old/runtime"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-no-compat = ["tokio-boring/fips-no-compat"] - # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 2aed8fb5..8a475515 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -19,16 +19,6 @@ rustdoc-args = ["--cfg", "docsrs"] # Use a FIPS-validated version of boringssl. fips = ["boring/fips", "boring-sys/fips"] -# Use a FIPS build of BoringSSL, but don't set "fips-compat". -# -# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer -# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, -# which means the "fips-compat" feature is no longer needed. -# -# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply -# "fips-compat". -fips-no-compat = ["boring/fips-no-compat"] - # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"] From 867f2b3b9995848faa566add7a155309ba92fc5a Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Tue, 11 Mar 2025 08:17:41 -0700 Subject: [PATCH 31/34] boring-sys: Ignore patches when boringSSL is precompiled Internal users often have two builds for `boring`, one using a precompiled build of boringSSL and another built from source with patches applied. However the features that enable these builds are mutually exclusive. For example, the `"pq-experimental"` feature is required to build the source with all of the necessary codepoints for PQ key exchange, but if this feature is enabled and a precompiled boringSSL is provided, then the build will fail. This means users will have to also control their builds with mutually exclusive features. An alternative is to *ignore* features that enable patches whenever a precompiled boringSSL is provided. This is a little different from the "assume patched" environment variable, which applies whenever we're building from source. --- boring-sys/build/config.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/boring-sys/build/config.rs b/boring-sys/build/config.rs index 28a43ccc..19a63f52 100644 --- a/boring-sys/build/config.rs +++ b/boring-sys/build/config.rs @@ -96,10 +96,15 @@ impl Config { || self.features.underscore_wildcards; let patches_required = features_with_patches_enabled && !self.env.assume_patched; - let build_from_sources_required = self.features.fips_link_precompiled || patches_required; - if is_precompiled_native_lib && build_from_sources_required { - panic!("precompiled BoringSSL was provided, so FIPS configuration or optional patches can't be applied"); + if is_precompiled_native_lib && patches_required { + println!( + "cargo:warning=precompiled BoringSSL was provided, so patches will be ignored" + ); + } + + if is_precompiled_native_lib && self.features.fips_link_precompiled { + panic!("precompiled BoringSSL was provided, so FIPS configuration can't be applied"); } } } From d8975dc413830f0d5f23c50c2b1f7172c8faede8 Mon Sep 17 00:00:00 2001 From: Christopher Patton Date: Tue, 11 Mar 2025 09:52:04 -0700 Subject: [PATCH 32/34] boring: Disable `SslCurve` API with "fips" feature The "fips" feature implies use of a prebuilt boringSSL. The boringSSL API consumed by `SslCurve` in incompatible with older versions of boringSSL. In the `ffi` bindings, the following symbols don't exist in older builds: * NID_X25519MLKEM768 * SSL_CURVE_X25519_MLKEM768 * NID_X25519Kyber768Draft00Old The following symbols have been renamed: * SSL_CURVE_P256KYBER768DRAFT00 => SSL_CURVE_P256_KYBER768_DRAFT00 * SSL_CURVE_X25519KYBER512DRAFT00 => SSL_CURVE_X25519_KYBER512_DRAFT00 * SSL_CURVE_X25519KYBER768DRAFT00OLD => SSL_CURVE_X25519_KYBER768_DRAFT00_OLD * SSL_CURVE_P256KYBER768DRAFT00 => SSL_CURVE_P256_KYBER768_DRAFT00 Meanwhile, the `ssl_set_curves_list()` API is stable across these versions of boringSSL. These codepoints are added to the `SslCurve` API whenever "pq-experimental" is enabled. Since this feature is no longer mutually exclusive with prebuilt boringSSL (`boring-sys` just ignores patches), we also need to disable this API whenever "fips" is enabled. --- boring/src/ssl/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index c4979f97..02cc142d 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -718,15 +718,15 @@ impl SslCurve { pub const X25519_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] pub const X25519_KYBER768_DRAFT00_OLD: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD as _); - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] pub const X25519_KYBER512_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 as _); - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); /// Returns the curve name @@ -761,13 +761,13 @@ impl SslCurve { ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), #[cfg(not(feature = "fips"))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), - #[cfg(feature = "pq-experimental")] + #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] ffi::SSL_CURVE_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), _ => None, } From 11630058f098769b3ed5c5f3f9ecdc70b6607770 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Mon, 17 Mar 2025 21:37:14 -0500 Subject: [PATCH 33/34] Revert "Remove "fips-no-compat", decouple "fips-compat" from "fips"" (#334) --- .github/workflows/ci.yml | 4 ++-- boring-sys/build/main.rs | 2 +- boring/Cargo.toml | 21 +++++++++++++++------ boring/src/fips.rs | 12 ++++++++++-- boring/src/lib.rs | 2 +- boring/src/ssl/mod.rs | 12 ++++++------ boring/src/ssl/test/mod.rs | 6 +++--- hyper-boring/Cargo.toml | 10 ++++++++++ tokio-boring/Cargo.toml | 10 ++++++++++ 9 files changed, 58 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f798c632..0910a482 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -263,7 +263,7 @@ jobs: working-directory: ${{ runner.temp }}/llvm/bin run: ln -s clang clang++-12 - name: Run tests - run: cargo test --features fips,fips-compat + run: cargo test --features fips - name: Test boring-sys cargo publish (FIPS) # Running `cargo publish --dry-run` tests two things: # @@ -338,7 +338,7 @@ jobs: - name: Set CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER run: echo "CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=${{ matrix.target }}-gcc" >> $GITHUB_ENV - name: Build for ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} --all-targets --features fips,fips-compat + run: cargo build --target ${{ matrix.target }} --all-targets --features fips test-features: name: Test features diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 5af2df76..06756a7d 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -760,7 +760,7 @@ fn main() { "des.h", "dtls1.h", "hkdf.h", - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] "hpke.h", "hmac.h", "hrss.h", diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 52de7814..491b1702 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -19,13 +19,22 @@ rustdoc-args = ["--cfg", "docsrs"] [features] # Controlling the build -# Use a FIPS-validated version of BoringSSL. Note that depending on how old the -# version you're using, is, you may also need `fips-compat`. -fips = ["boring-sys/fips"] +# Use a FIPS-validated version of BoringSSL. This feature sets "fips-compat". +fips = ["fips-compat", "boring-sys/fips"] -# Build with compatibility for older versions of boringSSL, primarily -# fips-20220613. This feature doesn't enable `fips` itself, which is useful if, -# e.g., you use `fips-link-precompiled`. +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["boring-sys/fips"] + +# Build with compatibility for the BoringSSL FIPS version, without enabling the +# `fips` feature itself (useful e.g. if `fips-link-precompiled` is used with an +# older BoringSSL version). fips-compat = [] # Link with precompiled FIPS-validated `bcm.o` module. diff --git a/boring/src/fips.rs b/boring/src/fips.rs index de28f260..29dbfae0 100644 --- a/boring/src/fips.rs +++ b/boring/src/fips.rs @@ -14,8 +14,16 @@ pub fn enabled() -> bool { #[test] fn is_enabled() { - #[cfg(any(feature = "fips", feature = "fips-link-precompiled"))] + #[cfg(any( + feature = "fips", + feature = "fips-no-compat", + feature = "fips-link-precompiled" + ))] assert!(enabled()); - #[cfg(not(any(feature = "fips", feature = "fips-link-precompiled")))] + #[cfg(not(any( + feature = "fips", + feature = "fips-no-compat", + feature = "fips-link-precompiled" + )))] assert!(!enabled()); } diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 1b23edac..7c870c5d 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -128,7 +128,7 @@ pub mod error; pub mod ex_data; pub mod fips; pub mod hash; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub mod hpke; pub mod memcmp; pub mod nid; diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 02cc142d..3eaa2e83 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -104,7 +104,7 @@ pub use self::async_callbacks::{ pub use self::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub use self::ech::{SslEchKeys, SslEchKeysRef}; pub use self::error::{Error, ErrorCode, HandshakeError}; @@ -112,7 +112,7 @@ mod async_callbacks; mod bio; mod callbacks; mod connector; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] mod ech; mod error; mod mut_only; @@ -714,7 +714,7 @@ impl SslCurve { pub const X25519: SslCurve = SslCurve(ffi::SSL_CURVE_X25519 as _); - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] pub const X25519_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 as _); @@ -759,7 +759,7 @@ impl SslCurve { ffi::SSL_CURVE_SECP384R1 => Some(ffi::NID_secp384r1), ffi::SSL_CURVE_SECP521R1 => Some(ffi::NID_secp521r1), ffi::SSL_CURVE_X25519 => Some(ffi::NID_X25519), - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00 => Some(ffi::NID_X25519Kyber768Draft00), #[cfg(all(not(feature = "fips"), feature = "pq-experimental"))] ffi::SSL_CURVE_X25519_KYBER768_DRAFT00_OLD => Some(ffi::NID_X25519Kyber768Draft00Old), @@ -2010,7 +2010,7 @@ impl SslContextBuilder { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } @@ -2267,7 +2267,7 @@ impl SslContextRef { /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function /// is safe to call even after the `SSL_CTX` has been associated with connections on various /// threads. - #[cfg(not(feature = "fips"))] + #[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] #[corresponds(SSL_CTX_set1_ech_keys)] pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())).map(|_| ()) } diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 4566b73c..69d0dbf6 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -21,13 +21,13 @@ use crate::ssl::{ use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509}; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] use super::CompliancePolicy; mod cert_compressor; mod cert_verify; mod custom_verify; -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] mod ech; mod private_key_method; mod server; @@ -990,7 +990,7 @@ fn test_get_ciphers() { } #[test] -#[cfg(not(feature = "fips"))] +#[cfg(not(any(feature = "fips", feature = "fips-no-compat")))] fn test_set_compliance() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_compliance_policy(CompliancePolicy::FIPS_202205) diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index a6ed3180..7c9921f2 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -23,6 +23,16 @@ runtime = ["hyper_old/runtime"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["tokio-boring/fips-no-compat"] + # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] diff --git a/tokio-boring/Cargo.toml b/tokio-boring/Cargo.toml index 8a475515..2aed8fb5 100644 --- a/tokio-boring/Cargo.toml +++ b/tokio-boring/Cargo.toml @@ -19,6 +19,16 @@ rustdoc-args = ["--cfg", "docsrs"] # Use a FIPS-validated version of boringssl. fips = ["boring/fips", "boring-sys/fips"] +# Use a FIPS build of BoringSSL, but don't set "fips-compat". +# +# As of boringSSL commit a430310d6563c0734ddafca7731570dfb683dc19, we no longer +# need to make exceptions for the types of BufLen, ProtosLen, and ValueLen, +# which means the "fips-compat" feature is no longer needed. +# +# TODO(cjpatton) Delete this feature and modify "fips" so that it doesn't imply +# "fips-compat". +fips-no-compat = ["boring/fips-no-compat"] + # Link with precompiled FIPS-validated `bcm.o` module. fips-link-precompiled = ["boring/fips-link-precompiled", "boring-sys/fips-link-precompiled"] From d5bd85b3e525cae204fd4845f7600434a0f28dc1 Mon Sep 17 00:00:00 2001 From: Felix Hanau Date: Tue, 18 Mar 2025 11:16:43 -0400 Subject: [PATCH 34/34] Document linking to C++ standard library (#335) This was added in #264, but not documented so far. --- boring/src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 7c870c5d..a54e2bfa 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -61,6 +61,13 @@ //! Note that `BORING_BSSL_PRECOMPILED_BCM_O` is never used, as linking BoringSSL with precompiled non-FIPS //! module is not supported. //! +//! ## Linking with a C++ standard library +//! +//! Recent versions of boringssl require some C++ standard library features, so boring needs to link +//! with a STL implementation. This can be controlled using the BORING_BSSL_RUST_CPPLIB variable. If +//! no library is specified, libc++ is used on macOS and iOS whereas libstdc++ is used on other Unix +//! systems. +//! //! # Optional patches //! //! ## Raw Public Key