Add mutable ex_data APIs for X509StoreContext

This commit is contained in:
Anthony Ramine 2025-06-02 08:56:54 +02:00 committed by Kornel
parent 15975ddde4
commit 45f8589d48
3 changed files with 83 additions and 16 deletions

View File

@ -108,6 +108,8 @@ extern crate libc;
#[cfg(test)] #[cfg(test)]
extern crate hex; extern crate hex;
use std::ffi::{c_long, c_void};
#[doc(inline)] #[doc(inline)]
pub use crate::ffi::init; pub use crate::ffi::init;
@ -193,3 +195,16 @@ fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
Ok(r) Ok(r)
} }
} }
unsafe extern "C" fn free_data_box<T>(
_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::<T>::from_raw(ptr as *mut T));
}
}

View File

@ -58,7 +58,7 @@
//! } //! }
//! ``` //! ```
use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; 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 openssl_macros::corresponds;
use std::any::TypeId; use std::any::TypeId;
use std::collections::HashMap; use std::collections::HashMap;
@ -81,7 +81,6 @@ 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::ffi;
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};
@ -95,6 +94,7 @@ use crate::x509::{
X509Name, X509Ref, X509StoreContextRef, X509VerifyError, X509VerifyResult, X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyError, X509VerifyResult, X509,
}; };
use crate::{cvt, cvt_0i, cvt_n, cvt_p, init}; use crate::{cvt, cvt_0i, cvt_n, cvt_p, init};
use crate::{ffi, free_data_box};
pub use self::async_callbacks::{ pub use self::async_callbacks::{
AsyncPrivateKeyMethod, AsyncPrivateKeyMethodError, AsyncSelectCertError, BoxCustomVerifyFinish, AsyncPrivateKeyMethod, AsyncPrivateKeyMethodError, AsyncSelectCertError, BoxCustomVerifyFinish,
@ -439,19 +439,6 @@ static SESSION_CTX_INDEX: LazyLock<Index<Ssl, SslContext>> =
static RPK_FLAG_INDEX: LazyLock<Index<SslContext, bool>> = static RPK_FLAG_INDEX: LazyLock<Index<SslContext, bool>> =
LazyLock::new(|| SslContext::new_ex_index().unwrap()); LazyLock::new(|| SslContext::new_ex_index().unwrap());
unsafe extern "C" fn free_data_box<T>(
_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::<T>::from_raw(ptr as *mut T));
}
}
/// An error returned from the SNI callback. /// An error returned from the SNI callback.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SniError(c_int); pub struct SniError(c_int);

View File

@ -30,7 +30,6 @@ use crate::bio::{MemBio, MemBioSlice};
use crate::conf::ConfRef; use crate::conf::ConfRef;
use crate::error::ErrorStack; use crate::error::ErrorStack;
use crate::ex_data::Index; use crate::ex_data::Index;
use crate::ffi;
use crate::hash::{DigestBytes, MessageDigest}; use crate::hash::{DigestBytes, MessageDigest};
use crate::nid::Nid; use crate::nid::Nid;
use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public};
@ -40,6 +39,7 @@ use crate::string::OpensslString;
use crate::util::ForeignTypeRefExt; use crate::util::ForeignTypeRefExt;
use crate::x509::verify::{X509VerifyParam, X509VerifyParamRef}; use crate::x509::verify::{X509VerifyParam, X509VerifyParamRef};
use crate::{cvt, cvt_n, cvt_p}; use crate::{cvt, cvt_n, cvt_p};
use crate::{ffi, free_data_box};
pub mod extension; pub mod extension;
pub mod store; pub mod store;
@ -72,6 +72,22 @@ impl X509StoreContext {
cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext::from_ptr(p)) 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<T>() -> Result<Index<X509StoreContext, T>, ErrorStack>
where
T: 'static + Sync + Send,
{
unsafe {
ffi::init();
let idx = cvt_n(get_new_x509_store_ctx_idx(Some(free_data_box::<T>)))?;
Ok(Index::from_raw(idx))
}
}
} }
impl X509StoreContextRef { 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<T>(&mut self, index: Index<X509StoreContext, T>) -> 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<T>(&mut self, index: Index<X509StoreContext, T>, 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. /// Returns the verify result of the context.
#[corresponds(X509_STORE_CTX_get_error)] #[corresponds(X509_STORE_CTX_get_error)]
pub fn verify_result(&self) -> X509VerifyResult { 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::X509_OBJECT_free_contents(x);
ffi::OPENSSL_free(x as *mut libc::c_void); 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)
}