* Move ffi type container to boring-additions

* Use boring::derive for EC and ED instead of own implementation
This commit is contained in:
Jan Rüth 2023-11-23 21:11:25 +01:00
commit aa74b45a0f
15 changed files with 417 additions and 410 deletions

View file

@ -1,9 +1,14 @@
use std::ptr; use std::ptr;
use boring::error::ErrorStack; use boring::error::ErrorStack;
use foreign_types::ForeignType;
mod types;
use crate::helper::{cvt, cvt_p}; use crate::helper::{cvt, cvt_p};
pub use self::types::*;
pub struct Algorithm(*const boring_sys::EVP_AEAD); pub struct Algorithm(*const boring_sys::EVP_AEAD);
impl Algorithm { impl Algorithm {
@ -55,14 +60,11 @@ impl Algorithm {
} }
pub struct Crypter { pub struct Crypter {
ctx: *mut boring_sys::EVP_AEAD_CTX, ctx: EvpAeadCtx,
max_overhead: usize, max_overhead: usize,
nonce_len: usize, nonce_len: usize,
} }
unsafe impl Send for Crypter {}
unsafe impl Sync for Crypter {}
impl Crypter { impl Crypter {
pub fn new(aead_alg: Algorithm, key: &[u8]) -> Result<Self, ErrorStack> { pub fn new(aead_alg: Algorithm, key: &[u8]) -> Result<Self, ErrorStack> {
assert_eq!(aead_alg.key_length(), key.len()); assert_eq!(aead_alg.key_length(), key.len());
@ -70,12 +72,12 @@ impl Crypter {
let this = unsafe { let this = unsafe {
Self { 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, aead_alg.0,
key.as_ptr(), key.as_ptr(),
key.len(), key.len(),
boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as usize, boring_sys::EVP_AEAD_DEFAULT_TAG_LENGTH as usize,
))?, ))?),
max_overhead: aead_alg.max_overhead(), max_overhead: aead_alg.max_overhead(),
nonce_len: aead_alg.nonce_len(), nonce_len: aead_alg.nonce_len(),
} }
@ -104,7 +106,7 @@ impl Crypter {
let mut tag_len = tag.len(); let mut tag_len = tag.len();
unsafe { unsafe {
cvt(boring_sys::EVP_AEAD_CTX_seal_scatter( cvt(boring_sys::EVP_AEAD_CTX_seal_scatter(
self.ctx, self.ctx.as_ptr(),
buffer.as_mut_ptr(), buffer.as_mut_ptr(),
tag.as_mut_ptr(), tag.as_mut_ptr(),
&mut tag_len, &mut tag_len,
@ -133,7 +135,7 @@ impl Crypter {
unsafe { unsafe {
cvt(boring_sys::EVP_AEAD_CTX_open_gather( cvt(boring_sys::EVP_AEAD_CTX_open_gather(
self.ctx, self.ctx.as_ptr(),
buffer.as_mut_ptr(), buffer.as_mut_ptr(),
nonce.as_ptr(), nonce.as_ptr(),
nonce.len(), 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)] #[cfg(test)]
mod tests { mod tests {
use super::Crypter; use super::Crypter;

View file

@ -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<boring_sys::EVP_AEAD_CTX>);
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()) }
}
}

View file

@ -0,0 +1,3 @@
mod types;
pub use types::*;

View file

@ -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<boring_sys::EVP_PKEY_CTX>);
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()) }
}
}

View file

@ -0,0 +1,3 @@
mod types;
pub use types::*;

View file

@ -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<boring_sys::HMAC_CTX>);
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()) }
}
}

View file

@ -1,2 +1,4 @@
pub mod aead; pub mod aead;
pub mod evp;
pub(crate) mod helper; pub(crate) mod helper;
pub mod hmac;

View file

@ -36,9 +36,6 @@ pub(crate) struct BoringAeadCrypter<T: BoringAead> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
unsafe impl<T: BoringAead> Sync for BoringAeadCrypter<T> {}
unsafe impl<T: BoringAead> Send for BoringAeadCrypter<T> {}
impl<T: BoringAead> AeadCore for BoringAeadCrypter<T> { impl<T: BoringAead> AeadCore for BoringAeadCrypter<T> {
// inherit all properties from the Algorithm // inherit all properties from the Algorithm
@ -185,9 +182,6 @@ where
pub(crate) struct Aead<T: BoringCipher>(PhantomData<T>); pub(crate) struct Aead<T: BoringCipher>(PhantomData<T>);
unsafe impl<T: BoringCipher> Sync for Aead<T> {}
unsafe impl<T: BoringCipher> Send for Aead<T> {}
impl<T: BoringCipher> Aead<T> { impl<T: BoringCipher> Aead<T> {
pub const DEFAULT: Self = Self(PhantomData); pub const DEFAULT: Self = Self(PhantomData);
} }

View file

@ -1,6 +1,8 @@
use std::{os::raw::c_void, ptr}; use std::{os::raw::c_void, ptr};
use boring::hash::MessageDigest; use boring::hash::MessageDigest;
use boring_additions::hmac::HmacCtx;
use foreign_types::ForeignType;
use rustls::crypto; use rustls::crypto;
use crate::helper::{cvt, cvt_p}; use crate::helper::{cvt, cvt_p};
@ -14,7 +16,7 @@ pub struct BoringHmac(pub boring::nid::Nid);
impl crypto::hmac::Hmac for BoringHmac { impl crypto::hmac::Hmac for BoringHmac {
fn with_key(&self, key: &[u8]) -> Box<dyn crypto::hmac::Key> { fn with_key(&self, key: &[u8]) -> Box<dyn crypto::hmac::Key> {
Box::new(unsafe { 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(); let md = boring::hash::MessageDigest::from_nid(self.0).unwrap();
@ -33,31 +35,13 @@ impl crypto::hmac::Hmac for BoringHmac {
} }
} }
#[derive(Clone)]
struct BoringHmacKey { struct BoringHmacKey {
ctx: *mut boring_sys::HMAC_CTX, ctx: HmacCtx,
md: MessageDigest, md: MessageDigest,
key: Vec<u8>, key: Vec<u8>,
} }
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 { impl crypto::hmac::Key for BoringHmacKey {
fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag {
let mut out = [0u8; 32]; let mut out = [0u8; 32];
@ -65,7 +49,7 @@ impl crypto::hmac::Key for BoringHmacKey {
crypto::hmac::Tag::new(unsafe { crypto::hmac::Tag::new(unsafe {
// initialize a new hmac // initialize a new hmac
cvt(boring_sys::HMAC_Init_ex( cvt(boring_sys::HMAC_Init_ex(
self.ctx, self.ctx.as_ptr(),
self.key.as_ptr() as *const c_void, self.key.as_ptr() as *const c_void,
self.key.len(), self.key.len(),
self.md.as_ptr(), self.md.as_ptr(),
@ -74,21 +58,31 @@ impl crypto::hmac::Key for BoringHmacKey {
.unwrap(); .unwrap();
cvt(boring_sys::HMAC_Update( cvt(boring_sys::HMAC_Update(
self.ctx, self.ctx.as_ptr(),
first.as_ptr(), first.as_ptr(),
first.len(), first.len(),
)) ))
.unwrap(); .unwrap();
for m in middle { 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; let mut out_len = 0;
cvt(boring_sys::HMAC_Final( cvt(boring_sys::HMAC_Final(
self.ctx, self.ctx.as_ptr(),
out.as_mut_ptr(), out.as_mut_ptr(),
&mut out_len, &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)] #[cfg(test)]
mod tests { mod tests {
use super::SHA256; use super::SHA256;

View file

@ -1,11 +1,10 @@
use rustls::crypto::{self, ActiveKeyExchange}; use rustls::crypto::{self, ActiveKeyExchange};
mod dh; mod dh;
mod evp; mod ex;
#[derive(Debug)]
enum DhKeyType { enum DhKeyType {
EC(i32), EC((boring::ec::EcGroup, i32)),
ED(i32), ED(i32),
FFDHE2048, FFDHE2048,
} }
@ -16,7 +15,7 @@ pub struct X25519;
impl crypto::SupportedKxGroup for X25519 { impl crypto::SupportedKxGroup for X25519 {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> { fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> {
Ok(Box::new( 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 { impl crypto::SupportedKxGroup for X448 {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> { fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> {
Ok(Box::new( 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 { impl crypto::SupportedKxGroup for Secp256r1 {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> { fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> {
Ok(Box::new( 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 { impl crypto::SupportedKxGroup for Secp384r1 {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> { fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> {
Ok(Box::new( 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 { impl crypto::SupportedKxGroup for Secp521r1 {
fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> { fn start(&self) -> Result<Box<(dyn ActiveKeyExchange + 'static)>, rustls::Error> {
Ok(Box::new( 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 { mod tests {
use rustls::crypto::ActiveKeyExchange; 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] #[test]
fn test_derive_dh() { fn test_derive_dh() {
let alice = super::dh::BoringDhKey::generate_ffdhe_2048().unwrap(); let alice = super::dh::BoringDhKey::generate_ffdhe_2048().unwrap();

View file

@ -1,4 +1,4 @@
use boring::error::ErrorStack; use boring::{dh::Dh, error::ErrorStack, pkey::Private};
use foreign_types::ForeignType; use foreign_types::ForeignType;
use rustls::crypto; use rustls::crypto;
@ -7,7 +7,7 @@ use crate::helper::{cvt, cvt_p};
use super::DhKeyType; use super::DhKeyType;
pub struct BoringDhKey { pub struct BoringDhKey {
dh: boring::dh::Dh<boring::pkey::Private>, dh: Dh<Private>,
pub_bytes: Vec<u8>, pub_bytes: Vec<u8>,
key_type: DhKeyType, key_type: DhKeyType,
} }
@ -15,7 +15,7 @@ pub struct BoringDhKey {
impl BoringDhKey { impl BoringDhKey {
pub fn generate_ffdhe_2048() -> Result<Self, ErrorStack> { pub fn generate_ffdhe_2048() -> Result<Self, ErrorStack> {
let mut me = Self { 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(), pub_bytes: Vec::new(),
key_type: DhKeyType::FFDHE2048, key_type: DhKeyType::FFDHE2048,
}; };

View file

@ -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<boring_sys::EVP_PKEY_CTX>);
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<u8>,
}
unsafe impl Sync for BoringEvpKey {}
unsafe impl Send for BoringEvpKey {}
impl BoringEvpKey {
pub fn generate_x25519() -> Result<Self, ErrorStack> {
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<Self, ErrorStack> {
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<Self, ErrorStack> {
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<Self, ErrorStack> {
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<Self, ErrorStack> {
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<BoringEvpPkeyCtx, ErrorStack> {
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::Params> = 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<BoringEvpPkeyCtx, ErrorStack> {
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<Self, ErrorStack> {
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::Private> = 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<boring::pkey::Private>,
) -> Result<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, ErrorStack> {
let peerkey: boring::pkey::PKey<boring::pkey::Public> = 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<Vec<u8>, 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<Self>,
peer_pub_key: &[u8],
) -> Result<crypto::SharedSecret, rustls::Error> {
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!(),
}
}
}

View file

@ -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<Private>,
pub_bytes: Vec<u8>,
key_type: DhKeyType,
}
impl ExKeyExchange {
pub fn with_x25519() -> Result<Self, ErrorStack> {
Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X25519))
}
pub fn with_x448() -> Result<Self, ErrorStack> {
Self::ed_from_curve(Nid::from_raw(boring_sys::NID_X448))
}
pub fn with_secp256r1() -> Result<Self, ErrorStack> {
Self::ec_from_curve(Nid::X9_62_PRIME256V1)
}
pub fn with_secp384r1() -> Result<Self, ErrorStack> {
Self::ec_from_curve(Nid::SECP384R1)
}
pub fn with_secp521r1() -> Result<Self, ErrorStack> {
Self::ec_from_curve(Nid::SECP521R1)
}
fn ec_from_curve(nid: Nid) -> Result<Self, ErrorStack> {
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<Self, ErrorStack> {
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<Private> = 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<Private>) -> Vec<u8> {
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<Self>,
peer_pub_key: &[u8],
) -> Result<crypto::SharedSecret, rustls::Error> {
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();
}
}

View file

@ -1,7 +1,7 @@
use rustls::{SignatureScheme, WebPkiSupportedAlgorithms}; use rustls::{SignatureScheme, WebPkiSupportedAlgorithms};
pub(crate) mod ec; pub(crate) mod ec;
mod ed; pub(crate) mod ed;
pub(crate) mod rsa; pub(crate) mod rsa;
#[allow(unused)] #[allow(unused)]

View file

@ -20,7 +20,7 @@ impl SignatureVerificationAlgorithm for BoringEdVerifier {
message: &[u8], message: &[u8],
signature: &[u8], signature: &[u8],
) -> Result<(), rustls_pki_types::InvalidSignature> { ) -> 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()); let mut verifier = ed_verifier_from_params(public_key.as_ref());
verifier.verify_oneshot(signature, message).map_or_else( verifier.verify_oneshot(signature, message).map_or_else(
@ -55,18 +55,25 @@ fn ed_verifier_from_params(
verifier verifier
} }
fn ed_public_key( fn ed_public_key_for_scheme(
spki_spk: &[u8], spki_spk: &[u8],
scheme: SignatureScheme, scheme: SignatureScheme,
) -> Result<boring::pkey::PKey<boring::pkey::Public>, InvalidSignature> { ) -> Result<boring::pkey::PKey<boring::pkey::Public>, InvalidSignature> {
let typ = match scheme { let nid = boring::nid::Nid::from_raw(match scheme {
SignatureScheme::ED25519 => boring_sys::EVP_PKEY_ED25519, SignatureScheme::ED25519 => boring_sys::EVP_PKEY_ED25519,
SignatureScheme::ED448 => boring_sys::EVP_PKEY_ED448, SignatureScheme::ED448 => boring_sys::EVP_PKEY_ED448,
_ => unimplemented!(), _ => unimplemented!(),
}; });
ed_public_key(spki_spk, nid)
}
pub fn ed_public_key(
spki_spk: &[u8],
nid: boring::nid::Nid,
) -> Result<boring::pkey::PKey<boring::pkey::Public>, InvalidSignature> {
Ok(unsafe { Ok(unsafe {
let pkey = cvt_p(boring_sys::EVP_PKEY_new_raw_public_key( let pkey = cvt_p(boring_sys::EVP_PKEY_new_raw_public_key(
typ, nid.as_raw(),
ptr::null_mut(), ptr::null_mut(),
spki_spk.as_ptr(), spki_spk.as_ptr(),
spki_spk.len(), spki_spk.len(),