Expose a safe Rust interface for the session resumption callback
This commit is contained in:
parent
ac1d71cb54
commit
ab8513ef8f
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::cvt;
|
||||||
|
use crate::error::ErrorStack;
|
||||||
|
use crate::hash::MessageDigest;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
|
use foreign_types::ForeignType;
|
||||||
|
|
||||||
|
foreign_type_and_impl_send_sync! {
|
||||||
|
type CType = ffi::HMAC_CTX;
|
||||||
|
fn drop = ffi::HMAC_CTX_free;
|
||||||
|
|
||||||
|
pub struct HmacCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HmacCtx {
|
||||||
|
/// Configures HmacCtx to use `md` as the hash function and `key` as the key.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/hmac.h.html#HMAC_Init_ex
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller must ensure HMAC_CTX has been initalized.
|
||||||
|
pub unsafe fn init(&mut self, key: &[u8], md: &MessageDigest) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::HMAC_Init_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
key.as_ptr() as *const c_void,
|
||||||
|
key.len(),
|
||||||
|
md.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
core::ptr::null_mut(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -137,6 +137,7 @@ pub mod error;
|
||||||
pub mod ex_data;
|
pub mod ex_data;
|
||||||
pub mod fips;
|
pub mod fips;
|
||||||
pub mod hash;
|
pub mod hash;
|
||||||
|
pub mod hmac;
|
||||||
pub mod hpke;
|
pub mod hpke;
|
||||||
pub mod memcmp;
|
pub mod memcmp;
|
||||||
pub mod nid;
|
pub mod nid;
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,15 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::error::ErrorStack;
|
use crate::error::ErrorStack;
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
use crate::hmac::HmacCtx;
|
||||||
use crate::ssl::TicketKeyCallbackResult;
|
use crate::ssl::TicketKeyCallbackResult;
|
||||||
|
use crate::symm::CipherCtx;
|
||||||
use crate::x509::{X509StoreContext, X509StoreContextRef};
|
use crate::x509::{X509StoreContext, X509StoreContextRef};
|
||||||
use foreign_types::ForeignType;
|
use foreign_types::ForeignType;
|
||||||
use foreign_types::ForeignTypeRef;
|
use foreign_types::ForeignTypeRef;
|
||||||
use libc::{c_char, c_int, c_uchar, c_uint, c_void};
|
use libc::{c_char, c_int, c_uchar, c_uint, c_void};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::{ManuallyDrop, MaybeUninit};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
@ -288,8 +290,8 @@ where
|
||||||
&SslRef,
|
&SslRef,
|
||||||
&mut [u8; 16],
|
&mut [u8; 16],
|
||||||
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
*mut ffi::EVP_CIPHER_CTX,
|
&mut CipherCtx,
|
||||||
*mut ffi::HMAC_CTX,
|
&mut HmacCtx,
|
||||||
bool,
|
bool,
|
||||||
) -> TicketKeyCallbackResult
|
) -> TicketKeyCallbackResult
|
||||||
+ 'static
|
+ 'static
|
||||||
|
|
@ -325,7 +327,11 @@ where
|
||||||
let key_name = unsafe { key_name.assume_init_mut() };
|
let key_name = unsafe { key_name.assume_init_mut() };
|
||||||
let iv = unsafe { iv.assume_init_mut() };
|
let iv = unsafe { iv.assume_init_mut() };
|
||||||
|
|
||||||
callback(ssl, key_name, iv, evp_ctx, hmac_ctx, encrypt).into()
|
// The EVP_CIPHER_CTX and HMAC_CTX are owned by boringSSL.
|
||||||
|
let mut evp_ctx = ManuallyDrop::new(unsafe { CipherCtx::from_ptr(evp_ctx) });
|
||||||
|
let mut hmac_ctx = ManuallyDrop::new(unsafe { HmacCtx::from_ptr(hmac_ctx) });
|
||||||
|
|
||||||
|
callback(ssl, key_name, iv, &mut evp_ctx, &mut hmac_ctx, encrypt).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe extern "C" fn raw_alpn_select<F>(
|
pub(super) unsafe extern "C" fn raw_alpn_select<F>(
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ use crate::dh::DhRef;
|
||||||
use crate::ec::EcKeyRef;
|
use crate::ec::EcKeyRef;
|
||||||
use crate::error::ErrorStack;
|
use crate::error::ErrorStack;
|
||||||
use crate::ex_data::Index;
|
use crate::ex_data::Index;
|
||||||
|
use crate::hmac::HmacCtx;
|
||||||
use crate::nid::Nid;
|
use crate::nid::Nid;
|
||||||
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
|
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
|
||||||
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
|
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
|
||||||
|
|
@ -88,6 +89,7 @@ use crate::ssl::bio::BioMethod;
|
||||||
use crate::ssl::callbacks::*;
|
use crate::ssl::callbacks::*;
|
||||||
use crate::ssl::error::InnerError;
|
use crate::ssl::error::InnerError;
|
||||||
use crate::stack::{Stack, StackRef, Stackable};
|
use crate::stack::{Stack, StackRef, Stackable};
|
||||||
|
use crate::symm::CipherCtx;
|
||||||
use crate::x509::store::{X509Store, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef};
|
use crate::x509::store::{X509Store, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef};
|
||||||
use crate::x509::verify::X509VerifyParamRef;
|
use crate::x509::verify::X509VerifyParamRef;
|
||||||
use crate::x509::{
|
use crate::x509::{
|
||||||
|
|
@ -1137,6 +1139,8 @@ impl SslContextBuilder {
|
||||||
/// prior to TLS 1.3, retroactively decrypt all application traffic from sessions using that
|
/// prior to TLS 1.3, retroactively decrypt all application traffic from sessions using that
|
||||||
/// ticket key. Thus ticket keys must be regularly rotated for forward secrecy.
|
/// ticket key. Thus ticket keys must be regularly rotated for forward secrecy.
|
||||||
///
|
///
|
||||||
|
/// CipherCtx and HmacCtx are guaranteed to be initialized.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This method panics if this `Ssl` is associated with a RPK context.
|
/// This method panics if this `Ssl` is associated with a RPK context.
|
||||||
|
|
@ -1148,14 +1152,14 @@ impl SslContextBuilder {
|
||||||
///
|
///
|
||||||
/// [`SSL_CTX_set_tlsext_ticket_key_cb`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_tlsext_ticket_key_cb
|
/// [`SSL_CTX_set_tlsext_ticket_key_cb`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_tlsext_ticket_key_cb
|
||||||
#[corresponds(SSL_CTX_set_tlsext_ticket_key_cb)]
|
#[corresponds(SSL_CTX_set_tlsext_ticket_key_cb)]
|
||||||
pub unsafe fn set_ticket_key_callback_unsafe<F>(&mut self, callback: F)
|
pub unsafe fn set_ticket_key_callback<F>(&mut self, callback: F)
|
||||||
where
|
where
|
||||||
F: Fn(
|
F: Fn(
|
||||||
&SslRef,
|
&SslRef,
|
||||||
&mut [u8; 16],
|
&mut [u8; 16],
|
||||||
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
*mut ffi::EVP_CIPHER_CTX,
|
&mut CipherCtx,
|
||||||
*mut ffi::HMAC_CTX,
|
&mut HmacCtx,
|
||||||
bool,
|
bool,
|
||||||
) -> TicketKeyCallbackResult
|
) -> TicketKeyCallbackResult
|
||||||
+ 'static
|
+ 'static
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use super::server::Server;
|
use super::server::Server;
|
||||||
use crate::ssl::test::MessageDigest;
|
use crate::ssl::test::MessageDigest;
|
||||||
|
use crate::ssl::HmacCtx;
|
||||||
use crate::ssl::SslRef;
|
use crate::ssl::SslRef;
|
||||||
use crate::ssl::SslSession;
|
use crate::ssl::SslSession;
|
||||||
use crate::ssl::SslSessionCacheMode;
|
use crate::ssl::SslSessionCacheMode;
|
||||||
use crate::ssl::TicketKeyCallbackResult;
|
use crate::ssl::TicketKeyCallbackResult;
|
||||||
use crate::symm::Cipher;
|
use crate::symm::Cipher;
|
||||||
use std::ffi::c_void;
|
use crate::symm::CipherCtx;
|
||||||
use std::sync::atomic::{AtomicU8, Ordering};
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
|
@ -60,7 +61,7 @@ fn custom_callback_success() {
|
||||||
unsafe {
|
unsafe {
|
||||||
server
|
server
|
||||||
.ctx()
|
.ctx()
|
||||||
.set_ticket_key_callback_unsafe(test_success_tickey_key_callback)
|
.set_ticket_key_callback(test_success_tickey_key_callback)
|
||||||
};
|
};
|
||||||
let server = server.build();
|
let server = server.build();
|
||||||
|
|
||||||
|
|
@ -105,7 +106,7 @@ fn custom_callback_unrecognized_decryption_ticket() {
|
||||||
unsafe {
|
unsafe {
|
||||||
server
|
server
|
||||||
.ctx()
|
.ctx()
|
||||||
.set_ticket_key_callback_unsafe(test_noop_tickey_key_callback)
|
.set_ticket_key_callback(test_noop_tickey_key_callback)
|
||||||
};
|
};
|
||||||
let server = server.build();
|
let server = server.build();
|
||||||
|
|
||||||
|
|
@ -147,8 +148,8 @@ fn test_noop_tickey_key_callback(
|
||||||
_ssl: &SslRef,
|
_ssl: &SslRef,
|
||||||
key_name: &mut [u8; 16],
|
key_name: &mut [u8; 16],
|
||||||
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
evp_ctx: *mut ffi::EVP_CIPHER_CTX,
|
evp_ctx: &mut CipherCtx,
|
||||||
hmac_ctx: *mut ffi::HMAC_CTX,
|
hmac_ctx: &mut HmacCtx,
|
||||||
encrypt: bool,
|
encrypt: bool,
|
||||||
) -> TicketKeyCallbackResult {
|
) -> TicketKeyCallbackResult {
|
||||||
// These should only be used for testing purposes.
|
// These should only be used for testing purposes.
|
||||||
|
|
@ -164,31 +165,16 @@ fn test_noop_tickey_key_callback(
|
||||||
assert_eq!(iv, &[0; 16]);
|
assert_eq!(iv, &[0; 16]);
|
||||||
|
|
||||||
NOOP_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
NOOP_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
// Set the encryption context.
|
// Set the encryption context.
|
||||||
let ret = unsafe {
|
unsafe {
|
||||||
ffi::EVP_EncryptInit_ex(
|
evp_ctx
|
||||||
evp_ctx,
|
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
|
||||||
cipher.as_ptr(),
|
.unwrap()
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
TEST_AES_128_CBC_KEY.as_ptr(),
|
|
||||||
TEST_CBC_IV.as_ptr(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
assert!(ret == 1);
|
|
||||||
|
|
||||||
// Set the hmac context.
|
// Set the hmac context.
|
||||||
let ret = unsafe {
|
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
|
||||||
ffi::HMAC_Init_ex(
|
|
||||||
hmac_ctx,
|
|
||||||
TEST_HMAC_KEY.as_ptr() as *const c_void,
|
|
||||||
TEST_HMAC_KEY.len(),
|
|
||||||
digest.as_ptr(),
|
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
assert!(ret == 1);
|
|
||||||
|
|
||||||
TicketKeyCallbackResult::Success
|
TicketKeyCallbackResult::Success
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -202,8 +188,8 @@ fn test_success_tickey_key_callback(
|
||||||
_ssl: &SslRef,
|
_ssl: &SslRef,
|
||||||
key_name: &mut [u8; 16],
|
key_name: &mut [u8; 16],
|
||||||
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
evp_ctx: *mut ffi::EVP_CIPHER_CTX,
|
evp_ctx: &mut CipherCtx,
|
||||||
hmac_ctx: *mut ffi::HMAC_CTX,
|
hmac_ctx: &mut HmacCtx,
|
||||||
encrypt: bool,
|
encrypt: bool,
|
||||||
) -> TicketKeyCallbackResult {
|
) -> TicketKeyCallbackResult {
|
||||||
// These should only be used for testing purposes.
|
// These should only be used for testing purposes.
|
||||||
|
|
@ -219,58 +205,27 @@ fn test_success_tickey_key_callback(
|
||||||
assert_eq!(iv, &[0; 16]);
|
assert_eq!(iv, &[0; 16]);
|
||||||
|
|
||||||
SUCCESS_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
SUCCESS_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|
||||||
// Set the encryption context.
|
// Set the encryption context.
|
||||||
let ret = unsafe {
|
unsafe {
|
||||||
ffi::EVP_EncryptInit_ex(
|
evp_ctx
|
||||||
evp_ctx,
|
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
|
||||||
cipher.as_ptr(),
|
.unwrap()
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
TEST_AES_128_CBC_KEY.as_ptr(),
|
|
||||||
TEST_CBC_IV.as_ptr(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
assert!(ret == 1);
|
|
||||||
|
|
||||||
// Set the hmac context.
|
// Set the hmac context.
|
||||||
let ret = unsafe {
|
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
|
||||||
ffi::HMAC_Init_ex(
|
|
||||||
hmac_ctx,
|
|
||||||
TEST_HMAC_KEY.as_ptr() as *const c_void,
|
|
||||||
TEST_HMAC_KEY.len(),
|
|
||||||
digest.as_ptr(),
|
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
assert!(ret == 1);
|
|
||||||
} else {
|
} else {
|
||||||
SUCCESS_DECRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
SUCCESS_DECRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
|
||||||
// Set the decryption context.
|
// Set the decryption context.
|
||||||
let ret = unsafe {
|
unsafe {
|
||||||
ffi::EVP_DecryptInit_ex(
|
evp_ctx
|
||||||
evp_ctx,
|
.init_decrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
|
||||||
cipher.as_ptr(),
|
.unwrap()
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
TEST_AES_128_CBC_KEY.as_ptr(),
|
|
||||||
TEST_CBC_IV.as_ptr(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
assert!(ret == 1);
|
|
||||||
|
|
||||||
// Set the hmac context.
|
// Set the hmac context.
|
||||||
let ret = unsafe {
|
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
|
||||||
ffi::HMAC_Init_ex(
|
|
||||||
hmac_ctx,
|
|
||||||
TEST_HMAC_KEY.as_ptr() as *const c_void,
|
|
||||||
TEST_HMAC_KEY.len(),
|
|
||||||
digest.as_ptr(),
|
|
||||||
// ENGINE api is deprecated
|
|
||||||
core::ptr::null_mut(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
assert!(ret == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TicketKeyCallbackResult::Success
|
TicketKeyCallbackResult::Success
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
use foreign_types::ForeignType;
|
||||||
use libc::{c_int, c_uint};
|
use libc::{c_int, c_uint};
|
||||||
use openssl_macros::corresponds;
|
use openssl_macros::corresponds;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
|
@ -68,6 +69,77 @@ pub enum Mode {
|
||||||
Decrypt,
|
Decrypt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreign_type_and_impl_send_sync! {
|
||||||
|
type CType = ffi::EVP_CIPHER_CTX;
|
||||||
|
fn drop = ffi::EVP_CIPHER_CTX_free;
|
||||||
|
|
||||||
|
pub struct CipherCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CipherCtx {
|
||||||
|
/// Configures CipherCtx for a fresh encryption operation using `cipher`.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_EncryptInit_ex
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller must ensure EVP_CIPHER_CTX has been initalized.
|
||||||
|
///
|
||||||
|
/// The caller is responsible for ensuring the length of `key` and `iv` are appropriate for the
|
||||||
|
/// chosen Cipher.
|
||||||
|
pub unsafe fn init_encrypt(
|
||||||
|
&mut self,
|
||||||
|
cipher: &Cipher,
|
||||||
|
key: &[u8],
|
||||||
|
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_EncryptInit_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
cipher.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
ptr::null_mut(),
|
||||||
|
key.as_ptr(),
|
||||||
|
iv.as_ptr(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configures CipherCtx for a fresh decryption operation using `cipher`.
|
||||||
|
///
|
||||||
|
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_DecryptInit_ex
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller must ensure EVP_CIPHER_CTX has been initalized.
|
||||||
|
///
|
||||||
|
/// The caller is responsible for ensuring the length of `key` and `iv` are appropriate for the
|
||||||
|
/// chosen Cipher.
|
||||||
|
pub unsafe fn init_decrypt(
|
||||||
|
&mut self,
|
||||||
|
cipher: &Cipher,
|
||||||
|
key: &[u8],
|
||||||
|
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
|
||||||
|
) -> Result<(), ErrorStack> {
|
||||||
|
ffi::init();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_DecryptInit_ex(
|
||||||
|
self.as_ptr(),
|
||||||
|
cipher.as_ptr(),
|
||||||
|
// ENGINE api is deprecated
|
||||||
|
ptr::null_mut(),
|
||||||
|
key.as_ptr(),
|
||||||
|
iv.as_ptr(),
|
||||||
|
))
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a particular cipher algorithm.
|
/// Represents a particular cipher algorithm.
|
||||||
///
|
///
|
||||||
/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.
|
/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue