From 45f8589d489e6177359727b5d59a6223da13aa75 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 2 Jun 2025 08:56:54 +0200 Subject: [PATCH] Add mutable ex_data APIs for X509StoreContext --- boring/src/lib.rs | 15 ++++++++++ boring/src/ssl/mod.rs | 17 ++--------- boring/src/x509/mod.rs | 67 +++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 16 deletions(-) diff --git a/boring/src/lib.rs b/boring/src/lib.rs index aaa268b6..4b84b7c5 100644 --- a/boring/src/lib.rs +++ b/boring/src/lib.rs @@ -108,6 +108,8 @@ extern crate libc; #[cfg(test)] extern crate hex; +use std::ffi::{c_long, c_void}; + #[doc(inline)] pub use crate::ffi::init; @@ -193,3 +195,16 @@ fn cvt_n(r: c_int) -> Result { Ok(r) } } + +unsafe extern "C" fn free_data_box( + _parent: *mut c_void, + ptr: *mut c_void, + _ad: *mut ffi::CRYPTO_EX_DATA, + _idx: c_int, + _argl: c_long, + _argp: *mut c_void, +) { + if !ptr.is_null() { + drop(Box::::from_raw(ptr as *mut T)); + } +} diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index c6dd92e7..a03cdf6e 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -58,7 +58,7 @@ //! } //! ``` use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; -use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void}; +use libc::{c_char, c_int, c_uchar, c_uint, c_void}; use openssl_macros::corresponds; use std::any::TypeId; use std::collections::HashMap; @@ -81,7 +81,6 @@ use crate::dh::DhRef; use crate::ec::EcKeyRef; use crate::error::ErrorStack; use crate::ex_data::Index; -use crate::ffi; use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; @@ -95,6 +94,7 @@ use crate::x509::{ X509Name, X509Ref, X509StoreContextRef, X509VerifyError, X509VerifyResult, X509, }; use crate::{cvt, cvt_0i, cvt_n, cvt_p, init}; +use crate::{ffi, free_data_box}; pub use self::async_callbacks::{ AsyncPrivateKeyMethod, AsyncPrivateKeyMethodError, AsyncSelectCertError, BoxCustomVerifyFinish, @@ -439,19 +439,6 @@ static SESSION_CTX_INDEX: LazyLock> = static RPK_FLAG_INDEX: LazyLock> = LazyLock::new(|| SslContext::new_ex_index().unwrap()); -unsafe extern "C" fn free_data_box( - _parent: *mut c_void, - ptr: *mut c_void, - _ad: *mut ffi::CRYPTO_EX_DATA, - _idx: c_int, - _argl: c_long, - _argp: *mut c_void, -) { - if !ptr.is_null() { - drop(Box::::from_raw(ptr as *mut T)); - } -} - /// An error returned from the SNI callback. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SniError(c_int); diff --git a/boring/src/x509/mod.rs b/boring/src/x509/mod.rs index 308dc85d..8ffa732d 100644 --- a/boring/src/x509/mod.rs +++ b/boring/src/x509/mod.rs @@ -30,7 +30,6 @@ use crate::bio::{MemBio, MemBioSlice}; use crate::conf::ConfRef; use crate::error::ErrorStack; use crate::ex_data::Index; -use crate::ffi; use crate::hash::{DigestBytes, MessageDigest}; use crate::nid::Nid; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; @@ -40,6 +39,7 @@ use crate::string::OpensslString; use crate::util::ForeignTypeRefExt; use crate::x509::verify::{X509VerifyParam, X509VerifyParamRef}; use crate::{cvt, cvt_n, cvt_p}; +use crate::{ffi, free_data_box}; pub mod extension; pub mod store; @@ -72,6 +72,22 @@ impl X509StoreContext { cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext::from_ptr(p)) } } + + /// Returns a new extra data index. + /// + /// Each invocation of this function is guaranteed to return a distinct index. These can be used + /// to store data in the context that can be retrieved later by callbacks, for example. + #[corresponds(SSL_CTX_get_ex_new_index)] + pub fn new_ex_index() -> Result, ErrorStack> + where + T: 'static + Sync + Send, + { + unsafe { + ffi::init(); + let idx = cvt_n(get_new_x509_store_ctx_idx(Some(free_data_box::)))?; + Ok(Index::from_raw(idx)) + } + } } impl X509StoreContextRef { @@ -88,6 +104,44 @@ impl X509StoreContextRef { } } + /// Returns a mutable reference to the extra data at the specified index. + #[corresponds(X509_STORE_CTX_get_ex_data)] + pub fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { + unsafe { + let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); + if data.is_null() { + None + } else { + Some(&mut *(data as *mut T)) + } + } + } + + /// Sets or overwrites the extra data at the specified index. + /// + /// This can be used to provide data to callbacks registered with the context. Use the + /// `Ssl::new_ex_index` method to create an `Index`. + /// + /// The previous value, if any, will be returned. + #[corresponds(X509_STORE_CTX_set_ex_data)] + pub fn set_ex_data(&mut self, index: Index, data: T) { + if let Some(old) = self.ex_data_mut(index) { + *old = data; + + return; + } + + unsafe { + let data = Box::new(data); + + ffi::X509_STORE_CTX_set_ex_data( + self.as_ptr(), + index.as_raw(), + Box::into_raw(data) as *mut c_void, + ); + } + } + /// Returns the verify result of the context. #[corresponds(X509_STORE_CTX_get_error)] pub fn verify_result(&self) -> X509VerifyResult { @@ -1688,3 +1742,14 @@ unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { ffi::X509_OBJECT_free_contents(x); ffi::OPENSSL_free(x as *mut libc::c_void); } + +unsafe fn get_new_x509_store_ctx_idx(f: ffi::CRYPTO_EX_free) -> c_int { + // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest + static ONCE: Once = Once::new(); + + ONCE.call_once(|| { + ffi::X509_STORE_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None); + }); + + ffi::X509_STORE_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f) +}