From 9053b5d905e8eaa6fd6e05a1cd713f5533fe58a5 Mon Sep 17 00:00:00 2001 From: 0x676e67 Date: Wed, 14 Aug 2024 17:53:57 +0800 Subject: [PATCH 01/21] chore(boring-sys): Fix git apply patch on Windows (#261) * chore(boring-sys): Fix git apply patch on Windows * cargo fmt --all --- 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 4d2ab6c0..05242028 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -501,12 +501,16 @@ fn ensure_patches_applied(config: &Config) -> io::Result<()> { fn apply_patch(config: &Config, patch_name: &str) -> io::Result<()> { let src_path = get_boringssl_source_path(config); + #[cfg(not(windows))] let cmd_path = config .manifest_dir .join("patches") .join(patch_name) .canonicalize()?; + #[cfg(windows)] + let cmd_path = config.manifest_dir.join("patches").join(patch_name); + let mut args = vec!["apply", "-v", "--whitespace=fix"]; // non-bazel versions of BoringSSL have no src/ dir From 1b5ae3251fbc54c00ed830c07024feff6c4c7f34 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Fri, 9 Aug 2024 04:16:07 -0700 Subject: [PATCH 02/21] Expose mTLS related APIs --- boring/src/ssl/mod.rs | 57 ++++++++++++++++++++++++++++++++++++++++++ boring/src/x509/mod.rs | 24 ++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index be26aa94..83b616a6 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -2918,6 +2918,25 @@ impl SslRef { unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits() as c_int, None) } } + /// Sets the certificate verification depth. + /// + /// If the peer's certificate chain is longer than this value, verification will fail. + /// + /// This corresponds to [`SSL_set_verify_depth`]. + /// + /// [`SSL_set_verify_depth`]: https://docs.openssl.org/1.1.1/man3/SSL_CTX_set_verify/ + pub fn set_verify_depth(&mut self, depth: u32) { + #[cfg(feature = "rpk")] + assert!( + !self.ssl_context().is_rpk(), + "This API is not supported for RPK" + ); + + unsafe { + ffi::SSL_set_verify_depth(self.as_ptr(), depth as c_int); + } + } + /// Returns the verify mode that was set using `set_verify`. /// /// This corresponds to [`SSL_get_verify_mode`]. @@ -2975,6 +2994,25 @@ impl SslRef { } } + /// Sets a custom certificate store for verifying peer certificates. + /// + /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. + /// + /// [`SSL_set0_verify_cert_store`]: https://docs.openssl.org/1.0.2/man3/SSL_CTX_set1_verify_cert_store/ + pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { + #[cfg(feature = "rpk")] + assert!( + !self.ssl_context().is_rpk(), + "This API is not supported for RPK" + ); + + unsafe { + cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?; + mem::forget(cert_store); + Ok(()) + } + } + /// Like [`SslContextBuilder::set_custom_verify_callback`]. /// /// This corresponds to [`SSL_set_custom_verify`]. @@ -3800,6 +3838,25 @@ impl SslRef { Ok(()) } + /// Sets the list of CA names sent to the client. + /// + /// The CA certificates must still be added to the trust root - they are not automatically set + /// as trusted by this method. + /// + /// This corresponds to [`SSL_set_client_CA_list`]. + /// + /// [`SSL_set_client_CA_list`]: https://docs.openssl.org/1.1.1/man3/SSL_CTX_set0_CA_list/ + pub fn set_client_ca_list(&mut self, list: Stack) { + #[cfg(feature = "rpk")] + assert!( + !self.ssl_context().is_rpk(), + "This API is not supported for RPK" + ); + + unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) } + mem::forget(list); + } + /// Sets the private key. /// /// This corresponds to [`SSL_use_PrivateKey`]. diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 30a4b2b8..1ef04454 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -474,6 +474,30 @@ impl X509Ref { } } + /// Returns this certificate's subject key id. + /// + /// This corresponds to [`X509_get0_subject_key_id`]. + /// + /// [`X509_get0_subject_key_id`]: https://docs.openssl.org/1.1.1/man3/X509_get_extension_flags/ + pub fn subject_key_id(&self) -> &Asn1StringRef { + unsafe { + let name = ffi::X509_get0_subject_key_id(self.as_ptr()); + Asn1StringRef::from_ptr(name as _) + } + } + + /// Returns this certificate's authority key id. + /// + /// This corresponds to [`X509_get0_authority_key_id`]. + /// + /// [`X509_get0_authority_key_id`]: https://docs.openssl.org/1.1.1/man3/X509_get_extension_flags/ + pub fn authority_key_id(&self) -> &Asn1StringRef { + unsafe { + let name = ffi::X509_get0_authority_key_id(self.as_ptr()); + Asn1StringRef::from_ptr(name as _) + } + } + pub fn public_key(&self) -> Result, ErrorStack> { unsafe { let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; From 2be6e100b6335747a8aee983386e4bbde8d63b1c Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Tue, 13 Aug 2024 17:24:42 -0700 Subject: [PATCH 03/21] Introduce ForeignTypeExt and ForeignTypeRefExt `ForeignTypeExt` and `ForeignTypeRefExt` are inspired by https://github.com/sfackler/rust-openssl/pull/1345, which make dealing with FFI safer and more ergonomic. The new APIs (e.g. from_const_ptr_opt`) also allow for gracefully handling instances where the initial API call results in `NULL`. Instead of crashing the program, `None` will be returned. --- boring/src/util.rs | 31 ++++++++++++++++++++++++-- boring/src/x509/mod.rs | 50 ++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/boring/src/util.rs b/boring/src/util.rs index 21591d2f..bb6373c1 100644 --- a/boring/src/util.rs +++ b/boring/src/util.rs @@ -1,10 +1,10 @@ +use crate::error::ErrorStack; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; -use crate::error::ErrorStack; - /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). /// @@ -65,3 +65,30 @@ where } } } + +#[allow(dead_code)] +pub trait ForeignTypeExt: ForeignType { + unsafe fn from_ptr_opt(ptr: *mut Self::CType) -> Option { + if ptr.is_null() { + None + } else { + Some(Self::from_ptr(ptr)) + } + } +} +impl ForeignTypeExt for FT {} + +pub trait ForeignTypeRefExt: ForeignTypeRef { + unsafe fn from_const_ptr<'a>(ptr: *const Self::CType) -> &'a Self { + Self::from_ptr(ptr as *mut Self::CType) + } + + unsafe fn from_const_ptr_opt<'a>(ptr: *const Self::CType) -> Option<&'a Self> { + if ptr.is_null() { + None + } else { + Some(Self::from_const_ptr(ptr as *mut Self::CType)) + } + } +} +impl ForeignTypeRefExt for FT {} diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 1ef04454..eb55c305 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -36,6 +36,7 @@ use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use crate::ssl::SslRef; use crate::stack::{Stack, StackRef, Stackable}; use crate::string::OpensslString; +use crate::util::ForeignTypeRefExt; use crate::x509::verify::X509VerifyParamRef; use crate::{cvt, cvt_n, cvt_p}; @@ -407,8 +408,7 @@ impl X509Ref { pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = ffi::X509_get_subject_name(self.as_ptr()); - assert!(!name.is_null()); - X509NameRef::from_ptr(name) + X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") } } @@ -419,19 +419,6 @@ impl X509Ref { unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } } - /// Returns this certificate's issuer name. - /// - /// This corresponds to [`X509_get_issuer_name`]. - /// - /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html - pub fn issuer_name(&self) -> &X509NameRef { - unsafe { - let name = ffi::X509_get_issuer_name(self.as_ptr()); - assert!(!name.is_null()); - X509NameRef::from_ptr(name) - } - } - /// Returns this certificate's subject alternative name entries, if they exist. /// /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. @@ -453,6 +440,15 @@ impl X509Ref { } } + /// Returns this certificate's issuer name. + #[corresponds(X509_get_issuer_name)] + pub fn issuer_name(&self) -> &X509NameRef { + unsafe { + let name = ffi::X509_get_issuer_name(self.as_ptr()); + X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") + } + } + /// Returns this certificate's issuer alternative name entries, if they exist. /// /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. @@ -474,27 +470,19 @@ impl X509Ref { } } - /// Returns this certificate's subject key id. - /// - /// This corresponds to [`X509_get0_subject_key_id`]. - /// - /// [`X509_get0_subject_key_id`]: https://docs.openssl.org/1.1.1/man3/X509_get_extension_flags/ - pub fn subject_key_id(&self) -> &Asn1StringRef { + /// Returns this certificate's subject key id, if it exists. + pub fn subject_key_id(&self) -> Option<&Asn1StringRef> { unsafe { - let name = ffi::X509_get0_subject_key_id(self.as_ptr()); - Asn1StringRef::from_ptr(name as _) + let data = ffi::X509_get0_subject_key_id(self.as_ptr()); + Asn1StringRef::from_const_ptr_opt(data) } } - /// Returns this certificate's authority key id. - /// - /// This corresponds to [`X509_get0_authority_key_id`]. - /// - /// [`X509_get0_authority_key_id`]: https://docs.openssl.org/1.1.1/man3/X509_get_extension_flags/ - pub fn authority_key_id(&self) -> &Asn1StringRef { + /// Returns this certificate's authority key id, if it exists. + pub fn authority_key_id(&self) -> Option<&Asn1StringRef> { unsafe { - let name = ffi::X509_get0_authority_key_id(self.as_ptr()); - Asn1StringRef::from_ptr(name as _) + let data = ffi::X509_get0_authority_key_id(self.as_ptr()); + Asn1StringRef::from_const_ptr_opt(data) } } From fae2f7fbf1bb2f5eb77c5abbcaf72d8736be1ed1 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Mon, 12 Aug 2024 21:21:29 -0700 Subject: [PATCH 04/21] Introduce `corresponds` macro from openssl-macros Our rustdocs are miserably broken. We manually link to openssl docs in most binding definitions, and openssl keeps changing their documentation URL, so in order to fix everything I'd have to touch every single binding definition in every single file. Instead, we should use the `corresponds` macro from the openssl-macros crate which nicely adds a link to the openssl documentation on our behalf. If the openssl documentation url ever changes again in the future, a simple dependency bump should solve the issue. --- Cargo.toml | 1 + boring/Cargo.toml | 1 + boring/src/ssl/mod.rs | 793 +++++++++-------------------------------- boring/src/x509/mod.rs | 82 ++--- 4 files changed, 204 insertions(+), 673 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3836084b..e8bf6e38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,5 +40,6 @@ http = "0.2" hyper = { version = "0.14", default-features = false } linked_hash_set = "0.1" once_cell = "1.0" +openssl-macros = "0.1.1" tower = "0.4" tower-layer = "0.3" diff --git a/boring/Cargo.toml b/boring/Cargo.toml index 0a576ab4..a558eefa 100644 --- a/boring/Cargo.toml +++ b/boring/Cargo.toml @@ -69,6 +69,7 @@ kx-client-nist-required = ["kx-safe-default"] 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/mod.rs b/boring/src/ssl/mod.rs index 83b616a6..12ffedf5 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -57,10 +57,10 @@ //! } //! } //! ``` -use crate::ffi; 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; use std::convert::TryInto; @@ -82,6 +82,7 @@ use crate::dh::DhRef; use crate::ec::EcKeyRef; use crate::error::ErrorStack; use crate::ex_data::Index; +use crate::ffi; use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; @@ -243,9 +244,7 @@ pub struct SslMethod(*const ffi::SSL_METHOD); impl SslMethod { /// Support all versions of the TLS protocol. - /// - /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` - /// on OpenSSL 1.0.x. + #[corresponds(TLS_method)] pub fn tls() -> SslMethod { unsafe { SslMethod(TLS_method()) } } @@ -257,25 +256,19 @@ impl SslMethod { } /// Support all versions of the DTLS protocol. - /// - /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` - /// on OpenSSL 1.0.x. + #[corresponds(DTLS_method)] pub fn dtls() -> SslMethod { unsafe { SslMethod(DTLS_method()) } } /// Support all versions of the TLS protocol, explicitly as a client. - /// - /// This corresponds to `TLS_client_method` on OpenSSL 1.1.0 and - /// `SSLv23_client_method` on OpenSSL 1.0.x. + #[corresponds(TLS_client_method)] pub fn tls_client() -> SslMethod { unsafe { SslMethod(TLS_client_method()) } } /// Support all versions of the TLS protocol, explicitly as a server. - /// - /// This corresponds to `TLS_server_method` on OpenSSL 1.1.0 and - /// `SSLv23_server_method` on OpenSSL 1.0.x. + #[corresponds(TLS_server_method)] pub fn tls_server() -> SslMethod { unsafe { SslMethod(TLS_server_method()) } } @@ -285,6 +278,7 @@ impl SslMethod { /// # Safety /// /// The caller must ensure the pointer is valid. + #[corresponds(TLS_server_method)] pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod { SslMethod(ptr) } @@ -737,6 +731,7 @@ impl SslCurve { /// 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 { let ptr = ffi::SSL_get_curve_name(self.0 as u16); @@ -858,10 +853,7 @@ pub struct SslContextBuilder { #[cfg(feature = "rpk")] impl SslContextBuilder { /// Creates a new `SslContextBuilder` to be used with Raw Public Key. - /// - /// This corresponds to [`SSL_CTX_new`]. - /// - /// [`SSL_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_new.html + #[corresponds(SSL_CTX_new)] pub fn new_rpk() -> Result { unsafe { init(); @@ -901,10 +893,7 @@ impl SslContextBuilder { impl SslContextBuilder { /// Creates a new `SslContextBuilder`. - /// - /// This corresponds to [`SSL_CTX_new`]. - /// - /// [`SSL_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_new.html + #[corresponds(SSL_CTX_new)] pub fn new(method: SslMethod) -> Result { unsafe { init(); @@ -955,10 +944,7 @@ impl SslContextBuilder { } /// Configures the certificate verification method for new connections. - /// - /// This corresponds to [`SSL_CTX_set_verify`]. - /// - /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + #[corresponds(SSL_CTX_set_verify)] pub fn set_verify(&mut self, mode: SslVerifyMode) { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -981,13 +967,10 @@ impl SslContextBuilder { /// Those callbacks can inspect the peer-sent chain, call [`X509StoreContextRef::verify_cert`] /// and inspect the result, or perform other operations more straightforwardly. /// - /// This corresponds to [`SSL_CTX_set_verify`]. - /// /// # Panics /// /// This method panics if this `Ssl` is associated with a RPK context. - /// - /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html + #[corresponds(SSL_CTX_set_verify)] pub fn set_verify_callback(&mut self, mode: SslVerifyMode, callback: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, @@ -1015,6 +998,7 @@ impl SslContextBuilder { /// # Panics /// /// This method panics if this `Ssl` is associated with a RPK context. + #[corresponds(SSL_CTX_set_custom_verify)] pub fn set_custom_verify_callback(&mut self, mode: SslVerifyMode, callback: F) where F: Fn(&mut SslRef) -> Result<(), SslVerifyError> + 'static + Sync + Send, @@ -1040,10 +1024,8 @@ impl SslContextBuilder { /// Obtain the server name with the `servername` method and then set the corresponding context /// with `set_ssl_context` /// - /// This corresponds to [`SSL_CTX_set_tlsext_servername_callback`]. - /// - /// [`SSL_CTX_set_tlsext_servername_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_tlsext_servername_callback.html // FIXME tlsext prefix? + #[corresponds(SSL_CTX_set_tlsext_servername_callback)] pub fn set_servername_callback(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, @@ -1069,10 +1051,7 @@ impl SslContextBuilder { /// Sets the certificate verification depth. /// /// If the peer's certificate chain is longer than this value, verification will fail. - /// - /// This corresponds to [`SSL_CTX_set_verify_depth`]. - /// - /// [`SSL_CTX_set_verify_depth`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify_depth.html + #[corresponds(SSL_CTX_set_verify_depth)] pub fn set_verify_depth(&mut self, depth: u32) { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1083,10 +1062,7 @@ impl SslContextBuilder { } /// Sets a custom certificate store for verifying peer certificates. - /// - /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. - /// - /// [`SSL_CTX_set0_verify_cert_store`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set0_verify_cert_store.html + #[corresponds(SSL_CTX_set0_verify_cert_store)] pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1101,10 +1077,7 @@ impl SslContextBuilder { } /// Replaces the context's certificate store. - /// - /// This corresponds to [`SSL_CTX_set_cert_store`]. - /// - /// [`SSL_CTX_set_cert_store`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_cert_store.html + #[corresponds(SSL_CTX_set_cert_store)] pub fn set_cert_store(&mut self, cert_store: X509Store) { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1121,10 +1094,7 @@ impl SslContextBuilder { /// instead of a single record at a time. /// /// It has no effect when used with DTLS. - /// - /// This corresponds to [`SSL_CTX_set_read_ahead`]. - /// - /// [`SSL_CTX_set_read_ahead`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_read_ahead.html + #[corresponds(SSL_CTX_set_read_ahead)] pub fn set_read_ahead(&mut self, read_ahead: bool) { unsafe { ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_int); @@ -1132,27 +1102,20 @@ impl SslContextBuilder { } /// Sets the mode used by the context, returning the new bit-mask after adding mode. - /// - /// This corresponds to [`SSL_CTX_set_mode`]. - /// - /// [`SSL_CTX_set_mode`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_mode.html + #[corresponds(SSL_CTX_set_mode)] pub fn set_mode(&mut self, mode: SslMode) -> SslMode { let bits = unsafe { ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits()) }; SslMode::from_bits_retain(bits) } /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange. - /// - /// This corresponds to [`SSL_CTX_set_tmp_dh`]. - /// - /// [`SSL_CTX_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html + #[corresponds(SSL_CTX_set_tmp_dh)] pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange. - /// - /// This corresponds to `SSL_CTX_set_tmp_ecdh`. + #[corresponds(SSL_CTX_set_tmp_ecdh)] pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } @@ -1161,10 +1124,7 @@ impl SslContextBuilder { /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables /// if present, or defaults specified at OpenSSL build time otherwise. - /// - /// This corresponds to [`SSL_CTX_set_default_verify_paths`]. - /// - /// [`SSL_CTX_set_default_verify_paths`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_default_verify_paths.html + #[corresponds(SSL_CTX_set_default_verify_paths)] pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1175,10 +1135,7 @@ impl SslContextBuilder { /// Loads trusted root certificates from a file. /// /// The file should contain a sequence of PEM-formatted CA certificates. - /// - /// This corresponds to [`SSL_CTX_load_verify_locations`]. - /// - /// [`SSL_CTX_load_verify_locations`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_load_verify_locations.html + #[corresponds(SSL_CTX_load_verify_locations)] pub fn set_ca_file>(&mut self, file: P) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1198,10 +1155,7 @@ impl SslContextBuilder { /// /// The CA certificates must still be added to the trust root - they are not automatically set /// as trusted by this method. - /// - /// This corresponds to [`SSL_CTX_set_client_CA_list`]. - /// - /// [`SSL_CTX_set_client_CA_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html + #[corresponds(SSL_CTX_set_client_CA_list)] pub fn set_client_ca_list(&mut self, list: Stack) { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1214,10 +1168,7 @@ impl SslContextBuilder { /// Add the provided CA certificate to the list sent by the server to the client when /// requesting client-side TLS authentication. - /// - /// This corresponds to [`SSL_CTX_add_client_CA`]. - /// - /// [`SSL_CTX_add_client_CA`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_client_CA_list.html + #[corresponds(SSL_CTX_add_client_CA)] pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1233,10 +1184,7 @@ impl SslContextBuilder { /// /// This value should be set when using client certificates, or each request will fail its /// handshake and need to be restarted. - /// - /// This corresponds to [`SSL_CTX_set_session_id_context`]. - /// - /// [`SSL_CTX_set_session_id_context`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_session_id_context.html + #[corresponds(SSL_CTX_set_session_id_context)] pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(sid_ctx.len() <= c_uint::MAX as usize); @@ -1254,10 +1202,7 @@ impl SslContextBuilder { /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a /// single file. - /// - /// This corresponds to [`SSL_CTX_use_certificate_file`]. - /// - /// [`SSL_CTX_use_certificate_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate_file)] pub fn set_certificate_file>( &mut self, file: P, @@ -1282,10 +1227,7 @@ impl SslContextBuilder { /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf /// certificate, and the remainder forming the chain of certificates up to and including the /// trusted root certificate. - /// - /// This corresponds to [`SSL_CTX_use_certificate_chain_file`]. - /// - /// [`SSL_CTX_use_certificate_chain_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate_chain_file)] pub fn set_certificate_chain_file>( &mut self, file: P, @@ -1303,10 +1245,7 @@ impl SslContextBuilder { /// Sets the leaf certificate. /// /// Use `add_extra_chain_cert` to add the remainder of the certificate chain. - /// - /// This corresponds to [`SSL_CTX_use_certificate`]. - /// - /// [`SSL_CTX_use_certificate`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html + #[corresponds(SSL_CTX_use_certificate)] pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } @@ -1315,10 +1254,7 @@ impl SslContextBuilder { /// /// This chain should contain all certificates necessary to go from the certificate specified by /// `set_certificate` to a trusted root. - /// - /// This corresponds to [`SSL_CTX_add_extra_chain_cert`]. - /// - /// [`SSL_CTX_add_extra_chain_cert`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html + #[corresponds(SSL_CTX_add_extra_chain_cert)] pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1331,10 +1267,7 @@ impl SslContextBuilder { } /// Loads the private key from a file. - /// - /// This corresponds to [`SSL_CTX_use_PrivateKey_file`]. - /// - /// [`SSL_CTX_use_PrivateKey_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html + #[corresponds(SSL_CTX_use_PrivateKey_file)] pub fn set_private_key_file>( &mut self, file: P, @@ -1352,10 +1285,7 @@ impl SslContextBuilder { } /// Sets the private key. - /// - /// This corresponds to [`SSL_CTX_use_PrivateKey`]. - /// - /// [`SSL_CTX_use_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html + #[corresponds(SSL_CTX_use_PrivateKey)] pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPrivate, @@ -1371,10 +1301,8 @@ impl SslContextBuilder { /// /// See [`ciphers`] for details on the format. /// - /// This corresponds to [`SSL_CTX_set_cipher_list`]. - /// - /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html - /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_cipher_list.html + /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html + #[corresponds(SSL_CTX_set_cipher_list)] pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { @@ -1390,44 +1318,33 @@ impl SslContextBuilder { /// /// See [`ciphers`] for details on the format /// - /// This corresponds to [`SSL_CTX_get_ciphers`]. - /// /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html - /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html + #[corresponds(SSL_CTX_get_ciphers)] pub fn ciphers(&self) -> Option<&StackRef> { self.ctx.ciphers() } /// Sets the options used by the context, returning the old set. /// - /// This corresponds to [`SSL_CTX_set_options`]. - /// /// # Note /// /// This *enables* the specified options, but does not disable unspecified options. Use /// `clear_options` for that. - /// - /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + #[corresponds(SSL_CTX_set_options)] pub fn set_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; SslOptions::from_bits_retain(bits) } /// Returns the options used by the context. - /// - /// This corresponds to [`SSL_CTX_get_options`]. - /// - /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + #[corresponds(SSL_CTX_get_options)] pub fn options(&self) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; SslOptions::from_bits_retain(bits) } /// Clears the options used by the context, returning the old set. - /// - /// This corresponds to [`SSL_CTX_clear_options`]. - /// - /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html + #[corresponds(SSL_CTX_clear_options)] pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; SslOptions::from_bits_retain(bits) @@ -1437,10 +1354,7 @@ impl SslContextBuilder { /// /// If version is `None`, the default minimum version is used. For BoringSSL this defaults to /// TLS 1.0. - /// - /// This corresponds to [`SSL_CTX_set_min_proto_version`]. - /// - /// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html + #[corresponds(SSL_CTX_set_min_proto_version)] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_min_proto_version( @@ -1454,10 +1368,7 @@ impl SslContextBuilder { /// Sets the maximum supported protocol version. /// /// If version is `None`, the default maximum version is used. For BoringSSL this is TLS 1.3. - /// - /// This corresponds to [`SSL_CTX_set_max_proto_version`]. - /// - /// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_max_proto_version.html + #[corresponds(SSL_CTX_set_max_proto_version)] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_max_proto_version( @@ -1469,10 +1380,7 @@ impl SslContextBuilder { } /// Gets the minimum supported protocol version. - /// - /// This corresponds to [`SSL_CTX_get_min_proto_version`]. - /// - /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_min_proto_version.html + #[corresponds(SSL_CTX_get_min_proto_version)] pub fn min_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); @@ -1485,10 +1393,7 @@ impl SslContextBuilder { } /// Gets the maximum supported protocol version. - /// - /// This corresponds to [`SSL_CTX_get_max_proto_version`]. - /// - /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man3.1/man3/SSL_CTX_get_max_proto_version.html + #[corresponds(SSL_CTX_get_max_proto_version)] pub fn max_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); @@ -1506,10 +1411,7 @@ impl SslContextBuilder { /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1` /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by /// preference. - /// - /// This corresponds to [`SSL_CTX_set_alpn_protos`]. - /// - /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html + #[corresponds(SSL_CTX_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { #[cfg_attr(not(feature = "fips"), allow(clippy::unnecessary_cast))] @@ -1531,10 +1433,7 @@ impl SslContextBuilder { } /// Enables the DTLS extension "use_srtp" as defined in RFC5764. - /// - /// This corresponds to [`SSL_CTX_set_tlsext_use_srtp`]. - /// - /// [`SSL_CTX_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_CTX_set_tlsext_use_srtp)] pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { unsafe { let cstr = CString::new(protocols).unwrap(); @@ -1557,11 +1456,9 @@ impl SslContextBuilder { /// of those protocols on success. The [`select_next_proto`] function implements the standard /// protocol selection algorithm. /// - /// This corresponds to [`SSL_CTX_set_alpn_select_cb`]. - /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`select_next_proto`]: fn.select_next_proto.html - /// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html + #[corresponds(SSL_CTX_set_alpn_select_cb)] pub fn set_alpn_select_callback(&mut self, callback: F) where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, @@ -1579,10 +1476,7 @@ impl SslContextBuilder { /// Sets a callback that is called before most ClientHello processing and before the decision whether /// to resume a session is made. The callback may inspect the ClientHello and configure the /// connection. - /// - /// This corresponds to [`SSL_CTX_set_select_certificate_cb`]. - /// - /// [`SSL_CTX_set_select_certificate_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_select_certificate_cb.html + #[corresponds(SSL_CTX_set_select_certificate_cb)] pub fn set_select_certificate_callback(&mut self, callback: F) where F: Fn(ClientHello<'_>) -> Result<(), SelectCertError> + Sync + Send + 'static, @@ -1599,10 +1493,7 @@ impl SslContextBuilder { /// Configures a custom private key method on the context. /// /// See [`PrivateKeyMethod`] for more details. - /// - /// This corresponds to [`SSL_CTX_set_private_key_method`] - /// - /// [`SSL_CTX_set_private_key_method`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_private_key_method + #[corresponds(SSL_CTX_set_private_key_method)] pub fn set_private_key_method(&mut self, method: M) where M: PrivateKeyMethod, @@ -1622,19 +1513,13 @@ impl SslContextBuilder { } /// Checks for consistency between the private key and certificate. - /// - /// This corresponds to [`SSL_CTX_check_private_key`]. - /// - /// [`SSL_CTX_check_private_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_check_private_key.html + #[corresponds(SSL_CTX_check_private_key)] pub fn check_private_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } } /// Returns a shared reference to the context's certificate store. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store(&self) -> &X509StoreBuilderRef { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1643,10 +1528,7 @@ impl SslContextBuilder { } /// Returns a mutable reference to the context's certificate store. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { #[cfg(feature = "rpk")] assert!(!self.is_rpk, "This API is not supported for RPK"); @@ -1666,10 +1548,7 @@ impl SslContextBuilder { /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and /// `Ok(false)` indicates that the status should not be returned to the client. - /// - /// This corresponds to [`SSL_CTX_set_tlsext_status_cb`]. - /// - /// [`SSL_CTX_set_tlsext_status_cb`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tlsext_status_cb.html + #[corresponds(SSL_CTX_set_tlsext_status_cb)] pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> where F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, @@ -1689,10 +1568,7 @@ impl SslContextBuilder { /// The callback will be called with the SSL context, an identity hint if one was provided /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The /// identity must be written as a null-terminated C string. - /// - /// This corresponds to [`SSL_CTX_set_psk_client_callback`]. - /// - /// [`SSL_CTX_set_psk_client_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_client_callback.html + #[corresponds(SSL_CTX_set_psk_client_callback)] pub fn set_psk_client_callback(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result @@ -1722,10 +1598,7 @@ impl SslContextBuilder { /// The callback will be called with the SSL context, an identity provided by the client, /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of /// bytes in the pre-shared key. - /// - /// This corresponds to [`SSL_CTX_set_psk_server_callback`]. - /// - /// [`SSL_CTX_set_psk_server_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_server_callback.html + #[corresponds(SSL_CTX_set_psk_server_callback)] pub fn set_psk_server_callback(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result @@ -1750,11 +1623,9 @@ impl SslContextBuilder { /// Note that session caching must be enabled for the callback to be invoked, and it defaults /// off for clients. [`set_session_cache_mode`] controls that behavior. /// - /// This corresponds to [`SSL_CTX_sess_set_new_cb`]. - /// /// [`SslRef::session`]: struct.SslRef.html#method.session /// [`set_session_cache_mode`]: #method.set_session_cache_mode - /// [`SSL_CTX_sess_set_new_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + #[corresponds(SSL_CTX_sess_set_new_cb)] pub fn set_new_session_callback(&mut self, callback: F) where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, @@ -1768,10 +1639,7 @@ impl SslContextBuilder { /// Sets the callback which is called when sessions are removed from the context. /// /// Sessions can be removed because they have timed out or because they are considered faulty. - /// - /// This corresponds to [`SSL_CTX_sess_set_remove_cb`]. - /// - /// [`SSL_CTX_sess_set_remove_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + #[corresponds(SSL_CTX_sess_set_remove_cb)] pub fn set_remove_session_callback(&mut self, callback: F) where F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, @@ -1792,13 +1660,10 @@ impl SslContextBuilder { /// return the session corresponding to that ID if available. This is only used for servers, not /// clients. /// - /// This corresponds to [`SSL_CTX_sess_set_get_cb`]. - /// /// # Safety /// /// The returned [`SslSession`] must not be associated with a different [`SslContext`]. - /// - /// [`SSL_CTX_sess_set_get_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html + #[corresponds(SSL_CTX_sess_set_get_cb)] pub unsafe fn set_get_session_callback(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> Result, GetSessionPendingError> @@ -1815,10 +1680,7 @@ impl SslContextBuilder { /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message /// traffic. The line does not contain a trailing newline. - /// - /// This corresponds to [`SSL_CTX_set_keylog_callback`]. - /// - /// [`SSL_CTX_set_keylog_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_keylog_callback.html + #[corresponds(SSL_CTX_set_keylog_callback)] pub fn set_keylog_callback(&mut self, callback: F) where F: Fn(&SslRef, &str) + 'static + Sync + Send, @@ -1832,10 +1694,7 @@ impl SslContextBuilder { /// Sets the session caching mode use for connections made with the context. /// /// Returns the previous session caching mode. - /// - /// This corresponds to [`SSL_CTX_set_session_cache_mode`]. - /// - /// [`SSL_CTX_set_session_cache_mode`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_session_cache_mode.html + #[corresponds(SSL_CTX_set_session_cache_mode)] pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode { unsafe { let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits()); @@ -1848,12 +1707,9 @@ impl SslContextBuilder { /// This can be used to provide data to callbacks registered with the context. Use the /// `SslContext::new_ex_index` method to create an `Index`. /// - /// This corresponds to [`SSL_CTX_set_ex_data`]. - /// /// Note that if this method is called multiple times with the same index, any previous /// value stored in the `SslContextBuilder` will be leaked. - /// - /// [`SSL_CTX_set_ex_data`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ex_data.html + #[corresponds(SSL_CTX_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { unsafe { self.ctx.set_ex_data(index, data); @@ -1865,11 +1721,8 @@ impl SslContextBuilder { /// This can be used to provide data to callbacks registered with the context. Use the /// `Ssl::new_ex_index` method to create an `Index`. /// - /// This corresponds to [`SSL_set_ex_data`]. - /// /// Any previous value will be returned and replaced by the new one. - /// - /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_CTX_set_ex_data)] pub fn replace_ex_data(&mut self, index: Index, data: T) -> Option { unsafe { self.ctx.replace_ex_data(index, data) } } @@ -1877,20 +1730,14 @@ impl SslContextBuilder { /// Sets the context's session cache size limit, returning the previous limit. /// /// A value of 0 means that the cache size is unbounded. - /// - /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. - /// - /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + #[corresponds(SSL_CTX_sess_set_cache_size)] #[allow(clippy::useless_conversion)] pub fn set_session_cache_size(&mut self, size: u32) -> u64 { unsafe { ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size.into()).into() } } /// Sets the context's supported signature algorithms. - /// - /// This corresponds to [`SSL_CTX_set1_sigalgs_list`]. - /// - /// [`SSL_CTX_set1_sigalgs_list`]: https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set1_sigalgs_list.html + #[corresponds(SSL_CTX_set1_sigalgs_list)] pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> { let sigalgs = CString::new(sigalgs).unwrap(); unsafe { @@ -1900,33 +1747,24 @@ impl SslContextBuilder { } /// Set's whether the context should enable GREASE. - /// - /// This corresponds to [`SSL_CTX_set_grease_enabled`] - /// - /// [`SSL_CTX_set_grease_enabled`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_grease_enabled + #[corresponds(SSL_CTX_set_grease_enabled)] pub fn set_grease_enabled(&mut self, enabled: bool) { unsafe { ffi::SSL_CTX_set_grease_enabled(self.as_ptr(), enabled as _) } } /// Configures whether ClientHello extensions should be permuted. /// - /// This corresponds to [`SSL_CTX_set_permute_extensions`]. - /// - /// [`SSL_CTX_set_permute_extensions`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_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. /// Once the submoduled fips commit is upgraded, these gates can be removed. + #[corresponds(SSL_CTX_set_permute_extensions)] #[cfg(not(feature = "fips"))] pub fn set_permute_extensions(&mut self, enabled: bool) { unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) } } /// Sets the context's supported signature verification algorithms. - /// - /// This corresponds to [`SSL_CTX_set_verify_algorithm_prefs`] - /// - /// [`SSL_CTX_set_verify_algorithm_prefs`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_verify_algorithm_prefs + #[corresponds(SSL_CTX_set_verify_algorithm_prefs)] pub fn set_verify_algorithm_prefs( &mut self, prefs: &[SslSignatureAlgorithm], @@ -1942,32 +1780,23 @@ impl SslContextBuilder { } /// Enables SCT requests on all client SSL handshakes. - /// - /// This corresponds to [`SSL_CTX_enable_signed_cert_timestamps`] - /// - /// [`SSL_CTX_enable_signed_cert_timestamps`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_enable_signed_cert_timestamps + #[corresponds(SSL_CTX_enable_signed_cert_timestamps)] pub fn enable_signed_cert_timestamps(&mut self) { unsafe { ffi::SSL_CTX_enable_signed_cert_timestamps(self.as_ptr()) } } /// Enables OCSP stapling on all client SSL handshakes. - /// - /// This corresponds to [`SSL_CTX_enable_ocsp_stapling`] - /// - /// [`SSL_CTX_enable_ocsp_stapling`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_enable_ocsp_stapling + #[corresponds(SSL_CTX_enable_ocsp_stapling)] pub fn enable_ocsp_stapling(&mut self) { unsafe { ffi::SSL_CTX_enable_ocsp_stapling(self.as_ptr()) } } /// Sets the context's supported curves. - /// - /// This corresponds to [`SSL_CTX_set1_curves`] - /// - /// [`SSL_CTX_set1_curves`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set1_curves // // If the "kx-*" flags are used to set key exchange preference, then don't allow the user to // set them here. This ensures we don't override the user's preference without telling them: // when the flags are used, the preferences are set just before connecting or accepting. + #[corresponds(SSL_CTX_set1_curves)] #[cfg(not(feature = "kx-safe-default"))] pub fn set_curves(&mut self, curves: &[SslCurve]) -> Result<(), ErrorStack> { let curves: Vec = curves.iter().filter_map(|curve| curve.nid()).collect(); @@ -1984,10 +1813,8 @@ impl SslContextBuilder { /// Sets the context's compliance policy. /// - /// This corresponds to [`SSL_CTX_set_compliance_policy`] - /// - /// [`SSL_CTX_set_compliance_policy`] https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_compliance_policy /// This feature isn't available in the certified version of BoringSSL. + #[corresponds(SSL_CTX_set_compliance_policy)] #[cfg(not(feature = "fips"))] pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } @@ -2044,10 +1871,7 @@ impl SslContext { /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. - /// - /// This corresponds to [`SSL_CTX_get_ex_new_index`]. - /// - /// [`SSL_CTX_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get_ex_new_index.html + #[corresponds(SSL_CTX_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, @@ -2078,10 +1902,8 @@ impl SslContext { /// /// See [`ciphers`] for details on the format /// - /// This corresponds to [`SSL_CTX_get_ciphers`]. - /// /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html - /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ciphers.html + #[corresponds(SSL_CTX_get_ciphers)] pub fn ciphers(&self) -> Option<&StackRef> { unsafe { let ciphers = ffi::SSL_CTX_get_ciphers(self.as_ptr()); @@ -2096,10 +1918,7 @@ impl SslContext { impl SslContextRef { /// Returns the certificate associated with this `SslContext`, if present. - /// - /// This corresponds to [`SSL_CTX_get0_certificate`]. - /// - /// [`SSL_CTX_get0_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html + #[corresponds(SSL_CTX_get0_certificate)] pub fn certificate(&self) -> Option<&X509Ref> { #[cfg(feature = "rpk")] assert!(!self.is_rpk(), "This API is not supported for RPK"); @@ -2115,10 +1934,7 @@ impl SslContextRef { } /// Returns the private key associated with this `SslContext`, if present. - /// - /// This corresponds to [`SSL_CTX_get0_privatekey`]. - /// - /// [`SSL_CTX_get0_privatekey`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html + #[corresponds(SSL_CTX_get0_privatekey)] pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr()); @@ -2131,10 +1947,7 @@ impl SslContextRef { } /// Returns a shared reference to the certificate store used for verification. - /// - /// This corresponds to [`SSL_CTX_get_cert_store`]. - /// - /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html + #[corresponds(SSL_CTX_get_cert_store)] pub fn cert_store(&self) -> &X509StoreRef { #[cfg(feature = "rpk")] assert!(!self.is_rpk(), "This API is not supported for RPK"); @@ -2143,8 +1956,7 @@ impl SslContextRef { } /// Returns a shared reference to the stack of certificates making up the chain from the leaf. - /// - /// This corresponds to `SSL_CTX_get_extra_chain_certs`. + #[corresponds(SSL_CTX_get_extra_chain_certs)] pub fn extra_chain_certs(&self) -> &StackRef { unsafe { let mut chain = ptr::null_mut(); @@ -2155,10 +1967,7 @@ impl SslContextRef { } /// Returns a reference to the extra data at the specified index. - /// - /// This corresponds to [`SSL_CTX_get_ex_data`]. - /// - /// [`SSL_CTX_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ex_data.html + #[corresponds(SSL_CTX_get_ex_data)] pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); @@ -2172,6 +1981,7 @@ impl SslContextRef { // Unsafe because SSL contexts are not guaranteed to be unique, we call // this only from SslContextBuilder. + #[corresponds(SSL_CTX_get_ex_data)] unsafe fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { @@ -2183,6 +1993,7 @@ impl SslContextRef { // Unsafe because SSL contexts are not guaranteed to be unique, we call // this only from SslContextBuilder. + #[corresponds(SSL_CTX_set_ex_data)] unsafe fn set_ex_data(&mut self, index: Index, data: T) { unsafe { let data = Box::into_raw(Box::new(data)) as *mut c_void; @@ -2192,6 +2003,7 @@ impl SslContextRef { // Unsafe because SSL contexts are not guaranteed to be unique, we call // this only from SslContextBuilder. + #[corresponds(SSL_CTX_set_ex_data)] unsafe fn replace_ex_data(&mut self, index: Index, data: T) -> Option { if let Some(old) = self.ex_data_mut(index) { return Some(mem::replace(old, data)); @@ -2206,14 +2018,11 @@ impl SslContextRef { /// /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present. /// - /// This corresponds to [`SSL_CTX_add_session`]. - /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session has never been used with another /// `SslContext` than this one. - /// - /// [`SSL_CTX_add_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + #[corresponds(SSL_CTX_add_session)] pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool { ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0 } @@ -2222,14 +2031,11 @@ impl SslContextRef { /// /// Returns `true` if the session was successfully found and removed, and `false` otherwise. /// - /// This corresponds to [`SSL_CTX_remove_session`]. - /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session has never been used with another /// `SslContext` than this one. - /// - /// [`SSL_CTX_remove_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + #[corresponds(SSL_CTX_remove_session)] pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool { ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0 } @@ -2237,10 +2043,7 @@ impl SslContextRef { /// Returns the context's session cache size limit. /// /// A value of 0 means that the cache size is unbounded. - /// - /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. - /// - /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + #[corresponds(SSL_CTX_sess_get_cache_size)] #[allow(clippy::useless_conversion)] pub fn session_cache_size(&self) -> u64 { unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()).into() } @@ -2248,10 +2051,8 @@ impl SslContextRef { /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`]. /// - /// This corresponds to [`SSL_CTX_get_verify_mode`]. - /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify - /// [`SSL_CTX_get_verify_mode`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_verify_mode.html + #[corresponds(SSL_CTX_get_verify_mode)] pub fn verify_mode(&self) -> SslVerifyMode { #[cfg(feature = "rpk")] assert!(!self.is_rpk(), "This API is not supported for RPK"); @@ -2353,6 +2154,7 @@ impl ClientHello<'_> { pub struct SslCipher(*mut ffi::SSL_CIPHER); impl SslCipher { + #[corresponds(SSL_get_cipher_by_value)] pub fn from_value(value: u16) -> Option { unsafe { let ptr = ffi::SSL_get_cipher_by_value(value); @@ -2409,10 +2211,7 @@ unsafe impl ForeignTypeRef for SslCipherRef { impl SslCipherRef { /// Returns the name of the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_name`]. - /// - /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_get_name)] pub fn name(&self) -> &'static str { unsafe { let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); @@ -2421,10 +2220,7 @@ impl SslCipherRef { } /// Returns the RFC-standard name of the cipher, if one exists. - /// - /// This corresponds to [`SSL_CIPHER_standard_name`]. - /// - /// [`SSL_CIPHER_standard_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_standard_name)] pub fn standard_name(&self) -> Option<&'static str> { unsafe { let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr()); @@ -2437,10 +2233,7 @@ impl SslCipherRef { } /// Returns the SSL/TLS protocol version that first defined the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_version`]. - /// - /// [`SSL_CIPHER_get_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_get_version)] pub fn version(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr()); @@ -2451,10 +2244,7 @@ impl SslCipherRef { } /// Returns the number of bits used for the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_bits`]. - /// - /// [`SSL_CIPHER_get_bits`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_get_bits)] #[allow(clippy::useless_conversion)] pub fn bits(&self) -> CipherBits { unsafe { @@ -2468,10 +2258,7 @@ impl SslCipherRef { } /// Returns a textual description of the cipher. - /// - /// This corresponds to [`SSL_CIPHER_description`]. - /// - /// [`SSL_CIPHER_description`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[corresponds(SSL_CIPHER_description)] pub fn description(&self) -> String { unsafe { // SSL_CIPHER_description requires a buffer of at least 128 bytes. @@ -2482,19 +2269,13 @@ impl SslCipherRef { } /// Returns one if the cipher uses an AEAD cipher. - /// - /// This corresponds to [`SSL_CIPHER_is_aead`]. - /// - /// [`SSL_CIPHER_is_aead`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_is_aead.html + #[corresponds(SSL_CIPHER_is_aead)] pub fn cipher_is_aead(&self) -> bool { unsafe { ffi::SSL_CIPHER_is_aead(self.as_ptr()) != 0 } } /// Returns the NID corresponding to the cipher's authentication type. - /// - /// This corresponds to [`SSL_CIPHER_get_auth_nid`]. - /// - /// [`SSL_CIPHER_get_auth_nid`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_auth_nid.html + #[corresponds(SSL_CIPHER_get_auth_nid)] pub fn cipher_auth_nid(&self) -> Option { let n = unsafe { ffi::SSL_CIPHER_get_auth_nid(self.as_ptr()) }; if n == 0 { @@ -2505,10 +2286,7 @@ impl SslCipherRef { } /// Returns the NID corresponding to the cipher. - /// - /// This corresponds to [`SSL_CIPHER_get_cipher_nid`]. - /// - /// [`SSL_CIPHER_get_cipher_nid`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CIPHER_get_cipher_nid.html + #[corresponds(SSL_CIPHER_get_cipher_nid)] pub fn cipher_nid(&self) -> Option { let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) }; if n == 0 { @@ -2562,10 +2340,7 @@ impl ToOwned for SslSessionRef { impl SslSessionRef { /// Returns the SSL session ID. - /// - /// This corresponds to [`SSL_SESSION_get_id`]. - /// - /// [`SSL_SESSION_get_id`]: https://www.openssl.org/docs/manmaster/man3/SSL_SESSION_get_id.html + #[corresponds(SSL_SESSION_get_id)] pub fn id(&self) -> &[u8] { unsafe { let mut len = 0; @@ -2575,10 +2350,7 @@ impl SslSessionRef { } /// Returns the length of the master key. - /// - /// This corresponds to [`SSL_SESSION_get_master_key`]. - /// - /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html + #[corresponds(SSL_SESSION_get_master_key)] pub fn master_key_len(&self) -> usize { unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } } @@ -2586,19 +2358,13 @@ impl SslSessionRef { /// Copies the master key into the provided buffer. /// /// Returns the number of bytes written, or the size of the master key if the buffer is empty. - /// - /// This corresponds to [`SSL_SESSION_get_master_key`]. - /// - /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html + #[corresponds(SSL_SESSION_get_master_key)] pub fn master_key(&self, buf: &mut [u8]) -> usize { unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } } /// Returns the time at which the session was established, in seconds since the Unix epoch. - /// - /// This corresponds to [`SSL_SESSION_get_time`]. - /// - /// [`SSL_SESSION_get_time`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + #[corresponds(SSL_SESSION_get_time)] #[allow(clippy::useless_conversion)] pub fn time(&self) -> u64 { unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) } @@ -2607,20 +2373,14 @@ impl SslSessionRef { /// Returns the sessions timeout, in seconds. /// /// A session older than this time should not be used for session resumption. - /// - /// This corresponds to [`SSL_SESSION_get_timeout`]. - /// - /// [`SSL_SESSION_get_timeout`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + #[corresponds(SSL_SESSION_get_timeout)] #[allow(clippy::useless_conversion)] pub fn timeout(&self) -> u32 { unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()) } } /// Returns the session's TLS protocol version. - /// - /// This corresponds to [`SSL_SESSION_get_protocol_version`]. - /// - /// [`SSL_SESSION_get_protocol_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_protocol_version.html + #[corresponds(SSL_SESSION_get_protocol_version)] pub fn protocol_version(&self) -> SslVersion { unsafe { let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr()); @@ -2663,10 +2423,7 @@ impl Ssl { /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. - /// - /// This corresponds to [`SSL_get_ex_new_index`]. - /// - /// [`SSL_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_ex_new_index.html + #[corresponds(SSL_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, @@ -2695,10 +2452,8 @@ impl Ssl { /// Creates a new `Ssl`. /// - /// This corresponds to [`SSL_new`]. - /// - /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html // FIXME should take &SslContextRef + #[corresponds(SSL_new)] pub fn new(ctx: &SslContext) -> Result { unsafe { let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; @@ -2711,10 +2466,9 @@ impl Ssl { /// Creates a new [`Ssl`]. /// - /// This corresponds to [`SSL_new`](`ffi::SSL_new`). - /// /// This function does the same as [`Self:new`] except that it takes &[SslContextRef]. // Both functions exist for backward compatibility (no breaking API). + #[corresponds(SSL_new)] pub fn new_from_ref(ctx: &SslContextRef) -> Result { unsafe { let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; @@ -2836,6 +2590,7 @@ impl SslRef { unsafe { ffi::SSL_get_rbio(self.as_ptr()) } } + #[corresponds(SSL_set1_curves_list)] #[cfg(feature = "kx-safe-default")] fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> { let curves = CString::new(curves).unwrap(); @@ -2881,10 +2636,7 @@ impl SslRef { } /// Returns the [`SslCurve`] used for this `SslRef`. - /// - /// This corresponds to [`SSL_get_curve_id`] - /// - /// [`SSL_get_curve_id`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_get_curve_id + #[corresponds(SSL_get_curve_id)] pub fn curve(&self) -> Option { let curve_id = unsafe { ffi::SSL_get_curve_id(self.as_ptr()) }; if curve_id == 0 { @@ -2894,20 +2646,15 @@ impl SslRef { } /// Returns an `ErrorCode` value for the most recent operation on this `SslRef`. - /// - /// This corresponds to [`SSL_get_error`]. - /// - /// [`SSL_get_error`]: https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L475 + #[corresponds(SSL_get_error)] pub fn error_code(&self, ret: c_int) -> ErrorCode { unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } } /// Like [`SslContextBuilder::set_verify`]. /// - /// This corresponds to [`SSL_set_verify`]. - /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify - /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + #[corresponds(SSL_set_verify)] pub fn set_verify(&mut self, mode: SslVerifyMode) { #[cfg(feature = "rpk")] assert!( @@ -2921,10 +2668,7 @@ impl SslRef { /// Sets the certificate verification depth. /// /// If the peer's certificate chain is longer than this value, verification will fail. - /// - /// This corresponds to [`SSL_set_verify_depth`]. - /// - /// [`SSL_set_verify_depth`]: https://docs.openssl.org/1.1.1/man3/SSL_CTX_set_verify/ + #[corresponds(SSL_set_verify_depth)] pub fn set_verify_depth(&mut self, depth: u32) { #[cfg(feature = "rpk")] assert!( @@ -2938,10 +2682,7 @@ impl SslRef { } /// Returns the verify mode that was set using `set_verify`. - /// - /// This corresponds to [`SSL_get_verify_mode`]. - /// - /// [`SSL_get_verify_mode`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_verify_mode.html + #[corresponds(SSL_get_verify_mode)] pub fn verify_mode(&self) -> SslVerifyMode { #[cfg(feature = "rpk")] assert!( @@ -2966,13 +2707,10 @@ impl SslRef { /// call [`X509StoreContextRef::verify_cert`] and inspect the result, or perform /// other operations more straightforwardly. /// - /// This corresponds to [`SSL_set_verify`]. - /// /// # Panics /// /// This method panics if this `Ssl` is associated with a RPK context. - /// - /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html + #[corresponds(SSL_set_verify)] pub fn set_verify_callback(&mut self, mode: SslVerifyMode, callback: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, @@ -2995,10 +2733,7 @@ impl SslRef { } /// Sets a custom certificate store for verifying peer certificates. - /// - /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. - /// - /// [`SSL_set0_verify_cert_store`]: https://docs.openssl.org/1.0.2/man3/SSL_CTX_set1_verify_cert_store/ + #[corresponds(SSL_set0_verify_cert_store)] pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { #[cfg(feature = "rpk")] assert!( @@ -3015,11 +2750,10 @@ impl SslRef { /// Like [`SslContextBuilder::set_custom_verify_callback`]. /// - /// This corresponds to [`SSL_set_custom_verify`]. - /// /// # Panics /// /// This method panics if this `Ssl` is associated with a RPK context. + #[corresponds(SSL_set_custom_verify)] pub fn set_custom_verify_callback(&mut self, mode: SslVerifyMode, callback: F) where F: Fn(&mut SslRef) -> Result<(), SslVerifyError> + 'static + Sync + Send, @@ -3043,19 +2777,16 @@ impl SslRef { /// Like [`SslContextBuilder::set_tmp_dh`]. /// - /// This corresponds to [`SSL_set_tmp_dh`]. - /// /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh - /// [`SSL_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html + #[corresponds(SSL_set_tmp_dh)] pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } /// Like [`SslContextBuilder::set_tmp_ecdh`]. /// - /// This corresponds to `SSL_set_tmp_ecdh`. - /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh + #[corresponds(SSL_set_tmp_ecdh)] pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } @@ -3076,10 +2807,8 @@ impl SslRef { /// Like [`SslContextBuilder::set_alpn_protos`]. /// - /// This corresponds to [`SSL_set_alpn_protos`]. - /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos - /// [`SSL_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_alpn_protos.html + #[corresponds(SSL_set_alpn_protos)] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { #[cfg_attr(not(feature = "fips"), allow(clippy::unnecessary_cast))] @@ -3101,10 +2830,7 @@ impl SslRef { } /// Returns the stack of available SslCiphers for `SSL`, sorted by preference. - /// - /// This corresponds to [`SSL_get_ciphers`]. - /// - /// [`SSL_get_ciphers`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_get_ciphers.html + #[corresponds(SSL_get_ciphers)] pub fn ciphers(&self) -> &StackRef { unsafe { let cipher_list = ffi::SSL_get_ciphers(self.as_ptr()); @@ -3113,10 +2839,7 @@ impl SslRef { } /// Returns the current cipher if the session is active. - /// - /// This corresponds to [`SSL_get_current_cipher`]. - /// - /// [`SSL_get_current_cipher`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_current_cipher.html + #[corresponds(SSL_get_current_cipher)] pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); @@ -3130,10 +2853,7 @@ impl SslRef { } /// Returns a short string describing the state of the session. - /// - /// This corresponds to [`SSL_state_string`]. - /// - /// [`SSL_state_string`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_state_string.html + #[corresponds(SSL_state_string)] pub fn state_string(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string(self.as_ptr()); @@ -3144,10 +2864,7 @@ impl SslRef { } /// Returns a longer string describing the state of the session. - /// - /// This corresponds to [`SSL_state_string_long`]. - /// - /// [`SSL_state_string_long`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_state_string_long.html + #[corresponds(SSL_state_string_long)] pub fn state_string_long(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string_long(self.as_ptr()); @@ -3160,10 +2877,7 @@ impl SslRef { /// Sets the host name to be sent to the server for Server Name Indication (SNI). /// /// It has no effect for a server-side connection. - /// - /// This corresponds to [`SSL_set_tlsext_host_name`]. - /// - /// [`SSL_set_tlsext_host_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername_type.html + #[corresponds(SSL_set_tlsext_host_name)] pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> { let cstr = CString::new(hostname).unwrap(); unsafe { @@ -3173,10 +2887,7 @@ impl SslRef { } /// Returns the peer's certificate, if present. - /// - /// This corresponds to [`SSL_get_peer_certificate`]. - /// - /// [`SSL_get_peer_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_certificate.html + #[corresponds(SSL_get_peer_certificate)] pub fn peer_certificate(&self) -> Option { #[cfg(feature = "rpk")] assert!( @@ -3198,10 +2909,7 @@ impl SslRef { /// /// On the client side, the chain includes the leaf certificate, but on the server side it does /// not. Fun! - /// - /// This corresponds to [`SSL_get_peer_cert_chain`]. - /// - /// [`SSL_get_peer_cert_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_cert_chain.html + #[corresponds(SSL_get_peer_certificate)] pub fn peer_cert_chain(&self) -> Option<&StackRef> { #[cfg(feature = "rpk")] assert!( @@ -3220,10 +2928,7 @@ impl SslRef { } /// Like [`SslContext::certificate`]. - /// - /// This corresponds to `SSL_get_certificate`. - /// - /// [`SslContext::certificate`]: struct.SslContext.html#method.certificate + #[corresponds(SSL_get_certificate)] pub fn certificate(&self) -> Option<&X509Ref> { #[cfg(feature = "rpk")] assert!( @@ -3242,10 +2947,7 @@ impl SslRef { } /// Like [`SslContext::private_key`]. - /// - /// This corresponds to `SSL_get_privatekey`. - /// - /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key + #[corresponds(SSL_get_privatekey)] pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_get_privatekey(self.as_ptr()); @@ -3263,10 +2965,7 @@ impl SslRef { } /// Returns the protocol version of the session. - /// - /// This corresponds to [`SSL_version`]. - /// - /// [`SSL_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_version.html + #[corresponds(SSL_version)] pub fn version2(&self) -> Option { unsafe { let r = ffi::SSL_version(self.as_ptr()); @@ -3279,10 +2978,7 @@ impl SslRef { } /// Returns a string describing the protocol version of the session. - /// - /// This corresponds to [`SSL_get_version`]. - /// - /// [`SSL_get_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_version.html + #[corresponds(SSL_get_version)] pub fn version_str(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_get_version(self.as_ptr()); @@ -3296,10 +2992,7 @@ impl SslRef { /// /// If version is `None`, the default minimum version is used. For BoringSSL this defaults to /// TLS 1.0. - /// - /// This corresponds to [`SSL_set_min_proto_version`]. - /// - /// [`SSL_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[corresponds(SSL_set_min_proto_version)] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_min_proto_version( @@ -3313,10 +3006,7 @@ impl SslRef { /// Sets the maximum supported protocol version. /// /// If version is `None`, the default maximum version is used. For BoringSSL this is TLS 1.3. - /// - /// This corresponds to [`SSL_set_max_proto_version`]. - /// - /// [`SSL_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_max_proto_version.html + #[corresponds(SSL_set_max_proto_version)] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_max_proto_version( @@ -3328,10 +3018,7 @@ impl SslRef { } /// Gets the minimum supported protocol version. - /// - /// This corresponds to [`SSL_get_min_proto_version`]. - /// - /// [`SSL_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html + #[corresponds(SSL_get_min_proto_version)] pub fn min_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_get_min_proto_version(self.as_ptr()); @@ -3344,10 +3031,7 @@ impl SslRef { } /// Gets the maximum supported protocol version. - /// - /// This corresponds to [`SSL_get_max_proto_version`]. - /// - /// [`SSL_get_max_proto_version`]: https://www.openssl.org/docs/man3.1/man3/SSL_get_max_proto_version.html + #[corresponds(SSL_get_max_proto_version)] pub fn max_proto_version(&self) -> Option { let r = unsafe { ffi::SSL_get_max_proto_version(self.as_ptr()) }; if r == 0 { @@ -3361,10 +3045,7 @@ impl SslRef { /// /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// to interpret it. - /// - /// This corresponds to [`SSL_get0_alpn_selected`]. - /// - /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html + #[corresponds(SSL_get0_alpn_selected)] pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); @@ -3382,10 +3063,7 @@ impl SslRef { } /// Enables the DTLS extension "use_srtp" as defined in RFC5764. - /// - /// This corresponds to [`SSL_set_tlsext_use_srtp`]. - /// - /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_set_tlsext_use_srtp)] pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { unsafe { let cstr = CString::new(protocols).unwrap(); @@ -3403,10 +3081,7 @@ impl SslRef { /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp /// /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. - /// - /// This corresponds to [`SSL_get_srtp_profiles`]. - /// - /// [`SSL_get_srtp_profiles`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_get_strp_profiles)] pub fn srtp_profiles(&self) -> Option<&StackRef> { unsafe { let chain = ffi::SSL_get_srtp_profiles(self.as_ptr()); @@ -3422,10 +3097,7 @@ impl SslRef { /// Gets the SRTP profile selected by handshake. /// /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. - /// - /// This corresponds to [`SSL_get_selected_srtp_profile`]. - /// - /// [`SSL_get_selected_srtp_profile`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html + #[corresponds(SSL_get_selected_srtp_profile)] pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> { unsafe { let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr()); @@ -3442,10 +3114,7 @@ impl SslRef { /// /// If this is greater than 0, the next call to `read` will not call down to the underlying /// stream. - /// - /// This corresponds to [`SSL_pending`]. - /// - /// [`SSL_pending`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_pending.html + #[corresponds(SSL_pending)] pub fn pending(&self) -> usize { unsafe { ffi::SSL_pending(self.as_ptr()) as usize } } @@ -3454,8 +3123,6 @@ impl SslRef { /// /// It is only useful on the server side. /// - /// This corresponds to [`SSL_get_servername`]. - /// /// # Note /// /// While the SNI specification requires that servernames be valid domain names (and therefore @@ -3463,8 +3130,8 @@ impl SslRef { /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns /// the raw bytes and does not have this restriction. /// - /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html // FIXME maybe rethink in 0.11? + #[corresponds(SSL_get_servername)] pub fn servername(&self, type_: NameType) -> Option<&str> { self.servername_raw(type_) .and_then(|b| str::from_utf8(b).ok()) @@ -3474,13 +3141,10 @@ impl SslRef { /// /// It is only useful on the server side. /// - /// This corresponds to [`SSL_get_servername`]. - /// /// # Note /// /// Unlike `servername`, this method does not require the name be valid UTF-8. - /// - /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + #[corresponds(SSL_get_servername)] pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { unsafe { let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); @@ -3495,17 +3159,13 @@ impl SslRef { /// Changes the context corresponding to the current connection. /// /// It is most commonly used in the Server Name Indication (SNI) callback. - /// - /// This corresponds to `SSL_set_SSL_CTX`. + #[corresponds(SSL_set_SSL_CTX)] pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> { unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } } /// Returns the context corresponding to the current connection. - /// - /// This corresponds to [`SSL_get_SSL_CTX`]. - /// - /// [`SSL_get_SSL_CTX`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_SSL_CTX.html + #[corresponds(SSL_get_SSL_CTX)] pub fn ssl_context(&self) -> &SslContextRef { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); @@ -3514,10 +3174,7 @@ impl SslRef { } /// Returns a mutable reference to the X509 verification configuration. - /// - /// This corresponds to [`SSL_get0_param`]. - /// - /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html + #[corresponds(SSL_get0_param)] pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { #[cfg(feature = "rpk")] assert!( @@ -3534,10 +3191,7 @@ impl SslRef { } /// Returns the certificate verification result. - /// - /// This corresponds to [`SSL_get_verify_result`]. - /// - /// [`SSL_get_verify_result`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html + #[corresponds(SSL_get_verify_result)] pub fn verify_result(&self) -> X509VerifyResult { #[cfg(feature = "rpk")] assert!( @@ -3549,10 +3203,7 @@ impl SslRef { } /// Returns a shared reference to the SSL session. - /// - /// This corresponds to [`SSL_get_session`]. - /// - /// [`SSL_get_session`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_session.html + #[corresponds(SSL_get_session)] pub fn session(&self) -> Option<&SslSessionRef> { unsafe { let p = ffi::SSL_get_session(self.as_ptr()); @@ -3568,10 +3219,7 @@ impl SslRef { /// /// Returns the number of bytes copied, or if the buffer is empty, the size of the client_random /// value. - /// - /// This corresponds to [`SSL_get_client_random`]. - /// - /// [`SSL_get_client_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html + #[corresponds(SSL_get_client_random)] pub fn client_random(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) @@ -3582,10 +3230,7 @@ impl SslRef { /// /// Returns the number of bytes copied, or if the buffer is empty, the size of the server_random /// value. - /// - /// This corresponds to [`SSL_get_server_random`]. - /// - /// [`SSL_get_server_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html + #[corresponds(SSL_get_server_random)] pub fn server_random(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) @@ -3593,10 +3238,7 @@ impl SslRef { } /// Derives keying material for application use in accordance to RFC 5705. - /// - /// This corresponds to [`SSL_export_keying_material`]. - /// - /// [`SSL_export_keying_material`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material.html + #[corresponds(SSL_export_keying_material)] pub fn export_keying_material( &self, out: &mut [u8], @@ -3628,32 +3270,23 @@ impl SslRef { /// session. If the server is not willing to reuse the session, a new one will be transparently /// negotiated. /// - /// This corresponds to [`SSL_set_session`]. - /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session is associated /// with the same `SslContext` as this `Ssl`. - /// - /// [`SSL_set_session`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_session.html + #[corresponds(SSL_set_session)] pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) } /// Determines if the session provided to `set_session` was successfully reused. - /// - /// This corresponds to [`SSL_session_reused`]. - /// - /// [`SSL_session_reused`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_session_reused.html + #[corresponds(SSL_session_reused)] pub fn session_reused(&self) -> bool { unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 } } /// Sets the status response a client wishes the server to reply with. - /// - /// This corresponds to [`SSL_set_tlsext_status_type`]. - /// - /// [`SSL_set_tlsext_status_type`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + #[corresponds(SSL_set_tlsext_status_type)] pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) @@ -3661,10 +3294,7 @@ impl SslRef { } /// Returns the server's OCSP response, if present. - /// - /// This corresponds to [`SSL_get_tlsext_status_ocsp_resp`]. - /// - /// [`SSL_get_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + #[corresponds(SSL_get_tlsext_status_ocsp_resp)] pub fn ocsp_status(&self) -> Option<&[u8]> { unsafe { let mut p = ptr::null(); @@ -3679,10 +3309,7 @@ impl SslRef { } /// Sets the OCSP response to be returned to the client. - /// - /// This corresponds to [`SSL_set_tlsext_status_ocsp_resp`]. - /// - /// [`SSL_set_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html + #[corresponds(SSL_set_tlsext_status_ocsp_resp)] pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(response.len() <= c_int::MAX as usize); @@ -3698,10 +3325,7 @@ impl SslRef { } /// Determines if this `Ssl` is configured for server-side or client-side use. - /// - /// This corresponds to [`SSL_is_server`]. - /// - /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html + #[corresponds(SSL_is_server)] pub fn is_server(&self) -> bool { unsafe { SSL_is_server(self.as_ptr()) != 0 } } @@ -3711,12 +3335,9 @@ 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`. /// - /// This corresponds to [`SSL_set_ex_data`]. - /// /// Note that if this method is called multiple times with the same index, any previous /// value stored in the `SslContextBuilder` will be leaked. - /// - /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { if let Some(old) = self.ex_data_mut(index) { *old = data; @@ -3739,11 +3360,8 @@ 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`. /// - /// This corresponds to [`SSL_set_ex_data`]. - /// /// Any previous value will be dropped and replaced by the new one. - /// - /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[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) { return Some(mem::replace(old, data)); @@ -3755,10 +3373,7 @@ impl SslRef { } /// Returns a reference to the extra data at the specified index. - /// - /// This corresponds to [`SSL_get_ex_data`]. - /// - /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_get_ex_data)] pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); @@ -3771,10 +3386,7 @@ impl SslRef { } /// Returns a mutable reference to the extra data at the specified index. - /// - /// This corresponds to [`SSL_get_ex_data`]. - /// - /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html + #[corresponds(SSL_get_ex_data)] pub fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { unsafe { let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); @@ -3790,8 +3402,7 @@ impl SslRef { /// /// The total size of the message is returned, so this can be used to determine the size of the /// buffer required. - /// - /// This corresponds to `SSL_get_finished`. + #[corresponds(SSL_get_finished)] pub fn finished(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } @@ -3801,8 +3412,7 @@ impl SslRef { /// /// The total size of the message is returned, so this can be used to determine the size of the /// buffer required. - /// - /// This corresponds to `SSL_get_peer_finished`. + #[corresponds(SSL_get_peer_finished)] pub fn peer_finished(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) @@ -3810,26 +3420,19 @@ impl SslRef { } /// Determines if the initial handshake has been completed. - /// - /// This corresponds to [`SSL_is_init_finished`]. - /// - /// [`SSL_is_init_finished`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_is_init_finished.html + #[corresponds(SSL_is_init_finished)] pub fn is_init_finished(&self) -> bool { unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 } } /// Sets the MTU used for DTLS connections. - /// - /// This corresponds to `SSL_set_mtu`. + #[corresponds(SSL_set_mtu)] pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as c_uint) as c_int).map(|_| ()) } } /// Sets the certificate. - /// - /// This corresponds to [`SSL_use_certificate`]. - /// - /// [`SSL_use_certificate`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_use_certificate.html + #[corresponds(SSL_use_certificate)] pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?; @@ -3842,10 +3445,7 @@ impl SslRef { /// /// The CA certificates must still be added to the trust root - they are not automatically set /// as trusted by this method. - /// - /// This corresponds to [`SSL_set_client_CA_list`]. - /// - /// [`SSL_set_client_CA_list`]: https://docs.openssl.org/1.1.1/man3/SSL_CTX_set0_CA_list/ + #[corresponds(SSL_set_client_CA_list)] pub fn set_client_ca_list(&mut self, list: Stack) { #[cfg(feature = "rpk")] assert!( @@ -3858,10 +3458,7 @@ impl SslRef { } /// Sets the private key. - /// - /// This corresponds to [`SSL_use_PrivateKey`]. - /// - /// [`SSL_use_PrivateKey`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_use_PrivateKey.html + #[corresponds(SSL_use_PrivateKey)] pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPrivate, @@ -3871,10 +3468,7 @@ impl SslRef { /// Enables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting /// enabled modes. - /// - /// This corresponds to [`SSL_set_mode`]. - /// - /// [`SSL_set_mode`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_mode.html + #[corresponds(SSL_set_mode)] pub fn set_mode(&mut self, mode: SslMode) -> SslMode { let bits = unsafe { ffi::SSL_set_mode(self.as_ptr(), mode.bits()) }; SslMode::from_bits_retain(bits) @@ -3882,20 +3476,14 @@ impl SslRef { /// Disables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting /// enabled modes. - /// - /// This corresponds to [`SSL_clear_mode`]. - /// - /// [`SSL_clear_mode`]: https://www.openssl.org/docs/man3.1/man3/SSL_clear_mode.html + #[corresponds(SSL_clear_mode)] pub fn clear_mode(&mut self, mode: SslMode) -> SslMode { let bits = unsafe { ffi::SSL_clear_mode(self.as_ptr(), mode.bits()) }; SslMode::from_bits_retain(bits) } /// Appends `cert` to the chain associated with the current certificate of `SSL`. - /// - /// This corresponds to [`SSL_add1_chain_cert`]. - /// - /// [`SSL_add1_chain_cert`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_add1_chain_cert.html + #[corresponds(SSL_add1_chain_cert)] 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(|_| ()) } } @@ -4060,10 +3648,7 @@ impl SslStream { /// /// It is particularly useful with a nonblocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. - /// - /// This corresponds to [`SSL_read`]. - /// - /// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html + #[corresponds(SSL_read)] pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { // SAFETY: `ssl_read_uninit` does not de-initialize the buffer. unsafe { @@ -4098,10 +3683,7 @@ impl SslStream { /// /// It is particularly useful with a nonblocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. - /// - /// This corresponds to [`SSL_write`]. - /// - /// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html + #[corresponds(SSL_write)] pub fn ssl_write(&mut self, buf: &[u8]) -> Result { if buf.is_empty() { return Ok(0); @@ -4125,10 +3707,7 @@ impl SslStream { /// While the connection may be closed after the first step, it is recommended to fully shut the /// session down. In particular, it must be fully shut down if the connection is to be used for /// further communication in the future. - /// - /// This corresponds to [`SSL_shutdown`]. - /// - /// [`SSL_shutdown`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_shutdown.html + #[corresponds(SSL_shutdown)] pub fn shutdown(&mut self) -> Result { match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } { 0 => Ok(ShutdownResult::Sent), @@ -4138,10 +3717,7 @@ impl SslStream { } /// Returns the session's shutdown state. - /// - /// This corresponds to [`SSL_get_shutdown`]. - /// - /// [`SSL_get_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html + #[corresponds(SSL_get_shutdown)] pub fn get_shutdown(&mut self) -> ShutdownState { unsafe { let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr()); @@ -4153,19 +3729,13 @@ impl SslStream { /// /// This can be used to tell OpenSSL that the session should be cached even if a full two-way /// shutdown was not completed. - /// - /// This corresponds to [`SSL_set_shutdown`]. - /// - /// [`SSL_set_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html + #[corresponds(SSL_set_shutdown)] pub fn set_shutdown(&mut self, state: ShutdownState) { unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) } } /// Initiates a client-side TLS handshake. - /// - /// This corresponds to [`SSL_connect`]. - /// - /// [`SSL_connect`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_connect.html + #[corresponds(SSL_connect)] pub fn connect(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) }; if ret > 0 { @@ -4176,10 +3746,7 @@ impl SslStream { } /// Initiates a server-side TLS handshake. - /// - /// This corresponds to [`SSL_accept`]. - /// - /// [`SSL_accept`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_accept.html + #[corresponds(SSL_accept)] pub fn accept(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) }; if ret > 0 { @@ -4190,10 +3757,7 @@ impl SslStream { } /// Initiates the handshake. - /// - /// This corresponds to [`SSL_do_handshake`]. - /// - /// [`SSL_do_handshake`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_do_handshake.html + #[corresponds(SSL_do_handshake)] pub fn do_handshake(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) }; if ret > 0 { @@ -4326,19 +3890,13 @@ where } /// Configure as an outgoing stream from a client. - /// - /// This corresponds to [`SSL_set_connect_state`]. - /// - /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html + #[corresponds(SSL_set_connect_state)] pub fn set_connect_state(&mut self) { unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } } /// Configure as an incoming stream to a server. - /// - /// This corresponds to [`SSL_set_accept_state`]. - /// - /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html + #[corresponds(SSL_set_accept_state)] pub fn set_accept_state(&mut self) { unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } } @@ -4408,10 +3966,7 @@ where /// Initiates the handshake. /// /// This will fail if `set_accept_state` or `set_connect_state` was not called first. - /// - /// 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(self) -> Result, HandshakeError> { let mut stream = self.inner; let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) }; diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index eb55c305..a90a4934 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -9,6 +9,7 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long, c_void}; +use openssl_macros::corresponds; use std::convert::TryInto; use std::error::Error; use std::ffi::{CStr, CString}; @@ -58,15 +59,13 @@ foreign_type_and_impl_send_sync! { impl X509StoreContext { /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a /// context. + #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)] pub fn ssl_idx() -> Result, ErrorStack> { unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } } /// Creates a new `X509StoreContext` instance. - /// - /// This corresponds to [`X509_STORE_CTX_new`]. - /// - /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html + #[corresponds(X509_STORE_CTX_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -77,10 +76,7 @@ impl X509StoreContext { impl X509StoreContextRef { /// Returns application data pertaining to an `X509` store context. - /// - /// This corresponds to [`X509_STORE_CTX_get_ex_data`]. - /// - /// [`X509_STORE_CTX_get_ex_data`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_ex_data.html + #[corresponds(X509_STORE_CTX_get_ex_data)] pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); @@ -93,10 +89,7 @@ impl X509StoreContextRef { } /// Returns the verify result of the context. - /// - /// This corresponds to [`X509_STORE_CTX_get_error`]. - /// - /// [`X509_STORE_CTX_get_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error.html + #[corresponds(X509_STORE_CTX_get_error)] pub fn verify_result(&self) -> X509VerifyResult { unsafe { X509VerifyError::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } } @@ -150,10 +143,7 @@ impl X509StoreContextRef { } /// Returns a mutable reference to the X509 verification configuration. - /// - /// This corresponds to [`X509_STORE_CTX_get0_param`]. - /// - /// [`SSL_get0_param`]: https://www.openssl.org/docs/manmaster/man3/X509_STORE_CTX_get0_param.html + #[corresponds(X509_STORE_CTX_get0_param)] pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::X509_STORE_CTX_get0_param(self.as_ptr())) } } @@ -164,19 +154,13 @@ impl X509StoreContextRef { /// validation error if the certificate was not valid. /// /// This will only work inside of a call to `init`. - /// - /// This corresponds to [`X509_verify_cert`]. - /// - /// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html + #[corresponds(X509_verify_cert)] pub fn verify_cert(&mut self) -> Result { unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } } /// Set the verify result of the context. - /// - /// This corresponds to [`X509_STORE_CTX_set_error`]. - /// - /// [`X509_STORE_CTX_set_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_set_error.html + #[corresponds(X509_STORE_CTX_set_error)] pub fn set_error(&mut self, result: X509VerifyResult) { unsafe { ffi::X509_STORE_CTX_set_error( @@ -191,10 +175,7 @@ impl X509StoreContextRef { /// Returns a reference to the certificate which caused the error or None if /// no certificate is relevant to the error. - /// - /// This corresponds to [`X509_STORE_CTX_get_current_cert`]. - /// - /// [`X509_STORE_CTX_get_current_cert`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_current_cert.html + #[corresponds(X509_STORE_CTX_get_current_cert)] pub fn current_cert(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); @@ -210,19 +191,13 @@ impl X509StoreContextRef { /// chain where the error occurred. If it is zero it occurred in the end /// entity certificate, one if it is the certificate which signed the end /// entity certificate and so on. - /// - /// This corresponds to [`X509_STORE_CTX_get_error_depth`]. - /// - /// [`X509_STORE_CTX_get_error_depth`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error_depth.html + #[corresponds(X509_STORE_CTX_get_error_depth)] pub fn error_depth(&self) -> u32 { unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } } /// Returns a reference to a complete valid `X509` certificate chain. - /// - /// This corresponds to [`X509_STORE_CTX_get0_chain`]. - /// - /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html + #[corresponds(X509_STORE_CTX_get0_chain)] pub fn chain(&self) -> Option<&StackRef> { unsafe { let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); @@ -241,6 +216,7 @@ pub struct X509Builder(X509); impl X509Builder { /// Creates a new builder. + #[corresponds(X509_new)] pub fn new() -> Result { unsafe { ffi::init(); @@ -249,11 +225,13 @@ impl X509Builder { } /// Sets the notAfter constraint on the certificate. + #[corresponds(X509_set1_notAfter)] pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } } /// Sets the notBefore constraint on the certificate. + #[corresponds(X509_set1_notBefore)] pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } } @@ -262,11 +240,13 @@ impl X509Builder { /// /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of /// the X.509 standard should pass `2` to this method. + #[corresponds(X509_set_version)] pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } } /// Sets the serial number of the certificate. + #[corresponds(X509_set_serialNumber)] pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_serialNumber( @@ -278,6 +258,7 @@ impl X509Builder { } /// Sets the issuer name of the certificate. + #[corresponds(X509_set_issuer_name)] pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_issuer_name( @@ -306,6 +287,7 @@ impl X509Builder { /// let mut x509 = boring::x509::X509::builder().unwrap(); /// x509.set_subject_name(&x509_name).unwrap(); /// ``` + #[corresponds(X509_set_subject_name)] pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_subject_name( @@ -317,6 +299,7 @@ impl X509Builder { } /// Sets the public key associated with the certificate. + #[corresponds(X509_set_pubkey)] pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -327,6 +310,7 @@ impl X509Builder { /// Returns a context object which is needed to create certain X509 extension values. /// /// Set `issuer` to `None` if the certificate will be self-signed. + #[corresponds(X509V3_set_ctx)] pub fn x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, @@ -366,10 +350,7 @@ impl X509Builder { } /// Adds an X509 extension value to the certificate. - /// - /// This corresponds to [`X509_add_ext`]. - /// - /// [`X509_add_ext`]: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html + #[corresponds(X509_add_ext)] pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; @@ -378,6 +359,7 @@ impl X509Builder { } /// Signs the certificate with a private key. + #[corresponds(X509_sign)] pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate, @@ -401,10 +383,7 @@ foreign_type_and_impl_send_sync! { impl X509Ref { /// Returns this certificate's subject name. - /// - /// This corresponds to [`X509_get_subject_name`]. - /// - /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html + #[corresponds(X509_get_subject_name)] pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = ffi::X509_get_subject_name(self.as_ptr()); @@ -413,17 +392,13 @@ impl X509Ref { } /// Returns the hash of the certificates subject - /// - /// This corresponds to `X509_subject_name_hash`. + #[corresponds(X509_subject_name_hash)] pub fn subject_name_hash(&self) -> u32 { unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } } /// Returns this certificate's subject alternative name entries, if they exist. - /// - /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. - /// - /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html + #[corresponds(X509_get_ext_d2i)] pub fn subject_alt_names(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( @@ -450,10 +425,7 @@ impl X509Ref { } /// Returns this certificate's issuer alternative name entries, if they exist. - /// - /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. - /// - /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html + #[corresponds(X509_get_ext_d2i)] pub fn issuer_alt_names(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( @@ -471,6 +443,7 @@ impl X509Ref { } /// Returns this certificate's subject key id, if it exists. + #[corresponds(X509_get0_subject_key_id)] pub fn subject_key_id(&self) -> Option<&Asn1StringRef> { unsafe { let data = ffi::X509_get0_subject_key_id(self.as_ptr()); @@ -479,6 +452,7 @@ impl X509Ref { } /// Returns this certificate's authority key id, if it exists. + #[corresponds(X509_get0_authority_key_id)] pub fn authority_key_id(&self) -> Option<&Asn1StringRef> { unsafe { let data = ffi::X509_get0_authority_key_id(self.as_ptr()); From 96981dd6c6d73a7274a2f5efa924419972f2e286 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Tue, 13 Aug 2024 17:35:43 -0700 Subject: [PATCH 05/21] Expose X509NameRef::print_ex --- boring/src/x509/mod.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index a90a4934..b234bd2b 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -26,7 +26,7 @@ use crate::asn1::{ Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, }; -use crate::bio::MemBioSlice; +use crate::bio::{MemBio, MemBioSlice}; use crate::conf::ConfRef; use crate::error::ErrorStack; use crate::ex_data::Index; @@ -1044,6 +1044,20 @@ impl X509NameRef { } } + /// Returns an owned String representing the X509 name configurable via incoming flags. + /// + /// This function will return `None` if the underlying string contains invalid utf-8. + #[corresponds(X509_NAME_print_ex)] + pub fn print_ex(&self, flags: i32) -> Option { + unsafe { + let bio = MemBio::new().ok()?; + ffi::X509_NAME_print_ex(bio.as_ptr(), self.as_ptr(), 0, flags as _); + let buf = bio.get_buf().to_vec(); + let res = String::from_utf8(buf); + res.ok() + } + } + to_der! { /// Serializes the certificate into a DER-encoded X509 name structure. /// From ef8146be7ce1a9b2cb6790f718b51ea92036dd07 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 15 Aug 2024 13:42:12 -0700 Subject: [PATCH 06/21] Add tests for X509Ref::subject_key_id, X509Ref::authority_key_id, and X509NameRef::print_ex --- boring/src/x509/tests/mod.rs | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/boring/src/x509/tests/mod.rs b/boring/src/x509/tests/mod.rs index 65bb7f90..b3867ce2 100644 --- a/boring/src/x509/tests/mod.rs +++ b/boring/src/x509/tests/mod.rs @@ -179,6 +179,49 @@ fn test_subject_alt_name_iter() { assert!(subject_alt_names_iter.next().is_none()); } +#[test] +fn test_subject_key_id() { + // nid_test_cert_pem has SKI, but no AKI + let cert = include_bytes!("../../../test/nid_test_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let ski = cert.subject_key_id().expect("unable to extract SKI"); + assert_eq!( + ski.as_slice(), + [ + 80, 107, 158, 237, 95, 61, 235, 100, 212, 115, 249, 244, 219, 163, 124, 55, 141, 2, 76, + 5 + ] + ); + + let aki = cert.authority_key_id(); + assert!(aki.is_none()); +} + +#[test] +fn test_x509_name_print_ex() { + let cert = include_bytes!("../../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let name_no_flags = cert + .subject_name() + .print_ex(0) + .expect("failed to print cert subject name"); + assert_eq!( + name_no_flags, + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=foobar.com" + ); + + let name_rfc2253 = cert + .subject_name() + .print_ex(ffi::XN_FLAG_RFC2253) + .expect("failed to print cert subject name"); + assert_eq!( + name_rfc2253, + "CN=foobar.com,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU" + ); +} + #[test] fn x509_builder() { let pkey = pkey(); From a7bfe0d92c01f55faf21c0dca378eeb5753a351e Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Thu, 15 Aug 2024 13:42:28 -0700 Subject: [PATCH 07/21] Fix macos FIPS crossbuild --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb68529c..fb3c07cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -322,7 +322,8 @@ jobs: working-directory: ${{ runner.temp }}/llvm/bin run: ln -s clang clang++-12 - name: Install ${{ matrix.target }} toolchain - run: brew tap messense/macos-cross-toolchains && brew install --overwrite python@3.11 && brew install ${{ matrix.target }} + # TODO(rmehra): find a better way to overwrite the python3 version without specifying version + run: brew tap messense/macos-cross-toolchains && brew install --overwrite python@3.12 && brew install ${{ matrix.target }} - name: Set BORING_BSSL_FIPS_COMPILER_EXTERNAL_TOOLCHAIN run: echo "BORING_BSSL_FIPS_COMPILER_EXTERNAL_TOOLCHAIN=$(brew --prefix ${{ matrix.target }})/toolchain" >> $GITHUB_ENV shell: bash From e5b6627efcb6decd00b9e1dfe6a34dbbaabb7ed4 Mon Sep 17 00:00:00 2001 From: Evan Rittenhouse Date: Mon, 19 Aug 2024 17:26:33 -0500 Subject: [PATCH 08/21] Expose RSAPSS public key Id type --- boring/src/pkey.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boring/src/pkey.rs b/boring/src/pkey.rs index b8a157f6..9897635e 100644 --- a/boring/src/pkey.rs +++ b/boring/src/pkey.rs @@ -72,6 +72,7 @@ pub struct Id(c_int); impl Id { pub const RSA: Id = Id(ffi::EVP_PKEY_RSA); + pub const RSAPSS: Id = Id(ffi::EVP_PKEY_RSA_PSS); pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); pub const EC: Id = Id(ffi::EVP_PKEY_EC); @@ -303,6 +304,7 @@ impl fmt::Debug for PKey { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let alg = match self.id() { Id::RSA => "RSA", + Id::RSAPSS => "RSAPSS", Id::DSA => "DSA", Id::DH => "DH", Id::EC => "EC", From 7324db2b75abbf32cc47bb3497c6c8cc32af41f0 Mon Sep 17 00:00:00 2001 From: Rushil Mehra Date: Tue, 3 Sep 2024 08:04:30 -0700 Subject: [PATCH 09/21] Use ForeignType::into_ptr wherever applicable --- boring/src/dsa.rs | 3 +-- boring/src/ssl/mod.rs | 15 ++++++--------- boring/src/x509/mod.rs | 4 +--- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/boring/src/dsa.rs b/boring/src/dsa.rs index 60c0c197..d9c35505 100644 --- a/boring/src/dsa.rs +++ b/boring/src/dsa.rs @@ -280,8 +280,7 @@ impl Dsa { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, q, g)); - cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; - mem::forget(pub_key); + cvt(DSA_set0_key(dsa.0, pub_key.into_ptr(), ptr::null_mut()))?; Ok(dsa) } } diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 12ffedf5..04e0ee43 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -1068,9 +1068,9 @@ impl SslContextBuilder { assert!(!self.is_rpk, "This API is not supported for RPK"); unsafe { - let ptr = cert_store.as_ptr(); - cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?; - mem::forget(cert_store); + cvt( + ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), cert_store.into_ptr()) as c_int, + )?; Ok(()) } @@ -1083,8 +1083,7 @@ impl SslContextBuilder { assert!(!self.is_rpk, "This API is not supported for RPK"); unsafe { - ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.as_ptr()); - mem::forget(cert_store); + ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.into_ptr()); } } @@ -1260,8 +1259,7 @@ impl SslContextBuilder { assert!(!self.is_rpk, "This API is not supported for RPK"); unsafe { - cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?; - mem::forget(cert); + cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.into_ptr()) as c_int)?; Ok(()) } } @@ -2742,8 +2740,7 @@ impl SslRef { ); unsafe { - cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?; - mem::forget(cert_store); + cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.into_ptr()) as c_int)?; Ok(()) } } diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index b234bd2b..34896d6a 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -1584,9 +1584,7 @@ impl GeneralName { ffi::init(); let gn = cvt_p(ffi::GENERAL_NAME_new())?; (*gn).type_ = ffi::GEN_RID; - (*gn).d.registeredID = oid.as_ptr(); - - mem::forget(oid); + (*gn).d.registeredID = oid.into_ptr(); Ok(GeneralName::from_ptr(gn)) } From b2525f2ed24147e13b98a0ee3979cc7b74ab67d4 Mon Sep 17 00:00:00 2001 From: Evan Rittenhouse Date: Wed, 11 Sep 2024 03:35:51 -0500 Subject: [PATCH 10/21] Expose SSL_CTX_set_info_callback (#266) Model callback arguments as structs --- boring/src/ssl/callbacks.rs | 34 ++++++++++++++++-- boring/src/ssl/mod.rs | 72 +++++++++++++++++++++++++++++++++++++ boring/src/ssl/test/mod.rs | 14 ++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) diff --git a/boring/src/ssl/callbacks.rs b/boring/src/ssl/callbacks.rs index 7841950c..f592d9d2 100644 --- a/boring/src/ssl/callbacks.rs +++ b/boring/src/ssl/callbacks.rs @@ -2,8 +2,9 @@ use super::{ AlpnError, ClientHello, GetSessionPendingError, PrivateKeyMethod, PrivateKeyMethodError, - SelectCertError, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, - SslSessionRef, SslSignatureAlgorithm, SslVerifyError, SESSION_CTX_INDEX, + SelectCertError, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslInfoCallbackAlert, + SslInfoCallbackMode, SslInfoCallbackValue, SslRef, SslSession, SslSessionRef, + SslSignatureAlgorithm, SslVerifyError, SESSION_CTX_INDEX, }; use crate::error::ErrorStack; use crate::ffi; @@ -521,3 +522,32 @@ where Err(err) => err.0, } } + +pub(super) unsafe extern "C" fn raw_info_callback( + ssl: *const ffi::SSL, + mode: c_int, + value: c_int, +) where + F: Fn(&SslRef, SslInfoCallbackMode, SslInfoCallbackValue) + Send + Sync + 'static, +{ + // Due to FFI signature requirements we have to pass a *const SSL into this function, but + // foreign-types requires a *mut SSL to get the Rust SslRef + let mut_ref = ssl as *mut ffi::SSL; + + // SAFETY: boring provides valid inputs. + let ssl = unsafe { SslRef::from_ptr(mut_ref) }; + let ssl_context = ssl.ssl_context(); + + let callback = ssl_context + .ex_data(SslContext::cached_ex_index::()) + .expect("BUG: info callback missing"); + + let value = match mode { + ffi::SSL_CB_READ_ALERT | ffi::SSL_CB_WRITE_ALERT => { + SslInfoCallbackValue::Alert(SslInfoCallbackAlert(value)) + } + _ => SslInfoCallbackValue::Unit, + }; + + callback(ssl, SslInfoCallbackMode(mode), value); +} diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 04e0ee43..be32e545 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -834,6 +834,66 @@ pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8] } } +/// Options controlling the behavior of the info callback. +#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] +pub struct SslInfoCallbackMode(i32); + +impl SslInfoCallbackMode { + /// Signaled for each alert received, warning or fatal. + pub const READ_ALERT: Self = Self(ffi::SSL_CB_READ_ALERT); + + /// Signaled for each alert sent, warning or fatal. + pub const WRITE_ALERT: Self = Self(ffi::SSL_CB_WRITE_ALERT); + + /// Signaled when a handshake begins. + pub const HANDSHAKE_START: Self = Self(ffi::SSL_CB_HANDSHAKE_START); + + /// Signaled when a handshake completes successfully. + pub const HANDSHAKE_DONE: Self = Self(ffi::SSL_CB_HANDSHAKE_DONE); + + /// Signaled when a handshake progresses to a new state. + pub const ACCEPT_LOOP: Self = Self(ffi::SSL_CB_ACCEPT_LOOP); +} + +/// The `value` argument to an info callback. The most-significant byte is the alert level, while +/// the least significant byte is the alert itself. +#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] +pub enum SslInfoCallbackValue { + /// The unit value (1). Some BoringSSL info callback modes, like ACCEPT_LOOP, always call the + /// callback with `value` set to the unit value. If the [`SslInfoCallbackValue`] is a + /// `Unit`, it can safely be disregarded. + Unit, + /// An alert. See [`SslInfoCallbackAlert`] for details on how to manipulate the alert. This + /// variant should only be present if the info callback was called with a `READ_ALERT` or + /// `WRITE_ALERT` mode. + Alert(SslInfoCallbackAlert), +} + +#[derive(Hash, Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] +pub struct SslInfoCallbackAlert(c_int); + +impl SslInfoCallbackAlert { + /// The level of the SSL alert. + pub fn alert_level(&self) -> Ssl3AlertLevel { + let value = self.0 >> 8; + Ssl3AlertLevel(value) + } + + /// The value of the SSL alert. + pub fn alert(&self) -> SslAlert { + let value = self.0 & (u8::MAX as i32); + SslAlert(value) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct Ssl3AlertLevel(c_int); + +impl Ssl3AlertLevel { + pub const WARNING: Ssl3AlertLevel = Self(ffi::SSL3_AL_WARNING); + pub const FATAL: Ssl3AlertLevel = Self(ffi::SSL3_AL_FATAL); +} + #[cfg(feature = "rpk")] extern "C" fn rpk_verify_failure_callback( _ssl: *mut ffi::SSL, @@ -1818,6 +1878,18 @@ impl SslContextBuilder { unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) } } + /// Sets the context's info callback. + #[corresponds(SSL_CTX_set_info_callback)] + pub fn set_info_callback(&mut self, callback: F) + where + F: Fn(&SslRef, SslInfoCallbackMode, SslInfoCallbackValue) + Send + Sync + 'static, + { + unsafe { + self.replace_ex_data(SslContext::cached_ex_index::(), callback); + ffi::SSL_CTX_set_info_callback(self.as_ptr(), Some(callbacks::raw_info_callback::)); + } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.ctx diff --git a/boring/src/ssl/test/mod.rs b/boring/src/ssl/test/mod.rs index 131b1127..f3b0fd29 100644 --- a/boring/src/ssl/test/mod.rs +++ b/boring/src/ssl/test/mod.rs @@ -1052,3 +1052,17 @@ fn drop_ex_data_in_ssl() { assert_eq!(ssl.replace_ex_data(index, "camembert"), Some("comté")); assert_eq!(ssl.replace_ex_data(index, "raclette"), Some("camembert")); } + +#[test] +fn test_info_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + let mut client = server.client(); + client.ctx().set_info_callback(move |_, _, _| { + CALLED_BACK.store(true, Ordering::Relaxed); + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::Relaxed)); +} From 4b37d88b803f3d86bf3d7899b2c5aeb048e560f1 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Tue, 17 Sep 2024 10:00:25 +0200 Subject: [PATCH 11/21] Expose SSL(_CTX)_set1_curves_list (#270) set_surves_list is similar to set_curves, but the curves are specified by a string. This makes it convenient when the supported curves of the underlying BoringSSL is not known at compile time. Also fix a bug in checking return value of SSL_set1_curves_list. --- boring/src/ssl/mod.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index be32e545..6a9361e1 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -1849,6 +1849,24 @@ impl SslContextBuilder { unsafe { ffi::SSL_CTX_enable_ocsp_stapling(self.as_ptr()) } } + /// Sets the context's supported curves. + // + // If the "kx-*" flags are used to set key exchange preference, then don't allow the user to + // set them here. This ensures we don't override the user's preference without telling them: + // when the flags are used, the preferences are set just before connecting or accepting. + #[cfg(not(feature = "kx-safe-default"))] + #[corresponds(SSL_CTX_set1_curves_list)] + pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> { + let curves = CString::new(curves).unwrap(); + unsafe { + cvt_0i(ffi::SSL_CTX_set1_curves_list( + self.as_ptr(), + curves.as_ptr() as *const _, + )) + .map(|_| ()) + } + } + /// Sets the context's supported curves. // // If the "kx-*" flags are used to set key exchange preference, then don't allow the user to @@ -2661,11 +2679,10 @@ impl SslRef { } #[corresponds(SSL_set1_curves_list)] - #[cfg(feature = "kx-safe-default")] - fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> { + pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> { let curves = CString::new(curves).unwrap(); unsafe { - cvt(ffi::SSL_set1_curves_list( + cvt_0i(ffi::SSL_set1_curves_list( self.as_ptr(), curves.as_ptr() as *const _, )) From 8cb5da61a68446c8473ce5337b89b03f24b56df2 Mon Sep 17 00:00:00 2001 From: Mike Aizatsky Date: Tue, 17 Sep 2024 15:45:56 -0700 Subject: [PATCH 12/21] Update bindgen to 0.70.1 bindgen has had a lot of improvements since 0.68, and this newer version seems to able to compile libbssl from within edgeworker --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e8bf6e38..f848893f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ boring-sys = { version = "4.9.1", path = "./boring-sys" } boring = { version = "4.9.1", path = "./boring" } tokio-boring = { version = "4.9.1", path = "./tokio-boring" } -bindgen = { version = "0.68.1", default-features = false, features = ["runtime"] } +bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } cmake = "0.1.18" fs_extra = "1.3.0" fslock = "0.2" From 2c0a14253a0abdbb1e09eaf4b681093a4cf41e76 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Tue, 10 Sep 2024 13:16:14 +0200 Subject: [PATCH 13/21] Revert "PQ: fix timing sidechannels and add IPDWing" For TLS, early adopters prefer X25519MLKEM768. Remove IPDWing in preparation for adding X25519MLKEM768. https://datatracker.ietf.org/doc/draft-kwiatkowski-tls-ecdhe-mlkem/ This reverts commit 4725a930d5fd1118517cc929fc520b2de3e6eff1. --- boring-sys/patches/boring-pq.patch | 2288 +++++++++++----------------- boring/src/lib.rs | 4 - boring/src/ssl/mod.rs | 5 - 3 files changed, 883 insertions(+), 1414 deletions(-) diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index d4294dc5..2ffeee6c 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -1,4 +1,4 @@ -From 836d390deaf8b50fed0cafd55b17a63e80454d7f Mon Sep 17 00:00:00 2001 +From 4cba2164726c8d2647e38548a266a70c4942d567 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Fri, 22 Jul 2022 16:43:48 +0200 Subject: [PATCH] Add temporary post-quantum key agreements @@ -20,55 +20,43 @@ This patch adds: key agreement should only be used for testing: to see if the smaller keyshare makes a difference. -4. Supportfor IPDWing under codepoint 0xfe41. This key agreement - is a preliminary version of X-Wing using the initial public draft - of ML-KEM. It should not be used. - The patch also replaces Google's implementation of Kyber, by the portable reference implementation, so as to support Kyber512. Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 --- - BUILD.generated.bzl | 7 +- + BUILD.generated.bzl | 5 +- BUILD.generated_tests.bzl | 4 - - CMakeLists.txt | 6 +- - sources.json | 11 +- - src/crypto/CMakeLists.txt | 7 +- - src/crypto/kyber/fips202.c | 699 +++++++ - src/crypto/kyber/fips202.h | 29 + + CMakeLists.txt | 4 +- + sources.json | 9 +- + src/crypto/CMakeLists.txt | 5 +- src/crypto/kyber/internal.h | 91 - - src/crypto/kyber/ipdwing.c | 110 ++ src/crypto/kyber/keccak.c | 204 -- - src/crypto/kyber/kyber.c | 2319 +++++++++++++++------- - src/crypto/kyber/kyber.h | 29 + + src/crypto/kyber/kyber.c | 2865 ++++++++++++++++++++------- src/crypto/kyber/kyber512.c | 5 + src/crypto/kyber/kyber768.c | 4 + src/crypto/kyber/kyber_test.cc | 229 --- - src/crypto/obj/obj_dat.h | 17 +- - src/crypto/obj/obj_mac.num | 4 + - src/crypto/obj/objects.txt | 6 +- - src/include/openssl/kyber.h | 252 ++- - src/include/openssl/nid.h | 12 + - src/include/openssl/ssl.h | 4 + + src/crypto/obj/obj_dat.h | 14 +- + src/crypto/obj/obj_mac.num | 3 + + src/crypto/obj/objects.txt | 5 +- + src/include/openssl/kyber.h | 199 +- + src/include/openssl/nid.h | 9 + + src/include/openssl/ssl.h | 3 + src/sources.cmake | 2 - - src/ssl/extensions.cc | 4 + - src/ssl/ssl_key_share.cc | 493 ++++- + src/ssl/extensions.cc | 3 + + src/ssl/ssl_key_share.cc | 412 +++- src/ssl/ssl_lib.cc | 2 +- - src/ssl/ssl_test.cc | 29 +- + src/ssl/ssl_test.cc | 25 +- src/tool/speed.cc | 162 +- - 30 files changed, 3276 insertions(+), 5445 deletions(-) - create mode 100644 src/crypto/kyber/fips202.c - create mode 100644 src/crypto/kyber/fips202.h + 26 files changed, 2797 insertions(+), 5447 deletions(-) delete mode 100644 src/crypto/kyber/internal.h - create mode 100644 src/crypto/kyber/ipdwing.c delete mode 100644 src/crypto/kyber/keccak.c - create mode 100644 src/crypto/kyber/kyber.h create mode 100644 src/crypto/kyber/kyber512.c create mode 100644 src/crypto/kyber/kyber768.c delete mode 100644 src/crypto/kyber/kyber_test.cc diff --git a/BUILD.generated.bzl b/BUILD.generated.bzl -index 738e1055f..d1d232399 100644 +index 738e1055f..9466757a2 100644 --- a/BUILD.generated.bzl +++ b/BUILD.generated.bzl @@ -253,7 +253,6 @@ crypto_internal_headers = [ @@ -79,16 +67,14 @@ index 738e1055f..d1d232399 100644 "src/crypto/lhash/internal.h", "src/crypto/obj/obj_dat.h", "src/crypto/pkcs7/internal.h", -@@ -382,8 +381,10 @@ crypto_sources = [ +@@ -382,8 +381,8 @@ crypto_sources = [ "src/crypto/fipsmodule/fips_shared_support.c", "src/crypto/hpke/hpke.c", "src/crypto/hrss/hrss.c", - "src/crypto/kyber/keccak.c", - "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/fips202.c", + "src/crypto/kyber/kyber512.c", + "src/crypto/kyber/kyber768.c", -+ "src/crypto/kyber/ipdwing.c", "src/crypto/lhash/lhash.c", "src/crypto/mem.c", "src/crypto/obj/obj.c", @@ -122,40 +108,36 @@ index 92dec1e01..8f70dedc0 100644 "src/crypto/pkcs8/test/no_encryption.p12", "src/crypto/pkcs8/test/nss.p12", diff --git a/CMakeLists.txt b/CMakeLists.txt -index faed2befa..678a0167a 100644 +index faed2befa..931c0e3a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -375,8 +375,10 @@ add_library( +@@ -375,8 +375,8 @@ add_library( src/crypto/fipsmodule/fips_shared_support.c src/crypto/hpke/hpke.c src/crypto/hrss/hrss.c - src/crypto/kyber/keccak.c - src/crypto/kyber/kyber.c -+ src/crypto/kyber/fips202.c + src/crypto/kyber/kyber512.c + src/crypto/kyber/kyber768.c -+ src/crypto/kyber/ipdwing.c src/crypto/lhash/lhash.c src/crypto/mem.c src/crypto/obj/obj.c diff --git a/sources.json b/sources.json -index 4c0048e1d..d021a14b1 100644 +index 4c0048e1d..f6ea5c40f 100644 --- a/sources.json +++ b/sources.json -@@ -111,8 +111,10 @@ +@@ -111,8 +111,8 @@ "src/crypto/fipsmodule/fips_shared_support.c", "src/crypto/hpke/hpke.c", "src/crypto/hrss/hrss.c", - "src/crypto/kyber/keccak.c", - "src/crypto/kyber/kyber.c", -+ "src/crypto/kyber/fips202.c", + "src/crypto/kyber/kyber512.c", + "src/crypto/kyber/kyber768.c", -+ "src/crypto/kyber/ipdwing.c", "src/crypto/lhash/lhash.c", "src/crypto/mem.c", "src/crypto/obj/obj.c", -@@ -549,7 +551,6 @@ +@@ -549,7 +549,6 @@ "src/crypto/hpke/hpke_test.cc", "src/crypto/hrss/hrss_test.cc", "src/crypto/impl_dispatch_test.cc", @@ -163,7 +145,7 @@ index 4c0048e1d..d021a14b1 100644 "src/crypto/lhash/lhash_test.cc", "src/crypto/obj/obj_test.cc", "src/crypto/pem/pem_test.cc", -@@ -634,8 +635,6 @@ +@@ -634,8 +633,6 @@ "src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt", "src/crypto/hmac_extra/hmac_tests.txt", "src/crypto/hpke/hpke_test_vectors.txt", @@ -172,7 +154,7 @@ index 4c0048e1d..d021a14b1 100644 "src/crypto/pkcs8/test/empty_password.p12", "src/crypto/pkcs8/test/no_encryption.p12", "src/crypto/pkcs8/test/nss.p12", -@@ -1060,4 +1059,4 @@ +@@ -1060,4 +1057,4 @@ "urandom_test": [ "src/crypto/fipsmodule/rand/urandom_test.cc" ] @@ -180,23 +162,21 @@ index 4c0048e1d..d021a14b1 100644 \ No newline at end of file +} diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt -index cdb5ddca1..9dcb7a566 100644 +index cdb5ddca1..2052fa791 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt -@@ -170,8 +170,10 @@ add_library( +@@ -170,8 +170,8 @@ add_library( ex_data.c hpke/hpke.c hrss/hrss.c - kyber/keccak.c - kyber/kyber.c -+ kyber/fips202.c + kyber/kyber512.c + kyber/kyber768.c -+ kyber/ipdwing.c lhash/lhash.c mem.c obj/obj.c -@@ -400,7 +402,6 @@ add_executable( +@@ -400,7 +400,6 @@ add_executable( hmac_extra/hmac_test.cc hrss/hrss_test.cc impl_dispatch_test.cc @@ -204,746 +184,6 @@ index cdb5ddca1..9dcb7a566 100644 lhash/lhash_test.cc obj/obj_test.cc pem/pem_test.cc -diff --git a/src/crypto/kyber/fips202.c b/src/crypto/kyber/fips202.c -new file mode 100644 -index 000000000..9713a4f7e ---- /dev/null -+++ b/src/crypto/kyber/fips202.c -@@ -0,0 +1,699 @@ -+/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from -+ * http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202" -+ * implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein, -+ * and Peter Schwabe */ -+ -+#include "fips202.h" -+ -+#define NROUNDS 24 -+#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) -+ -+/************************************************* -+* Name: load64 -+* -+* Description: Load 8 bytes into uint64_t in little-endian order -+* -+* Arguments: - const uint8_t *x: pointer to input byte array -+* -+* Returns the loaded 64-bit unsigned integer -+**************************************************/ -+static uint64_t load64(const uint8_t x[8]) { -+ unsigned int i; -+ uint64_t r = 0; -+ -+ for(i=0;i<8;i++) -+ r |= (uint64_t)x[i] << 8*i; -+ -+ return r; -+} -+ -+/************************************************* -+* Name: store64 -+* -+* Description: Store a 64-bit integer to array of 8 bytes in little-endian order -+* -+* Arguments: - uint8_t *x: pointer to the output byte array (allocated) -+* - uint64_t u: input 64-bit unsigned integer -+**************************************************/ -+static void store64(uint8_t x[8], uint64_t u) { -+ unsigned int i; -+ -+ for(i=0;i<8;i++) -+ x[i] = u >> 8*i; -+} -+ -+/* Keccak round constants */ -+static const uint64_t KeccakF_RoundConstants[NROUNDS] = { -+ (uint64_t)0x0000000000000001ULL, -+ (uint64_t)0x0000000000008082ULL, -+ (uint64_t)0x800000000000808aULL, -+ (uint64_t)0x8000000080008000ULL, -+ (uint64_t)0x000000000000808bULL, -+ (uint64_t)0x0000000080000001ULL, -+ (uint64_t)0x8000000080008081ULL, -+ (uint64_t)0x8000000000008009ULL, -+ (uint64_t)0x000000000000008aULL, -+ (uint64_t)0x0000000000000088ULL, -+ (uint64_t)0x0000000080008009ULL, -+ (uint64_t)0x000000008000000aULL, -+ (uint64_t)0x000000008000808bULL, -+ (uint64_t)0x800000000000008bULL, -+ (uint64_t)0x8000000000008089ULL, -+ (uint64_t)0x8000000000008003ULL, -+ (uint64_t)0x8000000000008002ULL, -+ (uint64_t)0x8000000000000080ULL, -+ (uint64_t)0x000000000000800aULL, -+ (uint64_t)0x800000008000000aULL, -+ (uint64_t)0x8000000080008081ULL, -+ (uint64_t)0x8000000000008080ULL, -+ (uint64_t)0x0000000080000001ULL, -+ (uint64_t)0x8000000080008008ULL -+}; -+ -+/************************************************* -+* Name: KeccakF1600_StatePermute -+* -+* Description: The Keccak F1600 Permutation -+* -+* Arguments: - uint64_t *state: pointer to input/output Keccak state -+**************************************************/ -+static void KeccakF1600_StatePermute(uint64_t state[25]) -+{ -+ int round; -+ -+ uint64_t Aba, Abe, Abi, Abo, Abu; -+ uint64_t Aga, Age, Agi, Ago, Agu; -+ uint64_t Aka, Ake, Aki, Ako, Aku; -+ uint64_t Ama, Ame, Ami, Amo, Amu; -+ uint64_t Asa, Ase, Asi, Aso, Asu; -+ uint64_t BCa, BCe, BCi, BCo, BCu; -+ uint64_t Da, De, Di, Do, Du; -+ uint64_t Eba, Ebe, Ebi, Ebo, Ebu; -+ uint64_t Ega, Ege, Egi, Ego, Egu; -+ uint64_t Eka, Eke, Eki, Eko, Eku; -+ uint64_t Ema, Eme, Emi, Emo, Emu; -+ uint64_t Esa, Ese, Esi, Eso, Esu; -+ -+ //copyFromState(A, state) -+ Aba = state[ 0]; -+ Abe = state[ 1]; -+ Abi = state[ 2]; -+ Abo = state[ 3]; -+ Abu = state[ 4]; -+ Aga = state[ 5]; -+ Age = state[ 6]; -+ Agi = state[ 7]; -+ Ago = state[ 8]; -+ Agu = state[ 9]; -+ Aka = state[10]; -+ Ake = state[11]; -+ Aki = state[12]; -+ Ako = state[13]; -+ Aku = state[14]; -+ Ama = state[15]; -+ Ame = state[16]; -+ Ami = state[17]; -+ Amo = state[18]; -+ Amu = state[19]; -+ Asa = state[20]; -+ Ase = state[21]; -+ Asi = state[22]; -+ Aso = state[23]; -+ Asu = state[24]; -+ -+ for(round = 0; round < NROUNDS; round += 2) { -+ // prepareTheta -+ BCa = Aba^Aga^Aka^Ama^Asa; -+ BCe = Abe^Age^Ake^Ame^Ase; -+ BCi = Abi^Agi^Aki^Ami^Asi; -+ BCo = Abo^Ago^Ako^Amo^Aso; -+ BCu = Abu^Agu^Aku^Amu^Asu; -+ -+ //thetaRhoPiChiIotaPrepareTheta(round, A, E) -+ Da = BCu^ROL(BCe, 1); -+ De = BCa^ROL(BCi, 1); -+ Di = BCe^ROL(BCo, 1); -+ Do = BCi^ROL(BCu, 1); -+ Du = BCo^ROL(BCa, 1); -+ -+ Aba ^= Da; -+ BCa = Aba; -+ Age ^= De; -+ BCe = ROL(Age, 44); -+ Aki ^= Di; -+ BCi = ROL(Aki, 43); -+ Amo ^= Do; -+ BCo = ROL(Amo, 21); -+ Asu ^= Du; -+ BCu = ROL(Asu, 14); -+ Eba = BCa ^((~BCe)& BCi ); -+ Eba ^= (uint64_t)KeccakF_RoundConstants[round]; -+ Ebe = BCe ^((~BCi)& BCo ); -+ Ebi = BCi ^((~BCo)& BCu ); -+ Ebo = BCo ^((~BCu)& BCa ); -+ Ebu = BCu ^((~BCa)& BCe ); -+ -+ Abo ^= Do; -+ BCa = ROL(Abo, 28); -+ Agu ^= Du; -+ BCe = ROL(Agu, 20); -+ Aka ^= Da; -+ BCi = ROL(Aka, 3); -+ Ame ^= De; -+ BCo = ROL(Ame, 45); -+ Asi ^= Di; -+ BCu = ROL(Asi, 61); -+ Ega = BCa ^((~BCe)& BCi ); -+ Ege = BCe ^((~BCi)& BCo ); -+ Egi = BCi ^((~BCo)& BCu ); -+ Ego = BCo ^((~BCu)& BCa ); -+ Egu = BCu ^((~BCa)& BCe ); -+ -+ Abe ^= De; -+ BCa = ROL(Abe, 1); -+ Agi ^= Di; -+ BCe = ROL(Agi, 6); -+ Ako ^= Do; -+ BCi = ROL(Ako, 25); -+ Amu ^= Du; -+ BCo = ROL(Amu, 8); -+ Asa ^= Da; -+ BCu = ROL(Asa, 18); -+ Eka = BCa ^((~BCe)& BCi ); -+ Eke = BCe ^((~BCi)& BCo ); -+ Eki = BCi ^((~BCo)& BCu ); -+ Eko = BCo ^((~BCu)& BCa ); -+ Eku = BCu ^((~BCa)& BCe ); -+ -+ Abu ^= Du; -+ BCa = ROL(Abu, 27); -+ Aga ^= Da; -+ BCe = ROL(Aga, 36); -+ Ake ^= De; -+ BCi = ROL(Ake, 10); -+ Ami ^= Di; -+ BCo = ROL(Ami, 15); -+ Aso ^= Do; -+ BCu = ROL(Aso, 56); -+ Ema = BCa ^((~BCe)& BCi ); -+ Eme = BCe ^((~BCi)& BCo ); -+ Emi = BCi ^((~BCo)& BCu ); -+ Emo = BCo ^((~BCu)& BCa ); -+ Emu = BCu ^((~BCa)& BCe ); -+ -+ Abi ^= Di; -+ BCa = ROL(Abi, 62); -+ Ago ^= Do; -+ BCe = ROL(Ago, 55); -+ Aku ^= Du; -+ BCi = ROL(Aku, 39); -+ Ama ^= Da; -+ BCo = ROL(Ama, 41); -+ Ase ^= De; -+ BCu = ROL(Ase, 2); -+ Esa = BCa ^((~BCe)& BCi ); -+ Ese = BCe ^((~BCi)& BCo ); -+ Esi = BCi ^((~BCo)& BCu ); -+ Eso = BCo ^((~BCu)& BCa ); -+ Esu = BCu ^((~BCa)& BCe ); -+ -+ // prepareTheta -+ BCa = Eba^Ega^Eka^Ema^Esa; -+ BCe = Ebe^Ege^Eke^Eme^Ese; -+ BCi = Ebi^Egi^Eki^Emi^Esi; -+ BCo = Ebo^Ego^Eko^Emo^Eso; -+ BCu = Ebu^Egu^Eku^Emu^Esu; -+ -+ //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) -+ Da = BCu^ROL(BCe, 1); -+ De = BCa^ROL(BCi, 1); -+ Di = BCe^ROL(BCo, 1); -+ Do = BCi^ROL(BCu, 1); -+ Du = BCo^ROL(BCa, 1); -+ -+ Eba ^= Da; -+ BCa = Eba; -+ Ege ^= De; -+ BCe = ROL(Ege, 44); -+ Eki ^= Di; -+ BCi = ROL(Eki, 43); -+ Emo ^= Do; -+ BCo = ROL(Emo, 21); -+ Esu ^= Du; -+ BCu = ROL(Esu, 14); -+ Aba = BCa ^((~BCe)& BCi ); -+ Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; -+ Abe = BCe ^((~BCi)& BCo ); -+ Abi = BCi ^((~BCo)& BCu ); -+ Abo = BCo ^((~BCu)& BCa ); -+ Abu = BCu ^((~BCa)& BCe ); -+ -+ Ebo ^= Do; -+ BCa = ROL(Ebo, 28); -+ Egu ^= Du; -+ BCe = ROL(Egu, 20); -+ Eka ^= Da; -+ BCi = ROL(Eka, 3); -+ Eme ^= De; -+ BCo = ROL(Eme, 45); -+ Esi ^= Di; -+ BCu = ROL(Esi, 61); -+ Aga = BCa ^((~BCe)& BCi ); -+ Age = BCe ^((~BCi)& BCo ); -+ Agi = BCi ^((~BCo)& BCu ); -+ Ago = BCo ^((~BCu)& BCa ); -+ Agu = BCu ^((~BCa)& BCe ); -+ -+ Ebe ^= De; -+ BCa = ROL(Ebe, 1); -+ Egi ^= Di; -+ BCe = ROL(Egi, 6); -+ Eko ^= Do; -+ BCi = ROL(Eko, 25); -+ Emu ^= Du; -+ BCo = ROL(Emu, 8); -+ Esa ^= Da; -+ BCu = ROL(Esa, 18); -+ Aka = BCa ^((~BCe)& BCi ); -+ Ake = BCe ^((~BCi)& BCo ); -+ Aki = BCi ^((~BCo)& BCu ); -+ Ako = BCo ^((~BCu)& BCa ); -+ Aku = BCu ^((~BCa)& BCe ); -+ -+ Ebu ^= Du; -+ BCa = ROL(Ebu, 27); -+ Ega ^= Da; -+ BCe = ROL(Ega, 36); -+ Eke ^= De; -+ BCi = ROL(Eke, 10); -+ Emi ^= Di; -+ BCo = ROL(Emi, 15); -+ Eso ^= Do; -+ BCu = ROL(Eso, 56); -+ Ama = BCa ^((~BCe)& BCi ); -+ Ame = BCe ^((~BCi)& BCo ); -+ Ami = BCi ^((~BCo)& BCu ); -+ Amo = BCo ^((~BCu)& BCa ); -+ Amu = BCu ^((~BCa)& BCe ); -+ -+ Ebi ^= Di; -+ BCa = ROL(Ebi, 62); -+ Ego ^= Do; -+ BCe = ROL(Ego, 55); -+ Eku ^= Du; -+ BCi = ROL(Eku, 39); -+ Ema ^= Da; -+ BCo = ROL(Ema, 41); -+ Ese ^= De; -+ BCu = ROL(Ese, 2); -+ Asa = BCa ^((~BCe)& BCi ); -+ Ase = BCe ^((~BCi)& BCo ); -+ Asi = BCi ^((~BCo)& BCu ); -+ Aso = BCo ^((~BCu)& BCa ); -+ Asu = BCu ^((~BCa)& BCe ); -+ } -+ -+ //copyToState(state, A) -+ state[ 0] = Aba; -+ state[ 1] = Abe; -+ state[ 2] = Abi; -+ state[ 3] = Abo; -+ state[ 4] = Abu; -+ state[ 5] = Aga; -+ state[ 6] = Age; -+ state[ 7] = Agi; -+ state[ 8] = Ago; -+ state[ 9] = Agu; -+ state[10] = Aka; -+ state[11] = Ake; -+ state[12] = Aki; -+ state[13] = Ako; -+ state[14] = Aku; -+ state[15] = Ama; -+ state[16] = Ame; -+ state[17] = Ami; -+ state[18] = Amo; -+ state[19] = Amu; -+ state[20] = Asa; -+ state[21] = Ase; -+ state[22] = Asi; -+ state[23] = Aso; -+ state[24] = Asu; -+} -+ -+ -+/************************************************* -+* Name: keccak_squeeze -+* -+* Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. -+* Modifies the state. Can be called multiple times to keep -+* squeezing, i.e., is incremental. -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: number of bytes to be squeezed (written to out) -+* - uint64_t *s: pointer to input/output Keccak state -+* - unsigned int pos: number of bytes in current block already squeezed -+* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) -+* -+* Returns new position pos in current block -+**************************************************/ -+static unsigned int keccak_squeeze(uint8_t *out, -+ size_t outlen, -+ uint64_t s[25], -+ unsigned int pos, -+ unsigned int r) -+{ -+ unsigned int i; -+ -+ while(outlen) { -+ if(pos == r) { -+ KeccakF1600_StatePermute(s); -+ pos = 0; -+ } -+ for(i=pos;i < r && i < pos+outlen; i++) -+ *out++ = s[i/8] >> 8*(i%8); -+ outlen -= i-pos; -+ pos = i; -+ } -+ -+ return pos; -+} -+ -+/************************************************* -+* Name: keccak_init -+* -+* Description: Initializes the Keccak state. -+* -+* Arguments: - uint64_t *s: pointer to Keccak state -+**************************************************/ -+static void keccak_init(uint64_t s[25]) -+{ -+ unsigned int i; -+ for(i=0;i<25;i++) -+ s[i] = 0; -+} -+ -+ -+/************************************************* -+* Name: keccak_absorb -+* -+* Description: Absorb step of Keccak; incremental. -+* -+* Arguments: - uint64_t *s: pointer to Keccak state -+* - unsigned int pos: position in current block to be absorbed -+* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+* -+* Returns new position pos in current block -+**************************************************/ -+static unsigned int keccak_absorb(uint64_t s[25], -+ unsigned int pos, -+ unsigned int r, -+ const uint8_t *in, -+ size_t inlen) -+{ -+ unsigned int i; -+ -+ while(pos+inlen >= r) { -+ for(i=pos;i= r) { -+ for(i=0;is, SHAKE128_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE128_RATE; -+} -+ -+/************************************************* -+* Name: shake128_squeezeblocks -+* -+* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of -+* SHAKE128_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes new block has not yet been -+* started (state->pos = SHAKE128_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); -+} -+ -+/************************************************* -+* Name: shake256_squeeze -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many -+* bytes. Can be called multiple times to keep squeezing. -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t outlen : number of bytes to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) -+{ -+ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256_init -+* -+* Description: Initilizes Keccak state for use as SHAKE256 XOF -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state -+**************************************************/ -+void shake256_init(keccak_state *state) -+{ -+ keccak_init(state->s); -+ state->pos = 0; -+} -+ -+/************************************************* -+* Name: shake256_absorb -+* -+* Description: Absorb step of the SHAKE256 XOF; incremental. -+* -+* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); -+} -+ -+/************************************************* -+* Name: shake256_finalize -+* -+* Description: Finalize absorb step of the SHAKE256 XOF. -+* -+* Arguments: - keccak_state *state: pointer to Keccak state -+**************************************************/ -+void shake256_finalize(keccak_state *state) -+{ -+ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: shake256_absorb_once -+* -+* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. -+* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *in: pointer to input to be absorbed into s -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) -+{ -+ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); -+ state->pos = SHAKE256_RATE; -+} -+ -+/************************************************* -+* Name: shake256_squeezeblocks -+* -+* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of -+* SHAKE256_RATE bytes each. Can be called multiple times -+* to keep squeezing. Assumes next block has not yet been -+* started (state->pos = SHAKE256_RATE). -+* -+* Arguments: - uint8_t *out: pointer to output blocks -+* - size_t nblocks: number of blocks to be squeezed (written to output) -+* - keccak_state *s: pointer to input/output Keccak state -+**************************************************/ -+void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) -+{ -+ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); -+} -+ -+/************************************************* -+* Name: shake256 -+* -+* Description: SHAKE256 XOF with non-incremental API -+* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: requested output length in bytes -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) -+{ -+ size_t nblocks; -+ keccak_state state; -+ -+ shake256_absorb_once(&state, in, inlen); -+ nblocks = outlen/SHAKE256_RATE; -+ shake256_squeezeblocks(out, nblocks, &state); -+ outlen -= nblocks*SHAKE256_RATE; -+ out += nblocks*SHAKE256_RATE; -+ shake256_squeeze(out, outlen, &state); -+} -+ -+/************************************************* -+* Name: sha3_256 -+* -+* Description: SHA3-256 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (32 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<4;i++) -+ store64(h+8*i,s[i]); -+} -+ -+/************************************************* -+* Name: sha3_512 -+* -+* Description: SHA3-512 with non-incremental API -+* -+* Arguments: - uint8_t *h: pointer to output (64 bytes) -+* - const uint8_t *in: pointer to input -+* - size_t inlen: length of input in bytes -+**************************************************/ -+void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) -+{ -+ unsigned int i; -+ uint64_t s[25]; -+ -+ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); -+ KeccakF1600_StatePermute(s); -+ for(i=0;i<8;i++) -+ store64(h+8*i,s[i]); -+} -+ -+ -diff --git a/src/crypto/kyber/fips202.h b/src/crypto/kyber/fips202.h -new file mode 100644 -index 000000000..7c37570bc ---- /dev/null -+++ b/src/crypto/kyber/fips202.h -@@ -0,0 +1,29 @@ -+#ifndef OPENSSL_HEADER_KYBER_FIPS202_H -+#define OPENSSL_HEADER_KYBER_FIPS202_H -+ -+#include -+#include -+ -+#define SHAKE128_RATE 168 -+#define SHAKE256_RATE 136 -+#define SHA3_256_RATE 136 -+#define SHA3_512_RATE 72 -+ -+typedef struct { -+ uint64_t s[25]; -+ unsigned int pos; -+} keccak_state; -+ -+void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); -+void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state); -+void shake256_init(keccak_state *state); -+void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake256_finalize(keccak_state *state); -+void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); -+void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); -+void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen); -+void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen); -+void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen); -+ -+#endif diff --git a/src/crypto/kyber/internal.h b/src/crypto/kyber/internal.h deleted file mode 100644 index b3bfa86b8..000000000 @@ -1041,122 +281,6 @@ index b3bfa86b8..000000000 -#endif - -#endif // OPENSSL_HEADER_CRYPTO_KYBER_INTERNAL_H -diff --git a/src/crypto/kyber/ipdwing.c b/src/crypto/kyber/ipdwing.c -new file mode 100644 -index 000000000..d55cfefc9 ---- /dev/null -+++ b/src/crypto/kyber/ipdwing.c -@@ -0,0 +1,110 @@ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "fips202.h" -+#include "kyber.h" -+ -+static const char *label = "\\.//^\\"; -+ -+static void combiner( -+ uint8_t out[32], -+ const uint8_t ss_m[32], -+ const uint8_t ss_x[32], -+ const uint8_t ct_x[32], -+ const uint8_t pk_x[32]) { -+ uint8_t buf[6+32*4]; -+ memcpy(buf, label, 6); -+ memcpy(buf+6, ss_m, 32); -+ memcpy(buf+6+32, ss_x, 32); -+ memcpy(buf+6+32*2, ct_x, 32); -+ memcpy(buf+6+32*3, pk_x, 32); -+ sha3_256(out, buf, 6+32*4); -+} -+ -+void IPDWING_generate_key( -+ struct IPDWING_public_key *out_pub, -+ struct IPDWING_private_key *out_priv, -+ const uint8_t seed[IPDWING_GENERATE_KEY_BYTES]) { -+ KYBER768_generate_key( -+ &out_pub->m, -+ &out_priv->m, -+ seed); -+ memcpy(out_priv->x, seed+64, 32); -+ X25519_public_from_private(out_pub->x, out_priv->x); -+ memcpy(out_priv->xpub, out_pub->x, 32); -+} -+ -+void IPDWING_encap( -+ uint8_t out_ciphertext[IPDWING_CIPHERTEXT_BYTES], -+ uint8_t ss[IPDWING_KEY_BYTES], -+ const struct IPDWING_public_key *in_pub, -+ const uint8_t seed[IPDWING_ENCAP_BYTES]) { -+ -+ uint8_t ss_m[32]; -+ uint8_t ss_x[32]; -+ uint8_t *ct_x = out_ciphertext + KYBER768_CIPHERTEXT_BYTES; -+ const uint8_t *ek_x = seed + 32; -+ X25519_public_from_private(ct_x, ek_x); -+ -+ X25519( -+ ss_x, -+ ek_x, -+ in_pub->x -+ ); -+ -+ KYBER768_encap2( -+ out_ciphertext, -+ ss_m, -+ &in_pub->m, -+ seed, -+ 1 -+ ); -+ -+ combiner(ss, ss_m, ss_x, ct_x, in_pub->x); -+} -+ -+void IPDWING_decap( -+ uint8_t out_shared_key[IPDWING_KEY_BYTES], -+ const struct IPDWING_private_key *in_priv, -+ const uint8_t *ct) { -+ -+ uint8_t ss_m[32]; -+ uint8_t ss_x[32]; -+ const uint8_t *ct_x = ct + KYBER768_CIPHERTEXT_BYTES; -+ -+ KYBER768_decap2( -+ ss_m, -+ &in_priv->m, -+ ct, -+ KYBER768_CIPHERTEXT_BYTES, -+ 1 -+ ); -+ -+ X25519( -+ ss_x, -+ in_priv->x, -+ ct_x -+ ); -+ -+ combiner(out_shared_key, ss_m, ss_x, ct_x, in_priv->xpub); -+} -+ -+void IPDWING_marshal_public_key( -+ uint8_t out[IPDWING_PUBLIC_KEY_BYTES], -+ const struct IPDWING_public_key *in) { -+ KYBER768_marshal_public_key(out, &in->m); -+ memcpy(out + KYBER768_PUBLIC_KEY_BYTES, in->x, 32); -+} -+ -+void IPDWING_parse_public_key( -+ struct IPDWING_public_key *out, -+ const uint8_t in[IPDWING_PUBLIC_KEY_BYTES]) { -+ KYBER768_parse_public_key(&out->m, in); -+ memcpy(out->x, in + KYBER768_PUBLIC_KEY_BYTES, 32); -+} -+ diff --git a/src/crypto/kyber/keccak.c b/src/crypto/kyber/keccak.c deleted file mode 100644 index f1c012d11..000000000 @@ -1368,10 +492,10 @@ index f1c012d11..000000000 - } -} diff --git a/src/crypto/kyber/kyber.c b/src/crypto/kyber/kyber.c -index 776c085f9..5acd45cd9 100644 +index 776c085f9..346d4daec 100644 --- a/src/crypto/kyber/kyber.c +++ b/src/crypto/kyber/kyber.c -@@ -1,833 +1,1706 @@ +@@ -1,833 +1,2252 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -1410,26 +534,21 @@ index 776c085f9..5acd45cd9 100644 +// implementation or https://github.com/cloudflare/circl/tree/main/pke/kyber +// +// - Option to keep A stored in private key. - --#include ++ +#ifndef KYBER_K +#error "Don't compile this file direcly" +#endif --#include --#include -+#include + #include +#include +-#include +-#include +- -#include -#include -+#include -+#include -+#include - -+#include "fips202.h" -+#include "kyber.h" - #include "../internal.h" +- +-#include "../internal.h" -#include "./internal.h" - - @@ -1493,6 +612,9 @@ index 776c085f9..5acd45cd9 100644 - 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, - 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154, -}; ++#include ++#include ++#include -// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] -static const uint16_t kInverseNTTRoots[128] = { @@ -1589,9 +711,6 @@ index 776c085f9..5acd45cd9 100644 +#define marshal_public_key KYBER_NAMESPACE(marshal_public_key) +#define parse_public_key KYBER_NAMESPACE(parse_public_key) + -+#define decap2 KYBER_NAMESPACE(decap2) -+#define encap2 KYBER_NAMESPACE(encap2) -+ + +// +// params.h @@ -1738,6 +857,30 @@ index 776c085f9..5acd45cd9 100644 +// fips202.h +// + ++#define SHAKE128_RATE 168 ++#define SHAKE256_RATE 136 ++#define SHA3_256_RATE 136 ++#define SHA3_512_RATE 72 ++ ++typedef struct { ++ uint64_t s[25]; ++ unsigned int pos; ++} keccak_state; ++ ++static void shake128_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); ++ ++static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state); ++static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); ++static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); ++ ++static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen); ++static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen); ++static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen); ++ ++// ++// symmetric.h ++// + +typedef keccak_state xof_state; + @@ -1748,7 +891,6 @@ index 776c085f9..5acd45cd9 100644 + +static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce); + -+ +#define XOF_BLOCKBYTES SHAKE128_RATE + +#define hash_h(OUT, IN, INBYTES) sha3_256(OUT, IN, INBYTES) @@ -1972,15 +1114,6 @@ index 776c085f9..5acd45cd9 100644 +#error "This implementation requires eta1 in {2,3}" +#endif +} -+ -+static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) -+{ -+#if KYBER_ETA2 == 2 -+ cbd2(r, buf); -+#else -+#error "This implementation requires eta2 = 2" -+#endif -+} -// In place inverse number theoretic transform of a given scalar, with pairs of -// entries of s->v being interpreted as elements of GF(3329^2). Just as with the @@ -2001,6 +1134,15 @@ index 776c085f9..5acd45cd9 100644 - uint16_t even = s->c[j]; - s->c[j] = reduce_once(odd + even); - s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); ++static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) ++{ ++#if KYBER_ETA2 == 2 ++ cbd2(r, buf); ++#else ++#error "This implementation requires eta2 = 2" ++#endif ++} ++ +// +// ntt.c +// @@ -2132,11 +1274,8 @@ index 776c085f9..5acd45cd9 100644 + + for(j = 0; j < 256; j++) + r[j] = fqmul(r[j], f); - } - --static void scalar_add(scalar *lhs, const scalar *rhs) { -- for (int i = 0; i < DEGREE; i++) { -- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); ++} ++ +/************************************************* +* Name: basemul +* @@ -2155,8 +1294,11 @@ index 776c085f9..5acd45cd9 100644 + r[0] += fqmul(a[0], b[0]); + r[1] = fqmul(a[0], b[1]); + r[1] += fqmul(a[1], b[0]); -+} -+ + } + +-static void scalar_add(scalar *lhs, const scalar *rhs) { +- for (int i = 0; i < DEGREE; i++) { +- lhs->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); +// +// poly.c +// @@ -2174,7 +1316,6 @@ index 776c085f9..5acd45cd9 100644 +{ + unsigned int i,j; + int16_t u; -+ uint32_t d0; + uint8_t t[8]; + +#if (KYBER_POLYCOMPRESSEDBYTES == 128) @@ -2183,11 +1324,7 @@ index 776c085f9..5acd45cd9 100644 + // map to positive standard representatives + u = a->coeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ d0 = u << 4; -+ d0 += 1665; -+ d0 *= 80635; -+ d0 >>= 28; -+ t[j] = d0 & 0xf; ++ t[j] = ((((uint16_t)u << 4) + KYBER_Q/2)/KYBER_Q) & 15; + } + + r[0] = t[0] | (t[1] << 4); @@ -2195,18 +1332,14 @@ index 776c085f9..5acd45cd9 100644 + r[2] = t[4] | (t[5] << 4); + r[3] = t[6] | (t[7] << 4); + r += 4; -+ } + } +#elif (KYBER_POLYCOMPRESSEDBYTES == 160) + for(i=0;icoeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ d0 = u << 5; -+ d0 += 1664; -+ d0 *= 40318; -+ d0 >>= 27; -+ t[j] = d0 & 0x1f; ++ t[j] = ((((uint32_t)u << 5) + KYBER_Q/2)/KYBER_Q) & 31; + } + + r[0] = (t[0] >> 0) | (t[1] << 5); @@ -2215,7 +1348,7 @@ index 776c085f9..5acd45cd9 100644 + r[3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6); + r[4] = (t[6] >> 2) | (t[7] << 3); + r += 5; - } ++ } +#else +#error "KYBER_POLYCOMPRESSEDBYTES needs to be in {128, 160}" +#endif @@ -2357,7 +1490,7 @@ index 776c085f9..5acd45cd9 100644 + + for(i=0;i> j)&1); ++ mask = -(int16_t)((msg[i] >> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); } } @@ -2382,17 +1515,14 @@ index 776c085f9..5acd45cd9 100644 +static void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a) +{ + unsigned int i,j; -+ uint32_t t; ++ uint16_t t; + + for(i=0;icoeffs[8*i+j]; -+ t <<= 1; -+ t += 1665; -+ t *= 80635; -+ t >>= 28; -+ t &= 1; ++ t += ((int16_t)t >> 15) & KYBER_Q; ++ t = (((t << 1) + KYBER_Q/2)/KYBER_Q) & 1; + msg[i] |= t << j; } } @@ -2671,7 +1801,6 @@ index 776c085f9..5acd45cd9 100644 +static void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a) +{ + unsigned int i,j,k; -+ uint64_t d0; + +#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352)) + uint16_t t[8]; @@ -2680,12 +1809,7 @@ index 776c085f9..5acd45cd9 100644 + for(k=0;k<8;k++) { + t[k] = a->vec[i].coeffs[8*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ d0 = t[k]; -+ d0 <<= 11; -+ d0 += 1664; -+ d0 *= 645084; -+ d0 >>= 31; -+ t[k] = d0 & 0x7ff; ++ t[k] = ((((uint32_t)t[k] << 11) + KYBER_Q/2)/KYBER_Q) & 0x7ff; } - element_bits_done += chunk_bits; @@ -2711,12 +1835,7 @@ index 776c085f9..5acd45cd9 100644 + for(k=0;k<4;k++) { + t[k] = a->vec[i].coeffs[4*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ d0 = t[k]; -+ d0 <<= 10; -+ d0 += 1665; -+ d0 *= 1290167; -+ d0 >>= 32; -+ t[k] = d0 & 0x3ff; ++ t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q/2)/ KYBER_Q) & 0x3ff; + } - if (out_byte_bits > 0) { @@ -2807,14 +1926,8 @@ index 776c085f9..5acd45cd9 100644 + unsigned int i; + for(i=0;ivec[i]); - } - --// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 --// (DEGREE) is divisible by 8, the individual vector entries will always fill a --// whole number of bytes, so we do not need to worry about bit packing here. --static void vector_encode(uint8_t *out, const vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); ++} ++ +/************************************************* +* Name: polyvec_frombytes +* @@ -2830,8 +1943,14 @@ index 776c085f9..5acd45cd9 100644 + unsigned int i; + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); -+} -+ + } + +-// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 +-// (DEGREE) is divisible by 8, the individual vector entries will always fill a +-// whole number of bytes, so we do not need to worry about bit packing here. +-static void vector_encode(uint8_t *out, const vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +/************************************************* +* Name: polyvec_ntt +* @@ -3350,28 +2469,35 @@ index 776c085f9..5acd45cd9 100644 - uint8_t public_key_hash[32]; - matrix m; -}; ++// ++// fips202.c ++// ++ ++/* Based on the public domain implementation in crypto_hash/keccakc512/simple/ from ++ * http://bench.cr.yp.to/supercop.html by Ronny Van Keer and the public domain "TweetFips202" ++ * implementation from https://twitter.com/tweetfips202 by Gilles Van Assche, Daniel J. Bernstein, ++ * and Peter Schwabe */ ++ ++#define NROUNDS 24 ++#define ROL(a, offset) ((a << offset) ^ (a >> (64-offset))) ++ +/************************************************* -+* Name: kyber_shake128_absorb ++* Name: load64 +* -+* Description: Absorb step of the SHAKE128 specialized for the Kyber context. ++* Description: Load 8 bytes into uint64_t in little-endian order +* -+* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state -+* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state -+* - uint8_t i: additional byte of input -+* - uint8_t j: additional byte of input ++* Arguments: - const uint8_t *x: pointer to input byte array ++* ++* Returns the loaded 64-bit unsigned integer +**************************************************/ -+void kyber_shake128_absorb(keccak_state *state, -+ const uint8_t seed[KYBER_SYMBYTES], -+ uint8_t x, -+ uint8_t y) -+{ -+ uint8_t extseed[KYBER_SYMBYTES+2]; ++static uint64_t load64(const uint8_t x[8]) { ++ unsigned int i; ++ uint64_t r = 0; + -+ memcpy(extseed, seed, KYBER_SYMBYTES); -+ extseed[KYBER_SYMBYTES+0] = x; -+ extseed[KYBER_SYMBYTES+1] = y; ++ for(i=0;i<8;i++) ++ r |= (uint64_t)x[i] << 8*i; + -+ shake128_absorb_once(state, extseed, sizeof(extseed)); ++ return r; +} -static struct public_key *public_key_from_external( @@ -3382,34 +2508,51 @@ index 776c085f9..5acd45cd9 100644 - "Kyber public key align incorrect"); - return (struct public_key *)external; +/************************************************* -+* Name: kyber_shake256_prf ++* Name: store64 +* -+* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input -+* and then generates outlen bytes of SHAKE256 output ++* Description: Store a 64-bit integer to array of 8 bytes in little-endian order +* -+* Arguments: - uint8_t *out: pointer to output -+* - size_t outlen: number of requested output bytes -+* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) -+* - uint8_t nonce: single-byte nonce (public PRF input) ++* Arguments: - uint8_t *x: pointer to the output byte array (allocated) ++* - uint64_t u: input 64-bit unsigned integer +**************************************************/ -+static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) -+{ -+ uint8_t extkey[KYBER_SYMBYTES+1]; ++static void store64(uint8_t x[8], uint64_t u) { ++ unsigned int i; + -+ memcpy(extkey, key, KYBER_SYMBYTES); -+ extkey[KYBER_SYMBYTES] = nonce; -+ -+ shake256(out, outlen, extkey, sizeof(extkey)); ++ for(i=0;i<8;i++) ++ x[i] = u >> 8*i; } -struct private_key { - struct public_key pub; - vector s; - uint8_t fo_failure_secret[32]; --}; -+// -+// kem.c -+// ++/* Keccak round constants */ ++static const uint64_t KeccakF_RoundConstants[NROUNDS] = { ++ (uint64_t)0x0000000000000001ULL, ++ (uint64_t)0x0000000000008082ULL, ++ (uint64_t)0x800000000000808aULL, ++ (uint64_t)0x8000000080008000ULL, ++ (uint64_t)0x000000000000808bULL, ++ (uint64_t)0x0000000080000001ULL, ++ (uint64_t)0x8000000080008081ULL, ++ (uint64_t)0x8000000000008009ULL, ++ (uint64_t)0x000000000000008aULL, ++ (uint64_t)0x0000000000000088ULL, ++ (uint64_t)0x0000000080008009ULL, ++ (uint64_t)0x000000008000000aULL, ++ (uint64_t)0x000000008000808bULL, ++ (uint64_t)0x800000000000008bULL, ++ (uint64_t)0x8000000000008089ULL, ++ (uint64_t)0x8000000000008003ULL, ++ (uint64_t)0x8000000000008002ULL, ++ (uint64_t)0x8000000000000080ULL, ++ (uint64_t)0x000000000000800aULL, ++ (uint64_t)0x800000008000000aULL, ++ (uint64_t)0x8000000080008081ULL, ++ (uint64_t)0x8000000000008080ULL, ++ (uint64_t)0x0000000080000001ULL, ++ (uint64_t)0x8000000080008008ULL + }; -static struct private_key *private_key_from_external( - const struct KYBER_private_key *external) { @@ -3439,7 +2582,311 @@ index 776c085f9..5acd45cd9 100644 - vector_encode(vector_output, &pub->t, kLog2Prime); - if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { - return 0; -- } ++/************************************************* ++* Name: KeccakF1600_StatePermute ++* ++* Description: The Keccak F1600 Permutation ++* ++* Arguments: - uint64_t *state: pointer to input/output Keccak state ++**************************************************/ ++static void KeccakF1600_StatePermute(uint64_t state[25]) ++{ ++ int round; ++ ++ uint64_t Aba, Abe, Abi, Abo, Abu; ++ uint64_t Aga, Age, Agi, Ago, Agu; ++ uint64_t Aka, Ake, Aki, Ako, Aku; ++ uint64_t Ama, Ame, Ami, Amo, Amu; ++ uint64_t Asa, Ase, Asi, Aso, Asu; ++ uint64_t BCa, BCe, BCi, BCo, BCu; ++ uint64_t Da, De, Di, Do, Du; ++ uint64_t Eba, Ebe, Ebi, Ebo, Ebu; ++ uint64_t Ega, Ege, Egi, Ego, Egu; ++ uint64_t Eka, Eke, Eki, Eko, Eku; ++ uint64_t Ema, Eme, Emi, Emo, Emu; ++ uint64_t Esa, Ese, Esi, Eso, Esu; ++ ++ //copyFromState(A, state) ++ Aba = state[ 0]; ++ Abe = state[ 1]; ++ Abi = state[ 2]; ++ Abo = state[ 3]; ++ Abu = state[ 4]; ++ Aga = state[ 5]; ++ Age = state[ 6]; ++ Agi = state[ 7]; ++ Ago = state[ 8]; ++ Agu = state[ 9]; ++ Aka = state[10]; ++ Ake = state[11]; ++ Aki = state[12]; ++ Ako = state[13]; ++ Aku = state[14]; ++ Ama = state[15]; ++ Ame = state[16]; ++ Ami = state[17]; ++ Amo = state[18]; ++ Amu = state[19]; ++ Asa = state[20]; ++ Ase = state[21]; ++ Asi = state[22]; ++ Aso = state[23]; ++ Asu = state[24]; ++ ++ for(round = 0; round < NROUNDS; round += 2) { ++ // prepareTheta ++ BCa = Aba^Aga^Aka^Ama^Asa; ++ BCe = Abe^Age^Ake^Ame^Ase; ++ BCi = Abi^Agi^Aki^Ami^Asi; ++ BCo = Abo^Ago^Ako^Amo^Aso; ++ BCu = Abu^Agu^Aku^Amu^Asu; ++ ++ //thetaRhoPiChiIotaPrepareTheta(round, A, E) ++ Da = BCu^ROL(BCe, 1); ++ De = BCa^ROL(BCi, 1); ++ Di = BCe^ROL(BCo, 1); ++ Do = BCi^ROL(BCu, 1); ++ Du = BCo^ROL(BCa, 1); ++ ++ Aba ^= Da; ++ BCa = Aba; ++ Age ^= De; ++ BCe = ROL(Age, 44); ++ Aki ^= Di; ++ BCi = ROL(Aki, 43); ++ Amo ^= Do; ++ BCo = ROL(Amo, 21); ++ Asu ^= Du; ++ BCu = ROL(Asu, 14); ++ Eba = BCa ^((~BCe)& BCi ); ++ Eba ^= (uint64_t)KeccakF_RoundConstants[round]; ++ Ebe = BCe ^((~BCi)& BCo ); ++ Ebi = BCi ^((~BCo)& BCu ); ++ Ebo = BCo ^((~BCu)& BCa ); ++ Ebu = BCu ^((~BCa)& BCe ); ++ ++ Abo ^= Do; ++ BCa = ROL(Abo, 28); ++ Agu ^= Du; ++ BCe = ROL(Agu, 20); ++ Aka ^= Da; ++ BCi = ROL(Aka, 3); ++ Ame ^= De; ++ BCo = ROL(Ame, 45); ++ Asi ^= Di; ++ BCu = ROL(Asi, 61); ++ Ega = BCa ^((~BCe)& BCi ); ++ Ege = BCe ^((~BCi)& BCo ); ++ Egi = BCi ^((~BCo)& BCu ); ++ Ego = BCo ^((~BCu)& BCa ); ++ Egu = BCu ^((~BCa)& BCe ); ++ ++ Abe ^= De; ++ BCa = ROL(Abe, 1); ++ Agi ^= Di; ++ BCe = ROL(Agi, 6); ++ Ako ^= Do; ++ BCi = ROL(Ako, 25); ++ Amu ^= Du; ++ BCo = ROL(Amu, 8); ++ Asa ^= Da; ++ BCu = ROL(Asa, 18); ++ Eka = BCa ^((~BCe)& BCi ); ++ Eke = BCe ^((~BCi)& BCo ); ++ Eki = BCi ^((~BCo)& BCu ); ++ Eko = BCo ^((~BCu)& BCa ); ++ Eku = BCu ^((~BCa)& BCe ); ++ ++ Abu ^= Du; ++ BCa = ROL(Abu, 27); ++ Aga ^= Da; ++ BCe = ROL(Aga, 36); ++ Ake ^= De; ++ BCi = ROL(Ake, 10); ++ Ami ^= Di; ++ BCo = ROL(Ami, 15); ++ Aso ^= Do; ++ BCu = ROL(Aso, 56); ++ Ema = BCa ^((~BCe)& BCi ); ++ Eme = BCe ^((~BCi)& BCo ); ++ Emi = BCi ^((~BCo)& BCu ); ++ Emo = BCo ^((~BCu)& BCa ); ++ Emu = BCu ^((~BCa)& BCe ); ++ ++ Abi ^= Di; ++ BCa = ROL(Abi, 62); ++ Ago ^= Do; ++ BCe = ROL(Ago, 55); ++ Aku ^= Du; ++ BCi = ROL(Aku, 39); ++ Ama ^= Da; ++ BCo = ROL(Ama, 41); ++ Ase ^= De; ++ BCu = ROL(Ase, 2); ++ Esa = BCa ^((~BCe)& BCi ); ++ Ese = BCe ^((~BCi)& BCo ); ++ Esi = BCi ^((~BCo)& BCu ); ++ Eso = BCo ^((~BCu)& BCa ); ++ Esu = BCu ^((~BCa)& BCe ); ++ ++ // prepareTheta ++ BCa = Eba^Ega^Eka^Ema^Esa; ++ BCe = Ebe^Ege^Eke^Eme^Ese; ++ BCi = Ebi^Egi^Eki^Emi^Esi; ++ BCo = Ebo^Ego^Eko^Emo^Eso; ++ BCu = Ebu^Egu^Eku^Emu^Esu; ++ ++ //thetaRhoPiChiIotaPrepareTheta(round+1, E, A) ++ Da = BCu^ROL(BCe, 1); ++ De = BCa^ROL(BCi, 1); ++ Di = BCe^ROL(BCo, 1); ++ Do = BCi^ROL(BCu, 1); ++ Du = BCo^ROL(BCa, 1); ++ ++ Eba ^= Da; ++ BCa = Eba; ++ Ege ^= De; ++ BCe = ROL(Ege, 44); ++ Eki ^= Di; ++ BCi = ROL(Eki, 43); ++ Emo ^= Do; ++ BCo = ROL(Emo, 21); ++ Esu ^= Du; ++ BCu = ROL(Esu, 14); ++ Aba = BCa ^((~BCe)& BCi ); ++ Aba ^= (uint64_t)KeccakF_RoundConstants[round+1]; ++ Abe = BCe ^((~BCi)& BCo ); ++ Abi = BCi ^((~BCo)& BCu ); ++ Abo = BCo ^((~BCu)& BCa ); ++ Abu = BCu ^((~BCa)& BCe ); ++ ++ Ebo ^= Do; ++ BCa = ROL(Ebo, 28); ++ Egu ^= Du; ++ BCe = ROL(Egu, 20); ++ Eka ^= Da; ++ BCi = ROL(Eka, 3); ++ Eme ^= De; ++ BCo = ROL(Eme, 45); ++ Esi ^= Di; ++ BCu = ROL(Esi, 61); ++ Aga = BCa ^((~BCe)& BCi ); ++ Age = BCe ^((~BCi)& BCo ); ++ Agi = BCi ^((~BCo)& BCu ); ++ Ago = BCo ^((~BCu)& BCa ); ++ Agu = BCu ^((~BCa)& BCe ); ++ ++ Ebe ^= De; ++ BCa = ROL(Ebe, 1); ++ Egi ^= Di; ++ BCe = ROL(Egi, 6); ++ Eko ^= Do; ++ BCi = ROL(Eko, 25); ++ Emu ^= Du; ++ BCo = ROL(Emu, 8); ++ Esa ^= Da; ++ BCu = ROL(Esa, 18); ++ Aka = BCa ^((~BCe)& BCi ); ++ Ake = BCe ^((~BCi)& BCo ); ++ Aki = BCi ^((~BCo)& BCu ); ++ Ako = BCo ^((~BCu)& BCa ); ++ Aku = BCu ^((~BCa)& BCe ); ++ ++ Ebu ^= Du; ++ BCa = ROL(Ebu, 27); ++ Ega ^= Da; ++ BCe = ROL(Ega, 36); ++ Eke ^= De; ++ BCi = ROL(Eke, 10); ++ Emi ^= Di; ++ BCo = ROL(Emi, 15); ++ Eso ^= Do; ++ BCu = ROL(Eso, 56); ++ Ama = BCa ^((~BCe)& BCi ); ++ Ame = BCe ^((~BCi)& BCo ); ++ Ami = BCi ^((~BCo)& BCu ); ++ Amo = BCo ^((~BCu)& BCa ); ++ Amu = BCu ^((~BCa)& BCe ); ++ ++ Ebi ^= Di; ++ BCa = ROL(Ebi, 62); ++ Ego ^= Do; ++ BCe = ROL(Ego, 55); ++ Eku ^= Du; ++ BCi = ROL(Eku, 39); ++ Ema ^= Da; ++ BCo = ROL(Ema, 41); ++ Ese ^= De; ++ BCu = ROL(Ese, 2); ++ Asa = BCa ^((~BCe)& BCi ); ++ Ase = BCe ^((~BCi)& BCo ); ++ Asi = BCi ^((~BCo)& BCu ); ++ Aso = BCo ^((~BCu)& BCa ); ++ Asu = BCu ^((~BCa)& BCe ); ++ } ++ ++ //copyToState(state, A) ++ state[ 0] = Aba; ++ state[ 1] = Abe; ++ state[ 2] = Abi; ++ state[ 3] = Abo; ++ state[ 4] = Abu; ++ state[ 5] = Aga; ++ state[ 6] = Age; ++ state[ 7] = Agi; ++ state[ 8] = Ago; ++ state[ 9] = Agu; ++ state[10] = Aka; ++ state[11] = Ake; ++ state[12] = Aki; ++ state[13] = Ako; ++ state[14] = Aku; ++ state[15] = Ama; ++ state[16] = Ame; ++ state[17] = Ami; ++ state[18] = Amo; ++ state[19] = Amu; ++ state[20] = Asa; ++ state[21] = Ase; ++ state[22] = Asi; ++ state[23] = Aso; ++ state[24] = Asu; ++} ++ ++ ++/************************************************* ++* Name: keccak_squeeze ++* ++* Description: Squeeze step of Keccak. Squeezes arbitratrily many bytes. ++* Modifies the state. Can be called multiple times to keep ++* squeezing, i.e., is incremental. ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: number of bytes to be squeezed (written to out) ++* - uint64_t *s: pointer to input/output Keccak state ++* - unsigned int pos: number of bytes in current block already squeezed ++* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) ++* ++* Returns new position pos in current block ++**************************************************/ ++static unsigned int keccak_squeeze(uint8_t *out, ++ size_t outlen, ++ uint64_t s[25], ++ unsigned int pos, ++ unsigned int r) ++{ ++ unsigned int i; ++ ++ while(outlen) { ++ if(pos == r) { ++ KeccakF1600_StatePermute(s); ++ pos = 0; ++ } ++ for(i=pos;i < r && i < pos+outlen; i++) ++ *out++ = s[i/8] >> 8*(i%8); ++ outlen -= i-pos; ++ pos = i; + } - return 1; -} - @@ -3470,42 +2917,40 @@ index 776c085f9..5acd45cd9 100644 - CBB_init_fixed(&cbb, out_encoded_public_key, KYBER_PUBLIC_KEY_BYTES); - if (!kyber_marshal_public_key(&cbb, &priv->pub)) { - abort(); -+// Modified crypto_kem_keypair to BoringSSL style API -+void generate_key(struct public_key *out_pub, struct private_key *out_priv, -+ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) -+{ -+ size_t i; -+ uint8_t* pk = &out_pub->opaque[0]; -+ uint8_t* sk = &out_priv->opaque[0]; + -+ indcpa_keypair(pk, sk, seed); -+ for(i=0;iopaque[0]; -+ uint8_t *ct = out_ciphertext; -+ -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; ++ unsigned int i; + -+ memcpy(buf, seed, KYBER_SYMBYTES); ++ for(i=0;i<25;i++) ++ s[i] = 0; + -+ if (ipd == 0) { -+ /* Don't release system RNG output */ -+ hash_h(buf, buf, KYBER_SYMBYTES); ++ while(inlen >= r) { ++ for(i=0;ipub.public_key_hash, sizeof(priv->pub.public_key_hash), @@ -3638,20 +3083,39 @@ index 776c085f9..5acd45cd9 100644 - for (int i = 0; i < 32; i++) { - input[i] = constant_time_select_8(mask, prekey_and_randomness[i], - priv->fo_failure_secret[i]); -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); -+ hash_g(kr, buf, 2*KYBER_SYMBYTES); ++ for(i=0;is, SHAKE128_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE128_RATE; } -// kyber_parse_public_key_no_hash parses |in| into |pub| but doesn't calculate @@ -3678,39 +3150,25 @@ index 776c085f9..5acd45cd9 100644 - !vector_decode(&pub->t, CBS_data(&t_bytes), kLog2Prime) || - !CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) { - return 0; -+// Internal version that allows us to select between initial public draft -+// (when ipd=1) and round3 kyber (ipd=0). -+void decap2(uint8_t out_shared_key[KYBER_SSBYTES], -+ const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd) -+{ -+ uint8_t *ss = out_shared_key; -+ const uint8_t *sk = &in_priv->opaque[0]; -+ -+ size_t i; -+ int fail = 1; -+ uint8_t buf[2*KYBER_SYMBYTES]; -+ /* Will contain key, coins */ -+ uint8_t kr[2*KYBER_SYMBYTES]; -+ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; -+ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; -+ -+ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { -+ indcpa_dec(buf, ct, sk); -+ -+ /* Multitarget countermeasure for coins + contributory KEM */ -+ for(i=0;im, pub->rho); - return 1; --} ++/************************************************* ++* Name: shake128_squeezeblocks ++* ++* Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of ++* SHAKE128_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes new block has not yet been ++* started (state->pos = SHAKE128_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); + } -int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { - struct public_key *pub = public_key_from_external(public_key); @@ -3718,36 +3176,23 @@ index 776c085f9..5acd45cd9 100644 - if (!kyber_parse_public_key_no_hash(pub, in) || // - CBS_len(in) != 0) { - return 0; -+ if (ipd == 1) { -+ /* Compute shared secret in case of rejection: ss2 = PRF(z || c). */ -+ uint8_t ss2[KYBER_SYMBYTES]; -+ keccak_state ks; -+ shake256_init(&ks); -+ shake256_absorb( -+ &ks, -+ sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, -+ KYBER_SYMBYTES -+ ); -+ shake256_absorb(&ks, ct, ciphertext_len); -+ shake256_finalize(&ks); -+ shake256_squeeze(ss2, KYBER_SYMBYTES, &ks); -+ -+ /* Set ss2 to the real shared secret if c = c' */ -+ cmov(ss2, kr, KYBER_SYMBYTES, 1-fail); -+ memcpy(ss, ss2, KYBER_SYMBYTES); -+ } else { -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); -+ -+ /* Overwrite pre-k with z on re-encryption failure */ -+ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); -+ -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); - } +- } - BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), - CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); - return 1; ++/************************************************* ++* Name: shake256_squeeze ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes arbitraily many ++* bytes. Can be called multiple times to keep squeezing. ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t outlen : number of bytes to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) ++{ ++ state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); } -int KYBER_marshal_private_key(CBB *out, @@ -3782,15 +3227,240 @@ index 776c085f9..5acd45cd9 100644 - sizeof(priv->fo_failure_secret)) || - CBS_len(in) != 0) { - return 0; -- } -- return 1; ++/************************************************* ++* Name: shake256_absorb_once ++* ++* Description: Initialize, absorb into and finalize SHAKE256 XOF; non-incremental. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ keccak_absorb_once(state->s, SHAKE256_RATE, in, inlen, 0x1F); ++ state->pos = SHAKE256_RATE; ++} ++ ++/************************************************* ++* Name: shake256_squeezeblocks ++* ++* Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of ++* SHAKE256_RATE bytes each. Can be called multiple times ++* to keep squeezing. Assumes next block has not yet been ++* started (state->pos = SHAKE256_RATE). ++* ++* Arguments: - uint8_t *out: pointer to output blocks ++* - size_t nblocks: number of blocks to be squeezed (written to output) ++* - keccak_state *s: pointer to input/output Keccak state ++**************************************************/ ++static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) ++{ ++ keccak_squeezeblocks(out, nblocks, state->s, SHAKE256_RATE); ++} ++ ++/************************************************* ++* Name: shake256 ++* ++* Description: SHAKE256 XOF with non-incremental API ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: requested output length in bytes ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) ++{ ++ size_t nblocks; ++ keccak_state state; ++ ++ shake256_absorb_once(&state, in, inlen); ++ nblocks = outlen/SHAKE256_RATE; ++ shake256_squeezeblocks(out, nblocks, &state); ++ outlen -= nblocks*SHAKE256_RATE; ++ out += nblocks*SHAKE256_RATE; ++ shake256_squeeze(out, outlen, &state); ++} ++ ++/************************************************* ++* Name: sha3_256 ++* ++* Description: SHA3-256 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (32 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; ++ ++ keccak_absorb_once(s, SHA3_256_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<4;i++) ++ store64(h+8*i,s[i]); ++} ++ ++/************************************************* ++* Name: sha3_512 ++* ++* Description: SHA3-512 with non-incremental API ++* ++* Arguments: - uint8_t *h: pointer to output (64 bytes) ++* - const uint8_t *in: pointer to input ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void sha3_512(uint8_t h[64], const uint8_t *in, size_t inlen) ++{ ++ unsigned int i; ++ uint64_t s[25]; ++ ++ keccak_absorb_once(s, SHA3_512_RATE, in, inlen, 0x06); ++ KeccakF1600_StatePermute(s); ++ for(i=0;i<8;i++) ++ store64(h+8*i,s[i]); ++} ++ ++// ++// symmetric-shake.c ++// ++ ++/************************************************* ++* Name: kyber_shake128_absorb ++* ++* Description: Absorb step of the SHAKE128 specialized for the Kyber context. ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) output Keccak state ++* - const uint8_t *seed: pointer to KYBER_SYMBYTES input to be absorbed into state ++* - uint8_t i: additional byte of input ++* - uint8_t j: additional byte of input ++**************************************************/ ++static void kyber_shake128_absorb(keccak_state *state, ++ const uint8_t seed[KYBER_SYMBYTES], ++ uint8_t x, ++ uint8_t y) ++{ ++ uint8_t extseed[KYBER_SYMBYTES+2]; ++ ++ memcpy(extseed, seed, KYBER_SYMBYTES); ++ extseed[KYBER_SYMBYTES+0] = x; ++ extseed[KYBER_SYMBYTES+1] = y; ++ ++ shake128_absorb_once(state, extseed, sizeof(extseed)); ++} ++ ++/************************************************* ++* Name: kyber_shake256_prf ++* ++* Description: Usage of SHAKE256 as a PRF, concatenates secret and public input ++* and then generates outlen bytes of SHAKE256 output ++* ++* Arguments: - uint8_t *out: pointer to output ++* - size_t outlen: number of requested output bytes ++* - const uint8_t *key: pointer to the key (of length KYBER_SYMBYTES) ++* - uint8_t nonce: single-byte nonce (public PRF input) ++**************************************************/ ++static void kyber_shake256_prf(uint8_t *out, size_t outlen, const uint8_t key[KYBER_SYMBYTES], uint8_t nonce) ++{ ++ uint8_t extkey[KYBER_SYMBYTES+1]; ++ ++ memcpy(extkey, key, KYBER_SYMBYTES); ++ extkey[KYBER_SYMBYTES] = nonce; ++ ++ shake256(out, outlen, extkey, sizeof(extkey)); ++} ++ ++// ++// kem.c ++// ++ ++// Modified crypto_kem_keypair to BoringSSL style API ++void generate_key(struct public_key *out_pub, struct private_key *out_priv, ++ const uint8_t seed[KYBER_GENERATE_KEY_BYTES]) ++{ ++ size_t i; ++ uint8_t* pk = &out_pub->opaque[0]; ++ uint8_t* sk = &out_priv->opaque[0]; ++ ++ indcpa_keypair(pk, sk, seed); ++ for(i=0;iopaque[0]; ++ uint8_t *ct = out_ciphertext; ++ ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ ++ memcpy(buf, seed, KYBER_SYMBYTES); ++ /* Don't release system RNG output */ ++ hash_h(buf, buf, KYBER_SYMBYTES); ++ ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ hash_h(buf+KYBER_SYMBYTES, pk, KYBER_PUBLICKEYBYTES); ++ hash_g(kr, buf, 2*KYBER_SYMBYTES); ++ ++ /* coins are in kr+KYBER_SYMBYTES */ ++ indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES); ++ ++ /* overwrite coins in kr with H(c) */ ++ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); ++ /* hash concatenation of pre-k and H(c) to k */ ++ kdf(ss, kr, 2*KYBER_SYMBYTES); ++} ++ +// Modified crypto_kem_decap to BoringSSL style API +void decap(uint8_t out_shared_key[KYBER_SSBYTES], + const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len) { -+ decap2(out_shared_key, in_priv, ct, ciphertext_len, 0); -+} ++ const uint8_t *ct, size_t ciphertext_len) ++{ ++ uint8_t *ss = out_shared_key; ++ const uint8_t *sk = &in_priv->opaque[0]; + ++ size_t i; ++ int fail = 1; ++ uint8_t buf[2*KYBER_SYMBYTES]; ++ /* Will contain key, coins */ ++ uint8_t kr[2*KYBER_SYMBYTES]; ++ uint8_t cmp[KYBER_CIPHERTEXTBYTES]; ++ const uint8_t *pk = sk+KYBER_INDCPA_SECRETKEYBYTES; ++ ++ if (ciphertext_len == KYBER_CIPHERTEXTBYTES) { ++ indcpa_dec(buf, ct, sk); ++ ++ /* Multitarget countermeasure for coins + contributory KEM */ ++ for(i=0;iopaque, in, KYBER_PUBLICKEYBYTES); } -diff --git a/src/crypto/kyber/kyber.h b/src/crypto/kyber/kyber.h -new file mode 100644 -index 000000000..16e47d582 ---- /dev/null -+++ b/src/crypto/kyber/kyber.h -@@ -0,0 +1,29 @@ -+#ifndef OPENSSL_HEADER_KYBER_KYBER_H -+#define OPENSSL_HEADER_KYBER_KYBER_H -+ -+#include -+ -+#include -+#include -+ -+void KYBER512_encap2(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], -+ uint8_t ss[KYBER_KEY_BYTES], -+ const struct KYBER512_public_key *in_pub, -+ const uint8_t seed[KYBER_ENCAP_BYTES], -+ int ipd); -+ -+void KYBER512_decap2(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER512_private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd); -+ -+void KYBER768_encap2(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], -+ uint8_t ss[KYBER_KEY_BYTES], -+ const struct KYBER768_public_key *in_pub, -+ const uint8_t seed[KYBER_ENCAP_BYTES], -+ int ipd); -+ -+void KYBER768_decap2(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct KYBER768_private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len, int ipd); -+ -+#endif diff --git a/src/crypto/kyber/kyber512.c b/src/crypto/kyber/kyber512.c new file mode 100644 index 000000000..21eed11a2 @@ -4093,7 +3728,7 @@ index eb76b5bd7..000000000 - FileTestGTest("crypto/kyber/kyber_tests.txt", KyberFileTest); -} diff --git a/src/crypto/obj/obj_dat.h b/src/crypto/obj/obj_dat.h -index 654b3c08e..0d3d9f24f 100644 +index 654b3c08e..06f80f971 100644 --- a/src/crypto/obj/obj_dat.h +++ b/src/crypto/obj/obj_dat.h @@ -57,7 +57,7 @@ @@ -4101,11 +3736,11 @@ index 654b3c08e..0d3d9f24f 100644 -#define NUM_NID 965 -+#define NUM_NID 969 ++#define NUM_NID 968 static const uint8_t kObjectData[] = { /* NID_rsadsi */ -@@ -8784,6 +8784,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { +@@ -8784,6 +8784,12 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"HKDF", "hkdf", NID_hkdf, 0, NULL, 0}, {"X25519Kyber768Draft00", "X25519Kyber768Draft00", NID_X25519Kyber768Draft00, 0, NULL, 0}, @@ -4115,19 +3750,10 @@ index 654b3c08e..0d3d9f24f 100644 + NULL, 0}, + {"X25519Kyber768Draft00Old", "X25519Kyber768Draft00Old", + NID_X25519Kyber768Draft00Old, 0, NULL, 0}, -+ {"IPDWing", "IPDWing", NID_IPDWing, 0, NULL, 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { -@@ -8889,6 +8896,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { - 35 /* IDEA-CFB */, - 36 /* IDEA-ECB */, - 46 /* IDEA-OFB */, -+ 968 /* IPDWing */, - 181 /* ISO */, - 183 /* ISO-US */, - 645 /* ITU-T */, -@@ -8916,6 +8924,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8916,6 +8922,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 18 /* OU */, 749 /* Oakley-EC2N-3 */, 750 /* Oakley-EC2N-4 */, @@ -4135,7 +3761,7 @@ index 654b3c08e..0d3d9f24f 100644 9 /* PBE-MD2-DES */, 168 /* PBE-MD2-RC2-64 */, 10 /* PBE-MD5-DES */, -@@ -8982,7 +8991,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8982,7 +8989,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { 458 /* UID */, 0 /* UNDEF */, 948 /* X25519 */, @@ -4145,15 +3771,7 @@ index 654b3c08e..0d3d9f24f 100644 961 /* X448 */, 11 /* X500 */, 378 /* X500algorithms */, -@@ -9787,6 +9798,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { - 431 /* Hold Instruction None */, - 433 /* Hold Instruction Reject */, - 634 /* ICC or token signature */, -+ 968 /* IPDWing */, - 294 /* IPSec End System */, - 295 /* IPSec Tunnel */, - 296 /* IPSec User */, -@@ -9829,6 +9841,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9829,6 +9838,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 366 /* OCSP Nonce */, 371 /* OCSP Service Locator */, 180 /* OCSP Signing */, @@ -4161,7 +3779,7 @@ index 654b3c08e..0d3d9f24f 100644 161 /* PBES2 */, 69 /* PBKDF2 */, 162 /* PBMAC1 */, -@@ -9853,7 +9866,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9853,7 +9863,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { 133 /* Time Stamping */, 375 /* Trust Root */, 948 /* X25519 */, @@ -4172,22 +3790,21 @@ index 654b3c08e..0d3d9f24f 100644 12 /* X509 */, 402 /* X509v3 AC Targeting */, diff --git a/src/crypto/obj/obj_mac.num b/src/crypto/obj/obj_mac.num -index a0519acee..019770f16 100644 +index a0519acee..caeb5eaed 100644 --- a/src/crypto/obj/obj_mac.num +++ b/src/crypto/obj/obj_mac.num -@@ -952,3 +952,7 @@ X448 961 +@@ -952,3 +952,6 @@ X448 961 sha512_256 962 hkdf 963 X25519Kyber768Draft00 964 +X25519Kyber512Draft00 965 +P256Kyber768Draft00 966 +X25519Kyber768Draft00Old 967 -+IPDWing 968 diff --git a/src/crypto/obj/objects.txt b/src/crypto/obj/objects.txt -index 3ad32ea3d..475d278df 100644 +index 3ad32ea3d..aa1404d83 100644 --- a/src/crypto/obj/objects.txt +++ b/src/crypto/obj/objects.txt -@@ -1332,8 +1332,12 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme +@@ -1332,8 +1332,11 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme : dh-std-kdf : dh-cofactor-kdf @@ -4197,12 +3814,11 @@ index 3ad32ea3d..475d278df 100644 : X25519Kyber768Draft00 + : P256Kyber768Draft00 + : X25519Kyber768Draft00Old -+ : IPDWing # See RFC 8410. 1 3 101 110 : X25519 diff --git a/src/include/openssl/kyber.h b/src/include/openssl/kyber.h -index cafae9d17..1c889a075 100644 +index cafae9d17..074ac5906 100644 --- a/src/include/openssl/kyber.h +++ b/src/include/openssl/kyber.h @@ -1,17 +1,3 @@ @@ -4223,23 +3839,20 @@ index cafae9d17..1c889a075 100644 #ifndef OPENSSL_HEADER_KYBER_H #define OPENSSL_HEADER_KYBER_H -@@ -21,105 +7,157 @@ +@@ -21,105 +7,100 @@ extern "C" { #endif -- --// Kyber768. +#define KYBER512_PUBLIC_KEY_BYTES 800 +#define KYBER512_CIPHERTEXT_BYTES 768 +#define KYBER512_PRIVATE_KEY_BYTES 1632 +#define KYBER768_PUBLIC_KEY_BYTES 1184 +#define KYBER768_CIPHERTEXT_BYTES 1088 +#define KYBER768_PRIVATE_KEY_BYTES 2400 -+#define IPDWING_PUBLIC_KEY_BYTES 1216 -+#define IPDWING_CIPHERTEXT_BYTES 1120 -+#define IPDWING_PRIVATE_KEY_BYTES 2464 - +-// Kyber768. +- +- -// KYBER_public_key contains a Kyber768 public key. The contents of this -// object should never leave the address space since the format is unstable. -struct KYBER_public_key { @@ -4261,10 +3874,11 @@ index cafae9d17..1c889a075 100644 +struct KYBER768_private_key { + uint8_t opaque[KYBER768_PRIVATE_KEY_BYTES]; +}; -+struct IPDWING_private_key { -+ struct KYBER768_private_key m; -+ uint8_t x[32]; -+ uint8_t xpub[32]; ++struct KYBER512_public_key { ++ uint8_t opaque[KYBER512_PUBLIC_KEY_BYTES]; ++}; ++struct KYBER768_public_key { ++ uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; }; -// KYBER_PUBLIC_KEY_BYTES is the number of bytes in an encoded Kyber768 public @@ -4343,39 +3957,18 @@ index cafae9d17..1c889a075 100644 -// there are trailing bytes in |in|. -OPENSSL_EXPORT int KYBER_parse_private_key( - struct KYBER_private_key *out_private_key, CBS *in); -+struct KYBER512_public_key { -+ uint8_t opaque[KYBER512_PUBLIC_KEY_BYTES]; -+}; -+struct KYBER768_public_key { -+ uint8_t opaque[KYBER768_PUBLIC_KEY_BYTES]; -+}; -+struct IPDWING_public_key { -+ struct KYBER768_public_key m; -+ uint8_t x[32]; -+}; - +- +// KYBER_GENERATE_KEY_BYTES is the number of bytes of entropy needed to +// generate a keypair. +#define KYBER_GENERATE_KEY_BYTES 64 + -+// IPDWING_GENERATE_KEY_BYTES is the number of bytes of entropy needed to -+// generate a keypair. -+#define IPDWING_GENERATE_KEY_BYTES 96 -+ +// KYBER_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a +// session key. +#define KYBER_ENCAP_BYTES 32 + -+// IPDWING_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a -+// session key. -+#define IPDWING_ENCAP_BYTES 64 -+ +// KYBER_KEY_BYTES is the number of bytes in a shared key. +#define KYBER_KEY_BYTES 32 + -+// IPDWING_KEY_BYTES is the number of bytes in a shared key. -+#define IPDWING_KEY_BYTES 32 -+ +// KYBER512_generate_key is a deterministic function that outputs a public and +// private key based on the given entropy. +OPENSSL_EXPORT void KYBER512_generate_key( @@ -4388,12 +3981,6 @@ index cafae9d17..1c889a075 100644 + struct KYBER768_public_key *out_pub, struct KYBER768_private_key *out_priv, + const uint8_t input[KYBER_GENERATE_KEY_BYTES]); + -+// IPDWING_generate_key is a deterministic function that outputs a public and -+// private key based on the given entropy. -+OPENSSL_EXPORT void IPDWING_generate_key( -+ struct IPDWING_public_key *out_pub, struct IPDWING_private_key *out_priv, -+ const uint8_t input[IPDWING_GENERATE_KEY_BYTES]); -+ +// KYBER512_encap is a deterministic function the generates and encrypts a random +// session key from the given entropy, writing those values to |out_shared_key| +// and |out_ciphertext|, respectively. @@ -4410,14 +3997,6 @@ index cafae9d17..1c889a075 100644 + const struct KYBER768_public_key *in_pub, + const uint8_t in[KYBER_ENCAP_BYTES]); + -+// IPDWING_encap is a deterministic function the generates and encrypts a random -+// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. -+OPENSSL_EXPORT void IPDWING_encap(uint8_t out_ciphertext[IPDWING_CIPHERTEXT_BYTES], -+ uint8_t out_shared_key[IPDWING_KEY_BYTES], -+ const struct IPDWING_public_key *in_pub, -+ const uint8_t in[IPDWING_ENCAP_BYTES]); -+ +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept @@ -4428,7 +4007,7 @@ index cafae9d17..1c889a075 100644 + const struct KYBER512_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len); + -+// KYBER768_decap decrypts a session key from |ciphertext_len| bytes of ++// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept +// in |in_priv|) is written. If the ciphertext is the wrong length then it will @@ -4438,16 +4017,6 @@ index cafae9d17..1c889a075 100644 + const struct KYBER768_private_key *in_priv, + const uint8_t *ciphertext, size_t ciphertext_len); + -+// IPDWING_decap decrypts a session key from IPDWING_CIPHERTEXT_BYTES bytes of -+// |ciphertext|. If the ciphertext is valid, the decrypted key is written to -+// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept -+// in |in_priv|) is written. If the ciphertext is the wrong length then it will -+// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. -+OPENSSL_EXPORT void IPDWING_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], -+ const struct IPDWING_private_key *in_priv, -+ const uint8_t *ciphertext); -+ +// KYBER512_marshal_public_key serialises |in_pub| to |out|. +OPENSSL_EXPORT void KYBER512_marshal_public_key( + uint8_t out[KYBER512_PUBLIC_KEY_BYTES], const struct KYBER512_public_key *in_pub); @@ -4456,10 +4025,6 @@ index cafae9d17..1c889a075 100644 +OPENSSL_EXPORT void KYBER768_marshal_public_key( + uint8_t out[KYBER768_PUBLIC_KEY_BYTES], const struct KYBER768_public_key *in_pub); + -+// IPDWING_marshal_public_key serialises |in_pub| to |out|. -+OPENSSL_EXPORT void IPDWING_marshal_public_key( -+ uint8_t out[IPDWING_PUBLIC_KEY_BYTES], const struct IPDWING_public_key *in_pub); -+ +// KYBER512_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER512_parse_public_key( + struct KYBER512_public_key *out, const uint8_t in[KYBER512_PUBLIC_KEY_BYTES]); @@ -4467,18 +4032,14 @@ index cafae9d17..1c889a075 100644 +// KYBER768_parse_public_key sets |*out| to the public-key encoded in |in|. +OPENSSL_EXPORT void KYBER768_parse_public_key( + struct KYBER768_public_key *out, const uint8_t in[KYBER768_PUBLIC_KEY_BYTES]); -+ -+// IPDWING_parse_public_key sets |*out| to the public-key encoded in |in|. -+OPENSSL_EXPORT void IPDWING_parse_public_key( -+ struct IPDWING_public_key *out, const uint8_t in[IPDWING_PUBLIC_KEY_BYTES]); #if defined(__cplusplus) } // extern C diff --git a/src/include/openssl/nid.h b/src/include/openssl/nid.h -index 4dd8841b1..09912d8bb 100644 +index 4dd8841b1..8237efb74 100644 --- a/src/include/openssl/nid.h +++ b/src/include/openssl/nid.h -@@ -4255,6 +4255,18 @@ extern "C" { +@@ -4255,6 +4255,15 @@ extern "C" { #define SN_X25519Kyber768Draft00 "X25519Kyber768Draft00" #define NID_X25519Kyber768Draft00 964 @@ -4490,25 +4051,21 @@ index 4dd8841b1..09912d8bb 100644 + +#define SN_X25519Kyber768Draft00Old "X25519Kyber768Draft00Old" +#define NID_X25519Kyber768Draft00Old 967 -+ -+#define SN_IPDWing "IPDWing" -+#define NID_IPDWing 968 + #if defined(__cplusplus) } /* extern C */ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..3091c6849 100644 +index 53aa9b453..8233ad210 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h -@@ -2378,6 +2378,10 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); +@@ -2378,6 +2378,9 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); #define SSL_CURVE_SECP521R1 25 #define SSL_CURVE_X25519 29 #define SSL_CURVE_X25519_KYBER768_DRAFT00 0x6399 +#define SSL_CURVE_X25519_KYBER512_DRAFT00 0xfe30 +#define SSL_CURVE_X25519_KYBER768_DRAFT00_OLD 0xfe31 +#define SSL_CURVE_P256_KYBER768_DRAFT00 0xfe32 -+#define SSL_CURVE_IPDWING 0xfe41 // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently // completed handshake or 0 if not applicable. @@ -4526,36 +4083,40 @@ index 5c7e881bf..3c0770cf3 100644 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..cf165df1f 100644 +index 5ee280221..0a706c411 100644 --- a/src/ssl/extensions.cc +++ b/src/ssl/extensions.cc -@@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { +@@ -207,6 +207,9 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { static bool is_post_quantum_group(uint16_t id) { switch (id) { case SSL_CURVE_X25519_KYBER768_DRAFT00: + case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: + case SSL_CURVE_X25519_KYBER512_DRAFT00: + case SSL_CURVE_P256_KYBER768_DRAFT00: -+ case SSL_CURVE_IPDWING: return true; default: return false; diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc -index 09a9ad380..d9d3b9032 100644 +index 09a9ad380..f7d2226e3 100644 --- a/src/ssl/ssl_key_share.cc +++ b/src/ssl/ssl_key_share.cc -@@ -193,63 +193,384 @@ class X25519KeyShare : public SSLKeyShare { +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -193,63 +194,384 @@ class X25519KeyShare : public SSLKeyShare { uint8_t private_key_[32]; }; -class X25519Kyber768KeyShare : public SSLKeyShare { +class P256Kyber768Draft00KeyShare : public SSLKeyShare { - public: -- X25519Kyber768KeyShare() {} ++ public: + P256Kyber768Draft00KeyShare() {} - -- uint16_t GroupID() const override { -- return SSL_CURVE_X25519_KYBER768_DRAFT00; ++ + uint16_t GroupID() const override { return SSL_CURVE_P256_KYBER768_DRAFT00; } + + bool Generate(CBB *out) override { @@ -4605,8 +4166,8 @@ index 09a9ad380..d9d3b9032 100644 + } + + return true; - } - ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + assert(!p256_private_key_); @@ -4769,7 +4330,8 @@ index 09a9ad380..d9d3b9032 100644 +}; + +class X25519Kyber768Draft00KeyShare : public SSLKeyShare { -+ public: + public: +- X25519Kyber768KeyShare() {} + X25519Kyber768Draft00KeyShare(uint16_t group_id) : group_id_(group_id) { + assert(group_id == SSL_CURVE_X25519_KYBER768_DRAFT00 + || group_id == SSL_CURVE_X25519_KYBER768_DRAFT00_OLD); @@ -4777,12 +4339,10 @@ index 09a9ad380..d9d3b9032 100644 + + uint16_t GroupID() const override { return group_id_; } + - bool Generate(CBB *out) override { - uint8_t x25519_public_key[32]; - X25519_keypair(x25519_public_key, x25519_private_key_); - -- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; -- KYBER_generate_key(kyber_public_key, &kyber_private_key_); ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER768_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4790,19 +4350,16 @@ index 09a9ad380..d9d3b9032 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); - - if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || -- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { ++ ++ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { - return false; - } - - return true; - } - -- bool Encap(CBB *out_ciphertext, Array *out_secret, -- uint8_t *out_alert, Span peer_key) override { ++ return false; ++ } ++ ++ return true; ++ } ++ + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + Array secret; @@ -4863,11 +4420,13 @@ index 09a9ad380..d9d3b9032 100644 + + KYBER768_decap(secret.data() + 32, &kyber_private_key_, + peer_key.data() + 32, peer_key.size() - 32); -+ + +- uint16_t GroupID() const override { +- return SSL_CURVE_X25519_KYBER768_DRAFT00; + *out_secret = std::move(secret); + return true; -+ } -+ + } + + private: + uint8_t x25519_private_key_[32]; + KYBER768_private_key kyber_private_key_; @@ -4880,10 +4439,12 @@ index 09a9ad380..d9d3b9032 100644 + + uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } + -+ bool Generate(CBB *out) override { -+ uint8_t x25519_public_key[32]; -+ X25519_keypair(x25519_public_key, x25519_private_key_); -+ + bool Generate(CBB *out) override { + uint8_t x25519_public_key[32]; + X25519_keypair(x25519_public_key, x25519_private_key_); + +- uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; +- KYBER_generate_key(kyber_public_key, &kyber_private_key_); + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; + KYBER512_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); @@ -4891,16 +4452,19 @@ index 09a9ad380..d9d3b9032 100644 + + uint8_t kyber_public_key_bytes[KYBER512_PUBLIC_KEY_BYTES]; + KYBER512_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); -+ -+ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || + + if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || +- !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { + !CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { -+ return false; -+ } -+ -+ return true; -+ } -+ + return false; + } + + return true; + } + +- bool Encap(CBB *out_ciphertext, Array *out_secret, +- uint8_t *out_alert, Span peer_key) override { + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { Array secret; @@ -4957,7 +4521,7 @@ index 09a9ad380..d9d3b9032 100644 return false; } -@@ -258,30 +579,111 @@ class X25519Kyber768KeyShare : public SSLKeyShare { +@@ -258,30 +580,32 @@ class X25519Kyber768KeyShare : public SSLKeyShare { } bool Decap(Array *out_secret, uint8_t *out_alert, @@ -4994,89 +4558,10 @@ index 09a9ad380..d9d3b9032 100644 uint8_t x25519_private_key_[32]; - KYBER_private_key kyber_private_key_; + KYBER512_private_key kyber_private_key_; -+}; -+ -+class IPDWingKeyShare : public SSLKeyShare { -+ public: -+ IPDWingKeyShare() {} -+ -+ uint16_t GroupID() const override { return SSL_CURVE_IPDWING; } -+ -+ bool Generate(CBB *out) override { -+ uint8_t entropy[IPDWING_GENERATE_KEY_BYTES]; -+ IPDWING_public_key public_key; -+ RAND_bytes(entropy, sizeof(entropy)); -+ IPDWING_generate_key(&public_key, &private_key_, entropy); -+ -+ uint8_t public_key_bytes[IPDWING_PUBLIC_KEY_BYTES]; -+ IPDWING_marshal_public_key(public_key_bytes, &public_key); -+ -+ if(!CBB_add_bytes(out, public_key_bytes, sizeof(public_key_bytes))) { -+ return false; -+ } -+ -+ return true; -+ } -+ -+ bool Encap(CBB *out_public_key, Array *out_secret, -+ uint8_t *out_alert, Span peer_key) override { -+ Array secret; -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ if (!secret.Init(IPDWING_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ IPDWING_public_key peer_public_key; -+ if (peer_key.size() != IPDWING_PUBLIC_KEY_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ IPDWING_parse_public_key(&peer_public_key, peer_key.data()); -+ -+ uint8_t ciphertext[IPDWING_CIPHERTEXT_BYTES]; -+ uint8_t entropy[IPDWING_ENCAP_BYTES]; -+ RAND_bytes(entropy, sizeof(entropy)); -+ -+ IPDWING_encap(ciphertext, secret.data(), &peer_public_key, entropy); -+ if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { -+ return false; -+ } -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ bool Decap(Array *out_secret, uint8_t *out_alert, -+ Span peer_key) override { -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ -+ Array secret; -+ if (!secret.Init(IPDWING_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ if (peer_key.size() != IPDWING_CIPHERTEXT_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ IPDWING_decap(secret.data(), &private_key_, peer_key.data()); -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ private: -+ IPDWING_private_key private_key_; }; constexpr NamedGroup kNamedGroups[] = { -@@ -290,8 +692,15 @@ constexpr NamedGroup kNamedGroups[] = { +@@ -290,8 +614,14 @@ constexpr NamedGroup kNamedGroups[] = { {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, @@ -5088,12 +4573,11 @@ index 09a9ad380..d9d3b9032 100644 + {NID_X25519Kyber768Draft00Old, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD, + "X25519Kyber768Draft00Old", "Xyber768D00Old"}, + {NID_P256Kyber768Draft00, SSL_CURVE_P256_KYBER768_DRAFT00, -+ "P256Kyber768Draft00", "P256Kyber768D00"}, -+ {NID_IPDWing, SSL_CURVE_IPDWING, "IPDWing", ""} ++ "P256Kyber768Draft00", "P256Kyber768D00"} }; } // namespace -@@ -312,8 +721,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { +@@ -312,8 +642,16 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { return MakeUnique(NID_secp521r1, SSL_CURVE_SECP521R1); case SSL_CURVE_X25519: return MakeUnique(); @@ -5108,8 +4592,6 @@ index 09a9ad380..d9d3b9032 100644 + group_id)); + case SSL_CURVE_P256_KYBER768_DRAFT00: + return UniquePtr(New()); -+ case SSL_CURVE_IPDWING: -+ return UniquePtr(New()); default: return nullptr; } @@ -5127,10 +4609,10 @@ index 838761af5..9eb201d37 100644 static const uint16_t kSigAlgs[] = { SSL_SIGN_RSA_PKCS1_SHA256, diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc -index ef43a9e98..bb79509ea 100644 +index ef43a9e98..9756fd2a0 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc -@@ -409,7 +409,34 @@ static const CurveTest kCurveTests[] = { +@@ -409,7 +409,30 @@ static const CurveTest kCurveTests[] = { "P-256:X25519Kyber768Draft00", { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER768_DRAFT00 }, }, @@ -5144,10 +4626,6 @@ index ef43a9e98..bb79509ea 100644 + { SSL_CURVE_X25519_KYBER768_DRAFT00 }, + }, + { -+ "IPDWing", -+ { SSL_CURVE_IPDWING }, -+ }, -+ { + "Xyber768D00:Xyber768D00Old", + { SSL_CURVE_X25519_KYBER768_DRAFT00, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD }, + }, @@ -5354,5 +4832,5 @@ index 5b0205953..831875514 100644 !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1, selected) || -- -2.45.2 +2.41.0 diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 4d477a72..6b3ade0f 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -83,10 +83,6 @@ //! boxes. //! - `P256Kyber768Draft00`. Similar again to `X25519Kyber768Draft00`, but uses P256 as classical //! part. It uses a non-standard codepoint. Not recommended. -//! - `IPDWing`. A preliminary version of -//! [X-Wing](https://datatracker.ietf.org/doc/draft-connolly-cfrg-xwing-kem/02/). -//! Similar to `X25519Kyber768Draft00Old`, but uses a newer (but not yet final) version of Kyber -//! called ML-KEM-ipd. Not recommended. //! //! Presently all these key agreements are deployed by Cloudflare, but we do not guarantee continued //! support for them. diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 6a9361e1..277002b7 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -723,9 +723,6 @@ impl SslCurve { #[cfg(feature = "pq-experimental")] pub const P256_KYBER768_DRAFT00: SslCurve = SslCurve(ffi::SSL_CURVE_P256_KYBER768_DRAFT00 as _); - #[cfg(feature = "pq-experimental")] - pub const IPD_WING: SslCurve = SslCurve(ffi::SSL_CURVE_IPDWING); - /// Returns the curve name /// /// This corresponds to [`SSL_get_curve_name`] @@ -768,8 +765,6 @@ impl SslCurve { ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), #[cfg(feature = "pq-experimental")] ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), - #[cfg(feature = "pq-experimental")] - ffi::SSL_CURVE_IPDWING => Some(ffi::NID_IPDWing), _ => None, } } From 6d3639f17384fdac1f6b8d9c2386b45e97e8a0a1 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Tue, 17 Sep 2024 16:07:57 +0200 Subject: [PATCH 14/21] Add post-quantum key agreement X25519MLKEM768 This is the successor of X25519Kyber768Draft00. Spec: https://datatracker.ietf.org/doc/draft-kwiatkowski-tls-ecdhe-mlkem/02/ IANA has assigned the codepoint. https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 Upstream BoringSSL support landed in. https://github.com/google/boringssl/commit/7fb4d3da5082225c7180267e9daad291887ce982 The version of BoringSSL we patch does not include it, so we add it manually. Chrome and Firefox are planning to enable in October. This PR is based on the IPD-Wing patch reviewed here: https://github.com/cloudflare/boring/pull/243 There are two changes. First we simplify the patch a bit as we do not need IPD-Wing. Secondly, we perform the encapsulation key check, which was a last minute addition of NIST. We perform this check also for Kyber. --- boring-sys/patches/boring-pq.patch | 1209 ++++++++++++++++++---------- boring/src/lib.rs | 4 +- boring/src/ssl/mod.rs | 12 +- 3 files changed, 778 insertions(+), 447 deletions(-) diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index 2ffeee6c..e6601d91 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -1,59 +1,71 @@ -From 4cba2164726c8d2647e38548a266a70c4942d567 Mon Sep 17 00:00:00 2001 +From b98d803dbecc9d6848d8cbffa62b5c943fb75f70 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Fri, 22 Jul 2022 16:43:48 +0200 -Subject: [PATCH] Add temporary post-quantum key agreements +Subject: [PATCH] Add additional post-quantum key agreements -BoringSSL upstream support X25519Kyber768Draft00 already under -codepoint 0x6399, which is the recommended post-quantum key -agreement to use +BoringSSL upstream has supported the temporary post-quantum +key agreement X25519Kyber768Draft00 (0x6399) for a while. +At the time of writing X25519Kyber768Draft00 is widely deployed by browsers. + +Recent BoringSSL adds support for X25519MLKEM768 (0x11ec), +which will be the long term post-quantum key agreement of choice, +and many browsers are expected to switch to it before the end of 2024. This patch adds: -1. Supports for P256Kyber768Draft00 under 0xfe32, which we temporarily +1. Support for MLKEM768X25519 under the codepoint 0x11ec. The version + of BoringSSL we patch against did not support it yet. + +2. Supports for P256Kyber768Draft00 under 0xfe32, which we temporarily need for compliance reasons. (Note that this is not the codepoint allocated for that exchange in the IANA table.) It also enables it in FIPS mode. -2. Support for X25519Kyber768Draft00 under the old codepoint 0xfe31. +3. Support for X25519Kyber768Draft00 under the old codepoint 0xfe31. -3. Support for X25519Kyber512Draft00 under the codepoint 0xfe30. This +4. Support for X25519Kyber512Draft00 under the codepoint 0xfe30. This key agreement should only be used for testing: to see if the smaller keyshare makes a difference. The patch also replaces Google's implementation of Kyber, by the portable reference implementation, so as to support Kyber512. -Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 +Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 RTG-3239 --- BUILD.generated.bzl | 5 +- BUILD.generated_tests.bzl | 4 - CMakeLists.txt | 4 +- + crypto_test_data.cc | 4 - sources.json | 9 +- src/crypto/CMakeLists.txt | 5 +- src/crypto/kyber/internal.h | 91 - src/crypto/kyber/keccak.c | 204 -- - src/crypto/kyber/kyber.c | 2865 ++++++++++++++++++++------- + src/crypto/kyber/keccak_tests.txt | 3071 ----------------------------- + src/crypto/kyber/kyber.c | 3011 +++++++++++++++++++++------- src/crypto/kyber/kyber512.c | 5 + src/crypto/kyber/kyber768.c | 4 + src/crypto/kyber/kyber_test.cc | 229 --- - src/crypto/obj/obj_dat.h | 14 +- - src/crypto/obj/obj_mac.num | 3 + - src/crypto/obj/objects.txt | 5 +- - src/include/openssl/kyber.h | 199 +- - src/include/openssl/nid.h | 9 + - src/include/openssl/ssl.h | 3 + + src/crypto/kyber/kyber_tests.txt | 905 --------- + src/crypto/obj/obj_dat.h | 17 +- + src/crypto/obj/obj_mac.num | 4 + + src/crypto/obj/objects.txt | 6 +- + src/include/openssl/kyber.h | 203 +- + src/include/openssl/nid.h | 12 + + src/include/openssl/ssl.h | 4 + src/sources.cmake | 2 - - src/ssl/extensions.cc | 3 + - src/ssl/ssl_key_share.cc | 412 +++- + src/ssl/extensions.cc | 4 + + src/ssl/ssl_key_share.cc | 525 ++++- src/ssl/ssl_lib.cc | 2 +- - src/ssl/ssl_test.cc | 25 +- + src/ssl/ssl_test.cc | 29 +- src/tool/speed.cc | 162 +- - 26 files changed, 2797 insertions(+), 5447 deletions(-) + 26 files changed, 3088 insertions(+), 5433 deletions(-) delete mode 100644 src/crypto/kyber/internal.h delete mode 100644 src/crypto/kyber/keccak.c + delete mode 100644 src/crypto/kyber/keccak_tests.txt create mode 100644 src/crypto/kyber/kyber512.c create mode 100644 src/crypto/kyber/kyber768.c delete mode 100644 src/crypto/kyber/kyber_test.cc + delete mode 100644 src/crypto/kyber/kyber_tests.txt diff --git a/BUILD.generated.bzl b/BUILD.generated.bzl index 738e1055f..9466757a2 100644 @@ -122,6 +134,28 @@ index faed2befa..931c0e3a8 100644 src/crypto/lhash/lhash.c src/crypto/mem.c src/crypto/obj/obj.c +diff --git a/crypto_test_data.cc b/crypto_test_data.cc +index 2268533f8..19b344af1 100644 +--- a/crypto_test_data.cc ++++ b/crypto_test_data.cc +@@ -74,7 +74,6 @@ + * crypto/fipsmodule/rand/ctrdrbg_vectors.txt \ + * crypto/hmac_extra/hmac_tests.txt \ + * crypto/hpke/hpke_test_vectors.txt \ +- * crypto/kyber/keccak_tests.txt \ + * crypto/kyber/kyber_tests.txt \ + * crypto/pkcs8/test/empty_password.p12 \ + * crypto/pkcs8/test/no_encryption.p12 \ +@@ -5269,9 +5268,6 @@ std::string GetTestData(const char *path) { + if (strcmp(path, "crypto/hpke/hpke_test_vectors.txt") == 0) { + return AssembleString(kData59, kLen59); + } +- if (strcmp(path, "crypto/kyber/keccak_tests.txt") == 0) { +- return AssembleString(kData60, kLen60); +- } + if (strcmp(path, "crypto/kyber/kyber_tests.txt") == 0) { + return AssembleString(kData61, kLen61); + } diff --git a/sources.json b/sources.json index 4c0048e1d..f6ea5c40f 100644 --- a/sources.json @@ -492,10 +526,10 @@ index f1c012d11..000000000 - } -} diff --git a/src/crypto/kyber/kyber.c b/src/crypto/kyber/kyber.c -index 776c085f9..346d4daec 100644 +index 776c085f9..ccb5b3d9b 100644 --- a/src/crypto/kyber/kyber.c +++ b/src/crypto/kyber/kyber.c -@@ -1,833 +1,2252 @@ +@@ -1,833 +1,2426 @@ -/* Copyright (c) 2023, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any @@ -520,6 +554,8 @@ index 776c085f9..346d4daec 100644 +// - Removed 90s version. +// - Seeds are passed as paramters. +// - Changed the API to be more BoringSSL-like ++// - Mitigated timing sidechannels (Kyberslash 1 and 2). ++// (Note that these do not affect ephemeral usage as in TLS.) +// +// TODO +// @@ -534,21 +570,24 @@ index 776c085f9..346d4daec 100644 +// implementation or https://github.com/cloudflare/circl/tree/main/pke/kyber +// +// - Option to keep A stored in private key. -+ + +-#include +#ifndef KYBER_K +#error "Don't compile this file direcly" +#endif - #include -+#include - -#include -#include -- ++#include ++#include + -#include -#include -- --#include "../internal.h" ++#include ++#include ++#include + + #include "../internal.h" -#include "./internal.h" - - @@ -612,9 +651,6 @@ index 776c085f9..346d4daec 100644 - 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, - 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154, -}; -+#include -+#include -+#include -// kInverseNTTRoots = [pow(17, -bitreverse(i), p) for i in range(128)] -static const uint16_t kInverseNTTRoots[128] = { @@ -844,7 +880,7 @@ index 776c085f9..346d4daec 100644 + uint8_t sk[KYBER_INDCPA_SECRETKEYBYTES], + const uint8_t seed[KYBER_SYMBYTES]); + -+static void indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], ++static int indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], + const uint8_t m[KYBER_INDCPA_MSGBYTES], + const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], + const uint8_t coins[KYBER_SYMBYTES]); @@ -873,6 +909,9 @@ index 776c085f9..346d4daec 100644 +static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state); +static void shake256_absorb_once(keccak_state *state, const uint8_t *in, size_t inlen); +static void shake256_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state); ++static void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen); ++static void shake256_finalize(keccak_state *state); ++static void shake256_init(keccak_state *state); + +static void shake256(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen); +static void sha3_256(uint8_t h[32], const uint8_t *in, size_t inlen); @@ -1064,13 +1103,10 @@ index 776c085f9..346d4daec 100644 + a = (d >> (4*j+0)) & 0x3; + b = (d >> (4*j+2)) & 0x3; + r->coeffs[8*i+j] = a - b; - } - } - } - --static void vector_ntt(vector *a) { -- for (int i = 0; i < RANK; i++) { -- scalar_ntt(&a->v[i]); ++ } ++ } ++} ++ +/************************************************* +* Name: cbd3 +* @@ -1099,7 +1135,7 @@ index 776c085f9..346d4daec 100644 + a = (d >> (6*j+0)) & 0x7; + b = (d >> (6*j+3)) & 0x7; + r->coeffs[4*i+j] = a - b; -+ } + } } } +#endif @@ -1115,25 +1151,9 @@ index 776c085f9..346d4daec 100644 +#endif +} --// In place inverse number theoretic transform of a given scalar, with pairs of --// entries of s->v being interpreted as elements of GF(3329^2). Just as with the --// number theoretic transform, this leaves off the first step of the normal iFFT --// to account for the fact that 3329 does not have a 512th root of unity, using --// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. --static void scalar_inverse_ntt(scalar *s) { -- int step = DEGREE / 2; -- // `int` is used here because using `size_t` throughout caused a ~5% slowdown -- // with Clang 14 on Aarch64. -- for (int offset = 2; offset < DEGREE; offset <<= 1) { -- step >>= 1; -- int k = 0; -- for (int i = 0; i < step; i++) { -- uint32_t step_root = kInverseNTTRoots[i + step]; -- for (int j = k; j < k + offset; j++) { -- uint16_t odd = s->c[j + offset]; -- uint16_t even = s->c[j]; -- s->c[j] = reduce_once(odd + even); -- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); +-static void vector_ntt(vector *a) { +- for (int i = 0; i < RANK; i++) { +- scalar_ntt(&a->v[i]); +static void poly_cbd_eta2(poly *r, const uint8_t buf[KYBER_ETA2*KYBER_N/4]) +{ +#if KYBER_ETA2 == 2 @@ -1176,8 +1196,8 @@ index 776c085f9..346d4daec 100644 + zetas[i] -= KYBER_Q; + if(zetas[i] < -KYBER_Q/2) + zetas[i] += KYBER_Q; -+ } -+} + } + } +*/ + +static const int16_t zetas[128] = { @@ -1212,7 +1232,26 @@ index 776c085f9..346d4daec 100644 +static int16_t fqmul(int16_t a, int16_t b) { + return montgomery_reduce((int32_t)a*b); +} -+ + +-// In place inverse number theoretic transform of a given scalar, with pairs of +-// entries of s->v being interpreted as elements of GF(3329^2). Just as with the +-// number theoretic transform, this leaves off the first step of the normal iFFT +-// to account for the fact that 3329 does not have a 512th root of unity, using +-// the precomputed 128 roots of unity stored in |kInverseNTTRoots|. +-static void scalar_inverse_ntt(scalar *s) { +- int step = DEGREE / 2; +- // `int` is used here because using `size_t` throughout caused a ~5% slowdown +- // with Clang 14 on Aarch64. +- for (int offset = 2; offset < DEGREE; offset <<= 1) { +- step >>= 1; +- int k = 0; +- for (int i = 0; i < step; i++) { +- uint32_t step_root = kInverseNTTRoots[i + step]; +- for (int j = k; j < k + offset; j++) { +- uint16_t odd = s->c[j + offset]; +- uint16_t even = s->c[j]; +- s->c[j] = reduce_once(odd + even); +- s->c[j + offset] = reduce(step_root * (even - odd + kPrime)); +/************************************************* +* Name: ntt +* @@ -1316,6 +1355,7 @@ index 776c085f9..346d4daec 100644 +{ + unsigned int i,j; + int16_t u; ++ uint32_t d0; + uint8_t t[8]; + +#if (KYBER_POLYCOMPRESSEDBYTES == 128) @@ -1324,7 +1364,11 @@ index 776c085f9..346d4daec 100644 + // map to positive standard representatives + u = a->coeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ t[j] = ((((uint16_t)u << 4) + KYBER_Q/2)/KYBER_Q) & 15; ++ d0 = u << 4; ++ d0 += 1665; ++ d0 *= 80635; ++ d0 >>= 28; ++ t[j] = d0 & 0xf; + } + + r[0] = t[0] | (t[1] << 4); @@ -1339,7 +1383,11 @@ index 776c085f9..346d4daec 100644 + // map to positive standard representatives + u = a->coeffs[8*i+j]; + u += (u >> 15) & KYBER_Q; -+ t[j] = ((((uint32_t)u << 5) + KYBER_Q/2)/KYBER_Q) & 31; ++ d0 = u << 5; ++ d0 += 1664; ++ d0 *= 40318; ++ d0 >>= 27; ++ t[j] = d0 & 0x1f; + } + + r[0] = (t[0] >> 0) | (t[1] << 5); @@ -1490,7 +1538,7 @@ index 776c085f9..346d4daec 100644 + + for(i=0;i> j)&1); ++ mask = -(int16_t)value_barrier_u32((msg[i] >> j)&1); + r->coeffs[8*i+j] = mask & ((KYBER_Q+1)/2); } } @@ -1515,14 +1563,17 @@ index 776c085f9..346d4daec 100644 +static void poly_tomsg(uint8_t msg[KYBER_INDCPA_MSGBYTES], const poly *a) +{ + unsigned int i,j; -+ uint16_t t; ++ uint32_t t; + + for(i=0;icoeffs[8*i+j]; -+ t += ((int16_t)t >> 15) & KYBER_Q; -+ t = (((t << 1) + KYBER_Q/2)/KYBER_Q) & 1; ++ t <<= 1; ++ t += 1665; ++ t *= 80635; ++ t >>= 28; ++ t &= 1; + msg[i] |= t << j; } } @@ -1801,6 +1852,7 @@ index 776c085f9..346d4daec 100644 +static void polyvec_compress(uint8_t r[KYBER_POLYVECCOMPRESSEDBYTES], const polyvec *a) +{ + unsigned int i,j,k; ++ uint64_t d0; + +#if (KYBER_POLYVECCOMPRESSEDBYTES == (KYBER_K * 352)) + uint16_t t[8]; @@ -1809,7 +1861,12 @@ index 776c085f9..346d4daec 100644 + for(k=0;k<8;k++) { + t[k] = a->vec[i].coeffs[8*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ t[k] = ((((uint32_t)t[k] << 11) + KYBER_Q/2)/KYBER_Q) & 0x7ff; ++ d0 = t[k]; ++ d0 <<= 11; ++ d0 += 1664; ++ d0 *= 645084; ++ d0 >>= 31; ++ t[k] = d0 & 0x7ff; } - element_bits_done += chunk_bits; @@ -1835,7 +1892,12 @@ index 776c085f9..346d4daec 100644 + for(k=0;k<4;k++) { + t[k] = a->vec[i].coeffs[4*j+k]; + t[k] += ((int16_t)t[k] >> 15) & KYBER_Q; -+ t[k] = ((((uint32_t)t[k] << 10) + KYBER_Q/2)/ KYBER_Q) & 0x3ff; ++ d0 = t[k]; ++ d0 <<= 10; ++ d0 += 1665; ++ d0 *= 1290167; ++ d0 >>= 32; ++ t[k] = d0 & 0x3ff; + } - if (out_byte_bits > 0) { @@ -1910,8 +1972,15 @@ index 776c085f9..346d4daec 100644 +#else +#error "KYBER_POLYVECCOMPRESSEDBYTES needs to be in {320*KYBER_K, 352*KYBER_K}" +#endif -+} -+ + } + +-// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 +-// (DEGREE) is divisible by 8, the individual vector entries will always fill a +-// whole number of bytes, so we do not need to worry about bit packing here. +-static void vector_encode(uint8_t *out, const vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +- } +/************************************************* +* Name: polyvec_tobytes +* @@ -1926,8 +1995,13 @@ index 776c085f9..346d4daec 100644 + unsigned int i; + for(i=0;ivec[i]); -+} -+ + } + +-// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in +-// |out|. It returns one on success and zero if any parsed value is >= +-// |kPrime|. +-static int scalar_decode(scalar *out, const uint8_t *in, int bits) { +- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); +/************************************************* +* Name: polyvec_frombytes +* @@ -1943,14 +2017,10 @@ index 776c085f9..346d4daec 100644 + unsigned int i; + for(i=0;ivec[i], a+i*KYBER_POLYBYTES); - } ++} --// Encodes an entire vector into 32*|RANK|*|bits| bytes. Note that since 256 --// (DEGREE) is divisible by 8, the individual vector entries will always fill a --// whole number of bytes, so we do not need to worry about bit packing here. --static void vector_encode(uint8_t *out, const vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_encode(out + i * bits * DEGREE / 8, &a->v[i], bits); +- uint8_t in_byte = 0; +- int in_byte_bits_left = 0; +/************************************************* +* Name: polyvec_ntt +* @@ -1964,7 +2034,10 @@ index 776c085f9..346d4daec 100644 + for(i=0;ivec[i]); +} -+ + +- for (int i = 0; i < DEGREE; i++) { +- uint16_t element = 0; +- int element_bits_done = 0; +/************************************************* +* Name: polyvec_invntt_tomont +* @@ -1979,7 +2052,13 @@ index 776c085f9..346d4daec 100644 + for(i=0;ivec[i]); +} -+ + +- while (element_bits_done < bits) { +- if (in_byte_bits_left == 0) { +- in_byte = *in; +- in++; +- in_byte_bits_left = 8; +- } +/************************************************* +* Name: polyvec_basemul_acc_montgomery +* @@ -1999,16 +2078,18 @@ index 776c085f9..346d4daec 100644 + for(i=1;ivec[i], &b->vec[i]); + poly_add(r, r, &t); - } -+ -+ poly_reduce(r); - } ++ } --// scalar_decode parses |DEGREE * bits| bits from |in| into |DEGREE| values in --// |out|. It returns one on success and zero if any parsed value is >= --// |kPrime|. --static int scalar_decode(scalar *out, const uint8_t *in, int bits) { -- assert(bits <= (int)sizeof(*out->c) * 8 && bits != 1); +- int chunk_bits = bits - element_bits_done; +- if (chunk_bits > in_byte_bits_left) { +- chunk_bits = in_byte_bits_left; +- } ++ poly_reduce(r); ++} + +- element |= (in_byte & kMasks[chunk_bits - 1]) << element_bits_done; +- in_byte_bits_left -= chunk_bits; +- in_byte >>= chunk_bits; +/************************************************* +* Name: polyvec_reduce +* @@ -2025,8 +2106,8 @@ index 776c085f9..346d4daec 100644 + poly_reduce(&r->vec[i]); +} -- uint8_t in_byte = 0; -- int in_byte_bits_left = 0; +- element_bits_done += chunk_bits; +- } +/************************************************* +* Name: polyvec_add +* @@ -2043,19 +2124,15 @@ index 776c085f9..346d4daec 100644 + poly_add(&r->vec[i], &a->vec[i], &b->vec[i]); +} -- for (int i = 0; i < DEGREE; i++) { -- uint16_t element = 0; -- int element_bits_done = 0; +- if (element >= kPrime) { +- return 0; +- } +- out->c[i] = element; +- } +// +// indcpa.c +// - -- while (element_bits_done < bits) { -- if (in_byte_bits_left == 0) { -- in_byte = *in; -- in++; -- in_byte_bits_left = 8; -- } ++ +/************************************************* +* Name: pack_pk +* @@ -2076,11 +2153,7 @@ index 776c085f9..346d4daec 100644 + for(i=0;i in_byte_bits_left) { -- chunk_bits = in_byte_bits_left; -- } ++ +/************************************************* +* Name: unpack_pk +* @@ -2091,19 +2164,34 @@ index 776c085f9..346d4daec 100644 +* - uint8_t *seed: pointer to output seed to generate matrix A +* - const uint8_t *packedpk: pointer to input serialized public key +**************************************************/ -+static void unpack_pk(polyvec *pk, ++static int unpack_pk(polyvec *pk, + uint8_t seed[KYBER_SYMBYTES], + const uint8_t packedpk[KYBER_INDCPA_PUBLICKEYBYTES]) +{ + size_t i; + polyvec_frombytes(pk, packedpk); ++ ++ // FIPS 203 encapsulation key check. We'll perform it even for Kyber. ++ uint8_t repacked[KYBER_POLYVECBYTES]; ++ polyvec_tobytes(repacked, pk); ++ ++ if(verify(repacked, packedpk, KYBER_POLYVECBYTES) != 0) ++ return 0; + + for(i=0;i>= chunk_bits; +-// scalar_decode_1 is |scalar_decode| specialised for |bits| == 1. +-static void scalar_decode_1(scalar *out, const uint8_t in[32]) { +- for (int i = 0; i < DEGREE; i += 8) { +- uint8_t in_byte = *in; +- in++; +- for (int j = 0; j < 8; j++) { +- out->c[i + j] = in_byte & 1; +- in_byte >>= 1; +- } +/************************************************* +* Name: pack_sk +* @@ -2116,9 +2204,7 @@ index 776c085f9..346d4daec 100644 +{ + polyvec_tobytes(r, sk); +} - -- element_bits_done += chunk_bits; -- } ++ +/************************************************* +* Name: unpack_sk +* @@ -2131,12 +2217,7 @@ index 776c085f9..346d4daec 100644 +{ + polyvec_frombytes(sk, packedsk); +} - -- if (element >= kPrime) { -- return 0; -- } -- out->c[i] = element; -- } ++ +/************************************************* +* Name: pack_ciphertext +* @@ -2153,8 +2234,7 @@ index 776c085f9..346d4daec 100644 + polyvec_compress(r, b); + poly_compress(r+KYBER_POLYVECCOMPRESSEDBYTES, v); +} - -- return 1; ++ +/************************************************* +* Name: unpack_ciphertext +* @@ -2169,17 +2249,8 @@ index 776c085f9..346d4daec 100644 +{ + polyvec_decompress(b, c); + poly_decompress(v, c+KYBER_POLYVECCOMPRESSEDBYTES); - } - --// scalar_decode_1 is |scalar_decode| specialised for |bits| == 1. --static void scalar_decode_1(scalar *out, const uint8_t in[32]) { -- for (int i = 0; i < DEGREE; i += 8) { -- uint8_t in_byte = *in; -- in++; -- for (int j = 0; j < 8; j++) { -- out->c[i + j] = in_byte & 1; -- in_byte >>= 1; -- } ++} ++ +/************************************************* +* Name: rej_uniform +* @@ -2268,8 +2339,8 @@ index 776c085f9..346d4daec 100644 } } - return 1; --} -- + } + -// Compresses (lossily) an input |x| mod 3329 into |bits| many bits by grouping -// numbers close to each other together. The formula used is -// round(2^|bits|/kPrime*x) mod 2^|bits|. @@ -2311,12 +2382,6 @@ index 776c085f9..346d4daec 100644 -static void scalar_compress(scalar *s, int bits) { - for (int i = 0; i < DEGREE; i++) { - s->c[i] = compress(s->c[i], bits); -- } - } - --static void scalar_decompress(scalar *s, int bits) { -- for (int i = 0; i < DEGREE; i++) { -- s->c[i] = decompress(s->c[i], bits); +/************************************************* +* Name: indcpa_keypair +* @@ -2365,9 +2430,9 @@ index 776c085f9..346d4daec 100644 + pack_pk(pk, &pkpv, publicseed); } --static void vector_compress(vector *a, int bits) { -- for (int i = 0; i < RANK; i++) { -- scalar_compress(&a->v[i], bits); +-static void scalar_decompress(scalar *s, int bits) { +- for (int i = 0; i < DEGREE; i++) { +- s->c[i] = decompress(s->c[i], bits); - } +/************************************************* +* Name: indcpa_enc @@ -2385,7 +2450,7 @@ index 776c085f9..346d4daec 100644 +* (of length KYBER_SYMBYTES) to deterministically +* generate all randomness +**************************************************/ -+static void indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], ++static int indcpa_enc(uint8_t c[KYBER_INDCPA_BYTES], + const uint8_t m[KYBER_INDCPA_MSGBYTES], + const uint8_t pk[KYBER_INDCPA_PUBLICKEYBYTES], + const uint8_t coins[KYBER_SYMBYTES]) @@ -2396,7 +2461,9 @@ index 776c085f9..346d4daec 100644 + polyvec sp, pkpv, ep, at[KYBER_K], b; + poly v, k, epp; + -+ unpack_pk(&pkpv, seed, pk); ++ if (!unpack_pk(&pkpv, seed, pk)) ++ return 0; ++ + poly_frommsg(&k, m); + gen_at(at, seed); + @@ -2424,11 +2491,12 @@ index 776c085f9..346d4daec 100644 + poly_reduce(&v); + + pack_ciphertext(c, &b, &v); ++ return 1; } --static void vector_decompress(vector *a, int bits) { +-static void vector_compress(vector *a, int bits) { - for (int i = 0; i < RANK; i++) { -- scalar_decompress(&a->v[i], bits); +- scalar_compress(&a->v[i], bits); - } +/************************************************* +* Name: indcpa_dec @@ -2463,12 +2531,10 @@ index 776c085f9..346d4daec 100644 + poly_tomsg(m, &mp); } --struct public_key { -- vector t; -- uint8_t rho[32]; -- uint8_t public_key_hash[32]; -- matrix m; --}; +-static void vector_decompress(vector *a, int bits) { +- for (int i = 0; i < RANK; i++) { +- scalar_decompress(&a->v[i], bits); +- } +// +// fips202.c +// @@ -2498,15 +2564,13 @@ index 776c085f9..346d4daec 100644 + r |= (uint64_t)x[i] << 8*i; + + return r; -+} + } --static struct public_key *public_key_from_external( -- const struct KYBER_public_key *external) { -- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), -- "Kyber public key is too small"); -- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), -- "Kyber public key align incorrect"); -- return (struct public_key *)external; +-struct public_key { +- vector t; +- uint8_t rho[32]; +- uint8_t public_key_hash[32]; +- matrix m; +/************************************************* +* Name: store64 +* @@ -2520,12 +2584,8 @@ index 776c085f9..346d4daec 100644 + + for(i=0;i<8;i++) + x[i] = u >> 8*i; - } - --struct private_key { -- struct public_key pub; -- vector s; -- uint8_t fo_failure_secret[32]; ++} ++ +/* Keccak round constants */ +static const uint64_t KeccakF_RoundConstants[NROUNDS] = { + (uint64_t)0x0000000000000001ULL, @@ -2554,34 +2614,13 @@ index 776c085f9..346d4daec 100644 + (uint64_t)0x8000000080008008ULL }; --static struct private_key *private_key_from_external( -- const struct KYBER_private_key *external) { -- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), -- "Kyber private key too small"); -- static_assert( -- alignof(struct KYBER_private_key) >= alignof(struct private_key), -- "Kyber private key align incorrect"); -- return (struct private_key *)external; --} -- --// Calls |KYBER_generate_key_external_entropy| with random bytes from --// |RAND_bytes|. --void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], -- struct KYBER_private_key *out_private_key) { -- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; -- RAND_bytes(entropy, sizeof(entropy)); -- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, -- entropy); --} -- --static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { -- uint8_t *vector_output; -- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { -- return 0; -- } -- vector_encode(vector_output, &pub->t, kLog2Prime); -- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { -- return 0; +-static struct public_key *public_key_from_external( +- const struct KYBER_public_key *external) { +- static_assert(sizeof(struct KYBER_public_key) >= sizeof(struct public_key), +- "Kyber public key is too small"); +- static_assert(alignof(struct KYBER_public_key) >= alignof(struct public_key), +- "Kyber public key align incorrect"); +- return (struct public_key *)external; +/************************************************* +* Name: KeccakF1600_StatePermute +* @@ -2851,9 +2890,38 @@ index 776c085f9..346d4daec 100644 + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; -+} -+ -+ + } + +-struct private_key { +- struct public_key pub; +- vector s; +- uint8_t fo_failure_secret[32]; +-}; + +-static struct private_key *private_key_from_external( +- const struct KYBER_private_key *external) { +- static_assert(sizeof(struct KYBER_private_key) >= sizeof(struct private_key), +- "Kyber private key too small"); +- static_assert( +- alignof(struct KYBER_private_key) >= alignof(struct private_key), +- "Kyber private key align incorrect"); +- return (struct private_key *)external; +-} +- +-// Calls |KYBER_generate_key_external_entropy| with random bytes from +-// |RAND_bytes|. +-void KYBER_generate_key(uint8_t out_encoded_public_key[KYBER_PUBLIC_KEY_BYTES], +- struct KYBER_private_key *out_private_key) { +- uint8_t entropy[KYBER_GENERATE_KEY_ENTROPY]; +- RAND_bytes(entropy, sizeof(entropy)); +- KYBER_generate_key_external_entropy(out_encoded_public_key, out_private_key, +- entropy); +-} +- +-static int kyber_marshal_public_key(CBB *out, const struct public_key *pub) { +- uint8_t *vector_output; +- if (!CBB_add_space(out, &vector_output, kEncodedVectorSize)) { +- return 0; +/************************************************* +* Name: keccak_squeeze +* @@ -2887,9 +2955,65 @@ index 776c085f9..346d4daec 100644 + outlen -= i-pos; + pos = i; } +- vector_encode(vector_output, &pub->t, kLog2Prime); +- if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { +- return 0; ++ ++ return pos; ++} ++ ++/************************************************* ++* Name: keccak_absorb ++* ++* Description: Absorb step of Keccak; incremental. ++* ++* Arguments: - uint64_t *s: pointer to Keccak state ++* - unsigned int pos: position in current block to be absorbed ++* - unsigned int r: rate in bytes (e.g., 168 for SHAKE128) ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++* ++* Returns new position pos in current block ++**************************************************/ ++static unsigned int keccak_absorb(uint64_t s[25], ++ unsigned int pos, ++ unsigned int r, ++ const uint8_t *in, ++ size_t inlen) ++{ ++ unsigned int i; ++ ++ while(pos+inlen >= r) { ++ for(i=pos;ipub)) { - abort(); + -+ return pos; -+} -+ -+ +/************************************************* +* Name: keccak_absorb_once +* @@ -3168,18 +3288,8 @@ index 776c085f9..346d4daec 100644 +static void shake128_squeezeblocks(uint8_t *out, size_t nblocks, keccak_state *state) +{ + keccak_squeezeblocks(out, nblocks, state->s, SHAKE128_RATE); - } - --int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { -- struct public_key *pub = public_key_from_external(public_key); -- CBS orig_in = *in; -- if (!kyber_parse_public_key_no_hash(pub, in) || // -- CBS_len(in) != 0) { -- return 0; -- } -- BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), -- CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); -- return 1; ++} ++ +/************************************************* +* Name: shake256_squeeze +* @@ -3193,40 +3303,8 @@ index 776c085f9..346d4daec 100644 +static void shake256_squeeze(uint8_t *out, size_t outlen, keccak_state *state) +{ + state->pos = keccak_squeeze(out, outlen, state->s, state->pos, SHAKE256_RATE); - } - --int KYBER_marshal_private_key(CBB *out, -- const struct KYBER_private_key *private_key) { -- const struct private_key *const priv = private_key_from_external(private_key); -- uint8_t *s_output; -- if (!CBB_add_space(out, &s_output, kEncodedVectorSize)) { -- return 0; -- } -- vector_encode(s_output, &priv->s, kLog2Prime); -- if (!kyber_marshal_public_key(out, &priv->pub) || -- !CBB_add_bytes(out, priv->pub.public_key_hash, -- sizeof(priv->pub.public_key_hash)) || -- !CBB_add_bytes(out, priv->fo_failure_secret, -- sizeof(priv->fo_failure_secret))) { -- return 0; -- } -- return 1; --} -- --int KYBER_parse_private_key(struct KYBER_private_key *out_private_key, -- CBS *in) { -- struct private_key *const priv = private_key_from_external(out_private_key); -- -- CBS s_bytes; -- if (!CBS_get_bytes(in, &s_bytes, kEncodedVectorSize) || -- !vector_decode(&priv->s, CBS_data(&s_bytes), kLog2Prime) || -- !kyber_parse_public_key_no_hash(&priv->pub, in) || -- !CBS_copy_bytes(in, priv->pub.public_key_hash, -- sizeof(priv->pub.public_key_hash)) || -- !CBS_copy_bytes(in, priv->fo_failure_secret, -- sizeof(priv->fo_failure_secret)) || -- CBS_len(in) != 0) { -- return 0; ++} ++ +/************************************************* +* Name: shake256_absorb_once +* @@ -3260,6 +3338,61 @@ index 776c085f9..346d4daec 100644 +} + +/************************************************* ++* Name: shake256_absorb ++* ++* Description: Absorb step of the SHAKE256 XOF; incremental. ++* ++* Arguments: - keccak_state *state: pointer to (initialized) output Keccak state ++* - const uint8_t *in: pointer to input to be absorbed into s ++* - size_t inlen: length of input in bytes ++**************************************************/ ++static void shake256_absorb(keccak_state *state, const uint8_t *in, size_t inlen) ++{ ++ state->pos = keccak_absorb(state->s, state->pos, SHAKE256_RATE, in, inlen); ++} ++ ++/************************************************* ++* Name: shake256_finalize ++* ++* Description: Finalize absorb step of the SHAKE256 XOF. ++* ++* Arguments: - keccak_state *state: pointer to Keccak state ++**************************************************/ ++static void shake256_finalize(keccak_state *state) ++{ ++ keccak_finalize(state->s, state->pos, SHAKE256_RATE, 0x1F); ++ state->pos = SHAKE256_RATE; ++} ++ ++/************************************************* ++* Name: keccak_init ++* ++* Description: Initializes the Keccak state. ++* ++* Arguments: - uint64_t *s: pointer to Keccak state ++**************************************************/ ++static void keccak_init(uint64_t s[25]) ++{ ++ unsigned int i; ++ for(i=0;i<25;i++) ++ s[i] = 0; ++} ++ ++/************************************************* ++* Name: shake256_init ++* ++* Description: Initilizes Keccak state for use as SHAKE256 XOF ++* ++* Arguments: - keccak_state *state: pointer to (uninitialized) Keccak state ++**************************************************/ ++static void shake256_init(keccak_state *state) ++{ ++ keccak_init(state->s); ++ state->pos = 0; ++} ++ ++ ++/************************************************* +* Name: shake256 +* +* Description: SHAKE256 XOF with non-incremental API @@ -3348,8 +3481,13 @@ index 776c085f9..346d4daec 100644 + extseed[KYBER_SYMBYTES+1] = y; + + shake128_absorb_once(state, extseed, sizeof(extseed)); -+} -+ + } + +-int KYBER_parse_public_key(struct KYBER_public_key *public_key, CBS *in) { +- struct public_key *pub = public_key_from_external(public_key); +- CBS orig_in = *in; +- if (!kyber_parse_public_key_no_hash(pub, in) || // +- CBS_len(in) != 0) { +/************************************************* +* Name: kyber_shake256_prf +* @@ -3392,10 +3530,10 @@ index 776c085f9..346d4daec 100644 +} + +// Modified crypto_kem_enc to BoringSSL style API -+void encap(uint8_t out_ciphertext[KYBER_CIPHERTEXTBYTES], ++int encap(uint8_t out_ciphertext[KYBER_CIPHERTEXTBYTES], + uint8_t ss[KYBER_KEY_BYTES], + const struct public_key *in_pub, -+ const uint8_t seed[KYBER_ENCAP_BYTES]) ++ const uint8_t seed[KYBER_ENCAP_BYTES], int mlkem) +{ + const uint8_t *pk = &in_pub->opaque[0]; + uint8_t *ct = out_ciphertext; @@ -3405,6 +3543,7 @@ index 776c085f9..346d4daec 100644 + uint8_t kr[2*KYBER_SYMBYTES]; + + memcpy(buf, seed, KYBER_SYMBYTES); ++ + /* Don't release system RNG output */ + hash_h(buf, buf, KYBER_SYMBYTES); + @@ -3413,18 +3552,32 @@ index 776c085f9..346d4daec 100644 + hash_g(kr, buf, 2*KYBER_SYMBYTES); + + /* coins are in kr+KYBER_SYMBYTES */ -+ indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES); -+ -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); -+} ++ if(!indcpa_enc(ct, buf, pk, kr+KYBER_SYMBYTES)) + return 0; + ++ if (mlkem == 1) { ++ memcpy(ss, kr, KYBER_SYMBYTES); ++ } else { ++ /* overwrite coins in kr with H(c) */ ++ hash_h(kr+KYBER_SYMBYTES, ct, KYBER_CIPHERTEXTBYTES); ++ /* hash concatenation of pre-k and H(c) to k */ ++ kdf(ss, kr, 2*KYBER_SYMBYTES); + } +- BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), +- CBS_data(&orig_in), CBS_len(&orig_in), boringssl_sha3_256); + return 1; + } + +-int KYBER_marshal_private_key(CBB *out, +- const struct KYBER_private_key *private_key) { +- const struct private_key *const priv = private_key_from_external(private_key); +- uint8_t *s_output; +- if (!CBB_add_space(out, &s_output, kEncodedVectorSize)) { +- return 0; +// Modified crypto_kem_decap to BoringSSL style API +void decap(uint8_t out_shared_key[KYBER_SSBYTES], + const struct private_key *in_priv, -+ const uint8_t *ct, size_t ciphertext_len) ++ const uint8_t *ct, size_t ciphertext_len, int mlkem) +{ + uint8_t *ss = out_shared_key; + const uint8_t *sk = &in_priv->opaque[0]; @@ -3450,23 +3603,64 @@ index 776c085f9..346d4daec 100644 + + fail = verify(ct, cmp, KYBER_CIPHERTEXTBYTES); } +- vector_encode(s_output, &priv->s, kLog2Prime); +- if (!kyber_marshal_public_key(out, &priv->pub) || +- !CBB_add_bytes(out, priv->pub.public_key_hash, +- sizeof(priv->pub.public_key_hash)) || +- !CBB_add_bytes(out, priv->fo_failure_secret, +- sizeof(priv->fo_failure_secret))) { +- return 0; ++ ++ if (mlkem == 1) { ++ /* Compute shared secret in case of rejection: ss2 = PRF(z || c). */ ++ uint8_t ss2[KYBER_SYMBYTES]; ++ keccak_state ks; ++ shake256_init(&ks); ++ shake256_absorb( ++ &ks, ++ sk + KYBER_SECRETKEYBYTES - KYBER_SYMBYTES, ++ KYBER_SYMBYTES ++ ); ++ shake256_absorb(&ks, ct, ciphertext_len); ++ shake256_finalize(&ks); ++ shake256_squeeze(ss2, KYBER_SYMBYTES, &ks); ++ ++ /* Set ss2 to the real shared secret if c = c' */ ++ cmov(ss2, kr, KYBER_SYMBYTES, 1-fail); ++ memcpy(ss, ss2, KYBER_SYMBYTES); ++ } else { ++ /* overwrite coins in kr with H(c) */ ++ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); ++ ++ /* Overwrite pre-k with z on re-encryption failure */ ++ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); ++ ++ /* hash concatenation of pre-k and H(c) to k */ ++ kdf(ss, kr, 2*KYBER_SYMBYTES); + } - return 1; -+ -+ /* overwrite coins in kr with H(c) */ -+ hash_h(kr+KYBER_SYMBYTES, ct, ciphertext_len); -+ -+ /* Overwrite pre-k with z on re-encryption failure */ -+ cmov(kr, sk+KYBER_SECRETKEYBYTES-KYBER_SYMBYTES, KYBER_SYMBYTES, fail); -+ -+ /* hash concatenation of pre-k and H(c) to k */ -+ kdf(ss, kr, 2*KYBER_SYMBYTES); -+} -+ + } + +-int KYBER_parse_private_key(struct KYBER_private_key *out_private_key, +- CBS *in) { +- struct private_key *const priv = private_key_from_external(out_private_key); +void marshal_public_key(uint8_t out[KYBER_PUBLICKEYBYTES], + const struct public_key *in_pub) { + memcpy(out, &in_pub->opaque, KYBER_PUBLICKEYBYTES); +} -+ + +- CBS s_bytes; +- if (!CBS_get_bytes(in, &s_bytes, kEncodedVectorSize) || +- !vector_decode(&priv->s, CBS_data(&s_bytes), kLog2Prime) || +- !kyber_parse_public_key_no_hash(&priv->pub, in) || +- !CBS_copy_bytes(in, priv->pub.public_key_hash, +- sizeof(priv->pub.public_key_hash)) || +- !CBS_copy_bytes(in, priv->fo_failure_secret, +- sizeof(priv->fo_failure_secret)) || +- CBS_len(in) != 0) { +- return 0; +- } +- return 1; +void parse_public_key(struct public_key *out, + const uint8_t in[KYBER_PUBLICKEYBYTES]) { + memcpy(&out->opaque, in, KYBER_PUBLICKEYBYTES); @@ -3728,7 +3922,7 @@ index eb76b5bd7..000000000 - FileTestGTest("crypto/kyber/kyber_tests.txt", KyberFileTest); -} diff --git a/src/crypto/obj/obj_dat.h b/src/crypto/obj/obj_dat.h -index 654b3c08e..06f80f971 100644 +index 654b3c08e..6cef2c079 100644 --- a/src/crypto/obj/obj_dat.h +++ b/src/crypto/obj/obj_dat.h @@ -57,7 +57,7 @@ @@ -3736,11 +3930,11 @@ index 654b3c08e..06f80f971 100644 -#define NUM_NID 965 -+#define NUM_NID 968 ++#define NUM_NID 969 static const uint8_t kObjectData[] = { /* NID_rsadsi */ -@@ -8784,6 +8784,12 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { +@@ -8784,6 +8784,13 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { {"HKDF", "hkdf", NID_hkdf, 0, NULL, 0}, {"X25519Kyber768Draft00", "X25519Kyber768Draft00", NID_X25519Kyber768Draft00, 0, NULL, 0}, @@ -3750,10 +3944,11 @@ index 654b3c08e..06f80f971 100644 + NULL, 0}, + {"X25519Kyber768Draft00Old", "X25519Kyber768Draft00Old", + NID_X25519Kyber768Draft00Old, 0, NULL, 0}, ++ {"X25519MLKEM768", "X25519MLKEM768", NID_X25519MLKEM768, 0, NULL, 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { -@@ -8916,6 +8922,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8916,6 +8923,7 @@ static const uint16_t kNIDsInShortNameOrder[] = { 18 /* OU */, 749 /* Oakley-EC2N-3 */, 750 /* Oakley-EC2N-4 */, @@ -3761,17 +3956,18 @@ index 654b3c08e..06f80f971 100644 9 /* PBE-MD2-DES */, 168 /* PBE-MD2-RC2-64 */, 10 /* PBE-MD5-DES */, -@@ -8982,7 +8989,9 @@ static const uint16_t kNIDsInShortNameOrder[] = { +@@ -8982,7 +8990,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { 458 /* UID */, 0 /* UNDEF */, 948 /* X25519 */, + 965 /* X25519Kyber512Draft00 */, 964 /* X25519Kyber768Draft00 */, + 967 /* X25519Kyber768Draft00Old */, ++ 968 /* X25519MLKEM768 */, 961 /* X448 */, 11 /* X500 */, 378 /* X500algorithms */, -@@ -9829,6 +9838,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9829,6 +9840,7 @@ static const uint16_t kNIDsInLongNameOrder[] = { 366 /* OCSP Nonce */, 371 /* OCSP Service Locator */, 180 /* OCSP Signing */, @@ -3779,32 +3975,34 @@ index 654b3c08e..06f80f971 100644 161 /* PBES2 */, 69 /* PBKDF2 */, 162 /* PBMAC1 */, -@@ -9853,7 +9863,9 @@ static const uint16_t kNIDsInLongNameOrder[] = { +@@ -9853,7 +9865,10 @@ static const uint16_t kNIDsInLongNameOrder[] = { 133 /* Time Stamping */, 375 /* Trust Root */, 948 /* X25519 */, + 965 /* X25519Kyber512Draft00 */, 964 /* X25519Kyber768Draft00 */, + 967 /* X25519Kyber768Draft00Old */, ++ 968 /* X25519MLKEM768 */, 961 /* X448 */, 12 /* X509 */, 402 /* X509v3 AC Targeting */, diff --git a/src/crypto/obj/obj_mac.num b/src/crypto/obj/obj_mac.num -index a0519acee..caeb5eaed 100644 +index a0519acee..2a46adfe8 100644 --- a/src/crypto/obj/obj_mac.num +++ b/src/crypto/obj/obj_mac.num -@@ -952,3 +952,6 @@ X448 961 +@@ -952,3 +952,7 @@ X448 961 sha512_256 962 hkdf 963 X25519Kyber768Draft00 964 +X25519Kyber512Draft00 965 +P256Kyber768Draft00 966 +X25519Kyber768Draft00Old 967 ++X25519MLKEM768 968 diff --git a/src/crypto/obj/objects.txt b/src/crypto/obj/objects.txt -index 3ad32ea3d..aa1404d83 100644 +index 3ad32ea3d..347fc556a 100644 --- a/src/crypto/obj/objects.txt +++ b/src/crypto/obj/objects.txt -@@ -1332,8 +1332,11 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme +@@ -1332,8 +1332,12 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme : dh-std-kdf : dh-cofactor-kdf @@ -3814,11 +4012,12 @@ index 3ad32ea3d..aa1404d83 100644 : X25519Kyber768Draft00 + : P256Kyber768Draft00 + : X25519Kyber768Draft00Old ++ : X25519MLKEM768 # See RFC 8410. 1 3 101 110 : X25519 diff --git a/src/include/openssl/kyber.h b/src/include/openssl/kyber.h -index cafae9d17..074ac5906 100644 +index cafae9d17..a05eb8957 100644 --- a/src/include/openssl/kyber.h +++ b/src/include/openssl/kyber.h @@ -1,17 +1,3 @@ @@ -3839,7 +4038,7 @@ index cafae9d17..074ac5906 100644 #ifndef OPENSSL_HEADER_KYBER_H #define OPENSSL_HEADER_KYBER_H -@@ -21,105 +7,100 @@ +@@ -21,105 +7,104 @@ extern "C" { #endif @@ -3983,39 +4182,43 @@ index cafae9d17..074ac5906 100644 + +// KYBER512_encap is a deterministic function the generates and encrypts a random +// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. -+OPENSSL_EXPORT void KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], ++// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-512. ++OPENSSL_EXPORT int KYBER512_encap(uint8_t out_ciphertext[KYBER512_CIPHERTEXT_BYTES], + uint8_t out_shared_key[KYBER_KEY_BYTES], + const struct KYBER512_public_key *in_pub, -+ const uint8_t in[KYBER_ENCAP_BYTES]); ++ const uint8_t in[KYBER_ENCAP_BYTES], ++ int mlkem); + +// KYBER768_encap is a deterministic function the generates and encrypts a random +// session key from the given entropy, writing those values to |out_shared_key| -+// and |out_ciphertext|, respectively. -+OPENSSL_EXPORT void KYBER768_encap(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], ++// and |out_ciphertext|, respectively. If |mlkem| is 1, will use ML-KEM-768. ++OPENSSL_EXPORT int KYBER768_encap(uint8_t out_ciphertext[KYBER768_CIPHERTEXT_BYTES], + uint8_t out_shared_key[KYBER_KEY_BYTES], + const struct KYBER768_public_key *in_pub, -+ const uint8_t in[KYBER_ENCAP_BYTES]); ++ const uint8_t in[KYBER_ENCAP_BYTES], ++ int mlkem); + +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept +// in |in_priv|) is written. If the ciphertext is the wrong length then it will +// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. ++// action in constant-time. If |mlkem| is 1, will use ML-KEM-512. +OPENSSL_EXPORT void KYBER512_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], + const struct KYBER512_private_key *in_priv, -+ const uint8_t *ciphertext, size_t ciphertext_len); ++ const uint8_t *ciphertext, size_t ciphertext_len, ++ int mlkem); + +// KYBER_decap decrypts a session key from |ciphertext_len| bytes of +// |ciphertext|. If the ciphertext is valid, the decrypted key is written to +// |out_shared_key|. Otherwise a key dervied from |ciphertext| and a secret key (kept +// in |in_priv|) is written. If the ciphertext is the wrong length then it will +// leak which was done via side-channels. Otherwise it should perform either -+// action in constant-time. ++// action in constant-time. If |mlkem| is 1, will use ML-KEM-768. +OPENSSL_EXPORT void KYBER768_decap(uint8_t out_shared_key[KYBER_KEY_BYTES], + const struct KYBER768_private_key *in_priv, -+ const uint8_t *ciphertext, size_t ciphertext_len); ++ const uint8_t *ciphertext, size_t ciphertext_len, ++ int mlkem); + +// KYBER512_marshal_public_key serialises |in_pub| to |out|. +OPENSSL_EXPORT void KYBER512_marshal_public_key( @@ -4036,10 +4239,10 @@ index cafae9d17..074ac5906 100644 #if defined(__cplusplus) } // extern C diff --git a/src/include/openssl/nid.h b/src/include/openssl/nid.h -index 4dd8841b1..8237efb74 100644 +index 4dd8841b1..5b102c610 100644 --- a/src/include/openssl/nid.h +++ b/src/include/openssl/nid.h -@@ -4255,6 +4255,15 @@ extern "C" { +@@ -4255,6 +4255,18 @@ extern "C" { #define SN_X25519Kyber768Draft00 "X25519Kyber768Draft00" #define NID_X25519Kyber768Draft00 964 @@ -4051,21 +4254,25 @@ index 4dd8841b1..8237efb74 100644 + +#define SN_X25519Kyber768Draft00Old "X25519Kyber768Draft00Old" +#define NID_X25519Kyber768Draft00Old 967 ++ ++#define SN_X25519MLKEM768 "X25519MLKEM768" ++#define NID_X25519MLKEM768 968 + #if defined(__cplusplus) } /* extern C */ diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h -index 53aa9b453..8233ad210 100644 +index 53aa9b453..f9683f4cf 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h -@@ -2378,6 +2378,9 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); +@@ -2378,6 +2378,10 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); #define SSL_CURVE_SECP521R1 25 #define SSL_CURVE_X25519 29 #define SSL_CURVE_X25519_KYBER768_DRAFT00 0x6399 +#define SSL_CURVE_X25519_KYBER512_DRAFT00 0xfe30 +#define SSL_CURVE_X25519_KYBER768_DRAFT00_OLD 0xfe31 +#define SSL_CURVE_P256_KYBER768_DRAFT00 0xfe32 ++#define SSL_CURVE_X25519_MLKEM768 0x11ec // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently // completed handshake or 0 if not applicable. @@ -4083,21 +4290,22 @@ index 5c7e881bf..3c0770cf3 100644 crypto/pkcs8/test/no_encryption.p12 crypto/pkcs8/test/nss.p12 diff --git a/src/ssl/extensions.cc b/src/ssl/extensions.cc -index 5ee280221..0a706c411 100644 +index 5ee280221..aae3e6a7f 100644 --- a/src/ssl/extensions.cc +++ b/src/ssl/extensions.cc -@@ -207,6 +207,9 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { +@@ -207,6 +207,10 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) { static bool is_post_quantum_group(uint16_t id) { switch (id) { case SSL_CURVE_X25519_KYBER768_DRAFT00: + case SSL_CURVE_X25519_KYBER768_DRAFT00_OLD: + case SSL_CURVE_X25519_KYBER512_DRAFT00: + case SSL_CURVE_P256_KYBER768_DRAFT00: ++ case SSL_CURVE_X25519_MLKEM768: return true; default: return false; diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc -index 09a9ad380..f7d2226e3 100644 +index 09a9ad380..d7a8f0a80 100644 --- a/src/ssl/ssl_key_share.cc +++ b/src/ssl/ssl_key_share.cc @@ -26,6 +26,7 @@ @@ -4108,13 +4316,14 @@ index 09a9ad380..f7d2226e3 100644 #include #include #include -@@ -193,63 +194,384 @@ class X25519KeyShare : public SSLKeyShare { +@@ -193,63 +194,292 @@ class X25519KeyShare : public SSLKeyShare { uint8_t private_key_[32]; }; -class X25519Kyber768KeyShare : public SSLKeyShare { +class P256Kyber768Draft00KeyShare : public SSLKeyShare { -+ public: + public: +- X25519Kyber768KeyShare() {} + P256Kyber768Draft00KeyShare() {} + + uint16_t GroupID() const override { return SSL_CURVE_P256_KYBER768_DRAFT00; } @@ -4159,15 +4368,17 @@ index 09a9ad380..f7d2226e3 100644 + + uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; + KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); -+ + +- uint16_t GroupID() const override { +- return SSL_CURVE_X25519_KYBER768_DRAFT00; + if (!CBB_add_bytes(out, kyber_public_key_bytes, + sizeof(kyber_public_key_bytes))) { + return false; + } + + return true; -+ } -+ + } + + bool Encap(CBB *out_public_key, Array *out_secret, + uint8_t *out_alert, Span peer_key) override { + assert(!p256_private_key_); @@ -4247,7 +4458,10 @@ index 09a9ad380..f7d2226e3 100644 + uint8_t entropy[KYBER_ENCAP_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); + -+ KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy); ++ if(!KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy, 0)) { ++ *out_alert = SSL_AD_ILLEGAL_PARAMETER; ++ return false; ++ } + if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { + return false; + } @@ -4318,7 +4532,7 @@ index 09a9ad380..f7d2226e3 100644 + } + + KYBER768_decap(secret.data() + 32, &kyber_private_key_, -+ peer_key.data() + 65, peer_key.size() - 65); ++ peer_key.data() + 65, peer_key.size() - 65, 0); + + *out_secret = std::move(secret); + return true; @@ -4330,114 +4544,13 @@ index 09a9ad380..f7d2226e3 100644 +}; + +class X25519Kyber768Draft00KeyShare : public SSLKeyShare { - public: -- X25519Kyber768KeyShare() {} ++ public: + X25519Kyber768Draft00KeyShare(uint16_t group_id) : group_id_(group_id) { + assert(group_id == SSL_CURVE_X25519_KYBER768_DRAFT00 + || group_id == SSL_CURVE_X25519_KYBER768_DRAFT00_OLD); + } + + uint16_t GroupID() const override { return group_id_; } -+ -+ bool Generate(CBB *out) override { -+ uint8_t x25519_public_key[32]; -+ X25519_keypair(x25519_public_key, x25519_private_key_); -+ -+ uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; -+ KYBER768_public_key kyber_public_key; -+ RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); -+ KYBER768_generate_key(&kyber_public_key, &kyber_private_key_, kyber_entropy); -+ -+ uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; -+ KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); -+ -+ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || -+ !CBB_add_bytes(out, kyber_public_key_bytes, -+ sizeof(kyber_public_key_bytes))) { -+ return false; -+ } -+ -+ return true; -+ } -+ -+ bool Encap(CBB *out_public_key, Array *out_secret, -+ uint8_t *out_alert, Span peer_key) override { -+ Array secret; -+ if (!secret.Init(32 + KYBER_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ uint8_t x25519_public_key[32]; -+ X25519_keypair(x25519_public_key, x25519_private_key_); -+ -+ KYBER768_public_key peer_public_key; -+ if (peer_key.size() != 32 + KYBER768_PUBLIC_KEY_BYTES) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ KYBER768_parse_public_key(&peer_public_key, peer_key.data() + 32); -+ -+ if (!X25519(secret.data(), x25519_private_key_, peer_key.data())) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ uint8_t ciphertext[KYBER768_CIPHERTEXT_BYTES]; -+ uint8_t entropy[KYBER_ENCAP_BYTES]; -+ RAND_bytes(entropy, sizeof(entropy)); -+ -+ KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy); -+ if(!CBB_add_bytes(out_public_key, x25519_public_key, -+ sizeof(x25519_public_key)) || -+ !CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { -+ return false; -+ } -+ -+ *out_secret = std::move(secret); -+ return true; -+ } -+ -+ bool Decap(Array *out_secret, uint8_t *out_alert, -+ Span peer_key) override { -+ *out_alert = SSL_AD_INTERNAL_ERROR; -+ -+ Array secret; -+ if (!secret.Init(32 + KYBER_KEY_BYTES)) { -+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); -+ return false; -+ } -+ -+ if (peer_key.size() != 32 + KYBER768_CIPHERTEXT_BYTES || -+ !X25519(secret.data(), x25519_private_key_, peer_key.data())) { -+ *out_alert = SSL_AD_DECODE_ERROR; -+ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); -+ return false; -+ } -+ -+ KYBER768_decap(secret.data() + 32, &kyber_private_key_, -+ peer_key.data() + 32, peer_key.size() - 32); - -- uint16_t GroupID() const override { -- return SSL_CURVE_X25519_KYBER768_DRAFT00; -+ *out_secret = std::move(secret); -+ return true; - } - -+ private: -+ uint8_t x25519_private_key_[32]; -+ KYBER768_private_key kyber_private_key_; -+ uint16_t group_id_; -+}; -+ -+class X25519Kyber512Draft00KeyShare : public SSLKeyShare { -+ public: -+ X25519Kyber512Draft00KeyShare() {} -+ -+ uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } + bool Generate(CBB *out) override { uint8_t x25519_public_key[32]; @@ -4446,12 +4559,12 @@ index 09a9ad380..f7d2226e3 100644 - uint8_t kyber_public_key[KYBER_PUBLIC_KEY_BYTES]; - KYBER_generate_key(kyber_public_key, &kyber_private_key_); + uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; -+ KYBER512_public_key kyber_public_key; ++ KYBER768_public_key kyber_public_key; + RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); -+ KYBER512_generate_key(&kyber_public_key, &kyber_private_key_, kyber_entropy); ++ KYBER768_generate_key(&kyber_public_key, &kyber_private_key_, kyber_entropy); + -+ uint8_t kyber_public_key_bytes[KYBER512_PUBLIC_KEY_BYTES]; -+ KYBER512_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); ++ uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; ++ KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || - !CBB_add_bytes(out, kyber_public_key, sizeof(kyber_public_key))) { @@ -4489,14 +4602,14 @@ index 09a9ad380..f7d2226e3 100644 - CBS_data(&peer_x25519_cbs)) || - !KYBER_parse_public_key(&peer_kyber_pub, &peer_kyber_cbs)) { + -+ KYBER512_public_key peer_public_key; -+ if (peer_key.size() != 32 + KYBER512_PUBLIC_KEY_BYTES) { ++ KYBER768_public_key peer_public_key; ++ if (peer_key.size() != 32 + KYBER768_PUBLIC_KEY_BYTES) { + *out_alert = SSL_AD_DECODE_ERROR; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); + return false; + } + -+ KYBER512_parse_public_key(&peer_public_key, peer_key.data() + 32); ++ KYBER768_parse_public_key(&peer_public_key, peer_key.data() + 32); + + if (!X25519(secret.data(), x25519_private_key_, peer_key.data())) { *out_alert = SSL_AD_DECODE_ERROR; @@ -4507,12 +4620,15 @@ index 09a9ad380..f7d2226e3 100644 - uint8_t kyber_ciphertext[KYBER_CIPHERTEXT_BYTES]; - KYBER_encap(kyber_ciphertext, secret.data() + 32, secret.size() - 32, - &peer_kyber_pub); -+ uint8_t ciphertext[KYBER512_CIPHERTEXT_BYTES]; ++ uint8_t ciphertext[KYBER768_CIPHERTEXT_BYTES]; + uint8_t entropy[KYBER_ENCAP_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); - if (!CBB_add_bytes(out_ciphertext, x25519_public_key, -+ KYBER512_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy); ++ if(!KYBER768_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy, 0)) { ++ *out_alert = SSL_AD_ILLEGAL_PARAMETER; ++ return false; ++ } + if(!CBB_add_bytes(out_public_key, x25519_public_key, sizeof(x25519_public_key)) || - !CBB_add_bytes(out_ciphertext, kyber_ciphertext, @@ -4521,11 +4637,111 @@ index 09a9ad380..f7d2226e3 100644 return false; } -@@ -258,30 +580,32 @@ class X25519Kyber768KeyShare : public SSLKeyShare { +@@ -258,30 +488,233 @@ class X25519Kyber768KeyShare : public SSLKeyShare { } bool Decap(Array *out_secret, uint8_t *out_alert, - Span ciphertext) override { ++ Span peer_key) override { ++ *out_alert = SSL_AD_INTERNAL_ERROR; ++ ++ Array secret; ++ if (!secret.Init(32 + KYBER_KEY_BYTES)) { ++ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); ++ return false; ++ } ++ ++ if (peer_key.size() != 32 + KYBER768_CIPHERTEXT_BYTES || ++ !X25519(secret.data(), x25519_private_key_, peer_key.data())) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ ++ KYBER768_decap(secret.data() + 32, &kyber_private_key_, ++ peer_key.data() + 32, peer_key.size() - 32, 0); ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ private: ++ uint8_t x25519_private_key_[32]; ++ KYBER768_private_key kyber_private_key_; ++ uint16_t group_id_; ++}; ++ ++class X25519MLKEM768KeyShare : public SSLKeyShare { ++ public: ++ X25519MLKEM768KeyShare() {} ++ ++ uint16_t GroupID() const override { return SSL_CURVE_X25519_MLKEM768; } ++ ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ ++ uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; ++ KYBER768_public_key kyber_public_key; ++ RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); ++ KYBER768_generate_key(&kyber_public_key, &kyber_private_key_, kyber_entropy); ++ ++ uint8_t kyber_public_key_bytes[KYBER768_PUBLIC_KEY_BYTES]; ++ KYBER768_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); ++ ++ if (!CBB_add_bytes(out, kyber_public_key_bytes, sizeof(kyber_public_key_bytes)) || ++ !CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key))) { ++ return false; ++ } ++ ++ return true; ++ } ++ ++ bool Encap(CBB *out_public_key, Array *out_secret, ++ uint8_t *out_alert, Span peer_key) override { ++ Array secret; ++ if (!secret.Init(32 + KYBER_KEY_BYTES)) { ++ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); ++ return false; ++ } ++ ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ ++ KYBER768_public_key peer_public_key; ++ if (peer_key.size() != KYBER768_PUBLIC_KEY_BYTES + 32) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ ++ KYBER768_parse_public_key(&peer_public_key, peer_key.data()); ++ ++ if (!X25519(secret.data() + 32, x25519_private_key_, ++ peer_key.data() + KYBER768_PUBLIC_KEY_BYTES)) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ ++ uint8_t ciphertext[KYBER768_CIPHERTEXT_BYTES]; ++ uint8_t entropy[KYBER_ENCAP_BYTES]; ++ RAND_bytes(entropy, sizeof(entropy)); ++ ++ if(!KYBER768_encap(ciphertext, secret.data(), &peer_public_key, entropy, 1)) { ++ *out_alert = SSL_AD_ILLEGAL_PARAMETER; ++ return false; ++ } ++ if(!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext)) || ++ !CBB_add_bytes(out_public_key, x25519_public_key, sizeof(x25519_public_key))) { ++ return false; ++ } ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ bool Decap(Array *out_secret, uint8_t *out_alert, + Span peer_key) override { *out_alert = SSL_AD_INTERNAL_ERROR; @@ -4538,8 +4754,9 @@ index 09a9ad380..f7d2226e3 100644 - if (ciphertext.size() != 32 + KYBER_CIPHERTEXT_BYTES || - !X25519(secret.data(), x25519_private_key_, ciphertext.data())) { -+ if (peer_key.size() != 32 + KYBER512_CIPHERTEXT_BYTES || -+ !X25519(secret.data(), x25519_private_key_, peer_key.data())) { ++ if (peer_key.size() != KYBER768_CIPHERTEXT_BYTES + 32 || ++ !X25519(secret.data() + 32, x25519_private_key_, ++ peer_key.data() + KYBER768_CIPHERTEXT_BYTES )) { *out_alert = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); return false; @@ -4547,8 +4764,108 @@ index 09a9ad380..f7d2226e3 100644 - KYBER_decap(secret.data() + 32, secret.size() - 32, ciphertext.data() + 32, - &kyber_private_key_); ++ KYBER768_decap(secret.data(), &kyber_private_key_, ++ peer_key.data(), peer_key.size() - 32, 1); ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ private: ++ uint8_t x25519_private_key_[32]; ++ KYBER768_private_key kyber_private_key_; ++}; ++ ++class X25519Kyber512Draft00KeyShare : public SSLKeyShare { ++ public: ++ X25519Kyber512Draft00KeyShare() {} ++ ++ uint16_t GroupID() const override { return SSL_CURVE_X25519_KYBER512_DRAFT00; } ++ ++ bool Generate(CBB *out) override { ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ ++ uint8_t kyber_entropy[KYBER_GENERATE_KEY_BYTES]; ++ KYBER512_public_key kyber_public_key; ++ RAND_bytes(kyber_entropy, sizeof(kyber_entropy)); ++ KYBER512_generate_key(&kyber_public_key, &kyber_private_key_, kyber_entropy); ++ ++ uint8_t kyber_public_key_bytes[KYBER512_PUBLIC_KEY_BYTES]; ++ KYBER512_marshal_public_key(kyber_public_key_bytes, &kyber_public_key); ++ ++ if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || ++ !CBB_add_bytes(out, kyber_public_key_bytes, ++ sizeof(kyber_public_key_bytes))) { ++ return false; ++ } ++ ++ return true; ++ } ++ ++ bool Encap(CBB *out_public_key, Array *out_secret, ++ uint8_t *out_alert, Span peer_key) override { ++ Array secret; ++ if (!secret.Init(32 + KYBER_KEY_BYTES)) { ++ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); ++ return false; ++ } ++ ++ uint8_t x25519_public_key[32]; ++ X25519_keypair(x25519_public_key, x25519_private_key_); ++ ++ KYBER512_public_key peer_public_key; ++ if (peer_key.size() != 32 + KYBER512_PUBLIC_KEY_BYTES) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ ++ KYBER512_parse_public_key(&peer_public_key, peer_key.data() + 32); ++ ++ if (!X25519(secret.data(), x25519_private_key_, peer_key.data())) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ ++ uint8_t ciphertext[KYBER512_CIPHERTEXT_BYTES]; ++ uint8_t entropy[KYBER_ENCAP_BYTES]; ++ RAND_bytes(entropy, sizeof(entropy)); ++ ++ if(!KYBER512_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy, 0)) { ++ *out_alert = SSL_AD_ILLEGAL_PARAMETER; ++ return false; ++ } ++ if(!CBB_add_bytes(out_public_key, x25519_public_key, ++ sizeof(x25519_public_key)) || ++ !CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { ++ return false; ++ } ++ ++ *out_secret = std::move(secret); ++ return true; ++ } ++ ++ bool Decap(Array *out_secret, uint8_t *out_alert, ++ Span peer_key) override { ++ *out_alert = SSL_AD_INTERNAL_ERROR; ++ ++ Array secret; ++ if (!secret.Init(32 + KYBER_KEY_BYTES)) { ++ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); ++ return false; ++ } ++ ++ if (peer_key.size() != 32 + KYBER512_CIPHERTEXT_BYTES || ++ !X25519(secret.data(), x25519_private_key_, peer_key.data())) { ++ *out_alert = SSL_AD_DECODE_ERROR; ++ OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); ++ return false; ++ } ++ + KYBER512_decap(secret.data() + 32, &kyber_private_key_, -+ peer_key.data() + 32, peer_key.size() - 32); ++ peer_key.data() + 32, peer_key.size() - 32, 0); + *out_secret = std::move(secret); return true; @@ -4561,7 +4878,7 @@ index 09a9ad380..f7d2226e3 100644 }; constexpr NamedGroup kNamedGroups[] = { -@@ -290,8 +614,14 @@ constexpr NamedGroup kNamedGroups[] = { +@@ -290,8 +723,16 @@ constexpr NamedGroup kNamedGroups[] = { {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, @@ -4573,11 +4890,13 @@ index 09a9ad380..f7d2226e3 100644 + {NID_X25519Kyber768Draft00Old, SSL_CURVE_X25519_KYBER768_DRAFT00_OLD, + "X25519Kyber768Draft00Old", "Xyber768D00Old"}, + {NID_P256Kyber768Draft00, SSL_CURVE_P256_KYBER768_DRAFT00, -+ "P256Kyber768Draft00", "P256Kyber768D00"} ++ "P256Kyber768Draft00", "P256Kyber768D00"}, ++ {NID_X25519MLKEM768, SSL_CURVE_X25519_MLKEM768, ++ "X25519MLKEM768", "X25519MLKEM768"} }; } // namespace -@@ -312,8 +642,16 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { +@@ -312,8 +753,18 @@ UniquePtr SSLKeyShare::Create(uint16_t group_id) { return MakeUnique(NID_secp521r1, SSL_CURVE_SECP521R1); case SSL_CURVE_X25519: return MakeUnique(); @@ -4592,6 +4911,8 @@ index 09a9ad380..f7d2226e3 100644 + group_id)); + case SSL_CURVE_P256_KYBER768_DRAFT00: + return UniquePtr(New()); ++ case SSL_CURVE_X25519_MLKEM768: ++ return UniquePtr(New()); default: return nullptr; } @@ -4609,10 +4930,10 @@ index 838761af5..9eb201d37 100644 static const uint16_t kSigAlgs[] = { SSL_SIGN_RSA_PKCS1_SHA256, diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc -index ef43a9e98..9756fd2a0 100644 +index ef43a9e98..22178b5f6 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc -@@ -409,7 +409,30 @@ static const CurveTest kCurveTests[] = { +@@ -409,7 +409,34 @@ static const CurveTest kCurveTests[] = { "P-256:X25519Kyber768Draft00", { SSL_CURVE_SECP256R1, SSL_CURVE_X25519_KYBER768_DRAFT00 }, }, @@ -4638,6 +4959,10 @@ index ef43a9e98..9756fd2a0 100644 + { SSL_CURVE_P256_KYBER768_DRAFT00 }, + }, + { ++ "X25519MLKEM768", ++ { SSL_CURVE_X25519_MLKEM768 }, ++ }, ++ { + "P-256:P256Kyber768D00", + { SSL_CURVE_SECP256R1, SSL_CURVE_P256_KYBER768_DRAFT00 }, + }, @@ -4645,7 +4970,7 @@ index ef43a9e98..9756fd2a0 100644 "P-256:P-384:P-521:X25519", { diff --git a/src/tool/speed.cc b/src/tool/speed.cc -index 5b0205953..831875514 100644 +index 5b0205953..6b3c67dab 100644 --- a/src/tool/speed.cc +++ b/src/tool/speed.cc @@ -904,6 +904,116 @@ static bool SpeedScrypt(const std::string &selected) { @@ -4684,7 +5009,7 @@ index 5b0205953..831875514 100644 + uint8_t entropy[KYBER_ENCAP_BYTES]; + uint8_t shared_key[KYBER_KEY_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); -+ KYBER768_encap(ciphertext, shared_key, &pub, entropy); ++ KYBER768_encap(ciphertext, shared_key, &pub, entropy, 0); + return true; + })) { + fprintf(stderr, "Failed to time KYBER768_encap.\n"); @@ -4695,7 +5020,7 @@ index 5b0205953..831875514 100644 + + if (!TimeFunction(&results, [&priv, &ciphertext]() -> bool { + uint8_t shared_key[KYBER_KEY_BYTES]; -+ KYBER768_decap(shared_key, &priv, ciphertext, sizeof(ciphertext)); ++ KYBER768_decap(shared_key, &priv, ciphertext, sizeof(ciphertext), 0); + return true; + })) { + fprintf(stderr, "Failed to time KYBER768_decap.\n"); @@ -4739,7 +5064,7 @@ index 5b0205953..831875514 100644 + uint8_t entropy[KYBER_ENCAP_BYTES]; + uint8_t shared_key[KYBER_KEY_BYTES]; + RAND_bytes(entropy, sizeof(entropy)); -+ KYBER512_encap(ciphertext, shared_key, &pub, entropy); ++ KYBER512_encap(ciphertext, shared_key, &pub, entropy, 0); + return true; + })) { + fprintf(stderr, "Failed to time KYBER512_encap.\n"); @@ -4750,7 +5075,7 @@ index 5b0205953..831875514 100644 + + if (!TimeFunction(&results, [&priv, &ciphertext]() -> bool { + uint8_t shared_key[KYBER_KEY_BYTES]; -+ KYBER512_decap(shared_key, &priv, ciphertext, sizeof(ciphertext)); ++ KYBER512_decap(shared_key, &priv, ciphertext, sizeof(ciphertext), 0); + return true; + })) { + fprintf(stderr, "Failed to time KYBER512_decap.\n"); @@ -4832,5 +5157,5 @@ index 5b0205953..831875514 100644 !SpeedTrustToken("TrustToken-Exp1-Batch1", TRUST_TOKEN_experiment_v1(), 1, selected) || -- -2.41.0 +2.46.0 diff --git a/boring/src/lib.rs b/boring/src/lib.rs index 6b3ade0f..6779586a 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -74,9 +74,11 @@ //! support by turning on `post-quantum` compilation feature. //! //! Upstream BoringSSL support the post-quantum hybrid key agreement `X25519Kyber768Draft00`. Most -//! users should stick to that one. Enabling this feature, adds a few other post-quantum key +//! users should stick to that one for now. Enabling this feature, adds a few other post-quantum key //! agreements: //! +//! - `X25519MLKEM768` is the successor of `X25519Kyber768Draft00`. We expect servers to switch +//! before the end of 2024. //! - `X25519Kyber768Draft00Old` is the same as `X25519Kyber768Draft00`, but under its old codepoint. //! - `X25519Kyber512Draft00`. Similar to `X25519Kyber768Draft00`, but uses level 1 parameter set for //! Kyber. Not recommended. It's useful to test whether the shorter ClientHello upsets fewer middle diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 277002b7..9bc27bc3 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -765,6 +765,8 @@ impl SslCurve { ffi::SSL_CURVE_X25519_KYBER512_DRAFT00 => Some(ffi::NID_X25519Kyber512Draft00), #[cfg(feature = "pq-experimental")] ffi::SSL_CURVE_P256_KYBER768_DRAFT00 => Some(ffi::NID_P256Kyber768Draft00), + #[cfg(feature = "pq-experimental")] + ffi::SSL_CURVE_X25519_MLKEM768 => Some(ffi::NID_X25519MLKEM768), _ => None, } } @@ -2691,13 +2693,13 @@ 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" + "X25519Kyber768Draft00:X25519MLKEM768:X25519:P256Kyber768Draft00:P-256:P-384:P-521" } } else if cfg!(feature = "kx-client-pq-supported") { 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") { @@ -2713,8 +2715,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( + "X25519Kyber768Draft00:X25519MLKEM768:P256Kyber768Draft00:X25519:P-256:P-384", + ) + .expect("invalid default server curves list"); } /// Returns the [`SslCurve`] used for this `SslRef`. From 193bf3b9d7ac06adfef5e614f077970c9d2a2f8e Mon Sep 17 00:00:00 2001 From: Anthony Ramine <123095+nox@users.noreply.github.com> Date: Wed, 18 Sep 2024 13:24:35 +0200 Subject: [PATCH 15/21] Implement optional Hyper 1 support in hyper-boring (#246) --- .github/workflows/ci.yml | 2 + Cargo.toml | 10 +- boring-sys/Cargo.toml | 3 + hyper-boring/Cargo.toml | 19 +- hyper-boring/src/lib.rs | 356 +--------------------- hyper-boring/src/v0.rs | 345 +++++++++++++++++++++ hyper-boring/src/v1.rs | 350 +++++++++++++++++++++ hyper-boring/{ => tests}/test/cert.pem | 0 hyper-boring/{ => tests}/test/key.pem | 0 hyper-boring/{ => tests}/test/root-ca.pem | 0 hyper-boring/{src/test.rs => tests/v0.rs} | 26 +- hyper-boring/tests/v1.rs | 160 ++++++++++ 12 files changed, 905 insertions(+), 366 deletions(-) create mode 100644 hyper-boring/src/v0.rs create mode 100644 hyper-boring/src/v1.rs rename hyper-boring/{ => tests}/test/cert.pem (100%) rename hyper-boring/{ => tests}/test/key.pem (100%) rename hyper-boring/{ => tests}/test/root-ca.pem (100%) rename hyper-boring/{src/test.rs => tests/v0.rs} (87%) create mode 100644 hyper-boring/tests/v1.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb3c07cb..083ee77c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -361,3 +361,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 + name: Run hyper 1.0 tests for hyper-boring diff --git a/Cargo.toml b/Cargo.toml index f848893f..a067f74f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ boring = { version = "4.9.1", path = "./boring" } tokio-boring = { version = "4.9.1", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } +bytes = "1" cmake = "0.1.18" fs_extra = "1.3.0" fslock = "0.2" @@ -36,10 +37,15 @@ futures = "0.3" tokio = "1" anyhow = "1" antidote = "1.0.0" -http = "0.2" -hyper = { version = "0.14", default-features = false } +http = "1" +http-body-util = "0.1.2" +http_old = { package = "http", version = "0.2" } +hyper = "1" +hyper-util = "0.1.6" +hyper_old = { package = "hyper", version = "0.14", default-features = false } linked_hash_set = "0.1" once_cell = "1.0" openssl-macros = "0.1.1" tower = "0.4" tower-layer = "0.3" +tower-service = "0.3" diff --git a/boring-sys/Cargo.toml b/boring-sys/Cargo.toml index c1471f20..5b623181 100644 --- a/boring-sys/Cargo.toml +++ b/boring-sys/Cargo.toml @@ -81,3 +81,6 @@ bindgen = { workspace = true } cmake = { workspace = true } fs_extra = { workspace = true } fslock = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "allow", check-cfg = ['cfg(const_fn)'] } diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml index b8c5c9d0..1e30d035 100644 --- a/hyper-boring/Cargo.toml +++ b/hyper-boring/Cargo.toml @@ -17,7 +17,7 @@ rustdoc-args = ["--cfg", "docsrs"] [features] default = ["runtime"] -runtime = ["hyper/runtime"] +runtime = ["hyper_old/runtime"] # Use a FIPS-validated version of boringssl. fips = ["tokio-boring/fips"] @@ -28,19 +28,30 @@ 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:http", "dep:hyper", "dep:hyper-util", "dep:tower-service"] + [dependencies] antidote = { workspace = true } -http = { workspace = true } -hyper = { workspace = true, features = ["client"] } +http = { workspace = true, optional = true } +http_old = { workspace = true } +hyper = { workspace = true, optional = true } +hyper-util = { workspace = true, optional = true, features = ["client", "client-legacy"] } +hyper_old = { workspace = true, features = ["client"] } linked_hash_set = { workspace = true } once_cell = { workspace = true } boring = { workspace = true } tokio = { workspace = true } tokio-boring = { workspace = true } tower-layer = { workspace = true } +tower-service = { workspace = true, optional = true } [dev-dependencies] -hyper = { workspace = true, features = [ "full" ] } +bytes = { workspace = true } +http-body-util = { workspace = true } +hyper-util = { workspace = true, features = ["http1", "http2", "service", "tokio"] } +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 53c12a46..736a3d89 100644 --- a/hyper-boring/src/lib.rs +++ b/hyper-boring/src/lib.rs @@ -2,91 +2,27 @@ #![warn(missing_docs)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] -use crate::cache::{SessionCache, SessionKey}; -use antidote::Mutex; +use crate::cache::SessionKey; use boring::error::ErrorStack; use boring::ex_data::Index; -use boring::ssl::{ - ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, - SslSessionCacheMode, -}; -use http::uri::Scheme; -use hyper::client::connect::{Connected, Connection}; -#[cfg(feature = "runtime")] -use hyper::client::HttpConnector; -use hyper::service::Service; -use hyper::Uri; +use boring::ssl::Ssl; use once_cell::sync::OnceCell; -use std::fmt::Debug; -use std::future::Future; -use std::io; -use std::net; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; -use std::{error::Error, fmt}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use std::fmt; use tokio_boring::SslStream; -use tower_layer::Layer; mod cache; -#[cfg(test)] -mod test; +mod v0; +/// Hyper 1 support. +#[cfg(feature = "hyper1")] +pub mod v1; + +pub use self::v0::*; fn key_index() -> Result, ErrorStack> { static IDX: OnceCell> = OnceCell::new(); IDX.get_or_try_init(Ssl::new_ex_index).copied() } -#[derive(Clone)] -struct Inner { - ssl: SslConnector, - cache: Arc>, - callback: Option, - ssl_callback: Option, -} - -type Callback = - Arc Result<(), ErrorStack> + Sync + Send>; -type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; - -impl Inner { - fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { - let mut conf = self.ssl.configure()?; - - if let Some(ref callback) = self.callback { - callback(&mut conf, uri)?; - } - - let key = SessionKey { - host: host.to_string(), - port: uri.port_u16().unwrap_or(443), - }; - - if let Some(session) = self.cache.lock().get(&key) { - unsafe { - conf.set_session(&session)?; - } - } - - let idx = key_index()?; - conf.set_ex_data(idx, key); - - let mut ssl = conf.into_ssl(host)?; - - if let Some(ref ssl_callback) = self.ssl_callback { - ssl_callback(&mut ssl, uri)?; - } - - Ok(ssl) - } -} - -/// A layer which wraps services in an `HttpsConnector`. -pub struct HttpsLayer { - inner: Inner, -} - /// Settings for [`HttpsLayer`] pub struct HttpsLayerSettings { session_cache_capacity: usize, @@ -123,214 +59,6 @@ impl HttpsLayerSettingsBuilder { } } -impl HttpsLayer { - /// Creates a new `HttpsLayer` with default settings. - /// - /// ALPN is configured to support both HTTP/1 and HTTP/1.1. - pub fn new() -> Result { - let mut ssl = SslConnector::builder(SslMethod::tls())?; - - ssl.set_alpn_protos(b"\x02h2\x08http/1.1")?; - - Self::with_connector(ssl) - } - - /// Creates a new `HttpsLayer`. - /// - /// The session cache configuration of `ssl` will be overwritten. - pub fn with_connector(ssl: SslConnectorBuilder) -> Result { - Self::with_connector_and_settings(ssl, Default::default()) - } - - /// Creates a new `HttpsLayer` with settings - pub fn with_connector_and_settings( - mut ssl: SslConnectorBuilder, - settings: HttpsLayerSettings, - ) -> Result { - let cache = Arc::new(Mutex::new(SessionCache::with_capacity( - settings.session_cache_capacity, - ))); - - ssl.set_session_cache_mode(SslSessionCacheMode::CLIENT); - - ssl.set_new_session_callback({ - let cache = cache.clone(); - move |ssl, session| { - if let Some(key) = key_index().ok().and_then(|idx| ssl.ex_data(idx)) { - cache.lock().insert(key.clone(), session); - } - } - }); - - Ok(HttpsLayer { - inner: Inner { - ssl: ssl.build(), - cache, - callback: None, - ssl_callback: None, - }, - }) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -impl Layer for HttpsLayer { - type Service = HttpsConnector; - - fn layer(&self, inner: S) -> HttpsConnector { - HttpsConnector { - http: inner, - inner: self.inner.clone(), - } - } -} - -/// A Connector using OpenSSL to support `http` and `https` schemes. -#[derive(Clone)] -pub struct HttpsConnector { - http: T, - inner: Inner, -} - -#[cfg(feature = "runtime")] -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, ErrorStack> { - let mut http = HttpConnector::new(); - http.enforce_http(false); - - HttpsLayer::new().map(|l| l.layer(http)) - } -} - -impl HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - T: AsyncRead + AsyncWrite + Connection + Unpin + Debug + Sync + Send + 'static, -{ - /// Creates a new `HttpsConnector`. - /// - /// The session cache configuration of `ssl` will be overwritten. - pub fn with_connector( - http: S, - ssl: SslConnectorBuilder, - ) -> Result, ErrorStack> { - HttpsLayer::with_connector(ssl).map(|l| l.layer(http)) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -impl Service for HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - S::Response: AsyncRead + AsyncWrite + Connection + Unpin + Debug + Sync + Send + 'static, -{ - type Response = MaybeHttpsStream; - type Error = Box; - #[allow(clippy::type_complexity)] - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.http.poll_ready(cx).map_err(Into::into) - } - - fn call(&mut self, uri: Uri) -> Self::Future { - let is_tls_scheme = uri - .scheme() - .map(|s| s == &Scheme::HTTPS || s.as_str() == "wss") - .unwrap_or(false); - - let tls_setup = if is_tls_scheme { - Some((self.inner.clone(), uri.clone())) - } else { - None - }; - - let connect = self.http.call(uri); - - let f = async { - let conn = connect.await.map_err(Into::into)?; - - let (inner, uri) = match tls_setup { - Some((inner, uri)) => (inner, uri), - None => return Ok(MaybeHttpsStream::Http(conn)), - }; - - let mut host = uri.host().ok_or("URI missing host")?; - - // If `host` is an IPv6 address, we must strip away the square brackets that surround - // it (otherwise, boring will fail to parse the host as an IP address, eventually - // causing the handshake to fail due a hostname verification error). - if !host.is_empty() { - let last = host.len() - 1; - let mut chars = host.chars(); - - if let (Some('['), Some(']')) = (chars.next(), chars.last()) { - if host[1..last].parse::().is_ok() { - host = &host[1..last]; - } - } - } - - let ssl = inner.setup_ssl(&uri, host)?; - let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) - .connect() - .await?; - - Ok(MaybeHttpsStream::Https(stream)) - }; - - Box::pin(f) - } -} - /// A stream which may be wrapped with TLS. pub enum MaybeHttpsStream { /// A raw HTTP stream. @@ -339,72 +67,6 @@ pub enum MaybeHttpsStream { Https(SslStream), } -impl AsyncRead for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &mut ReadBuf, - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_read(ctx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_read(ctx, buf), - } - } -} - -impl AsyncWrite for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_write(ctx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_write(ctx, buf), - } - } - - fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_flush(ctx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_flush(ctx), - } - } - - fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_shutdown(ctx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_shutdown(ctx), - } - } -} - -impl Connection for MaybeHttpsStream -where - T: Connection, -{ - fn connected(&self) -> Connected { - match self { - MaybeHttpsStream::Http(s) => s.connected(), - MaybeHttpsStream::Https(s) => { - let mut connected = s.get_ref().connected(); - - if s.ssl().selected_alpn_protocol() == Some(b"h2") { - connected = connected.negotiated_h2(); - } - - connected - } - } - } -} - impl fmt::Debug for MaybeHttpsStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/hyper-boring/src/v0.rs b/hyper-boring/src/v0.rs new file mode 100644 index 00000000..172d1640 --- /dev/null +++ b/hyper-boring/src/v0.rs @@ -0,0 +1,345 @@ +use crate::cache::{SessionCache, SessionKey}; +use crate::{key_index, HttpsLayerSettings, MaybeHttpsStream}; +use antidote::Mutex; +use boring::error::ErrorStack; +use boring::ssl::{ + ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, + SslSessionCacheMode, +}; +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; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; +use std::{fmt, io}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tower_layer::Layer; + +/// A Connector using OpenSSL to support `http` and `https` schemes. +#[derive(Clone)] +pub struct HttpsConnector { + http: T, + inner: Inner, +} + +#[cfg(feature = "runtime")] +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, ErrorStack> { + let mut http = HttpConnector::new(); + http.enforce_http(false); + + HttpsLayer::new().map(|l| l.layer(http)) + } +} + +impl HttpsConnector +where + S: Service + Send, + S::Error: Into>, + S::Future: Unpin + Send + 'static, + T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, +{ + /// Creates a new `HttpsConnector`. + /// + /// The session cache configuration of `ssl` will be overwritten. + pub fn with_connector( + http: S, + ssl: SslConnectorBuilder, + ) -> Result, ErrorStack> { + HttpsLayer::with_connector(ssl).map(|l| l.layer(http)) + } + + /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. + pub fn set_callback(&mut self, callback: F) + where + F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.callback = Some(Arc::new(callback)); + } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } +} + +/// A layer which wraps services in an `HttpsConnector`. +pub struct HttpsLayer { + inner: Inner, +} + +#[derive(Clone)] +struct Inner { + ssl: SslConnector, + cache: Arc>, + callback: Option, + ssl_callback: Option, +} + +type Callback = + Arc Result<(), ErrorStack> + Sync + Send>; +type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; + +impl HttpsLayer { + /// Creates a new `HttpsLayer` with default settings. + /// + /// ALPN is configured to support both HTTP/1 and HTTP/1.1. + pub fn new() -> Result { + let mut ssl = SslConnector::builder(SslMethod::tls())?; + + ssl.set_alpn_protos(b"\x02h2\x08http/1.1")?; + + Self::with_connector(ssl) + } + + /// Creates a new `HttpsLayer`. + /// + /// The session cache configuration of `ssl` will be overwritten. + pub fn with_connector(ssl: SslConnectorBuilder) -> Result { + Self::with_connector_and_settings(ssl, Default::default()) + } + + /// Creates a new `HttpsLayer` with settings + pub fn with_connector_and_settings( + mut ssl: SslConnectorBuilder, + settings: HttpsLayerSettings, + ) -> Result { + let cache = Arc::new(Mutex::new(SessionCache::with_capacity( + settings.session_cache_capacity, + ))); + + ssl.set_session_cache_mode(SslSessionCacheMode::CLIENT); + + ssl.set_new_session_callback({ + let cache = cache.clone(); + move |ssl, session| { + if let Some(key) = key_index().ok().and_then(|idx| ssl.ex_data(idx)) { + cache.lock().insert(key.clone(), session); + } + } + }); + + Ok(HttpsLayer { + inner: Inner { + ssl: ssl.build(), + cache, + callback: None, + ssl_callback: None, + }, + }) + } + + /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. + pub fn set_callback(&mut self, callback: F) + where + F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.callback = Some(Arc::new(callback)); + } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } +} + +impl Layer for HttpsLayer { + type Service = HttpsConnector; + + fn layer(&self, inner: S) -> HttpsConnector { + HttpsConnector { + http: inner, + inner: self.inner.clone(), + } + } +} + +impl Inner { + fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { + let mut conf = self.ssl.configure()?; + + if let Some(ref callback) = self.callback { + callback(&mut conf, uri)?; + } + + let key = SessionKey { + host: host.to_string(), + port: uri.port_u16().unwrap_or(443), + }; + + if let Some(session) = self.cache.lock().get(&key) { + unsafe { + conf.set_session(&session)?; + } + } + + let idx = key_index()?; + conf.set_ex_data(idx, key); + + let mut ssl = conf.into_ssl(host)?; + + if let Some(ref ssl_callback) = self.ssl_callback { + ssl_callback(&mut ssl, uri)?; + } + + Ok(ssl) + } +} + +impl Service for HttpsConnector +where + S: Service + Send, + S::Error: Into>, + S::Future: Unpin + Send + 'static, + S::Response: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, +{ + type Response = MaybeHttpsStream; + type Error = Box; + #[allow(clippy::type_complexity)] + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.http.poll_ready(cx).map_err(Into::into) + } + + fn call(&mut self, uri: Uri) -> Self::Future { + let is_tls_scheme = uri + .scheme() + .map(|s| s == &Scheme::HTTPS || s.as_str() == "wss") + .unwrap_or(false); + + let tls_setup = if is_tls_scheme { + Some((self.inner.clone(), uri.clone())) + } else { + None + }; + + let connect = self.http.call(uri); + + let f = async { + let conn = connect.await.map_err(Into::into)?; + + let (inner, uri) = match tls_setup { + Some((inner, uri)) => (inner, uri), + None => return Ok(MaybeHttpsStream::Http(conn)), + }; + + let mut host = uri.host().ok_or("URI missing host")?; + + // If `host` is an IPv6 address, we must strip away the square brackets that surround + // it (otherwise, boring will fail to parse the host as an IP address, eventually + // causing the handshake to fail due a hostname verification error). + if !host.is_empty() { + let last = host.len() - 1; + let mut chars = host.chars(); + + if let (Some('['), Some(']')) = (chars.next(), chars.last()) { + if host[1..last].parse::().is_ok() { + host = &host[1..last]; + } + } + } + + let ssl = inner.setup_ssl(&uri, host)?; + let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) + .connect() + .await?; + + Ok(MaybeHttpsStream::Https(stream)) + }; + + Box::pin(f) + } +} + +impl Connection for MaybeHttpsStream +where + T: Connection, +{ + fn connected(&self) -> Connected { + match self { + MaybeHttpsStream::Http(s) => s.connected(), + MaybeHttpsStream::Https(s) => { + let mut connected = s.get_ref().connected(); + + if s.ssl().selected_alpn_protocol() == Some(b"h2") { + connected = connected.negotiated_h2(); + } + + connected + } + } + } +} + +impl AsyncRead for MaybeHttpsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + fn poll_read( + mut self: Pin<&mut Self>, + ctx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(s) => Pin::new(s).poll_read(ctx, buf), + MaybeHttpsStream::Https(s) => Pin::new(s).poll_read(ctx, buf), + } + } +} + +impl AsyncWrite for MaybeHttpsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + fn poll_write( + mut self: Pin<&mut Self>, + ctx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(s) => Pin::new(s).poll_write(ctx, buf), + MaybeHttpsStream::Https(s) => Pin::new(s).poll_write(ctx, buf), + } + } + + fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(s) => Pin::new(s).poll_flush(ctx), + MaybeHttpsStream::Https(s) => Pin::new(s).poll_flush(ctx), + } + } + + fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(s) => Pin::new(s).poll_shutdown(ctx), + MaybeHttpsStream::Https(s) => Pin::new(s).poll_shutdown(ctx), + } + } +} diff --git a/hyper-boring/src/v1.rs b/hyper-boring/src/v1.rs new file mode 100644 index 00000000..e1f9a43d --- /dev/null +++ b/hyper-boring/src/v1.rs @@ -0,0 +1,350 @@ +use crate::cache::{SessionCache, SessionKey}; +use crate::{key_index, HttpsLayerSettings, MaybeHttpsStream}; +use antidote::Mutex; +use boring::error::ErrorStack; +use boring::ssl::{ + ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, + SslSessionCacheMode, +}; +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; +use std::fmt; +use std::future::Future; +use std::pin::Pin; +use std::sync::Arc; +use std::task::{Context, Poll}; +use std::{io, net}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tower_layer::Layer; +use tower_service::Service; + +/// A Connector using BoringSSL to support `http` and `https` schemes. +#[derive(Clone)] +pub struct HttpsConnector { + http: T, + inner: Inner, +} + +#[cfg(feature = "runtime")] +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, ErrorStack> { + let mut http = HttpConnector::new(); + http.enforce_http(false); + + HttpsLayer::new().map(|l| l.layer(http)) + } +} + +impl HttpsConnector +where + S: Service> + Send, + S::Error: Into>, + S::Future: Unpin + Send + 'static, + T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, +{ + /// Creates a new `HttpsConnector`. + /// + /// The session cache configuration of `ssl` will be overwritten. + pub fn with_connector( + http: S, + ssl: SslConnectorBuilder, + ) -> Result, ErrorStack> { + HttpsLayer::with_connector(ssl).map(|l| l.layer(http)) + } + + /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. + pub fn set_callback(&mut self, callback: F) + where + F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.callback = Some(Arc::new(callback)); + } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } +} + +/// A layer which wraps services in an `HttpsConnector`. +pub struct HttpsLayer { + inner: Inner, +} + +#[derive(Clone)] +struct Inner { + ssl: SslConnector, + cache: Arc>, + callback: Option, + ssl_callback: Option, +} + +type Callback = + Arc Result<(), ErrorStack> + Sync + Send>; +type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; + +impl HttpsLayer { + /// Creates a new `HttpsLayer` with default settings. + /// + /// ALPN is configured to support both HTTP/1 and HTTP/1.1. + pub fn new() -> Result { + let mut ssl = SslConnector::builder(SslMethod::tls())?; + + ssl.set_alpn_protos(b"\x02h2\x08http/1.1")?; + + Self::with_connector(ssl) + } + + /// Creates a new `HttpsLayer`. + /// + /// The session cache configuration of `ssl` will be overwritten. + pub fn with_connector(ssl: SslConnectorBuilder) -> Result { + Self::with_connector_and_settings(ssl, Default::default()) + } + + /// Creates a new `HttpsLayer` with settings + pub fn with_connector_and_settings( + mut ssl: SslConnectorBuilder, + settings: HttpsLayerSettings, + ) -> Result { + let cache = Arc::new(Mutex::new(SessionCache::with_capacity( + settings.session_cache_capacity, + ))); + + ssl.set_session_cache_mode(SslSessionCacheMode::CLIENT); + + ssl.set_new_session_callback({ + let cache = cache.clone(); + move |ssl, session| { + if let Some(key) = key_index().ok().and_then(|idx| ssl.ex_data(idx)) { + cache.lock().insert(key.clone(), session); + } + } + }); + + Ok(HttpsLayer { + inner: Inner { + ssl: ssl.build(), + cache, + callback: None, + ssl_callback: None, + }, + }) + } + + /// Registers a callback which can customize the configuration of each connection. + /// + /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), + /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] + /// instead. + pub fn set_callback(&mut self, callback: F) + where + F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.callback = Some(Arc::new(callback)); + } + + /// Registers a callback which can customize the `Ssl` of each connection. + pub fn set_ssl_callback(&mut self, callback: F) + where + F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, + { + self.inner.ssl_callback = Some(Arc::new(callback)); + } +} + +impl Layer for HttpsLayer { + type Service = HttpsConnector; + + fn layer(&self, inner: S) -> HttpsConnector { + HttpsConnector { + http: inner, + inner: self.inner.clone(), + } + } +} + +impl Inner { + fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { + let mut conf = self.ssl.configure()?; + + if let Some(ref callback) = self.callback { + callback(&mut conf, uri)?; + } + + let key = SessionKey { + host: host.to_string(), + port: uri.port_u16().unwrap_or(443), + }; + + if let Some(session) = self.cache.lock().get(&key) { + unsafe { + conf.set_session(&session)?; + } + } + + let idx = key_index()?; + conf.set_ex_data(idx, key); + + let mut ssl = conf.into_ssl(host)?; + + if let Some(ref ssl_callback) = self.ssl_callback { + ssl_callback(&mut ssl, uri)?; + } + + Ok(ssl) + } +} + +impl Service for HttpsConnector +where + S: Service> + Send, + S::Error: Into>, + S::Future: Unpin + Send + 'static, + T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, +{ + type Response = MaybeHttpsStream; + type Error = Box; + #[allow(clippy::type_complexity)] + type Future = Pin> + Send>>; + + fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { + self.http.poll_ready(cx).map_err(Into::into) + } + + fn call(&mut self, uri: Uri) -> Self::Future { + let is_tls_scheme = uri + .scheme() + .map(|s| s == &Scheme::HTTPS || s.as_str() == "wss") + .unwrap_or(false); + + let tls_setup = if is_tls_scheme { + Some((self.inner.clone(), uri.clone())) + } else { + None + }; + + let connect = self.http.call(uri); + + let f = async { + let conn = connect.await.map_err(Into::into)?.into_inner(); + + let (inner, uri) = match tls_setup { + Some((inner, uri)) => (inner, uri), + None => return Ok(MaybeHttpsStream::Http(conn)), + }; + + let mut host = uri.host().ok_or("URI missing host")?; + + // If `host` is an IPv6 address, we must strip away the square brackets that surround + // it (otherwise, boring will fail to parse the host as an IP address, eventually + // causing the handshake to fail due a hostname verification error). + if !host.is_empty() { + let last = host.len() - 1; + let mut chars = host.chars(); + + if let (Some('['), Some(']')) = (chars.next(), chars.last()) { + if host[1..last].parse::().is_ok() { + host = &host[1..last]; + } + } + } + + let ssl = inner.setup_ssl(&uri, host)?; + let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) + .connect() + .await?; + + Ok(MaybeHttpsStream::Https(stream)) + }; + + Box::pin(f) + } +} + +impl Connection for MaybeHttpsStream +where + T: Connection, +{ + fn connected(&self) -> Connected { + match self { + MaybeHttpsStream::Http(s) => s.connected(), + MaybeHttpsStream::Https(s) => { + let mut connected = s.get_ref().connected(); + + if s.ssl().selected_alpn_protocol() == Some(b"h2") { + connected = connected.negotiated_h2(); + } + + connected + } + } + } +} + +impl Read for MaybeHttpsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: ReadBufCursor<'_>, + ) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_read(cx, buf), + MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_read(cx, buf), + } + } +} + +impl Write for MaybeHttpsStream +where + T: AsyncRead + AsyncWrite + Unpin, +{ + fn poll_write( + mut self: Pin<&mut Self>, + ctx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(inner) => { + Pin::new(&mut TokioIo::new(inner)).poll_write(ctx, buf) + } + MaybeHttpsStream::Https(inner) => { + Pin::new(&mut TokioIo::new(inner)).poll_write(ctx, buf) + } + } + } + + fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_flush(ctx), + MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_flush(ctx), + } + } + + fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { + match &mut *self { + MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_shutdown(ctx), + MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_shutdown(ctx), + } + } +} diff --git a/hyper-boring/test/cert.pem b/hyper-boring/tests/test/cert.pem similarity index 100% rename from hyper-boring/test/cert.pem rename to hyper-boring/tests/test/cert.pem diff --git a/hyper-boring/test/key.pem b/hyper-boring/tests/test/key.pem similarity index 100% rename from hyper-boring/test/key.pem rename to hyper-boring/tests/test/key.pem diff --git a/hyper-boring/test/root-ca.pem b/hyper-boring/tests/test/root-ca.pem similarity index 100% rename from hyper-boring/test/root-ca.pem rename to hyper-boring/tests/test/root-ca.pem diff --git a/hyper-boring/src/test.rs b/hyper-boring/tests/v0.rs similarity index 87% rename from hyper-boring/src/test.rs rename to hyper-boring/tests/v0.rs index 006d5163..08cfce12 100644 --- a/hyper-boring/src/test.rs +++ b/hyper-boring/tests/v0.rs @@ -1,12 +1,12 @@ -use super::*; -use boring::ssl::{SslAcceptor, SslFiletype, SslMethod}; +use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; use futures::StreamExt; -use hyper::client::HttpConnector; -use hyper::server::conn::Http; -use hyper::{service, Response}; -use hyper::{Body, Client}; +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::iter; +use std::{io, iter}; use tokio::net::TcpListener; #[tokio::test] @@ -37,10 +37,10 @@ async fn localhost() { let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); acceptor.set_session_id_context(b"test").unwrap(); acceptor - .set_private_key_file("test/key.pem", SslFiletype::PEM) + .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) .unwrap(); acceptor - .set_certificate_chain_file("test/cert.pem") + .set_certificate_chain_file("tests/test/cert.pem") .unwrap(); let acceptor = acceptor.build(); @@ -69,7 +69,7 @@ async fn localhost() { let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - ssl.set_ca_file("test/root-ca.pem").unwrap(); + ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); use std::fs::File; use std::io::Write; @@ -104,10 +104,10 @@ async fn alpn_h2() { let server = async move { let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); acceptor - .set_certificate_chain_file("test/cert.pem") + .set_certificate_chain_file("tests/test/cert.pem") .unwrap(); acceptor - .set_private_key_file("test/key.pem", SslFiletype::PEM) + .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) .unwrap(); acceptor.set_alpn_select_callback(|_, client| { ssl::select_next_proto(b"\x02h2", client).ok_or(AlpnError::NOACK) @@ -138,7 +138,7 @@ async fn alpn_h2() { let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - ssl.set_ca_file("test/root-ca.pem").unwrap(); + ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); let mut ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); diff --git a/hyper-boring/tests/v1.rs b/hyper-boring/tests/v1.rs new file mode 100644 index 00000000..441caea6 --- /dev/null +++ b/hyper-boring/tests/v1.rs @@ -0,0 +1,160 @@ +#![cfg(feature = "hyper1")] + +use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; +use bytes::Bytes; +use futures::StreamExt; +use http_body_util::{BodyStream, Empty}; +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}; +use std::convert::Infallible; +use std::{io, iter}; +use tokio::net::TcpListener; + +#[tokio::test] +async fn google() { + let ssl = HttpsConnector::new().unwrap(); + let client = Client::builder(TokioExecutor::new()) + .pool_max_idle_per_host(0) + .build::<_, Empty>(ssl); + + for _ in 0..3 { + let resp = client + .get("https://www.google.com".parse().unwrap()) + .await + .expect("connection should succeed"); + let mut body = BodyStream::new(resp.into_body()); + while body.next().await.transpose().unwrap().is_some() {} + } +} + +#[tokio::test] +async fn localhost() { + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let port = addr.port(); + + let server = async move { + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_session_id_context(b"test").unwrap(); + acceptor + .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) + .unwrap(); + acceptor + .set_certificate_chain_file("tests/test/cert.pem") + .unwrap(); + let acceptor = acceptor.build(); + + for _ in 0..3 { + let stream = listener.accept().await.unwrap().0; + let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); + + let service = service::service_fn(|_| async { + Ok::<_, io::Error>(Response::new(>::new())) + }); + + hyper::server::conn::http1::Builder::new() + .keep_alive(false) + .serve_connection(TokioIo::new(stream), service) + .await + .unwrap(); + } + }; + tokio::spawn(server); + + let resolver = + tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); + + let mut connector = HttpConnector::new_with_resolver(resolver); + + connector.enforce_http(false); + + let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); + + ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); + + use std::fs::File; + use std::io::Write; + + let file = File::create("../target/keyfile.log").unwrap(); + ssl.set_keylog_callback(move |_, line| { + let _ = writeln!(&file, "{}", line); + }); + + let ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); + let client = Client::builder(TokioExecutor::new()).build::<_, Empty>(ssl); + + for _ in 0..3 { + let resp = client + .get(format!("https://foobar.com:{}", port).parse().unwrap()) + .await + .unwrap(); + assert!(resp.status().is_success(), "{}", resp.status()); + let mut body = BodyStream::new(resp.into_body()); + while body.next().await.transpose().unwrap().is_some() {} + } +} + +#[tokio::test] +async fn alpn_h2() { + use boring::ssl::{self, AlpnError}; + + let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); + let addr = listener.local_addr().unwrap(); + let port = addr.port(); + + let server = async move { + let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); + acceptor + .set_certificate_chain_file("tests/test/cert.pem") + .unwrap(); + acceptor + .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) + .unwrap(); + acceptor.set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x02h2", client).ok_or(AlpnError::NOACK) + }); + let acceptor = acceptor.build(); + + let stream = listener.accept().await.unwrap().0; + let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); + assert_eq!(stream.ssl().selected_alpn_protocol().unwrap(), b"h2"); + + let service = service::service_fn(|_| async { + Ok::<_, io::Error>(Response::new(>::new())) + }); + + hyper::server::conn::http2::Builder::new(TokioExecutor::new()) + .serve_connection(TokioIo::new(stream), service) + .await + .unwrap(); + }; + tokio::spawn(server); + + let resolver = + tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); + + let mut connector = HttpConnector::new_with_resolver(resolver); + + connector.enforce_http(false); + + let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); + + ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); + + let mut ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); + + ssl.set_ssl_callback(|ssl, _| ssl.set_alpn_protos(b"\x02h2\x08http/1.1")); + + let client = Client::builder(TokioExecutor::new()).build::<_, Empty>(ssl); + + let resp = client + .get(format!("https://foobar.com:{}", port).parse().unwrap()) + .await + .unwrap(); + assert!(resp.status().is_success(), "{}", resp.status()); + let mut body = BodyStream::new(resp.into_body()); + while body.next().await.transpose().unwrap().is_some() {} +} From b7f47dec46c8828c15953ab016cbf0c25fcdae76 Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:20:28 +0200 Subject: [PATCH 16/21] Release 4.10.0 (#274) --- Cargo.toml | 8 ++++---- RELEASE_NOTES | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a067f74f..137ceb8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.9.1" +version = "4.10.0" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.9.1", path = "./boring-sys" } -boring = { version = "4.9.1", path = "./boring" } -tokio-boring = { version = "4.9.1", path = "./tokio-boring" } +boring-sys = { version = "4.10.0", path = "./boring-sys" } +boring = { version = "4.10.0", path = "./boring" } +tokio-boring = { version = "4.10.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 ab943c5f..529d20e1 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,19 @@ +4.10.0 +- 2024-09-18 Implement optional Hyper 1 support in hyper-boring (#246) +- 2024-09-17 Add post-quantum key agreement X25519MLKEM768 +- 2024-09-10 Revert "PQ: fix timing sidechannels and add IPDWing" +- 2024-09-17 Update bindgen to 0.70.1 +- 2024-09-17 Expose SSL(_CTX)_set1_curves_list (#270) +- 2024-09-11 Expose SSL_CTX_set_info_callback (#266) +- 2024-09-03 Use ForeignType::into_ptr wherever applicable +- 2024-08-19 Expose RSAPSS public key Id type +- 2024-08-15 Fix macos FIPS crossbuild +- 2024-08-15 Add tests for X509Ref::subject_key_id, X509Ref::authority_key_id, and X509NameRef::print_ex +- 2024-08-14 Expose X509NameRef::print_ex +- 2024-08-13 Introduce `corresponds` macro from openssl-macros +- 2024-08-14 Introduce ForeignTypeExt and ForeignTypeRefExt +- 2024-08-09 Expose mTLS related APIs +- 2024-08-14 chore(boring-sys): Fix git apply patch on Windows (#261) 4.9.1 - 2024-08-04 Properly handle `Option` in `SslRef::set_curves` From b7eaa5bc95764c670655a00e5f41957409821f81 Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Wed, 18 Sep 2024 22:22:16 +0200 Subject: [PATCH 17/21] Don't support X25519MLKEM768 by default (yet) --- boring/src/ssl/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index 9bc27bc3..9bd1fdec 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -2693,13 +2693,13 @@ impl SslRef { if cfg!(feature = "kx-client-nist-required") { "P256Kyber768Draft00:P-256:P-384:P-521" } else { - "X25519Kyber768Draft00:X25519MLKEM768:X25519:P256Kyber768Draft00:P-256:P-384:P-521" + "X25519Kyber768Draft00:X25519:P256Kyber768Draft00:P-256:P-384:P-521" } } else if cfg!(feature = "kx-client-pq-supported") { if cfg!(feature = "kx-client-nist-required") { "P-256:P-384:P-521:P256Kyber768Draft00" } else { - "X25519:P-256:P-384:P-521:X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00" + "X25519:P-256:P-384:P-521:X25519Kyber768Draft00:P256Kyber768Draft00" } } else { if cfg!(feature = "kx-client-nist-required") { @@ -2715,10 +2715,8 @@ impl SslRef { #[cfg(feature = "kx-safe-default")] fn server_set_default_curves_list(&mut self) { - self.set_curves_list( - "X25519Kyber768Draft00:X25519MLKEM768:P256Kyber768Draft00:X25519:P-256:P-384", - ) - .expect("invalid default server curves list"); + self.set_curves_list("X25519Kyber768Draft00:P256Kyber768Draft00:X25519:P-256:P-384") + .expect("invalid default server curves list"); } /// Returns the [`SslCurve`] used for this `SslRef`. From df1c4f55e6b79fce4e283e35a54cafbf594ca5ba Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:53:02 +0200 Subject: [PATCH 18/21] Release 4.10.1 (#276) --- Cargo.toml | 8 ++++---- RELEASE_NOTES | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 137ceb8b..d5f2002d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.10.0" +version = "4.10.1" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.10.0", path = "./boring-sys" } -boring = { version = "4.10.0", path = "./boring" } -tokio-boring = { version = "4.10.0", path = "./tokio-boring" } +boring-sys = { version = "4.10.1", path = "./boring-sys" } +boring = { version = "4.10.1", path = "./boring" } +tokio-boring = { version = "4.10.1", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 529d20e1..edd13900 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,6 @@ +4.10.1 +- 2024-09-18 Don't support X25519MLKEM768 by default (yet) + 4.10.0 - 2024-09-18 Implement optional Hyper 1 support in hyper-boring (#246) - 2024-09-17 Add post-quantum key agreement X25519MLKEM768 From b1a7434c1917d36e09aee8496cb0c42fc42d7c3b Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Thu, 19 Sep 2024 00:04:04 +0200 Subject: [PATCH 19/21] boring-pq.patch Fix by not updating crypto_test_data.cc crypto_test_data.cc is not included anymore since 2475ef386bd6158151f5ad5c4cf697d02ceca2b0 --- boring-sys/patches/boring-pq.patch | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/boring-sys/patches/boring-pq.patch b/boring-sys/patches/boring-pq.patch index e6601d91..38488004 100644 --- a/boring-sys/patches/boring-pq.patch +++ b/boring-sys/patches/boring-pq.patch @@ -35,7 +35,6 @@ Cf RTG-2076 RTG-2051 RTG-2508 RTG-2707 RTG-2607 RTG-3239 BUILD.generated.bzl | 5 +- BUILD.generated_tests.bzl | 4 - CMakeLists.txt | 4 +- - crypto_test_data.cc | 4 - sources.json | 9 +- src/crypto/CMakeLists.txt | 5 +- src/crypto/kyber/internal.h | 91 - @@ -134,28 +133,6 @@ index faed2befa..931c0e3a8 100644 src/crypto/lhash/lhash.c src/crypto/mem.c src/crypto/obj/obj.c -diff --git a/crypto_test_data.cc b/crypto_test_data.cc -index 2268533f8..19b344af1 100644 ---- a/crypto_test_data.cc -+++ b/crypto_test_data.cc -@@ -74,7 +74,6 @@ - * crypto/fipsmodule/rand/ctrdrbg_vectors.txt \ - * crypto/hmac_extra/hmac_tests.txt \ - * crypto/hpke/hpke_test_vectors.txt \ -- * crypto/kyber/keccak_tests.txt \ - * crypto/kyber/kyber_tests.txt \ - * crypto/pkcs8/test/empty_password.p12 \ - * crypto/pkcs8/test/no_encryption.p12 \ -@@ -5269,9 +5268,6 @@ std::string GetTestData(const char *path) { - if (strcmp(path, "crypto/hpke/hpke_test_vectors.txt") == 0) { - return AssembleString(kData59, kLen59); - } -- if (strcmp(path, "crypto/kyber/keccak_tests.txt") == 0) { -- return AssembleString(kData60, kLen60); -- } - if (strcmp(path, "crypto/kyber/kyber_tests.txt") == 0) { - return AssembleString(kData61, kLen61); - } diff --git a/sources.json b/sources.json index 4c0048e1d..f6ea5c40f 100644 --- a/sources.json From 1a00540c165c5296061e01d775d7488776b7ee5f Mon Sep 17 00:00:00 2001 From: Rushil Mehra <84047965+rushilmehra@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:38:25 +0200 Subject: [PATCH 20/21] Release 4.10.2 (#278) --- Cargo.toml | 8 ++++---- RELEASE_NOTES | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d5f2002d..ffe403b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ resolver = "2" [workspace.package] -version = "4.10.1" +version = "4.10.2" repository = "https://github.com/cloudflare/boring" edition = "2021" @@ -19,9 +19,9 @@ tag-prefix = "" publish = false [workspace.dependencies] -boring-sys = { version = "4.10.1", path = "./boring-sys" } -boring = { version = "4.10.1", path = "./boring" } -tokio-boring = { version = "4.10.1", path = "./tokio-boring" } +boring-sys = { version = "4.10.2", path = "./boring-sys" } +boring = { version = "4.10.2", path = "./boring" } +tokio-boring = { version = "4.10.2", path = "./tokio-boring" } bindgen = { version = "0.70.1", default-features = false, features = ["runtime"] } bytes = "1" diff --git a/RELEASE_NOTES b/RELEASE_NOTES index edd13900..f1531f74 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,6 @@ +4.10.2 +- 2024-09-18 boring-pq.patch Fix by not updating crypto_test_data.cc + 4.10.1 - 2024-09-18 Don't support X25519MLKEM768 by default (yet) From 0596b2dcab5c776cba60e8b28b215545fa6ff9aa Mon Sep 17 00:00:00 2001 From: Yuchen Wu Date: Sat, 21 Sep 2024 12:42:39 -0700 Subject: [PATCH 21/21] Set MSRV to 1.70 (#279) With the bindgen 0.70 upgrade, the default rust target is set to be 1.77, which becomes the de facto MSRV of boring-sys since the change. This change makes sure that the MSRV of boring-sys is kept at 1.70, which is the same as that of bindgen. --- boring-sys/build/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/boring-sys/build/main.rs b/boring-sys/build/main.rs index 05242028..9b65492a 100644 --- a/boring-sys/build/main.rs +++ b/boring-sys/build/main.rs @@ -688,6 +688,7 @@ fn main() { }); let mut builder = bindgen::Builder::default() + .rust_target(bindgen::RustTarget::Stable_1_68) // bindgen MSRV is 1.70, so this is enough .derive_copy(true) .derive_debug(true) .derive_default(true)