From cc82196281e048559717a6562894e87dff52e4d4 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 13 Feb 2026 19:40:19 +0000 Subject: [PATCH 1/2] Fix null handling, sync with rust-openssl --- boring/src/pkcs12.rs | 49 ++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/boring/src/pkcs12.rs b/boring/src/pkcs12.rs index bb851421e..449b3fafe 100644 --- a/boring/src/pkcs12.rs +++ b/boring/src/pkcs12.rs @@ -10,7 +10,7 @@ use std::ptr; use crate::error::ErrorStack; use crate::nid::Nid; use crate::pkey::{HasPrivate, PKey, PKeyRef, Private}; -use crate::stack::Stack; +use crate::stack::{Stack, StackRef}; use crate::x509::{X509Ref, X509}; use crate::{cvt_0i, cvt_p}; @@ -31,33 +31,43 @@ impl Pkcs12Ref { ffi::i2d_PKCS12 } - /// Extracts the contents of the `Pkcs12`. + /// Extracts the contents of the `Pkcs12` with `pkey` and `cert` required. pub fn parse(&self, pass: &str) -> Result { + let p2 = self.parse2(pass)?; + Ok(ParsedPkcs12 { + pkey: p2 + .pkey + .ok_or_else(|| ErrorStack::internal_error_str("missing pkey"))?, + cert: p2 + .cert + .ok_or_else(|| ErrorStack::internal_error_str("missing cert"))?, + chain: p2.ca, + }) + } + + /// Extracts the contents of the `Pkcs12` with `pkey` and `cert` optional. + #[corresponds(PKCS12_parse)] + pub fn parse2(&self, pass: &str) -> Result { unsafe { let pass = CString::new(pass.as_bytes()).map_err(ErrorStack::internal_error)?; let mut pkey = ptr::null_mut(); let mut cert = ptr::null_mut(); - let mut chain = ptr::null_mut(); + let mut ca = ptr::null_mut(); cvt_0i(ffi::PKCS12_parse( self.as_ptr(), pass.as_ptr(), &mut pkey, &mut cert, - &mut chain, + &mut ca, ))?; - let pkey = PKey::from_ptr(pkey); - let cert = X509::from_ptr(cert); + let pkey = (!pkey.is_null()).then(|| PKey::from_ptr(pkey)); + let cert = (!cert.is_null()).then(|| X509::from_ptr(cert)); + let ca = (!ca.is_null()).then(|| Stack::from_ptr(ca)); - let chain = if chain.is_null() { - None - } else { - Some(Stack::from_ptr(chain)) - }; - - Ok(ParsedPkcs12 { pkey, cert, chain }) + Ok(ParsedPkcs12_2 { pkey, cert, ca }) } } } @@ -100,6 +110,19 @@ pub struct ParsedPkcs12 { pub chain: Option>, } +/// [`ParsedPkcs12`] with optional fields +pub struct ParsedPkcs12_2 { + pub pkey: Option>, + pub cert: Option, + pub ca: Option>, +} + +impl ParsedPkcs12_2 { + pub fn chain(&self) -> Option<&StackRef> { + self.ca.as_deref() + } +} + pub struct Pkcs12Builder { nid_key: Nid, nid_cert: Nid, From c400aac83b8a4054576ee1b4886244bd6b0c65b0 Mon Sep 17 00:00:00 2001 From: Kornel Date: Fri, 13 Feb 2026 19:56:42 +0000 Subject: [PATCH 2/2] Expose load_verify_locations like rust-openssl --- boring/src/ssl/mod.rs | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/boring/src/ssl/mod.rs b/boring/src/ssl/mod.rs index b330ce976..139979078 100644 --- a/boring/src/ssl/mod.rs +++ b/boring/src/ssl/mod.rs @@ -1272,15 +1272,26 @@ impl SslContextBuilder { /// The file should contain a sequence of PEM-formatted CA certificates. #[corresponds(SSL_CTX_load_verify_locations)] pub fn set_ca_file>(&mut self, file: P) -> Result<(), ErrorStack> { + self.load_verify_locations(Some(file.as_ref()), None) + } + + /// Loads trusted root certificates from a file and/or a directory. + #[corresponds(SSL_CTX_load_verify_locations)] + pub fn load_verify_locations( + &mut self, + ca_file: Option<&Path>, + ca_path: Option<&Path>, + ) -> Result<(), ErrorStack> { self.ctx.check_x509(); - let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes()) - .map_err(ErrorStack::internal_error)?; + let ca_file = ca_file.map(path_to_cstring).transpose()?; + let ca_path = ca_path.map(path_to_cstring).transpose()?; + unsafe { cvt(ffi::SSL_CTX_load_verify_locations( self.as_ptr(), - file.as_ptr(), - ptr::null(), + ca_file.as_ref().map_or(ptr::null(), |s| s.as_ptr()), + ca_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), )) } } @@ -1341,8 +1352,7 @@ impl SslContextBuilder { ) -> Result<(), ErrorStack> { self.ctx.check_x509(); - let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes()) - .map_err(ErrorStack::internal_error)?; + let file = path_to_cstring(file.as_ref())?; unsafe { cvt(ffi::SSL_CTX_use_certificate_file( self.as_ptr(), @@ -1362,8 +1372,7 @@ impl SslContextBuilder { &mut self, file: P, ) -> Result<(), ErrorStack> { - let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes()) - .map_err(ErrorStack::internal_error)?; + let file = path_to_cstring(file.as_ref())?; unsafe { cvt(ffi::SSL_CTX_use_certificate_chain_file( self.as_ptr(), @@ -1403,8 +1412,7 @@ impl SslContextBuilder { file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> { - let file = CString::new(file.as_ref().as_os_str().as_encoded_bytes()) - .map_err(ErrorStack::internal_error)?; + let file = path_to_cstring(file.as_ref())?; unsafe { cvt(ffi::SSL_CTX_use_PrivateKey_file( self.as_ptr(), @@ -4574,3 +4582,7 @@ unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f) } + +fn path_to_cstring(path: &Path) -> Result { + CString::new(path.as_os_str().as_encoded_bytes()).map_err(ErrorStack::internal_error) +}