From bd80bfc4d7d833a009b0d491679e3faa3ee88973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20R=C3=BCth?= Date: Fri, 24 Nov 2023 19:38:18 +0100 Subject: [PATCH] Enhance error handling and docs --- boring-additions/src/aead/mod.rs | 59 +++++++++---- boring-additions/src/helper.rs | 10 +-- boring-additions/src/hmac/types.rs | 11 ++- boring-rustls-provider/src/aead.rs | 9 +- boring-rustls-provider/src/aead/aes.rs | 6 +- boring-rustls-provider/src/aead/chacha20.rs | 3 +- boring-rustls-provider/src/hash.rs | 19 +++-- boring-rustls-provider/src/helper.rs | 18 ++-- boring-rustls-provider/src/hkdf.rs | 14 ++- boring-rustls-provider/src/hmac.rs | 95 ++++++++++++--------- boring-rustls-provider/src/kx.rs | 32 ++++--- boring-rustls-provider/src/kx/dh.rs | 25 +++--- boring-rustls-provider/src/kx/ex.rs | 76 +++++++++-------- boring-rustls-provider/src/lib.rs | 8 +- boring-rustls-provider/src/sign.rs | 18 ++-- boring-rustls-provider/src/verify/ec.rs | 45 +++++----- boring-rustls-provider/src/verify/ed.rs | 21 +++-- boring-rustls-provider/src/verify/rsa.rs | 32 +++++-- 18 files changed, 295 insertions(+), 206 deletions(-) diff --git a/boring-additions/src/aead/mod.rs b/boring-additions/src/aead/mod.rs index b7a0120..353d440 100644 --- a/boring-additions/src/aead/mod.rs +++ b/boring-additions/src/aead/mod.rs @@ -15,6 +15,7 @@ impl Algorithm { /// AES-128 in Galois Counter Mode. /// /// Note: AES-GCM should only be used with 12-byte (96-bit) nonces. Although it is specified to take a variable-length nonce, nonces with other lengths are effectively randomized, which means one must consider collisions. Unless implementing an existing protocol which has already specified incorrect parameters, only use 12-byte nonces. + #[must_use] pub fn aes_128_gcm() -> Self { Self(unsafe { boring_sys::EVP_aead_aes_128_gcm() }) } @@ -22,38 +23,45 @@ impl Algorithm { /// AES-256 in Galois Counter Mode. /// /// Note: AES-GCM should only be used with 12-byte (96-bit) nonces. Although it is specified to take a variable-length nonce, nonces with other lengths are effectively randomized, which means one must consider collisions. Unless implementing an existing protocol which has already specified incorrect parameters, only use 12-byte nonces. + #[must_use] pub fn aes_256_gcm() -> Self { Self(unsafe { boring_sys::EVP_aead_aes_256_gcm() }) } - /// ChaCha20 and Poly1305 as described in RFC 8439. + /// `ChaCha20` with `Poly1305` as described in RFC 8439. + #[must_use] pub fn chacha20_poly1305() -> Self { Self(unsafe { boring_sys::EVP_aead_chacha20_poly1305() }) } /// ChaCha20-Poly1305 with an extended nonce that makes random generation of nonces safe. #[allow(unused)] + #[must_use] pub fn xchacha20_poly1305() -> Self { Self(unsafe { boring_sys::EVP_aead_xchacha20_poly1305() }) } /// Returns the length, in bytes, of the keys used by aead + #[must_use] pub fn key_length(&self) -> usize { unsafe { boring_sys::EVP_AEAD_key_length(self.0) } } /// Returns the maximum number of additional bytes added by the act of sealing data with aead. + #[must_use] pub fn max_overhead(&self) -> usize { unsafe { boring_sys::EVP_AEAD_max_overhead(self.0) } } /// Returns the maximum tag length when using aead. #[allow(unused)] + #[must_use] pub fn max_tag_len(&self) -> usize { unsafe { boring_sys::EVP_AEAD_max_tag_len(self.0) } } /// Returns the length, in bytes, of the per-message nonce for aead. + #[must_use] pub fn nonce_len(&self) -> usize { unsafe { boring_sys::EVP_AEAD_nonce_length(self.0) } } @@ -66,7 +74,14 @@ pub struct Crypter { } impl Crypter { - pub fn new(aead_alg: Algorithm, key: &[u8]) -> Result { + /// Constructs a new AEAD crypter with the given algorithm and key + /// + /// # Errors + /// Returns the `BoringSSL` error in case of an internal error + /// + /// # Panics + /// * If the key length mismatches the `aead_alg` required key length + pub fn new(aead_alg: &Algorithm, key: &[u8]) -> Result { assert_eq!(aead_alg.key_length(), key.len()); boring_sys::init(); @@ -86,13 +101,25 @@ impl Crypter { Ok(this) } + /// Returns the maximum required overhead in bytes + /// that will be added to a ciphertext, e.g., + /// to hold an authentication tag. + #[must_use] pub fn max_overhead(&self) -> usize { self.max_overhead } - /// Encrypts and authenticates buffer and authenticates associated_data. - /// It writes the ciphertext to buffer and the authentication tag to tag. - /// On success, it returns the actual length of the tag + /// Encrypts and authenticates `buffer` and authenticates `associated_data`. + /// It writes the ciphertext to `buffer` and the authentication tag to `tag`. + /// `tag` needs to have sufficient space, see [`Self::max_overhead()`](fn@Self::max_overhead()) + /// On success, it returns the actual length of the `tag` + /// + /// # Errors + /// In case of an error, returns the `BoringSSL` error + /// + /// # Panics + /// * If the `nonce` is not the expected lenght + /// * If the `tag` has not enough space pub fn seal_in_place( &self, nonce: &[u8], @@ -124,6 +151,14 @@ impl Crypter { Ok(tag_len) } + /// Decrypts and authenticates `buffer` and authenticates `associated_data`. + /// It writes the cleartext to `buffer` and validates using `tag`. + /// + /// # Errors + /// In case of an error, returns the `BoringSSL` error + /// + /// # Panics + /// * if the nonce has the wrong lenght pub fn open_in_place( &self, nonce: &[u8], @@ -157,25 +192,19 @@ mod tests { #[test] fn in_out() { - let key = Crypter::new(super::Algorithm::aes_128_gcm(), &[0u8; 16]).unwrap(); + let key = Crypter::new(&super::Algorithm::aes_128_gcm(), &[0u8; 16]).unwrap(); let nonce = [0u8; 12]; - let associated_data = b"this is signed"; + let associated_data = b"this is authenticated"; let mut buffer = Vec::with_capacity(26); - buffer.push(b'A'); - buffer.push(b'B'); - buffer.push(b'C'); - buffer.push(b'D'); - buffer.push(b'E'); + buffer.extend_from_slice(b"ABCDE"); let mut tag = [0u8; 16]; key.seal_in_place(&nonce, associated_data, buffer.as_mut_slice(), &mut tag) .unwrap(); - println!("Encrypted: {:02X?}, Tag: {:02X?}", buffer, tag); - key.open_in_place(&nonce, associated_data, buffer.as_mut_slice(), &tag[..]) .unwrap(); - println!("Plaintext: {}", String::from_utf8(buffer).unwrap()); + assert_eq!(b"ABCDE", buffer.as_slice()); } } diff --git a/boring-additions/src/helper.rs b/boring-additions/src/helper.rs index 62255cc..8479fca 100644 --- a/boring-additions/src/helper.rs +++ b/boring-additions/src/helper.rs @@ -2,11 +2,11 @@ use std::os::raw::c_int; use boring::error::ErrorStack; -/// Check the value returned from a BoringSSL ffi call +/// Check the value returned from a `BoringSSL` ffi call /// that returns a pointer. /// -/// If the pointer is null, this method returns the BoringSSL -/// ErrorStack as Err, the pointer otherwise. +/// If the pointer is null, this method returns the +/// [`boring::error::ErrorStack`] as Err, the pointer otherwise. pub(crate) fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) @@ -15,10 +15,10 @@ pub(crate) fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { } } -/// Check the value returned from a BoringSSL ffi call that +/// Check the value returned from a `BoringSSL` ffi call that /// returns a integer. /// -/// Returns the BoringSSL Errorstack when the result is <= 0. +/// Returns the [`boring::error::ErrorStack`] when the result is <= 0. /// And forwards the return code otherwise pub(crate) fn cvt(r: c_int) -> Result { if r <= 0 { diff --git a/boring-additions/src/hmac/types.rs b/boring-additions/src/hmac/types.rs index 869e6e5..7601eb9 100644 --- a/boring-additions/src/hmac/types.rs +++ b/boring-additions/src/hmac/types.rs @@ -38,11 +38,14 @@ unsafe impl ForeignType for HmacCtx { impl Clone for HmacCtx { fn clone(&self) -> Self { unsafe { - let ctx = HmacCtx::from_ptr(cvt_p(boring_sys::HMAC_CTX_new()).unwrap()); - - cvt(boring_sys::HMAC_CTX_copy(ctx.as_ptr(), self.0.as_ptr())).unwrap(); - ctx + cvt_p(boring_sys::HMAC_CTX_new()) + .map(|ctx| HmacCtx::from_ptr(ctx)) + .and_then(|ctx| { + cvt(boring_sys::HMAC_CTX_copy(ctx.as_ptr(), self.0.as_ptr()))?; + Ok(ctx) + }) } + .expect("failed cloning hmac ctx") } } diff --git a/boring-rustls-provider/src/aead.rs b/boring-rustls-provider/src/aead.rs index b211418..4235e5b 100644 --- a/boring-rustls-provider/src/aead.rs +++ b/boring-rustls-provider/src/aead.rs @@ -6,7 +6,7 @@ use boring_additions::aead::Algorithm; use rustls::crypto::cipher::{self, make_tls12_aad, make_tls13_aad, Iv}; use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; -use crate::helper::error_stack_to_aead_error; +use crate::helper::log_and_map; pub(crate) mod aes; pub(crate) mod chacha20; @@ -47,6 +47,7 @@ impl AeadCore for BoringAeadCrypter { } impl BoringAeadCrypter { + /// Creates a new aead crypter pub fn new(iv: Iv, key: &[u8], tls_version: ProtocolVersion) -> Result { assert!(match tls_version { #[cfg(feature = "tls12")] @@ -63,7 +64,7 @@ impl BoringAeadCrypter { ); let crypter = BoringAeadCrypter { - crypter: boring_additions::aead::Crypter::new(cipher, key)?, + crypter: boring_additions::aead::Crypter::new(&cipher, key)?, iv, tls_version, phantom: PhantomData, @@ -82,7 +83,7 @@ impl aead::AeadInPlace for BoringAeadCrypter { let mut tag = Tag::::default(); self.crypter .seal_in_place(nonce, associated_data, buffer, &mut tag) - .map_err(|e| error_stack_to_aead_error("seal_in_place", e))?; + .map_err(|e| log_and_map("seal_in_place", e, aead::Error))?; Ok(tag) } @@ -96,7 +97,7 @@ impl aead::AeadInPlace for BoringAeadCrypter { ) -> aead::Result<()> { self.crypter .open_in_place(nonce, associated_data, buffer, tag) - .map_err(|e| error_stack_to_aead_error("open_in_place", e))?; + .map_err(|e| log_and_map("open_in_place", e, aead::Error))?; Ok(()) } } diff --git a/boring-rustls-provider/src/aead/aes.rs b/boring-rustls-provider/src/aead/aes.rs index aed003d..457cd6a 100644 --- a/boring-rustls-provider/src/aead/aes.rs +++ b/boring-rustls-provider/src/aead/aes.rs @@ -3,11 +3,10 @@ use aead::consts::{U12, U16}; use boring_additions::aead::Algorithm; use rustls::{crypto::cipher, ConnectionTrafficSecrets}; +/// Aes128 AEAD cipher pub struct Aes128 {} impl BoringAead for Aes128 {} -unsafe impl Send for Aes128 {} -unsafe impl Sync for Aes128 {} impl BoringCipher for Aes128 { fn new_cipher() -> Algorithm { @@ -37,11 +36,10 @@ impl aead::AeadCore for Aes128 { type CiphertextOverhead = U16; } +/// Aes256 AEAD cipher pub struct Aes256 {} impl BoringAead for Aes256 {} -unsafe impl Send for Aes256 {} -unsafe impl Sync for Aes256 {} impl BoringCipher for Aes256 { fn new_cipher() -> Algorithm { diff --git a/boring-rustls-provider/src/aead/chacha20.rs b/boring-rustls-provider/src/aead/chacha20.rs index 4b15462..6179a80 100644 --- a/boring-rustls-provider/src/aead/chacha20.rs +++ b/boring-rustls-provider/src/aead/chacha20.rs @@ -6,11 +6,10 @@ use aead::{ use boring_additions::aead::Algorithm; use rustls::{crypto::cipher, ConnectionTrafficSecrets}; +/// `ChaCha20` with `Poly1305` cipher pub struct ChaCha20Poly1305 {} impl BoringAead for ChaCha20Poly1305 {} -unsafe impl Send for ChaCha20Poly1305 {} -unsafe impl Sync for ChaCha20Poly1305 {} impl BoringCipher for ChaCha20Poly1305 { fn new_cipher() -> Algorithm { diff --git a/boring-rustls-provider/src/hash.rs b/boring-rustls-provider/src/hash.rs index 825e9f2..f576c6c 100644 --- a/boring-rustls-provider/src/hash.rs +++ b/boring-rustls-provider/src/hash.rs @@ -1,3 +1,4 @@ +use boring::hash::{Hasher, MessageDigest}; use rustls::crypto::hash; pub const SHA256: &dyn hash::Hash = &Hash(boring::nid::Nid::SHA256); @@ -7,8 +8,8 @@ pub struct Hash(pub boring::nid::Nid); impl hash::Hash for Hash { fn start(&self) -> Box { - let digest = boring::hash::MessageDigest::from_nid(self.0).unwrap(); - let hasher = boring::hash::Hasher::new(digest).unwrap(); + let digest = MessageDigest::from_nid(self.0).expect("failed getting hash digest"); + let hasher = Hasher::new(digest).expect("failed getting hasher"); Box::new(HasherContext(hasher)) } @@ -21,24 +22,26 @@ impl hash::Hash for Hash { fn algorithm(&self) -> hash::HashAlgorithm { match self.0 { boring::nid::Nid::SHA256 => hash::HashAlgorithm::SHA256, + boring::nid::Nid::SHA384 => hash::HashAlgorithm::SHA384, + boring::nid::Nid::SHA512 => hash::HashAlgorithm::SHA512, _ => unimplemented!(), } } fn output_len(&self) -> usize { - boring::hash::MessageDigest::from_nid(self.0) - .unwrap() + MessageDigest::from_nid(self.0) + .expect("failed getting digest") .size() } } -struct HasherContext(boring::hash::Hasher); +struct HasherContext(Hasher); impl hash::Context for HasherContext { fn fork_finish(&self) -> hash::Output { let mut cloned = self.0.clone(); - hash::Output::new(&cloned.finish().unwrap()[..]) + hash::Output::new(&cloned.finish().expect("failed finishing hash")[..]) } fn fork(&self) -> Box { @@ -46,11 +49,11 @@ impl hash::Context for HasherContext { } fn finish(mut self: Box) -> hash::Output { - hash::Output::new(&self.0.finish().unwrap()[..]) + hash::Output::new(&self.0.finish().expect("failed finishing hash")[..]) } fn update(&mut self, data: &[u8]) { - self.0.update(data).unwrap(); + self.0.update(data).expect("failed adding data to hash"); } } diff --git a/boring-rustls-provider/src/helper.rs b/boring-rustls-provider/src/helper.rs index 1f15c02..36a6318 100644 --- a/boring-rustls-provider/src/helper.rs +++ b/boring-rustls-provider/src/helper.rs @@ -4,11 +4,11 @@ use boring::error::ErrorStack; #[cfg(feature = "log")] use log::trace; -/// Check the value returned from a BoringSSL ffi call +/// Check the value returned from a `BoringSSL` ffi call /// that returns a pointer. /// -/// If the pointer is null, this method returns the BoringSSL -/// ErrorStack as Err, the pointer otherwise. +/// If the pointer is null, this method returns the +/// [`boring::error::ErrorStack`] as Err, the pointer otherwise. pub(crate) fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) @@ -17,10 +17,10 @@ pub(crate) fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { } } -/// Check the value returned from a BoringSSL ffi call that +/// Check the value returned from a `BoringSSL` ffi call that /// returns a integer. /// -/// Returns the BoringSSL Errorstack when the result is <= 0. +/// Returns the [`boring::error::ErrorStack`] when the result is <= 0. /// And forwards the return code otherwise pub(crate) fn cvt(r: c_int) -> Result { if r <= 0 { @@ -30,17 +30,13 @@ pub(crate) fn cvt(r: c_int) -> Result { } } -pub(crate) fn error_stack_to_aead_error(func: &'static str, e: ErrorStack) -> aead::Error { - map_error_stack(func, e, aead::Error) -} - #[cfg(feature = "log")] -pub(crate) fn map_error_stack(func: &'static str, e: ErrorStack, mapped: T) -> T { +pub(crate) fn log_and_map(func: &'static str, e: E, mapped: T) -> T { trace!("failed {}, error: {}", func, e); mapped } #[cfg(not(feature = "log"))] -pub(crate) fn map_error_stack(func: &'static str, e: ErrorStack, mapped: T) -> T { +pub(crate) fn log_and_map(func: &'static str, e: E, mapped: T) -> T { mapped } diff --git a/boring-rustls-provider/src/hkdf.rs b/boring-rustls-provider/src/hkdf.rs index 367fa28..64c37c4 100644 --- a/boring-rustls-provider/src/hkdf.rs +++ b/boring-rustls-provider/src/hkdf.rs @@ -5,10 +5,15 @@ use rustls::crypto::tls13::{self, Hkdf as RustlsHkdf}; use crate::helper::{cvt, cvt_p}; +/// A trait that is required for a Hkdf function pub trait BoringHash: Send + Sync { + /// Instantiate a new digest using + /// the hash function that this trait + /// is implemented for. fn new_hash() -> MessageDigest; } +/// SHA256-based for Hkdf pub struct Sha256(); impl BoringHash for Sha256 { fn new_hash() -> MessageDigest { @@ -16,6 +21,7 @@ impl BoringHash for Sha256 { } } +/// SHA384-based for Hkdf pub struct Sha384(); impl BoringHash for Sha384 { fn new_hash() -> MessageDigest { @@ -23,9 +29,12 @@ impl BoringHash for Sha384 { } } +/// A Hmac-based key derivation function +/// using T as the hash function pub struct Hkdf(PhantomData); impl Hkdf { + /// A default Hkdf implementation pub const DEFAULT: Self = Self(PhantomData); } @@ -130,7 +139,7 @@ impl RustlsHkdf for Hkdf { } } -pub struct HkdfExpander { +struct HkdfExpander { prk: [u8; boring_sys::EVP_MAX_MD_SIZE as usize], prk_len: usize, digest: MessageDigest, @@ -181,7 +190,8 @@ impl tls13::HkdfExpander for HkdfExpander { let mut output = [0u8; boring_sys::EVP_MAX_MD_SIZE as usize]; let output_len = self.hash_len(); - self.expand_slice(info, &mut output[..output_len]).unwrap(); + self.expand_slice(info, &mut output[..output_len]) + .expect("failed hkdf expand"); tls13::OkmBlock::new(&output[..output_len]) } diff --git a/boring-rustls-provider/src/hmac.rs b/boring-rustls-provider/src/hmac.rs index 9c4a0cc..5729ac0 100644 --- a/boring-rustls-provider/src/hmac.rs +++ b/boring-rustls-provider/src/hmac.rs @@ -7,30 +7,34 @@ use rustls::crypto; use crate::helper::{cvt, cvt_p}; +/// A SHA256-based Hmac #[allow(unused)] pub const SHA256: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA256); +/// A SHA384-based Hmac pub const SHA384: &dyn crypto::hmac::Hmac = &BoringHmac(boring::nid::Nid::SHA384); -pub struct BoringHmac(pub boring::nid::Nid); +struct BoringHmac(pub boring::nid::Nid); impl crypto::hmac::Hmac for BoringHmac { fn with_key(&self, key: &[u8]) -> Box { - Box::new(unsafe { - let ctx = HmacCtx::from_ptr(cvt_p(boring_sys::HMAC_CTX_new()).unwrap()); - - let md = boring::hash::MessageDigest::from_nid(self.0).unwrap(); - - BoringHmacKey { - ctx, - md, - key: key.to_vec(), - } + let ctx = unsafe { + HmacCtx::from_ptr( + cvt_p(boring_sys::HMAC_CTX_new()).expect("failed getting hmac context"), + ) + }; + + let md = MessageDigest::from_nid(self.0).expect("failed getting digest"); + + Box::new(BoringHmacKey { + ctx, + md, + key: key.to_vec(), }) } fn hash_output_len(&self) -> usize { - boring::hash::MessageDigest::from_nid(self.0) - .unwrap() + MessageDigest::from_nid(self.0) + .expect("failed getting digest") .size() } } @@ -42,11 +46,9 @@ struct BoringHmacKey { key: Vec, } -impl crypto::hmac::Key for BoringHmacKey { - fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { - let mut out = [0u8; 32]; - - crypto::hmac::Tag::new(unsafe { +impl BoringHmacKey { + fn init(&self) { + unsafe { // initialize a new hmac cvt(boring_sys::HMAC_Init_ex( self.ctx.as_ptr(), @@ -55,41 +57,50 @@ impl crypto::hmac::Key for BoringHmacKey { self.md.as_ptr(), ptr::null_mut(), )) - .unwrap(); - - cvt(boring_sys::HMAC_Update( - self.ctx.as_ptr(), - first.as_ptr(), - first.len(), - )) - .unwrap(); - - for m in middle { - cvt(boring_sys::HMAC_Update( - self.ctx.as_ptr(), - m.as_ptr(), - m.len(), - )) - .unwrap(); - } + } + .expect("failed initializing hmac"); + } + fn update(&self, bytes: &[u8]) { + unsafe { cvt(boring_sys::HMAC_Update( self.ctx.as_ptr(), - last.as_ptr(), - last.len(), + bytes.as_ptr(), + bytes.len(), )) - .unwrap(); + } + .expect("failed updating hmac"); + } - let mut out_len = 0; + fn finish(&self, out: &mut [u8]) -> usize { + let mut out_len = 0; + unsafe { cvt(boring_sys::HMAC_Final( self.ctx.as_ptr(), out.as_mut_ptr(), &mut out_len, )) - .unwrap(); + } + .expect("failed hmac final"); + out_len as usize + } +} - &out[..out_len as usize] - }) +impl crypto::hmac::Key for BoringHmacKey { + fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { + self.init(); + + self.update(first); + for m in middle { + self.update(m); + } + + self.update(last); + + let mut out = [0u8; 32]; + let out_len = self.finish(&mut out); + + crypto::hmac::Tag::new(&out[..out_len]) } fn tag_len(&self) -> usize { diff --git a/boring-rustls-provider/src/kx.rs b/boring-rustls-provider/src/kx.rs index 16ab2be..8ec7276 100644 --- a/boring-rustls-provider/src/kx.rs +++ b/boring-rustls-provider/src/kx.rs @@ -1,6 +1,6 @@ use rustls::crypto::{self, ActiveKeyExchange}; -use crate::helper::map_error_stack; +use crate::helper::log_and_map; mod dh; mod ex; @@ -11,13 +11,14 @@ enum DhKeyType { FFDHE2048, } +/// A X25519-based key exchange #[derive(Debug)] pub struct X25519; impl crypto::SupportedKxGroup for X25519 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(ex::ExKeyExchange::with_x25519().map_err(|e| { - map_error_stack("X25519.start", e, crypto::GetRandomFailed) + Ok(Box::new(ex::KeyExchange::with_x25519().map_err(|e| { + log_and_map("X25519.start", e, crypto::GetRandomFailed) })?)) } @@ -26,13 +27,14 @@ impl crypto::SupportedKxGroup for X25519 { } } +/// A X448-based key exchange #[derive(Debug)] pub struct X448; impl crypto::SupportedKxGroup for X448 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(ex::ExKeyExchange::with_x448().map_err(|e| { - map_error_stack("X448.start", e, crypto::GetRandomFailed) + Ok(Box::new(ex::KeyExchange::with_x448().map_err(|e| { + log_and_map("X448.start", e, crypto::GetRandomFailed) })?)) } @@ -41,13 +43,14 @@ impl crypto::SupportedKxGroup for X448 { } } +/// A secp256r1-based key exchange #[derive(Debug)] pub struct Secp256r1; impl crypto::SupportedKxGroup for Secp256r1 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(ex::ExKeyExchange::with_secp256r1().map_err( - |e| map_error_stack("Secp256r1.start", e, crypto::GetRandomFailed), + Ok(Box::new(ex::KeyExchange::with_secp256r1().map_err( + |e| log_and_map("Secp256r1.start", e, crypto::GetRandomFailed), )?)) } @@ -56,13 +59,14 @@ impl crypto::SupportedKxGroup for Secp256r1 { } } +/// A secp384r1-based key exchange #[derive(Debug)] pub struct Secp384r1; impl crypto::SupportedKxGroup for Secp384r1 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(ex::ExKeyExchange::with_secp384r1().map_err( - |e| map_error_stack("Secp384r1.start", e, crypto::GetRandomFailed), + Ok(Box::new(ex::KeyExchange::with_secp384r1().map_err( + |e| log_and_map("Secp384r1.start", e, crypto::GetRandomFailed), )?)) } @@ -71,13 +75,14 @@ impl crypto::SupportedKxGroup for Secp384r1 { } } +/// A secp521r1-based key exchange #[derive(Debug)] pub struct Secp521r1; impl crypto::SupportedKxGroup for Secp521r1 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(ex::ExKeyExchange::with_secp521r1().map_err( - |e| map_error_stack("Secp521r1.start", e, crypto::GetRandomFailed), + Ok(Box::new(ex::KeyExchange::with_secp521r1().map_err( + |e| log_and_map("Secp521r1.start", e, crypto::GetRandomFailed), )?)) } @@ -86,13 +91,14 @@ impl crypto::SupportedKxGroup for Secp521r1 { } } +/// A ffedhe2048-based key exchange #[derive(Debug)] pub struct FfDHe2048; impl crypto::SupportedKxGroup for FfDHe2048 { fn start(&self) -> Result, rustls::Error> { - Ok(Box::new(dh::DhKeyExchange::generate_ffdhe_2048().map_err( - |e| map_error_stack("FfDHe2048.start", e, crypto::GetRandomFailed), + Ok(Box::new(dh::KeyExchange::generate_ffdhe_2048().map_err( + |e| log_and_map("FfDHe2048.start", e, crypto::GetRandomFailed), )?)) } diff --git a/boring-rustls-provider/src/kx/dh.rs b/boring-rustls-provider/src/kx/dh.rs index beaffd9..b004e5b 100644 --- a/boring-rustls-provider/src/kx/dh.rs +++ b/boring-rustls-provider/src/kx/dh.rs @@ -2,17 +2,19 @@ use boring::{dh::Dh, error::ErrorStack, pkey::Private}; use foreign_types::ForeignType; use rustls::crypto; -use crate::helper::{cvt, cvt_p, map_error_stack}; +use crate::helper::{cvt, cvt_p, log_and_map}; use super::DhKeyType; -pub struct DhKeyExchange { +/// This type can be used to perform a +/// Diffie-Hellman key exchange. +pub struct KeyExchange { dh: Dh, pub_bytes: Vec, key_type: DhKeyType, } -impl DhKeyExchange { +impl KeyExchange { // Generate a new KeyExchange with a random FFDHE_2048 private key pub fn generate_ffdhe_2048() -> Result { let mut me = Self { @@ -49,9 +51,11 @@ impl DhKeyExchange { /// Generate a shared secret with the other's raw public key fn diffie_hellman(&self, raw_public_key: &[u8]) -> Result, ErrorStack> { - let peer = boring::bn::BigNum::from_slice(raw_public_key).unwrap(); + let peer = boring::bn::BigNum::from_slice(raw_public_key)?; + let secret_len = unsafe { cvt(boring_sys::DH_size(self.dh.as_ptr()))? } as usize; let mut secret = vec![0u8; secret_len]; + let secret_len = unsafe { cvt(boring_sys::DH_compute_key_padded( secret.as_mut_ptr(), @@ -59,12 +63,13 @@ impl DhKeyExchange { self.dh.as_ptr(), ))? } as usize; + secret.truncate(secret_len); Ok(secret) } } -impl crypto::ActiveKeyExchange for DhKeyExchange { +impl crypto::ActiveKeyExchange for KeyExchange { fn complete( self: Box, peer_pub_key: &[u8], @@ -78,8 +83,8 @@ impl crypto::ActiveKeyExchange for DhKeyExchange { Ok(crypto::SharedSecret::from( self.diffie_hellman(peer_pub_key) .map_err(|e| { - map_error_stack( - "dh.diffie_hellman", + log_and_map( + "dh::KeyExchange::diffie_hellman", e, rustls::PeerMisbehaved::InvalidKeyShare, ) @@ -102,13 +107,13 @@ impl crypto::ActiveKeyExchange for DhKeyExchange { #[cfg(test)] mod tests { - use crate::kx::dh::DhKeyExchange; + use crate::kx::dh::KeyExchange; use rustls::crypto::ActiveKeyExchange; #[test] fn test_derive_dh() { - let alice = DhKeyExchange::generate_ffdhe_2048().unwrap(); - let bob = DhKeyExchange::generate_ffdhe_2048().unwrap(); + let alice = KeyExchange::generate_ffdhe_2048().unwrap(); + let bob = KeyExchange::generate_ffdhe_2048().unwrap(); let shared_secret1 = alice.diffie_hellman(bob.pub_key()).unwrap(); let shared_secret2 = bob.diffie_hellman(alice.pub_key()).unwrap(); diff --git a/boring-rustls-provider/src/kx/ex.rs b/boring-rustls-provider/src/kx/ex.rs index f234d00..cd628a5 100644 --- a/boring-rustls-provider/src/kx/ex.rs +++ b/boring-rustls-provider/src/kx/ex.rs @@ -14,56 +14,59 @@ use foreign_types::ForeignType; use rustls::crypto; use spki::der::Decode; -use crate::helper::{cvt, cvt_p, map_error_stack}; +use crate::helper::{cvt, cvt_p, log_and_map}; use super::DhKeyType; -pub struct ExKeyExchange { +/// This type can be used to perform an +/// Eliptic Curve or Edwards Curve key +/// exchange. +pub struct KeyExchange { own_key: PKey, pub_bytes: Vec, key_type: DhKeyType, } -impl ExKeyExchange { - /// Creates a new KeyExchange using a random - /// private key for the X25519 Edwards curve +impl KeyExchange { + /// Creates a new `KeyExchange` using a random + /// private key for the `X25519` Edwards curve pub fn with_x25519() -> Result { Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X25519)) } - /// Creates a new KeyExchange using a random - /// private key for the X448 Edwards curve + /// Creates a new `KeyExchange` using a random + /// private key for the `X448` Edwards curve pub fn with_x448() -> Result { Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X448)) } - /// Creates a new KeyExchange using a random - /// private key for sepc256r1 curve - /// Also known as X9_62_PRIME256V1 + /// Creates a new `KeyExchange` using a random + /// private key for `sepc256r1` curve + /// Also known as `X9_62_PRIME256V1` pub fn with_secp256r1() -> Result { Self::ec_from_curve(Nid::X9_62_PRIME256V1) } - /// Creates a new KeyExchange using a random - /// private key for sepc384r1 curve + /// Creates a new `KeyExchange` using a random + /// private key for `sepc384r1` curve pub fn with_secp384r1() -> Result { Self::ec_from_curve(Nid::SECP384R1) } - /// Creates a new KeyExchange using a random - /// private key for sep521r1 curve + /// Creates a new `KeyExchange` using a random + /// private key for `sep521r1` curve pub fn with_secp521r1() -> Result { Self::ec_from_curve(Nid::SECP521R1) } - /// Allows getting a new KeyExchange using Eliptic Curves + /// Allows getting a new `KeyExchange` using Eliptic Curves /// on the specified curve fn ec_from_curve(nid: Nid) -> Result { let ec_group = EcGroup::from_curve_name(nid)?; let ec_key = EcKey::generate(&ec_group)?; let own_key = PKey::from_ec_key(ec_key)?; - let pub_bytes = Self::raw_public_key(&own_key); + let pub_bytes = Self::raw_public_key(&own_key)?; Ok(Self { own_key, pub_bytes, @@ -71,7 +74,7 @@ impl ExKeyExchange { }) } - /// Allows getting a new KeyExchange using Edwards Curves + /// Allows getting a new `KeyExchange` using Edwards Curves /// on the specified curve fn ed_from_curve(nid: Nid) -> Result { let pkey_ctx = unsafe { @@ -91,7 +94,7 @@ impl ExKeyExchange { PKey::from_ptr(pkey) }; - let pub_bytes = Self::raw_public_key(&own_key); + let pub_bytes = Self::raw_public_key(&own_key)?; Ok(Self { own_key, @@ -101,14 +104,19 @@ impl ExKeyExchange { } /// Decodes a SPKI public key to it's raw public key component - fn raw_public_key(pkey: &PKeyRef) -> Vec { - let spki = pkey.public_key_to_der().unwrap(); + fn raw_public_key(pkey: &PKeyRef) -> Result, ErrorStack> { + let spki = pkey.public_key_to_der()?; // parse the key - let key = spki::SubjectPublicKeyInfoRef::from_der(spki.as_ref()).unwrap(); + let pkey = spki::SubjectPublicKeyInfoRef::from_der(spki.as_ref()) + .expect("failed parsing spki bytes"); // return the raw public key as a new vec - Vec::from(key.subject_public_key.as_bytes().unwrap()) + Ok(Vec::from( + pkey.subject_public_key + .as_bytes() + .expect("failed getting raw spki bytes"), + )) } /// Derives a shared secret using the peer's raw public key @@ -117,13 +125,11 @@ impl ExKeyExchange { DhKeyType::EC((group, _)) => { let mut bn_ctx = boring::bn::BigNumContext::new()?; - let point = crate::verify::ec::ec_point(group, &mut bn_ctx, peer_pub_key)?; + let point = crate::verify::ec::get_ec_point(group, &mut bn_ctx, peer_pub_key)?; - crate::verify::ec::ec_public_key(group, point.as_ref())? - } - DhKeyType::ED(nid) => { - crate::verify::ed::ed_public_key(peer_pub_key, Nid::from_raw(*nid))? + crate::verify::ec::create_public_key(group, point.as_ref())? } + DhKeyType::ED(nid) => crate::verify::ed::public_key(peer_pub_key, Nid::from_raw(*nid))?, _ => unimplemented!(), }; @@ -135,7 +141,7 @@ impl ExKeyExchange { } } -impl crypto::ActiveKeyExchange for ExKeyExchange { +impl crypto::ActiveKeyExchange for KeyExchange { fn complete( self: Box, peer_pub_key: &[u8], @@ -143,8 +149,8 @@ impl crypto::ActiveKeyExchange for ExKeyExchange { self.diffie_hellman(peer_pub_key) .map(|x| crypto::SharedSecret::from(x.as_slice())) .map_err(|e| { - map_error_stack( - "ex.diffie_hellman", + log_and_map( + "ex::KeyExchange::diffie_hellman", e, rustls::Error::PeerMisbehaved(rustls::PeerMisbehaved::InvalidKeyShare), ) @@ -169,13 +175,13 @@ impl crypto::ActiveKeyExchange for ExKeyExchange { #[cfg(test)] mod tests { - use super::ExKeyExchange; + use super::KeyExchange; use rustls::crypto::ActiveKeyExchange; #[test] fn test_derive_ec() { - let alice = Box::new(ExKeyExchange::with_secp256r1().unwrap()); - let bob = ExKeyExchange::with_secp256r1().unwrap(); + let alice = Box::new(KeyExchange::with_secp256r1().unwrap()); + let bob = KeyExchange::with_secp256r1().unwrap(); assert_eq!( alice.diffie_hellman(bob.pub_key()).unwrap(), @@ -185,8 +191,8 @@ mod tests { #[test] fn test_derive_ed() { - let alice = Box::new(ExKeyExchange::with_x25519().unwrap()); - let bob = ExKeyExchange::with_x25519().unwrap(); + let alice = Box::new(KeyExchange::with_x25519().unwrap()); + let bob = KeyExchange::with_x25519().unwrap(); assert_eq!( alice.diffie_hellman(bob.pub_key()).unwrap(), diff --git a/boring-rustls-provider/src/lib.rs b/boring-rustls-provider/src/lib.rs index 91a60c1..54c460e 100644 --- a/boring-rustls-provider/src/lib.rs +++ b/boring-rustls-provider/src/lib.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use helper::log_and_map; use rustls::{ crypto::{CryptoProvider, GetRandomFailed, SupportedKxGroup}, SupportedCipherSuite, @@ -18,6 +19,7 @@ mod tls12; mod tls13; mod verify; +/// The boringssl-based Rustls Crypto provider pub static PROVIDER: &'static dyn CryptoProvider = &Provider; #[derive(Debug)] @@ -25,7 +27,7 @@ struct Provider; impl CryptoProvider for Provider { fn fill_random(&self, bytes: &mut [u8]) -> Result<(), GetRandomFailed> { - boring::rand::rand_bytes(bytes).map_err(|_| GetRandomFailed) + boring::rand::rand_bytes(bytes).map_err(|e| log_and_map("rand_bytes", e, GetRandomFailed)) } fn default_cipher_suites(&self) -> &'static [SupportedCipherSuite] { @@ -54,9 +56,7 @@ impl CryptoProvider for Provider { &self, key_der: PrivateKeyDer<'static>, ) -> Result, rustls::Error> { - sign::BoringPrivateKey::try_from(key_der) - .map(|x| Arc::new(x) as _) - .map_err(|_| rustls::Error::General("invalid private key".into())) + sign::BoringPrivateKey::try_from(key_der).map(|x| Arc::new(x) as _) } fn signature_verification_algorithms(&self) -> rustls::WebPkiSupportedAlgorithms { diff --git a/boring-rustls-provider/src/sign.rs b/boring-rustls-provider/src/sign.rs index 9e93760..736ddd1 100644 --- a/boring-rustls-provider/src/sign.rs +++ b/boring-rustls-provider/src/sign.rs @@ -9,6 +9,8 @@ use boring::{ use rustls::{sign::SigningKey, SignatureScheme}; use rustls_pki_types::PrivateKeyDer; +use crate::helper::log_and_map; + const ALL_RSA_SCHEMES: &[SignatureScheme] = &[ SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, @@ -24,6 +26,8 @@ const ALL_EC_SCHEMES: &[SignatureScheme] = &[ SignatureScheme::ECDSA_NISTP521_SHA512, ]; +/// An abstraction over a boringssl private key +/// used for signing #[derive(Debug)] pub struct BoringPrivateKey(Arc>, rustls::SignatureAlgorithm); @@ -33,10 +37,12 @@ impl TryFrom> for BoringPrivateKey { fn try_from(value: PrivateKeyDer<'static>) -> Result { let pkey = match value { PrivateKeyDer::Pkcs8(der) => { - boring::pkey::PKey::private_key_from_pkcs8(der.secret_pkcs8_der()).map_err(|_| ()) + boring::pkey::PKey::private_key_from_pkcs8(der.secret_pkcs8_der()) + .map_err(|e| log_and_map("private_key_from_pkcs8", e, ())) } PrivateKeyDer::Pkcs1(der) => { - boring::pkey::PKey::private_key_from_der(der.secret_pkcs1_der()).map_err(|_| ()) + boring::pkey::PKey::private_key_from_der(der.secret_pkcs1_der()) + .map_err(|e| log_and_map("private_key_from_der", e, ())) } _ => Err(()), } @@ -120,6 +126,7 @@ impl SigningKey for BoringPrivateKey { } } +/// A boringssl-based Signer #[derive(Debug)] pub struct BoringSigner(Arc>, rustls::SignatureScheme); @@ -156,10 +163,7 @@ impl BoringSigner { ec_signer_from_params(self.0.as_ref(), MessageDigest::sha512()) } - SignatureScheme::ED25519 => { - Signer::new_without_digest(self.0.as_ref()).expect("failed getting signer") - } - SignatureScheme::ED448 => { + SignatureScheme::ED25519 | SignatureScheme::ED448 => { Signer::new_without_digest(self.0.as_ref()).expect("failed getting signer") } @@ -178,7 +182,7 @@ impl rustls::sign::Signer for BoringSigner { let toatl_len = signer .sign(&mut msg_with_sig[..]) - .map_err(|_| rustls::Error::General("failed signing".into()))?; + .map_err(|e| log_and_map("sign", e, rustls::Error::General("failed signing".into())))?; msg_with_sig.truncate(toatl_len); Ok(msg_with_sig) } diff --git a/boring-rustls-provider/src/verify/ec.rs b/boring-rustls-provider/src/verify/ec.rs index d3567ac..5000065 100644 --- a/boring-rustls-provider/src/verify/ec.rs +++ b/boring-rustls-provider/src/verify/ec.rs @@ -2,6 +2,8 @@ use boring::{error::ErrorStack, hash::MessageDigest}; use rustls::SignatureScheme; use rustls_pki_types::{InvalidSignature, SignatureVerificationAlgorithm}; +use crate::helper; + pub struct BoringEcVerifier(SignatureScheme); impl BoringEcVerifier { @@ -17,11 +19,15 @@ impl SignatureVerificationAlgorithm for BoringEcVerifier { message: &[u8], signature: &[u8], ) -> Result<(), rustls_pki_types::InvalidSignature> { - let (group, mut bn_ctx) = setup_ec_key(self.0); - let ec_point = - ec_point(group.as_ref(), bn_ctx.as_mut(), public_key).map_err(|_| InvalidSignature)?; - let public_key = - ec_public_key(group.as_ref(), ec_point.as_ref()).map_err(|_| InvalidSignature)?; + let (group, mut bn_ctx) = setup_ec_key(self.0) + .map_err(|e| helper::log_and_map("setup_ec_key", e, InvalidSignature))?; + + let ec_point = get_ec_point(group.as_ref(), bn_ctx.as_mut(), public_key) + .map_err(|e| helper::log_and_map("ec_point", e, InvalidSignature))?; + + let public_key = create_public_key(group.as_ref(), ec_point.as_ref()) + .map_err(|e| helper::log_and_map("ec_public_key", e, InvalidSignature))?; + let mut verifier = match self.0 { SignatureScheme::ECDSA_NISTP256_SHA256 => { ec_verifier_from_params(public_key.as_ref(), MessageDigest::sha256()) @@ -34,9 +40,11 @@ impl SignatureVerificationAlgorithm for BoringEcVerifier { } _ => unimplemented!(), - }; + } + .map_err(|e| helper::log_and_map("ec_verifier_from_params", e, InvalidSignature))?; + verifier.verify_oneshot(signature, message).map_or_else( - |_| Err(InvalidSignature), + |e| Err(helper::log_and_map("verify_oneshot", e, InvalidSignature)), |res| if res { Ok(()) } else { Err(InvalidSignature) }, ) } @@ -74,30 +82,27 @@ impl SignatureVerificationAlgorithm for BoringEcVerifier { fn ec_verifier_from_params( key: &boring::pkey::PKeyRef, digest: MessageDigest, -) -> boring::sign::Verifier { - let verifier = boring::sign::Verifier::new(digest, key).expect("failed getting verifier"); - - verifier +) -> Result { + boring::sign::Verifier::new(digest, key) } -fn group_for_scheme(scheme: SignatureScheme) -> boring::ec::EcGroup { +fn group_for_scheme(scheme: SignatureScheme) -> Result { let nid = match scheme { SignatureScheme::ECDSA_NISTP256_SHA256 => boring::nid::Nid::X9_62_PRIME256V1, SignatureScheme::ECDSA_NISTP384_SHA384 => boring::nid::Nid::SECP384R1, SignatureScheme::ECDSA_NISTP521_SHA512 => boring::nid::Nid::SECP521R1, _ => unimplemented!(), }; - boring::ec::EcGroup::from_curve_name(nid).expect("failed getting verify curve") + boring::ec::EcGroup::from_curve_name(nid) } -fn setup_ec_key(scheme: SignatureScheme) -> (boring::ec::EcGroup, boring::bn::BigNumContext) { - ( - group_for_scheme(scheme), - boring::bn::BigNumContext::new().unwrap(), - ) +fn setup_ec_key( + scheme: SignatureScheme, +) -> Result<(boring::ec::EcGroup, boring::bn::BigNumContext), ErrorStack> { + Ok((group_for_scheme(scheme)?, boring::bn::BigNumContext::new()?)) } -pub(crate) fn ec_point( +pub(crate) fn get_ec_point( group: &boring::ec::EcGroupRef, bignum_ctx: &mut boring::bn::BigNumContextRef, spki_spk: &[u8], @@ -105,7 +110,7 @@ pub(crate) fn ec_point( boring::ec::EcPoint::from_bytes(group, spki_spk, bignum_ctx) } -pub(crate) fn ec_public_key( +pub(crate) fn create_public_key( group: &boring::ec::EcGroupRef, ec_point: &boring::ec::EcPointRef, ) -> Result, ErrorStack> { diff --git a/boring-rustls-provider/src/verify/ed.rs b/boring-rustls-provider/src/verify/ed.rs index 4917e2e..6cfa21b 100644 --- a/boring-rustls-provider/src/verify/ed.rs +++ b/boring-rustls-provider/src/verify/ed.rs @@ -5,7 +5,7 @@ use foreign_types::ForeignType; use rustls::SignatureScheme; use rustls_pki_types::{InvalidSignature, SignatureVerificationAlgorithm}; -use crate::helper::cvt_p; +use crate::helper::{cvt_p, log_and_map}; pub struct BoringEdVerifier(SignatureScheme); @@ -21,9 +21,11 @@ impl SignatureVerificationAlgorithm for BoringEdVerifier { message: &[u8], signature: &[u8], ) -> Result<(), rustls_pki_types::InvalidSignature> { - let public_key = - ed_public_key_for_scheme(public_key, self.0).map_err(|_| InvalidSignature)?; - let mut verifier = ed_verifier_from_params(public_key.as_ref()); + let public_key = ed_public_key_for_scheme(public_key, self.0) + .map_err(|e| log_and_map("ed_public_key_for_scheme", e, InvalidSignature))?; + + let mut verifier = ed_verifier_from_params(public_key.as_ref()) + .map_err(|e| log_and_map("ed_verifier_from_params", e, InvalidSignature))?; verifier.verify_oneshot(signature, message).map_or_else( |_| Err(InvalidSignature), @@ -50,11 +52,8 @@ impl SignatureVerificationAlgorithm for BoringEdVerifier { fn ed_verifier_from_params( key: &boring::pkey::PKeyRef, -) -> boring::sign::Verifier { - let verifier = - boring::sign::Verifier::new_without_digest(key).expect("failed getting verifier"); - - verifier +) -> Result { + boring::sign::Verifier::new_without_digest(key) } fn ed_public_key_for_scheme( @@ -66,10 +65,10 @@ fn ed_public_key_for_scheme( SignatureScheme::ED448 => boring_sys::EVP_PKEY_ED448, _ => unimplemented!(), }); - ed_public_key(spki_spk, nid) + public_key(spki_spk, nid) } -pub fn ed_public_key( +pub fn public_key( spki_spk: &[u8], nid: boring::nid::Nid, ) -> Result, ErrorStack> { diff --git a/boring-rustls-provider/src/verify/rsa.rs b/boring-rustls-provider/src/verify/rsa.rs index 6b16d62..82844d2 100644 --- a/boring-rustls-provider/src/verify/rsa.rs +++ b/boring-rustls-provider/src/verify/rsa.rs @@ -1,8 +1,16 @@ -use boring::{hash::MessageDigest, rsa::Padding, sign::RsaPssSaltlen}; +use boring::{ + bn::BigNum, + hash::MessageDigest, + pkey::PKey, + rsa::{Padding, Rsa}, + sign::RsaPssSaltlen, +}; use rustls::SignatureScheme; use rustls_pki_types::{InvalidSignature, SignatureVerificationAlgorithm}; use spki::der::Reader; +use crate::helper::log_and_map; + pub struct BoringRsaVerifier(SignatureScheme); impl BoringRsaVerifier { @@ -105,18 +113,24 @@ fn rsa_verifier_from_params( pub(crate) fn decode_spki_spk( spki_spk: &[u8], -) -> Result, InvalidSignature> { +) -> Result, InvalidSignature> { // public_key: unfortunately this is not a whole SPKI, but just the key material. // decode the two integers manually. - let mut reader = spki::der::SliceReader::new(spki_spk).map_err(|_| InvalidSignature)?; - let ne: [spki::der::asn1::UintRef; 2] = reader.decode().map_err(|_| InvalidSignature)?; + let mut reader = spki::der::SliceReader::new(spki_spk) + .map_err(|e| log_and_map("SliceReader::new", e, InvalidSignature))?; + let ne: [spki::der::asn1::UintRef; 2] = reader + .decode() + .map_err(|e| log_and_map("SliceReader::decode", e, InvalidSignature))?; - let n = boring::bn::BigNum::from_slice(ne[0].as_bytes()).map_err(|_| InvalidSignature)?; - let e = boring::bn::BigNum::from_slice(ne[1].as_bytes()).map_err(|_| InvalidSignature)?; + let n = BigNum::from_slice(ne[0].as_bytes()) + .map_err(|e| log_and_map("BigNum::from_slice", e, InvalidSignature))?; + let e = BigNum::from_slice(ne[1].as_bytes()) + .map_err(|e| log_and_map("BigNum::from_slice", e, InvalidSignature))?; - boring::pkey::PKey::from_rsa( - boring::rsa::Rsa::from_public_components(n, e).map_err(|_| InvalidSignature)?, + PKey::from_rsa( + Rsa::from_public_components(n, e) + .map_err(|e| log_and_map("Rsa::from_public_components", e, InvalidSignature))?, ) - .map_err(|_| InvalidSignature) + .map_err(|e| log_and_map("Pkey::from_rsa", e, InvalidSignature)) }