Skip to content

Commit fbf9dff

Browse files
committed
Expose a safe Rust interface for the session resumption callback
1 parent e395c52 commit fbf9dff

File tree

6 files changed

+152
-77
lines changed

6 files changed

+152
-77
lines changed

boring/src/hmac.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::cvt;
2+
use crate::error::ErrorStack;
3+
use crate::hash::MessageDigest;
4+
use std::ffi::c_void;
5+
6+
use foreign_types::ForeignType;
7+
8+
foreign_type_and_impl_send_sync! {
9+
type CType = ffi::HMAC_CTX;
10+
fn drop = ffi::HMAC_CTX_free;
11+
12+
pub struct HmacCtx;
13+
}
14+
15+
impl HmacCtx {
16+
/// Configures HmacCtx to use `md` as the hash function and `key` as the key.
17+
///
18+
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/hmac.h.html#HMAC_Init_ex
19+
///
20+
/// # Safety
21+
///
22+
/// The caller must ensure HMAC_CTX has been initalized.
23+
pub unsafe fn init(&mut self, key: &[u8], md: &MessageDigest) -> Result<(), ErrorStack> {
24+
ffi::init();
25+
26+
unsafe {
27+
cvt(ffi::HMAC_Init_ex(
28+
self.as_ptr(),
29+
key.as_ptr() as *const c_void,
30+
key.len(),
31+
md.as_ptr(),
32+
// ENGINE api is deprecated
33+
core::ptr::null_mut(),
34+
))
35+
.map(|_| ())
36+
}
37+
}
38+
}

boring/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub mod error;
137137
pub mod ex_data;
138138
pub mod fips;
139139
pub mod hash;
140+
pub mod hmac;
140141
pub mod hpke;
141142
pub mod memcmp;
142143
pub mod nid;

boring/src/ssl/callbacks.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ use super::{
88
};
99
use crate::error::ErrorStack;
1010
use crate::ffi;
11+
use crate::hmac::HmacCtx;
1112
use crate::ssl::TicketKeyCallbackResult;
13+
use crate::symm::CipherCtx;
1214
use crate::x509::{X509StoreContext, X509StoreContextRef};
1315
use foreign_types::ForeignType;
1416
use foreign_types::ForeignTypeRef;
1517
use libc::{c_char, c_int, c_uchar, c_uint, c_void};
1618
use std::ffi::CStr;
17-
use std::mem::MaybeUninit;
19+
use std::mem::{ManuallyDrop, MaybeUninit};
1820
use std::ptr;
1921
use std::slice;
2022
use std::str;
@@ -288,8 +290,8 @@ where
288290
&SslRef,
289291
&mut [u8; 16],
290292
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
291-
*mut ffi::EVP_CIPHER_CTX,
292-
*mut ffi::HMAC_CTX,
293+
&mut CipherCtx,
294+
&mut HmacCtx,
293295
bool,
294296
) -> TicketKeyCallbackResult
295297
+ 'static
@@ -325,7 +327,11 @@ where
325327
let key_name = unsafe { key_name.assume_init_mut() };
326328
let iv = unsafe { iv.assume_init_mut() };
327329

328-
callback(ssl, key_name, iv, evp_ctx, hmac_ctx, encrypt).into()
330+
// The EVP_CIPHER_CTX and HMAC_CTX are owned by boringSSL.
331+
let mut evp_ctx = ManuallyDrop::new(unsafe { CipherCtx::from_ptr(evp_ctx) });
332+
let mut hmac_ctx = ManuallyDrop::new(unsafe { HmacCtx::from_ptr(hmac_ctx) });
333+
334+
callback(ssl, key_name, iv, &mut evp_ctx, &mut hmac_ctx, encrypt).into()
329335
}
330336

331337
pub(super) unsafe extern "C" fn raw_alpn_select<F>(

boring/src/ssl/mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ use crate::dh::DhRef;
8181
use crate::ec::EcKeyRef;
8282
use crate::error::ErrorStack;
8383
use crate::ex_data::Index;
84+
use crate::hmac::HmacCtx;
8485
use crate::nid::Nid;
8586
use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
8687
use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
8788
use crate::ssl::bio::BioMethod;
8889
use crate::ssl::callbacks::*;
8990
use crate::ssl::error::InnerError;
9091
use crate::stack::{Stack, StackRef, Stackable};
92+
use crate::symm::CipherCtx;
9193
use crate::x509::store::{X509Store, X509StoreBuilder, X509StoreBuilderRef, X509StoreRef};
9294
use crate::x509::verify::X509VerifyParamRef;
9395
use crate::x509::{
@@ -1237,6 +1239,8 @@ impl SslContextBuilder {
12371239
/// prior to TLS 1.3, retroactively decrypt all application traffic from sessions using that
12381240
/// ticket key. Thus ticket keys must be regularly rotated for forward secrecy.
12391241
///
1242+
/// CipherCtx and HmacCtx are guaranteed to be initialized.
1243+
///
12401244
/// # Panics
12411245
///
12421246
/// This method panics if this `Ssl` is associated with a RPK context.
@@ -1248,14 +1252,14 @@ impl SslContextBuilder {
12481252
///
12491253
/// [`SSL_CTX_set_tlsext_ticket_key_cb`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_tlsext_ticket_key_cb
12501254
#[corresponds(SSL_CTX_set_tlsext_ticket_key_cb)]
1251-
pub unsafe fn set_ticket_key_callback_unsafe<F>(&mut self, callback: F)
1255+
pub unsafe fn set_ticket_key_callback<F>(&mut self, callback: F)
12521256
where
12531257
F: Fn(
12541258
&SslRef,
12551259
&mut [u8; 16],
12561260
&mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
1257-
*mut ffi::EVP_CIPHER_CTX,
1258-
*mut ffi::HMAC_CTX,
1261+
&mut CipherCtx,
1262+
&mut HmacCtx,
12591263
bool,
12601264
) -> TicketKeyCallbackResult
12611265
+ 'static

boring/src/ssl/test/session_resumption.rs

Lines changed: 25 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use super::server::Server;
22
use crate::ssl::test::MessageDigest;
3+
use crate::ssl::HmacCtx;
34
use crate::ssl::SslRef;
45
use crate::ssl::SslSession;
56
use crate::ssl::SslSessionCacheMode;
67
use crate::ssl::TicketKeyCallbackResult;
78
use crate::symm::Cipher;
8-
use std::ffi::c_void;
9+
use crate::symm::CipherCtx;
910
use std::sync::atomic::{AtomicU8, Ordering};
1011
use std::sync::OnceLock;
1112

@@ -60,7 +61,7 @@ fn custom_callback_success() {
6061
unsafe {
6162
server
6263
.ctx()
63-
.set_ticket_key_callback_unsafe(test_success_tickey_key_callback)
64+
.set_ticket_key_callback(test_success_tickey_key_callback)
6465
};
6566
let server = server.build();
6667

@@ -105,7 +106,7 @@ fn custom_callback_unrecognized_decryption_ticket() {
105106
unsafe {
106107
server
107108
.ctx()
108-
.set_ticket_key_callback_unsafe(test_noop_tickey_key_callback)
109+
.set_ticket_key_callback(test_noop_tickey_key_callback)
109110
};
110111
let server = server.build();
111112

@@ -147,8 +148,8 @@ fn test_noop_tickey_key_callback(
147148
_ssl: &SslRef,
148149
key_name: &mut [u8; 16],
149150
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
150-
evp_ctx: *mut ffi::EVP_CIPHER_CTX,
151-
hmac_ctx: *mut ffi::HMAC_CTX,
151+
evp_ctx: &mut CipherCtx,
152+
hmac_ctx: &mut HmacCtx,
152153
encrypt: bool,
153154
) -> TicketKeyCallbackResult {
154155
// These should only be used for testing purposes.
@@ -164,31 +165,16 @@ fn test_noop_tickey_key_callback(
164165
assert_eq!(iv, &[0; 16]);
165166

166167
NOOP_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
168+
167169
// Set the encryption context.
168-
let ret = unsafe {
169-
ffi::EVP_EncryptInit_ex(
170-
evp_ctx,
171-
cipher.as_ptr(),
172-
// ENGINE api is deprecated
173-
core::ptr::null_mut(),
174-
TEST_AES_128_CBC_KEY.as_ptr(),
175-
TEST_CBC_IV.as_ptr(),
176-
)
170+
unsafe {
171+
evp_ctx
172+
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
173+
.unwrap()
177174
};
178-
assert!(ret == 1);
179175

180176
// Set the hmac context.
181-
let ret = unsafe {
182-
ffi::HMAC_Init_ex(
183-
hmac_ctx,
184-
TEST_HMAC_KEY.as_ptr() as *const c_void,
185-
TEST_HMAC_KEY.len(),
186-
digest.as_ptr(),
187-
// ENGINE api is deprecated
188-
core::ptr::null_mut(),
189-
)
190-
};
191-
assert!(ret == 1);
177+
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
192178

193179
TicketKeyCallbackResult::Success
194180
} else {
@@ -202,8 +188,8 @@ fn test_success_tickey_key_callback(
202188
_ssl: &SslRef,
203189
key_name: &mut [u8; 16],
204190
iv: &mut [u8; ffi::EVP_MAX_IV_LENGTH as usize],
205-
evp_ctx: *mut ffi::EVP_CIPHER_CTX,
206-
hmac_ctx: *mut ffi::HMAC_CTX,
191+
evp_ctx: &mut CipherCtx,
192+
hmac_ctx: &mut HmacCtx,
207193
encrypt: bool,
208194
) -> TicketKeyCallbackResult {
209195
// These should only be used for testing purposes.
@@ -219,58 +205,27 @@ fn test_success_tickey_key_callback(
219205
assert_eq!(iv, &[0; 16]);
220206

221207
SUCCESS_ENCRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
208+
222209
// Set the encryption context.
223-
let ret = unsafe {
224-
ffi::EVP_EncryptInit_ex(
225-
evp_ctx,
226-
cipher.as_ptr(),
227-
// ENGINE api is deprecated
228-
core::ptr::null_mut(),
229-
TEST_AES_128_CBC_KEY.as_ptr(),
230-
TEST_CBC_IV.as_ptr(),
231-
)
210+
unsafe {
211+
evp_ctx
212+
.init_encrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
213+
.unwrap()
232214
};
233-
assert!(ret == 1);
234215

235216
// Set the hmac context.
236-
let ret = unsafe {
237-
ffi::HMAC_Init_ex(
238-
hmac_ctx,
239-
TEST_HMAC_KEY.as_ptr() as *const c_void,
240-
TEST_HMAC_KEY.len(),
241-
digest.as_ptr(),
242-
// ENGINE api is deprecated
243-
core::ptr::null_mut(),
244-
)
245-
};
246-
assert!(ret == 1);
217+
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
247218
} else {
248219
SUCCESS_DECRYPTION_CALLED_BACK.fetch_add(1, Ordering::SeqCst);
249220
// Set the decryption context.
250-
let ret = unsafe {
251-
ffi::EVP_DecryptInit_ex(
252-
evp_ctx,
253-
cipher.as_ptr(),
254-
// ENGINE api is deprecated
255-
core::ptr::null_mut(),
256-
TEST_AES_128_CBC_KEY.as_ptr(),
257-
TEST_CBC_IV.as_ptr(),
258-
)
221+
unsafe {
222+
evp_ctx
223+
.init_decrypt(&cipher, &TEST_AES_128_CBC_KEY, &TEST_CBC_IV)
224+
.unwrap()
259225
};
260-
assert!(ret == 1);
261226

262227
// Set the hmac context.
263-
let ret = unsafe {
264-
ffi::HMAC_Init_ex(
265-
hmac_ctx,
266-
TEST_HMAC_KEY.as_ptr() as *const c_void,
267-
TEST_HMAC_KEY.len(),
268-
digest.as_ptr(),
269-
// ENGINE api is deprecated
270-
core::ptr::null_mut(),
271-
)
272-
};
273-
assert!(ret == 1);
228+
unsafe { hmac_ctx.init(&TEST_HMAC_KEY, &digest).unwrap() };
274229
}
275230

276231
TicketKeyCallbackResult::Success

boring/src/symm.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
//! ```
5454
5555
use crate::ffi;
56+
use foreign_types::ForeignType;
5657
use libc::{c_int, c_uint};
5758
use openssl_macros::corresponds;
5859
use std::cmp;
@@ -68,6 +69,76 @@ pub enum Mode {
6869
Decrypt,
6970
}
7071

72+
foreign_type_and_impl_send_sync! {
73+
type CType = ffi::EVP_CIPHER_CTX;
74+
fn drop = ffi::EVP_CIPHER_CTX_free;
75+
76+
pub struct CipherCtx;
77+
}
78+
79+
impl CipherCtx {
80+
/// Configures CipherCtx for a fresh encryption operation using `cipher`.
81+
///
82+
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_EncryptInit_ex
83+
///
84+
/// # Safety
85+
///
86+
/// The caller must ensure EVP_CIPHER_CTX has been initalized.
87+
///
88+
/// The caller is responsible for ensuring the length of `key` and `iv` are appropriate for the
89+
/// chosen Cipher.
90+
pub unsafe fn init_encrypt(
91+
&mut self,
92+
cipher: &Cipher,
93+
key: &[u8],
94+
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
95+
) -> Result<(), ErrorStack> {
96+
ffi::init();
97+
98+
unsafe {
99+
cvt(ffi::EVP_EncryptInit_ex(
100+
self.as_ptr(),
101+
cipher.as_ptr(),
102+
// ENGINE api is deprecated
103+
ptr::null_mut(),
104+
key.as_ptr(),
105+
iv.as_ptr(),
106+
))
107+
.map(|_| ())
108+
}
109+
}
110+
111+
/// Configures CipherCtx for a fresh decryption operation using `cipher`.
112+
///
113+
/// https://commondatastorage.googleapis.com/chromium-boringssl-docs/cipher.h.html#EVP_DecryptInit_ex
114+
///
115+
/// SAFETY:
116+
/// The caller must ensure EVP_CIPHER_CTX has been initalized.
117+
///
118+
/// The caller is responsible for ensuring the length of `key` and `iv` are appropriate for the
119+
/// chosen Cipher.
120+
pub unsafe fn init_decrypt(
121+
&mut self,
122+
cipher: &Cipher,
123+
key: &[u8],
124+
iv: &[u8; ffi::EVP_MAX_IV_LENGTH as usize],
125+
) -> Result<(), ErrorStack> {
126+
ffi::init();
127+
128+
unsafe {
129+
cvt(ffi::EVP_DecryptInit_ex(
130+
self.as_ptr(),
131+
cipher.as_ptr(),
132+
// ENGINE api is deprecated
133+
ptr::null_mut(),
134+
key.as_ptr(),
135+
iv.as_ptr(),
136+
))
137+
.map(|_| ())
138+
}
139+
}
140+
}
141+
71142
/// Represents a particular cipher algorithm.
72143
///
73144
/// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms.

0 commit comments

Comments
 (0)