diff --git a/boring-additions/src/aead/mod.rs b/boring-additions/src/aead/mod.rs index 6ad4594..7c46556 100644 --- a/boring-additions/src/aead/mod.rs +++ b/boring-additions/src/aead/mod.rs @@ -1,9 +1,14 @@ use std::ptr; use boring::error::ErrorStack; +use foreign_types::ForeignType; + +mod types; use crate::helper::{cvt, cvt_p}; +pub use self::types::*; + pub struct Algorithm(*const boring_sys::EVP_AEAD); impl Algorithm { @@ -55,14 +60,11 @@ impl Algorithm { } pub struct Crypter { - ctx: *mut boring_sys::EVP_AEAD_CTX, + ctx: EvpAeadCtx, max_overhead: usize, nonce_len: usize, } -unsafe impl Send for Crypter {} -unsafe impl Sync for Crypter {} - impl Crypter { pub fn new(aead_alg: Algorithm, key: &[u8]) -> Result { assert_eq!(aead_alg.key_length(), key.len()); @@ -70,12 +72,12 @@ impl Crypter { let this = unsafe { Self { - ctx: cvt_p(boring_sys::EVP_AEAD_CTX_new( + ctx: EvpAeadCtx::from_ptr(cvt_p(boring_sys::EVP_AEAD_CTX_new( aead_alg.0, key.as_ptr(), key.len(), boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as usize, - ))?, + ))?), max_overhead: aead_alg.max_overhead(), nonce_len: aead_alg.nonce_len(), } @@ -104,7 +106,7 @@ impl Crypter { let mut tag_len = tag.len(); unsafe { cvt(boring_sys::EVP_AEAD_CTX_seal_scatter( - self.ctx, + self.ctx.as_ptr(), buffer.as_mut_ptr(), tag.as_mut_ptr(), &mut tag_len, @@ -133,7 +135,7 @@ impl Crypter { unsafe { cvt(boring_sys::EVP_AEAD_CTX_open_gather( - self.ctx, + self.ctx.as_ptr(), buffer.as_mut_ptr(), nonce.as_ptr(), nonce.len(), @@ -149,14 +151,6 @@ impl Crypter { } } -impl Drop for Crypter { - fn drop(&mut self) { - unsafe { - boring_sys::EVP_AEAD_CTX_free(self.ctx); - } - } -} - #[cfg(test)] mod tests { use super::Crypter; diff --git a/boring-additions/src/aead/types.rs b/boring-additions/src/aead/types.rs new file mode 100644 index 0000000..c5f842a --- /dev/null +++ b/boring-additions/src/aead/types.rs @@ -0,0 +1,56 @@ +use std::{ + ops::{Deref, DerefMut}, + ptr::NonNull, +}; + +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; + +pub struct EvpAeadCtxRef(Opaque); + +unsafe impl ForeignTypeRef for EvpAeadCtxRef { + type CType = boring_sys::EVP_AEAD_CTX; +} + +unsafe impl Sync for EvpAeadCtxRef {} +unsafe impl Send for EvpAeadCtxRef {} + +pub struct EvpAeadCtx(NonNull); + +unsafe impl Sync for EvpAeadCtx {} +unsafe impl Send for EvpAeadCtx {} + +unsafe impl ForeignType for EvpAeadCtx { + type CType = boring_sys::EVP_AEAD_CTX; + + type Ref = EvpAeadCtxRef; + + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Self(NonNull::new_unchecked(ptr)) + } + + fn as_ptr(&self) -> *mut Self::CType { + self.0.as_ptr() + } +} + +impl Drop for EvpAeadCtx { + fn drop(&mut self) { + unsafe { + boring_sys::EVP_AEAD_CTX_free(self.0.as_ptr()); + } + } +} + +impl Deref for EvpAeadCtx { + type Target = EvpAeadCtxRef; + + fn deref(&self) -> &EvpAeadCtxRef { + unsafe { EvpAeadCtxRef::from_ptr(self.as_ptr()) } + } +} + +impl DerefMut for EvpAeadCtx { + fn deref_mut(&mut self) -> &mut EvpAeadCtxRef { + unsafe { EvpAeadCtxRef::from_ptr_mut(self.as_ptr()) } + } +} diff --git a/boring-additions/src/evp/mod.rs b/boring-additions/src/evp/mod.rs new file mode 100644 index 0000000..b5d12e1 --- /dev/null +++ b/boring-additions/src/evp/mod.rs @@ -0,0 +1,3 @@ +mod types; + +pub use types::*; diff --git a/boring-additions/src/evp/types.rs b/boring-additions/src/evp/types.rs new file mode 100644 index 0000000..c0388e1 --- /dev/null +++ b/boring-additions/src/evp/types.rs @@ -0,0 +1,60 @@ +use std::{ + ops::{Deref, DerefMut}, + ptr::NonNull, +}; + +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; + +pub struct EvpPkeyCtxRef(Opaque); + +unsafe impl ForeignTypeRef for EvpPkeyCtxRef { + type CType = boring_sys::EVP_PKEY_CTX; +} + +unsafe impl Sync for EvpPkeyCtxRef {} +unsafe impl Send for EvpPkeyCtxRef {} + +unsafe impl Sync for EvpPkeyCtx {} +unsafe impl Send for EvpPkeyCtx {} + +pub struct EvpPkeyCtx(NonNull); +unsafe impl ForeignType for EvpPkeyCtx { + type CType = boring_sys::EVP_PKEY_CTX; + + type Ref = EvpPkeyCtxRef; + + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Self(NonNull::new_unchecked(ptr)) + } + + fn as_ptr(&self) -> *mut Self::CType { + self.0.as_ptr() + } +} +impl Drop for EvpPkeyCtx { + fn drop(&mut self) { + unsafe { + boring_sys::EVP_PKEY_CTX_free(self.0.as_ptr()); + } + } +} + +impl core::fmt::Debug for EvpPkeyCtx { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("EvpPkeyCtx").field(&self.0).finish() + } +} + +impl Deref for EvpPkeyCtx { + type Target = EvpPkeyCtxRef; + + fn deref(&self) -> &EvpPkeyCtxRef { + unsafe { EvpPkeyCtxRef::from_ptr(self.as_ptr()) } + } +} + +impl DerefMut for EvpPkeyCtx { + fn deref_mut(&mut self) -> &mut EvpPkeyCtxRef { + unsafe { EvpPkeyCtxRef::from_ptr_mut(self.as_ptr()) } + } +} diff --git a/boring-additions/src/hmac/mod.rs b/boring-additions/src/hmac/mod.rs new file mode 100644 index 0000000..b5d12e1 --- /dev/null +++ b/boring-additions/src/hmac/mod.rs @@ -0,0 +1,3 @@ +mod types; + +pub use types::*; diff --git a/boring-additions/src/hmac/types.rs b/boring-additions/src/hmac/types.rs new file mode 100644 index 0000000..869e6e5 --- /dev/null +++ b/boring-additions/src/hmac/types.rs @@ -0,0 +1,69 @@ +use std::{ + ops::{Deref, DerefMut}, + ptr::NonNull, +}; + +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; + +use crate::helper::{cvt, cvt_p}; + +pub struct HmacCtxRef(Opaque); + +unsafe impl ForeignTypeRef for HmacCtxRef { + type CType = boring_sys::HMAC_CTX; +} + +unsafe impl Sync for HmacCtxRef {} +unsafe impl Send for HmacCtxRef {} + +pub struct HmacCtx(NonNull); + +unsafe impl Sync for HmacCtx {} +unsafe impl Send for HmacCtx {} + +unsafe impl ForeignType for HmacCtx { + type CType = boring_sys::HMAC_CTX; + + type Ref = HmacCtxRef; + + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { + Self(NonNull::new_unchecked(ptr)) + } + + fn as_ptr(&self) -> *mut Self::CType { + self.0.as_ptr() + } +} + +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 + } + } +} + +impl Drop for HmacCtx { + fn drop(&mut self) { + unsafe { + boring_sys::HMAC_CTX_free(self.0.as_ptr()); + } + } +} + +impl Deref for HmacCtx { + type Target = HmacCtxRef; + + fn deref(&self) -> &HmacCtxRef { + unsafe { Self::Target::from_ptr(self.as_ptr()) } + } +} + +impl DerefMut for HmacCtx { + fn deref_mut(&mut self) -> &mut HmacCtxRef { + unsafe { HmacCtxRef::from_ptr_mut(self.as_ptr()) } + } +} diff --git a/boring-additions/src/lib.rs b/boring-additions/src/lib.rs index c98fc88..8636b09 100644 --- a/boring-additions/src/lib.rs +++ b/boring-additions/src/lib.rs @@ -1,2 +1,4 @@ pub mod aead; +pub mod evp; pub(crate) mod helper; +pub mod hmac; diff --git a/boring-rustls-provider/src/aead.rs b/boring-rustls-provider/src/aead.rs index 7fa01c6..eec923d 100644 --- a/boring-rustls-provider/src/aead.rs +++ b/boring-rustls-provider/src/aead.rs @@ -36,9 +36,6 @@ pub(crate) struct BoringAeadCrypter { phantom: PhantomData, } -unsafe impl Sync for BoringAeadCrypter {} -unsafe impl Send for BoringAeadCrypter {} - impl AeadCore for BoringAeadCrypter { // inherit all properties from the Algorithm @@ -185,9 +182,6 @@ where pub(crate) struct Aead(PhantomData); -unsafe impl Sync for Aead {} -unsafe impl Send for Aead {} - impl Aead { pub const DEFAULT: Self = Self(PhantomData); } diff --git a/boring-rustls-provider/src/hmac.rs b/boring-rustls-provider/src/hmac.rs index e52d13f..9c4a0cc 100644 --- a/boring-rustls-provider/src/hmac.rs +++ b/boring-rustls-provider/src/hmac.rs @@ -1,6 +1,8 @@ use std::{os::raw::c_void, ptr}; use boring::hash::MessageDigest; +use boring_additions::hmac::HmacCtx; +use foreign_types::ForeignType; use rustls::crypto; use crate::helper::{cvt, cvt_p}; @@ -14,7 +16,7 @@ pub struct BoringHmac(pub boring::nid::Nid); impl crypto::hmac::Hmac for BoringHmac { fn with_key(&self, key: &[u8]) -> Box { Box::new(unsafe { - let ctx = cvt_p(boring_sys::HMAC_CTX_new()).unwrap(); + let ctx = HmacCtx::from_ptr(cvt_p(boring_sys::HMAC_CTX_new()).unwrap()); let md = boring::hash::MessageDigest::from_nid(self.0).unwrap(); @@ -33,31 +35,13 @@ impl crypto::hmac::Hmac for BoringHmac { } } +#[derive(Clone)] struct BoringHmacKey { - ctx: *mut boring_sys::HMAC_CTX, + ctx: HmacCtx, md: MessageDigest, key: Vec, } -impl Clone for BoringHmacKey { - fn clone(&self) -> Self { - let ctx = unsafe { - let ctx = cvt_p(boring_sys::HMAC_CTX_new()).unwrap(); - - cvt(boring_sys::HMAC_CTX_copy(ctx, self.ctx)).unwrap(); - ctx - }; - Self { - ctx, - md: self.md.clone(), - key: self.key.clone(), - } - } -} - -unsafe impl Sync for BoringHmacKey {} -unsafe impl Send for BoringHmacKey {} - impl crypto::hmac::Key for BoringHmacKey { fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { let mut out = [0u8; 32]; @@ -65,7 +49,7 @@ impl crypto::hmac::Key for BoringHmacKey { crypto::hmac::Tag::new(unsafe { // initialize a new hmac cvt(boring_sys::HMAC_Init_ex( - self.ctx, + self.ctx.as_ptr(), self.key.as_ptr() as *const c_void, self.key.len(), self.md.as_ptr(), @@ -74,21 +58,31 @@ impl crypto::hmac::Key for BoringHmacKey { .unwrap(); cvt(boring_sys::HMAC_Update( - self.ctx, + self.ctx.as_ptr(), first.as_ptr(), first.len(), )) .unwrap(); for m in middle { - cvt(boring_sys::HMAC_Update(self.ctx, m.as_ptr(), m.len())).unwrap(); + cvt(boring_sys::HMAC_Update( + self.ctx.as_ptr(), + m.as_ptr(), + m.len(), + )) + .unwrap(); } - cvt(boring_sys::HMAC_Update(self.ctx, last.as_ptr(), last.len())).unwrap(); + cvt(boring_sys::HMAC_Update( + self.ctx.as_ptr(), + last.as_ptr(), + last.len(), + )) + .unwrap(); let mut out_len = 0; cvt(boring_sys::HMAC_Final( - self.ctx, + self.ctx.as_ptr(), out.as_mut_ptr(), &mut out_len, )) @@ -103,14 +97,6 @@ impl crypto::hmac::Key for BoringHmacKey { } } -impl Drop for BoringHmacKey { - fn drop(&mut self) { - unsafe { - boring_sys::HMAC_CTX_free(self.ctx); - } - } -} - #[cfg(test)] mod tests { use super::SHA256; diff --git a/boring-rustls-provider/src/kx.rs b/boring-rustls-provider/src/kx.rs index 14ead07..3595b36 100644 --- a/boring-rustls-provider/src/kx.rs +++ b/boring-rustls-provider/src/kx.rs @@ -1,11 +1,10 @@ use rustls::crypto::{self, ActiveKeyExchange}; mod dh; -mod evp; +mod ex; -#[derive(Debug)] enum DhKeyType { - EC(i32), + EC((boring::ec::EcGroup, i32)), ED(i32), FFDHE2048, } @@ -16,7 +15,7 @@ pub struct X25519; impl crypto::SupportedKxGroup for X25519 { fn start(&self) -> Result, rustls::Error> { Ok(Box::new( - evp::BoringEvpKey::generate_x25519().map_err(|_| crypto::GetRandomFailed)?, + ex::ExKeyExchange::with_x25519().map_err(|_| crypto::GetRandomFailed)?, )) } @@ -31,7 +30,7 @@ pub struct X448; impl crypto::SupportedKxGroup for X448 { fn start(&self) -> Result, rustls::Error> { Ok(Box::new( - evp::BoringEvpKey::generate_x448().map_err(|_| crypto::GetRandomFailed)?, + ex::ExKeyExchange::with_x448().map_err(|_| crypto::GetRandomFailed)?, )) } @@ -46,7 +45,7 @@ pub struct Secp256r1; impl crypto::SupportedKxGroup for Secp256r1 { fn start(&self) -> Result, rustls::Error> { Ok(Box::new( - evp::BoringEvpKey::generate_secp256r1().map_err(|_| crypto::GetRandomFailed)?, + ex::ExKeyExchange::with_secp256r1().map_err(|_| crypto::GetRandomFailed)?, )) } @@ -61,7 +60,7 @@ pub struct Secp384r1; impl crypto::SupportedKxGroup for Secp384r1 { fn start(&self) -> Result, rustls::Error> { Ok(Box::new( - evp::BoringEvpKey::generate_secp384r1().map_err(|_| crypto::GetRandomFailed)?, + ex::ExKeyExchange::with_secp384r1().map_err(|_| crypto::GetRandomFailed)?, )) } @@ -76,7 +75,7 @@ pub struct Secp521r1; impl crypto::SupportedKxGroup for Secp521r1 { fn start(&self) -> Result, rustls::Error> { Ok(Box::new( - evp::BoringEvpKey::generate_secp521r1().map_err(|_| crypto::GetRandomFailed)?, + ex::ExKeyExchange::with_secp521r1().map_err(|_| crypto::GetRandomFailed)?, )) } @@ -104,28 +103,6 @@ impl crypto::SupportedKxGroup for FfDHe2048 { mod tests { use rustls::crypto::ActiveKeyExchange; - #[test] - fn test_derive_ed() { - let alice = super::evp::BoringEvpKey::generate_x25519().unwrap(); - let bob = super::evp::BoringEvpKey::generate_x25519().unwrap(); - - let shared_secret1 = alice.diffie_hellman(&bob.pub_key()).unwrap(); - let shared_secret2 = bob.diffie_hellman(&alice.pub_key()).unwrap(); - - assert_eq!(shared_secret1, shared_secret2) - } - - #[test] - fn test_derive_ec() { - let alice = super::evp::BoringEvpKey::generate_secp256r1().unwrap(); - let bob = super::evp::BoringEvpKey::generate_secp256r1().unwrap(); - - let shared_secret1 = alice.diffie_hellman(&bob.pub_key()).unwrap(); - let shared_secret2 = bob.diffie_hellman(&alice.pub_key()).unwrap(); - - assert_eq!(shared_secret1, shared_secret2) - } - #[test] fn test_derive_dh() { let alice = super::dh::BoringDhKey::generate_ffdhe_2048().unwrap(); diff --git a/boring-rustls-provider/src/kx/dh.rs b/boring-rustls-provider/src/kx/dh.rs index 24b7353..bf19e69 100644 --- a/boring-rustls-provider/src/kx/dh.rs +++ b/boring-rustls-provider/src/kx/dh.rs @@ -1,4 +1,4 @@ -use boring::error::ErrorStack; +use boring::{dh::Dh, error::ErrorStack, pkey::Private}; use foreign_types::ForeignType; use rustls::crypto; @@ -7,7 +7,7 @@ use crate::helper::{cvt, cvt_p}; use super::DhKeyType; pub struct BoringDhKey { - dh: boring::dh::Dh, + dh: Dh, pub_bytes: Vec, key_type: DhKeyType, } @@ -15,7 +15,7 @@ pub struct BoringDhKey { impl BoringDhKey { pub fn generate_ffdhe_2048() -> Result { let mut me = Self { - dh: unsafe { boring::dh::Dh::from_ptr(cvt_p(boring_sys::DH_get_rfc7919_2048())?) }, + dh: unsafe { Dh::from_ptr(cvt_p(boring_sys::DH_get_rfc7919_2048())?) }, pub_bytes: Vec::new(), key_type: DhKeyType::FFDHE2048, }; diff --git a/boring-rustls-provider/src/kx/evp.rs b/boring-rustls-provider/src/kx/evp.rs deleted file mode 100644 index 8319fde..0000000 --- a/boring-rustls-provider/src/kx/evp.rs +++ /dev/null @@ -1,315 +0,0 @@ -use std::{ - mem::MaybeUninit, - ops::{Deref, DerefMut}, - ptr::{self, NonNull}, -}; - -use boring::error::ErrorStack; -use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; -use rustls::crypto; -use spki::der::Decode; - -use crate::helper::{cvt, cvt_p}; - -use super::DhKeyType; - -pub struct BoringEvpPkeyCtxRef(Opaque); - -unsafe impl ForeignTypeRef for BoringEvpPkeyCtxRef { - type CType = boring_sys::EVP_PKEY_CTX; -} - -unsafe impl Sync for BoringEvpPkeyCtxRef {} -unsafe impl Send for BoringEvpPkeyCtxRef {} - -unsafe impl Sync for BoringEvpPkeyCtx {} -unsafe impl Send for BoringEvpPkeyCtx {} - -pub struct BoringEvpPkeyCtx(NonNull); -unsafe impl ForeignType for BoringEvpPkeyCtx { - type CType = boring_sys::EVP_PKEY_CTX; - - type Ref = BoringEvpPkeyCtxRef; - - unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { - Self(NonNull::new_unchecked(ptr)) - } - - fn as_ptr(&self) -> *mut Self::CType { - self.0.as_ptr() - } -} -impl Drop for BoringEvpPkeyCtx { - fn drop(&mut self) { - unsafe { - boring_sys::EVP_PKEY_CTX_free(self.0.as_ptr()); - } - } -} - -impl core::fmt::Debug for BoringEvpPkeyCtx { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("BoringEvpPkeyCtx").field(&self.0).finish() - } -} - -impl Deref for BoringEvpPkeyCtx { - type Target = BoringEvpPkeyCtxRef; - - fn deref(&self) -> &BoringEvpPkeyCtxRef { - unsafe { BoringEvpPkeyCtxRef::from_ptr(self.as_ptr()) } - } -} - -impl DerefMut for BoringEvpPkeyCtx { - fn deref_mut(&mut self) -> &mut BoringEvpPkeyCtxRef { - unsafe { BoringEvpPkeyCtxRef::from_ptr_mut(self.as_ptr()) } - } -} - -#[derive(Debug)] -pub struct BoringEvpKey { - /// the private key context for deriving shared secrets - dctx: BoringEvpPkeyCtx, - - key_type: DhKeyType, - - pub_bytes: Vec, -} - -unsafe impl Sync for BoringEvpKey {} -unsafe impl Send for BoringEvpKey {} - -impl BoringEvpKey { - pub fn generate_x25519() -> Result { - unsafe { - Self::generate_with_ctx( - DhKeyType::ED(boring_sys::NID_X25519), - Self::generate_ctx_from_nid(boring_sys::NID_X25519)?, - ) - } - } - - pub fn generate_x448() -> Result { - unsafe { - Self::generate_with_ctx( - DhKeyType::ED(boring_sys::NID_X448), - Self::generate_ctx_from_nid(boring_sys::NID_X448)?, - ) - } - } - - pub fn generate_secp256r1() -> Result { - unsafe { - let pctx = Self::generate_ctx_with_ec_curve(boring_sys::NID_X9_62_prime256v1)?; - Self::generate_with_ctx(DhKeyType::EC(boring_sys::NID_X9_62_prime256v1), pctx) - } - } - pub fn generate_secp384r1() -> Result { - unsafe { - let pctx = Self::generate_ctx_with_ec_curve(boring_sys::NID_secp384r1)?; - Self::generate_with_ctx(DhKeyType::EC(boring_sys::NID_secp384r1), pctx) - } - } - pub fn generate_secp521r1() -> Result { - unsafe { - let pctx = Self::generate_ctx_with_ec_curve(boring_sys::NID_secp521r1)?; - Self::generate_with_ctx(DhKeyType::EC(boring_sys::NID_secp521r1), pctx) - } - } - - unsafe fn generate_ctx_with_ec_curve(curve_nid: i32) -> Result { - boring_sys::init(); - - let pctx = BoringEvpPkeyCtx::from_ptr(cvt_p(boring_sys::EVP_PKEY_CTX_new_id( - boring_sys::EVP_PKEY_EC, - ptr::null_mut(), - ))?); - - // The following function is for generating parameters - cvt(boring_sys::EVP_PKEY_paramgen_init(pctx.as_ptr()))?; - - // Set the curve - cvt(boring_sys::EVP_PKEY_CTX_set_ec_paramgen_curve_nid( - pctx.as_ptr(), - curve_nid, - ))?; - - // Used a named curve which has max compatiblity according man page - cvt(boring_sys::EVP_PKEY_CTX_set_ec_param_enc( - pctx.as_ptr(), - boring_sys::OPENSSL_EC_NAMED_CURVE, - ))?; - - // generate parameters - let mut pkey = MaybeUninit::<*mut boring_sys::EVP_PKEY>::new(ptr::null_mut()).assume_init(); - cvt(boring_sys::EVP_PKEY_paramgen(pctx.as_ptr(), &mut pkey))?; - let pkey: boring::pkey::PKey = boring::pkey::PKey::from_ptr(pkey); - - Ok(BoringEvpPkeyCtx::from_ptr( - // ctx will take ownership of pkey - cvt_p(boring_sys::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut())).expect("failed"), - )) - } - - fn generate_ctx_from_nid(nid: i32) -> Result { - boring_sys::init(); - Ok(unsafe { - BoringEvpPkeyCtx::from_ptr(cvt_p(boring_sys::EVP_PKEY_CTX_new_id( - nid, - ptr::null_mut(), - ))?) - }) - } - - unsafe fn generate_with_ctx( - key_type: DhKeyType, - pctx: BoringEvpPkeyCtx, - ) -> Result { - let mut pkey = MaybeUninit::<*mut boring_sys::EVP_PKEY>::new(ptr::null_mut()).assume_init(); - - cvt(boring_sys::EVP_PKEY_keygen_init(pctx.as_ptr()))?; - - cvt(boring_sys::EVP_PKEY_keygen(pctx.as_ptr(), &mut pkey))?; - let pkey: boring::pkey::PKey = boring::pkey::PKey::from_ptr(pkey); - - let dctx = BoringEvpPkeyCtx::from_ptr( - // dctx will take ownership of pkey, we can safely drop it - cvt_p(boring_sys::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?, - ); - - let pub_bytes = Self::raw_public_key(pkey.as_ref())?; - - Ok(Self { - dctx, - key_type, - pub_bytes, - }) - } - - fn raw_public_key( - pkey: &boring::pkey::PKeyRef, - ) -> Result, ErrorStack> { - let key_len = unsafe { - // figure out how many bytes we need for the key - cvt(boring_sys::i2d_PUBKEY(pkey.as_ptr(), ptr::null_mut()))? as usize - }; - let mut spki = vec![0u8; key_len]; - unsafe { - // write the key to spki - cvt(boring_sys::i2d_PUBKEY( - pkey.as_ptr(), - &mut spki.as_mut_ptr(), - ))?; - } - // parse the key - let key = spki::SubjectPublicKeyInfoRef::from_der(spki.as_ref()).unwrap(); - - // return the raw public key as a new vec - Ok(Vec::from(key.subject_public_key.as_bytes().unwrap())) - } - - pub fn diffie_hellman(&self, raw_public_key: &[u8]) -> Result, ErrorStack> { - match self.key_type { - DhKeyType::EC(nid) => self.diffie_hellman_ec(nid, raw_public_key), - DhKeyType::ED(nid) => self.diffie_hellman_ed(nid, raw_public_key), - _ => unimplemented!(), - } - } - - fn diffie_hellman_ec(&self, nid: i32, raw_public_key: &[u8]) -> Result, ErrorStack> { - // this is only the key data not the algo identifier etc - let group = boring::ec::EcGroup::from_curve_name(boring::nid::Nid::from_raw(nid))?; - let mut bn_ctx = boring::bn::BigNumContext::new()?; - let point = - crate::verify::ec::ec_point(group.as_ref(), &mut bn_ctx, raw_public_key).unwrap(); - - let peerkey = crate::verify::ec::ec_public_key(group.as_ref(), point.as_ref()).unwrap(); - - self.diffie_hellman_common(peerkey.as_ptr()) - } - - fn diffie_hellman_ed(&self, nid: i32, raw_public_key: &[u8]) -> Result, ErrorStack> { - let peerkey: boring::pkey::PKey = unsafe { - boring::pkey::PKey::from_ptr(cvt_p(boring_sys::EVP_PKEY_new_raw_public_key( - nid, - ptr::null_mut(), - raw_public_key.as_ptr(), - raw_public_key.len(), - ))?) - }; - - self.diffie_hellman_common(peerkey.as_ptr()) - } - - fn diffie_hellman_common( - &self, - peerkey: *mut boring_sys::EVP_PKEY, - ) -> Result, ErrorStack> { - unsafe { - // Initialize - cvt(boring_sys::EVP_PKEY_derive_init(self.dctx.as_ptr()))?; - - // Provide the peer public key - cvt(boring_sys::EVP_PKEY_derive_set_peer( - self.dctx.as_ptr(), - peerkey, - ))?; - } - - // Determine buffer length for shared secret - let mut secret_len = unsafe { - let mut secret_len = 0; - cvt(boring_sys::EVP_PKEY_derive( - self.dctx.as_ptr(), - ptr::null_mut(), - &mut secret_len, - ))?; - secret_len - }; - - let mut secret = vec![0u8; secret_len]; - unsafe { - cvt(boring_sys::EVP_PKEY_derive( - self.dctx.as_ptr(), - secret.as_mut_ptr(), - &mut secret_len, - ))?; - } - Ok(secret) - } -} - -impl crypto::ActiveKeyExchange for BoringEvpKey { - fn complete( - self: Box, - peer_pub_key: &[u8], - ) -> Result { - let expected_len = self.pub_bytes.len(); - - if peer_pub_key.len() != expected_len { - return Err(rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare)); - } - - Ok(crypto::SharedSecret::from( - self.diffie_hellman(peer_pub_key) - .map_err(|x| rustls::Error::General(x.to_string()))? - .as_ref(), - )) - } - - fn pub_key(&self) -> &[u8] { - self.pub_bytes.as_ref() - } - - fn group(&self) -> rustls::NamedGroup { - match self.key_type { - DhKeyType::ED(boring_sys::NID_X25519) => rustls::NamedGroup::X25519, - DhKeyType::ED(boring_sys::NID_X448) => rustls::NamedGroup::X448, - DhKeyType::EC(boring_sys::NID_X9_62_prime256v1) => rustls::NamedGroup::secp256r1, - DhKeyType::EC(boring_sys::NID_secp384r1) => rustls::NamedGroup::secp384r1, - DhKeyType::EC(boring_sys::NID_secp521r1) => rustls::NamedGroup::secp521r1, - _ => unimplemented!(), - } - } -} diff --git a/boring-rustls-provider/src/kx/ex.rs b/boring-rustls-provider/src/kx/ex.rs new file mode 100644 index 0000000..efe8231 --- /dev/null +++ b/boring-rustls-provider/src/kx/ex.rs @@ -0,0 +1,171 @@ +use std::{ + mem::MaybeUninit, + ptr::{self}, +}; + +use boring::{ + ec::{EcGroup, EcKey}, + error::ErrorStack, + nid::Nid, + pkey::{PKey, PKeyRef, Private}, +}; +use boring_additions::evp::EvpPkeyCtx; +use foreign_types::ForeignType; +use rustls::crypto; +use spki::der::Decode; + +use crate::helper::{cvt, cvt_p}; + +use super::DhKeyType; + +pub struct ExKeyExchange { + own_key: PKey, + pub_bytes: Vec, + key_type: DhKeyType, +} + +impl ExKeyExchange { + pub fn with_x25519() -> Result { + Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X25519)) + } + + pub fn with_x448() -> Result { + Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X448)) + } + + pub fn with_secp256r1() -> Result { + Self::ec_from_curve(Nid::X9_62_PRIME256V1) + } + + pub fn with_secp384r1() -> Result { + Self::ec_from_curve(Nid::SECP384R1) + } + + pub fn with_secp521r1() -> Result { + Self::ec_from_curve(Nid::SECP521R1) + } + + 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); + Ok(Self { + own_key, + pub_bytes, + key_type: DhKeyType::EC((ec_group, nid.as_raw())), + }) + } + + fn ed_from_curve(nid: Nid) -> Result { + let pkey_ctx = unsafe { + EvpPkeyCtx::from_ptr(cvt_p(boring_sys::EVP_PKEY_CTX_new_id( + nid.as_raw(), + ptr::null_mut(), + ))?) + }; + + let own_key: PKey = unsafe { + cvt(boring_sys::EVP_PKEY_keygen_init(pkey_ctx.as_ptr()))?; + + let mut pkey = + MaybeUninit::<*mut boring_sys::EVP_PKEY>::new(ptr::null_mut()).assume_init(); + cvt(boring_sys::EVP_PKEY_keygen(pkey_ctx.as_ptr(), &mut pkey))?; + + PKey::from_ptr(pkey) + }; + + let pub_bytes = Self::raw_public_key(&own_key); + + Ok(Self { + own_key, + pub_bytes, + key_type: DhKeyType::ED(nid.as_raw()), + }) + } + + fn raw_public_key(pkey: &PKeyRef) -> Vec { + let spki = pkey.public_key_to_der().unwrap(); + + // parse the key + let key = spki::SubjectPublicKeyInfoRef::from_der(spki.as_ref()).unwrap(); + + // return the raw public key as a new vec + Vec::from(key.subject_public_key.as_bytes().unwrap()) + } +} + +impl crypto::ActiveKeyExchange for ExKeyExchange { + fn complete( + self: Box, + peer_pub_key: &[u8], + ) -> Result { + let peerkey = match &self.key_type { + DhKeyType::EC((group, _)) => { + let mut bn_ctx = boring::bn::BigNumContext::new() + .map_err(|x| rustls::Error::General(x.to_string()))?; + + let point = crate::verify::ec::ec_point(group, &mut bn_ctx, peer_pub_key) + .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; + + crate::verify::ec::ec_public_key(group, point.as_ref()) + .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))? + } + DhKeyType::ED(nid) => { + crate::verify::ed::ed_public_key(peer_pub_key, Nid::from_raw(*nid)) + .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))? + } + _ => unimplemented!(), + }; + + let mut deriver = boring::derive::Deriver::new(&self.own_key).unwrap(); + + deriver + .set_peer(&peerkey) + .map_err(|_| rustls::Error::from(rustls::PeerMisbehaved::InvalidKeyShare))?; + + Ok(crypto::SharedSecret::from( + deriver.derive_to_vec().unwrap().as_slice(), + )) + } + + fn pub_key(&self) -> &[u8] { + &self.pub_bytes + } + + fn group(&self) -> rustls::NamedGroup { + match self.key_type { + DhKeyType::ED(boring_sys::NID_X25519) => rustls::NamedGroup::X25519, + DhKeyType::ED(boring_sys::NID_X448) => rustls::NamedGroup::X448, + DhKeyType::EC((_, boring_sys::NID_X9_62_prime256v1)) => rustls::NamedGroup::secp256r1, + DhKeyType::EC((_, boring_sys::NID_secp384r1)) => rustls::NamedGroup::secp384r1, + DhKeyType::EC((_, boring_sys::NID_secp521r1)) => rustls::NamedGroup::secp521r1, + _ => unimplemented!(), + } + } +} + +#[cfg(test)] +mod tests { + use super::ExKeyExchange; + use rustls::crypto::ActiveKeyExchange; + + #[test] + fn test_derive_ec() { + let kx = Box::new(ExKeyExchange::with_secp256r1().unwrap()); + let kx1 = ExKeyExchange::with_secp256r1().unwrap(); + + kx.group(); + kx.complete(kx1.pub_key()).unwrap(); + } + + #[test] + fn test_derive_ed() { + let kx = Box::new(ExKeyExchange::with_x25519().unwrap()); + let kx1 = ExKeyExchange::with_x25519().unwrap(); + + kx.group(); + kx.complete(kx1.pub_key()).unwrap(); + } +} diff --git a/boring-rustls-provider/src/verify.rs b/boring-rustls-provider/src/verify.rs index 4b6107a..5de9140 100644 --- a/boring-rustls-provider/src/verify.rs +++ b/boring-rustls-provider/src/verify.rs @@ -1,7 +1,7 @@ use rustls::{SignatureScheme, WebPkiSupportedAlgorithms}; pub(crate) mod ec; -mod ed; +pub(crate) mod ed; pub(crate) mod rsa; #[allow(unused)] diff --git a/boring-rustls-provider/src/verify/ed.rs b/boring-rustls-provider/src/verify/ed.rs index 8d0daf3..a96bcb8 100644 --- a/boring-rustls-provider/src/verify/ed.rs +++ b/boring-rustls-provider/src/verify/ed.rs @@ -20,7 +20,7 @@ impl SignatureVerificationAlgorithm for BoringEdVerifier { message: &[u8], signature: &[u8], ) -> Result<(), rustls_pki_types::InvalidSignature> { - let public_key = ed_public_key(public_key, self.0)?; + let public_key = ed_public_key_for_scheme(public_key, self.0)?; let mut verifier = ed_verifier_from_params(public_key.as_ref()); verifier.verify_oneshot(signature, message).map_or_else( @@ -55,18 +55,25 @@ fn ed_verifier_from_params( verifier } -fn ed_public_key( +fn ed_public_key_for_scheme( spki_spk: &[u8], scheme: SignatureScheme, ) -> Result, InvalidSignature> { - let typ = match scheme { + let nid = boring::nid::Nid::from_raw(match scheme { SignatureScheme::ED25519 => boring_sys::EVP_PKEY_ED25519, SignatureScheme::ED448 => boring_sys::EVP_PKEY_ED448, _ => unimplemented!(), - }; + }); + ed_public_key(spki_spk, nid) +} + +pub fn ed_public_key( + spki_spk: &[u8], + nid: boring::nid::Nid, +) -> Result, InvalidSignature> { Ok(unsafe { let pkey = cvt_p(boring_sys::EVP_PKEY_new_raw_public_key( - typ, + nid.as_raw(), ptr::null_mut(), spki_spk.as_ptr(), spki_spk.len(),