1use crate::bio::{MemBio, MemBioBuf};
15use crate::error::ErrorStack;
16use native_ossl_sys as sys;
17use std::ffi::CString;
18
19pub struct Pkcs12 {
25 ptr: *mut sys::PKCS12,
26}
27
28unsafe impl Send for Pkcs12 {}
29unsafe impl Sync for Pkcs12 {}
30
31impl Drop for Pkcs12 {
32 fn drop(&mut self) {
33 unsafe { sys::PKCS12_free(self.ptr) };
34 }
35}
36
37impl Pkcs12 {
38 pub fn new() -> Result<Self, ErrorStack> {
48 let ptr = unsafe { sys::PKCS12_new() };
53 if ptr.is_null() {
54 return Err(ErrorStack::drain());
55 }
56 Ok(Pkcs12 { ptr })
57 }
58
59 pub fn from_der(der: &[u8]) -> Result<Self, ErrorStack> {
63 let bio = MemBioBuf::new(der)?;
64 let ptr = unsafe { sys::d2i_PKCS12_bio(bio.as_ptr(), std::ptr::null_mut()) };
65 if ptr.is_null() {
66 return Err(ErrorStack::drain());
67 }
68 Ok(Pkcs12 { ptr })
69 }
70
71 pub fn to_der(&self) -> Result<Vec<u8>, ErrorStack> {
75 let mut bio = MemBio::new()?;
76 let rc = unsafe { sys::i2d_PKCS12_bio(bio.as_ptr(), self.ptr) };
77 if rc != 1 {
78 return Err(ErrorStack::drain());
79 }
80 Ok(bio.into_vec())
81 }
82
83 pub fn parse(
91 &self,
92 password: &str,
93 ) -> Result<
94 (
95 crate::pkey::Pkey<crate::pkey::Private>,
96 crate::x509::X509,
97 Vec<crate::x509::X509>,
98 ),
99 ErrorStack,
100 > {
101 let pass = CString::new(password).map_err(|_| ErrorStack::drain())?;
102
103 let mut pkey_ptr: *mut sys::EVP_PKEY = std::ptr::null_mut();
104 let mut cert_ptr: *mut sys::X509 = std::ptr::null_mut();
105 let mut ca_ptr: *mut sys::stack_st_X509 = std::ptr::null_mut();
106
107 let rc = unsafe {
108 sys::PKCS12_parse(
109 self.ptr,
110 pass.as_ptr(),
111 std::ptr::addr_of_mut!(pkey_ptr),
112 std::ptr::addr_of_mut!(cert_ptr),
113 std::ptr::addr_of_mut!(ca_ptr),
114 )
115 };
116 if rc != 1 {
117 return Err(ErrorStack::drain());
118 }
119
120 if pkey_ptr.is_null() || cert_ptr.is_null() {
121 if !pkey_ptr.is_null() {
123 unsafe { sys::EVP_PKEY_free(pkey_ptr) };
124 }
125 if !cert_ptr.is_null() {
126 unsafe { sys::X509_free(cert_ptr) };
127 }
128 free_x509_stack(ca_ptr);
129 return Err(ErrorStack::drain());
130 }
131
132 let key = unsafe { crate::pkey::Pkey::from_ptr(pkey_ptr) };
133 let cert = unsafe { crate::x509::X509::from_ptr(cert_ptr) };
134 let ca = drain_x509_stack(ca_ptr);
135 Ok((key, cert, ca))
136 }
137
138 pub fn create(
149 password: &str,
150 name: &str,
151 key: &crate::pkey::Pkey<crate::pkey::Private>,
152 cert: &crate::x509::X509,
153 ca: &[crate::x509::X509],
154 ) -> Result<Self, ErrorStack> {
155 let ca_stack = if ca.is_empty() {
157 std::ptr::null_mut()
158 } else {
159 build_x509_stack(ca)?
160 };
161
162 let pass = CString::new(password).map_err(|_| ErrorStack::drain())?;
163 let name = CString::new(name).map_err(|_| ErrorStack::drain())?;
164
165 let ptr = unsafe {
166 sys::PKCS12_create_ex(
167 pass.as_ptr(),
168 name.as_ptr(),
169 key.as_ptr(),
170 cert.as_ptr(),
171 ca_stack,
172 0, 0, 0, 0, 0, std::ptr::null_mut(), std::ptr::null(), )
180 };
181
182 if !ca_stack.is_null() {
184 unsafe {
185 sys::OPENSSL_sk_free(ca_stack.cast::<sys::OPENSSL_STACK>());
186 }
187 }
188
189 if ptr.is_null() {
190 return Err(ErrorStack::drain());
191 }
192 Ok(Pkcs12 { ptr })
193 }
194}
195
196fn drain_x509_stack(stack: *mut sys::stack_st_X509) -> Vec<crate::x509::X509> {
204 if stack.is_null() {
205 return Vec::new();
206 }
207 let n = unsafe { sys::OPENSSL_sk_num(stack.cast::<sys::OPENSSL_STACK>()) };
208 let n = usize::try_from(n).unwrap_or(0);
209 let mut out = Vec::with_capacity(n);
210 for i in 0..n {
211 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
213 let raw = unsafe { sys::OPENSSL_sk_value(stack.cast::<sys::OPENSSL_STACK>(), i as i32) };
214 if !raw.is_null() {
215 out.push(unsafe { crate::x509::X509::from_ptr(raw.cast::<sys::X509>()) });
217 }
218 }
219 unsafe { sys::OPENSSL_sk_free(stack.cast::<sys::OPENSSL_STACK>()) };
221 out
222}
223
224fn free_x509_stack(stack: *mut sys::stack_st_X509) {
226 if stack.is_null() {
227 return;
228 }
229 let n = unsafe { sys::OPENSSL_sk_num(stack.cast::<sys::OPENSSL_STACK>()) };
230 for i in 0..n {
231 let raw = unsafe { sys::OPENSSL_sk_value(stack.cast::<sys::OPENSSL_STACK>(), i) };
232 if !raw.is_null() {
233 unsafe { sys::X509_free(raw.cast::<sys::X509>()) };
234 }
235 }
236 unsafe { sys::OPENSSL_sk_free(stack.cast::<sys::OPENSSL_STACK>()) };
237}
238
239fn build_x509_stack(certs: &[crate::x509::X509]) -> Result<*mut sys::stack_st_X509, ErrorStack> {
245 let raw = unsafe { sys::OPENSSL_sk_new_null() };
248 if raw.is_null() {
249 return Err(ErrorStack::drain());
250 }
251 for cert in certs {
252 unsafe { sys::X509_up_ref(cert.as_ptr()) };
254 let rc = unsafe { sys::OPENSSL_sk_push(raw, cert.as_ptr().cast::<std::ffi::c_void>()) };
255 if rc == 0 {
256 unsafe { sys::X509_free(cert.as_ptr()) };
258 let n = unsafe { sys::OPENSSL_sk_num(raw) };
260 for i in 0..n {
261 let p = unsafe { sys::OPENSSL_sk_value(raw, i) };
262 if !p.is_null() {
263 unsafe { sys::X509_free(p.cast::<sys::X509>()) };
264 }
265 }
266 unsafe { sys::OPENSSL_sk_free(raw) };
267 return Err(ErrorStack::drain());
268 }
269 }
270 Ok(raw.cast::<sys::stack_st_X509>())
271}
272
273#[cfg(test)]
276mod tests {
277 use super::*;
278 use crate::pkey::{KeygenCtx, Pkey, Private, Public};
279 use crate::x509::{X509Builder, X509NameOwned};
280
281 fn make_self_signed() -> (crate::x509::X509, Pkey<Private>) {
282 let mut kgen = KeygenCtx::new(c"ED25519").unwrap();
283 let priv_key = kgen.generate().unwrap();
284 let pub_key = Pkey::<Public>::from(priv_key.clone());
285
286 let mut name = X509NameOwned::new().unwrap();
287 name.add_entry_by_txt(c"CN", b"PKCS12 Test").unwrap();
288
289 let cert = X509Builder::new()
290 .unwrap()
291 .set_version(2)
292 .unwrap()
293 .set_serial_number(1)
294 .unwrap()
295 .set_not_before_offset(0)
296 .unwrap()
297 .set_not_after_offset(365 * 86400)
298 .unwrap()
299 .set_subject_name(&name)
300 .unwrap()
301 .set_issuer_name(&name)
302 .unwrap()
303 .set_public_key(&pub_key)
304 .unwrap()
305 .sign(&priv_key, None)
306 .unwrap()
307 .build();
308
309 (cert, priv_key)
310 }
311
312 #[test]
313 fn pkcs12_new_is_ok() {
314 let p12 = Pkcs12::new().expect("PKCS12_new should succeed");
317 drop(p12);
318 }
319
320 #[test]
321 fn pkcs12_create_and_parse_roundtrip() {
322 let (cert, priv_key) = make_self_signed();
323
324 let p12 = Pkcs12::create("testpass", "test", &priv_key, &cert, &[]).unwrap();
325 let der = p12.to_der().unwrap();
326 assert!(!der.is_empty());
327
328 let p12b = Pkcs12::from_der(&der).unwrap();
330 let (key2, cert2, ca2) = p12b.parse("testpass").unwrap();
331
332 assert!(key2.is_a(c"ED25519"));
334 let subj = cert2.subject_name().to_string().unwrap();
336 assert!(subj.contains("PKCS12 Test"));
337 assert!(ca2.is_empty());
339 }
340
341 #[test]
342 fn pkcs12_der_roundtrip() {
343 let (cert, priv_key) = make_self_signed();
344 let p12 = Pkcs12::create("pass", "n", &priv_key, &cert, &[]).unwrap();
345 let der1 = p12.to_der().unwrap();
346 let p12b = Pkcs12::from_der(&der1).unwrap();
347 let der2 = p12b.to_der().unwrap();
348 assert_eq!(der1, der2);
349 }
350
351 #[test]
352 fn pkcs12_wrong_password_fails() {
353 let (cert, priv_key) = make_self_signed();
354 let p12 = Pkcs12::create("rightpass", "n", &priv_key, &cert, &[]).unwrap();
355 let der = p12.to_der().unwrap();
356 let p12b = Pkcs12::from_der(&der).unwrap();
357 assert!(p12b.parse("wrongpass").is_err());
358 }
359}