1use crate::ffi;
4use foreign_types::{ForeignType, ForeignTypeRef};
5use libc::c_int;
6use openssl_macros::corresponds;
7use std::ffi::CString;
8use std::ptr;
9
10use crate::error::ErrorStack;
11use crate::nid::Nid;
12use crate::pkey::{HasPrivate, PKey, PKeyRef, Private};
13use crate::stack::{Stack, StackRef};
14use crate::x509::{X509Ref, X509};
15use crate::{cvt_0i, cvt_p};
16
17pub const PKCS12_DEFAULT_ITER: c_int = 2048;
18
19foreign_type_and_impl_send_sync! {
20 type CType = ffi::PKCS12;
21 fn drop = ffi::PKCS12_free;
22
23 pub struct Pkcs12;
24}
25
26impl Pkcs12Ref {
27 to_der! {
28 #[corresponds(i2d_PKCS12)]
30 to_der,
31 ffi::i2d_PKCS12
32 }
33
34 pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
36 let p2 = self.parse2(pass)?;
37 Ok(ParsedPkcs12 {
38 pkey: p2
39 .pkey
40 .ok_or_else(|| ErrorStack::internal_error_str("missing pkey"))?,
41 cert: p2
42 .cert
43 .ok_or_else(|| ErrorStack::internal_error_str("missing cert"))?,
44 chain: p2.ca,
45 })
46 }
47
48 #[corresponds(PKCS12_parse)]
50 pub fn parse2(&self, pass: &str) -> Result<ParsedPkcs12_2, ErrorStack> {
51 unsafe {
52 let pass = CString::new(pass.as_bytes()).map_err(ErrorStack::internal_error)?;
53
54 let mut pkey = ptr::null_mut();
55 let mut cert = ptr::null_mut();
56 let mut ca = ptr::null_mut();
57
58 cvt_0i(ffi::PKCS12_parse(
59 self.as_ptr(),
60 pass.as_ptr(),
61 &mut pkey,
62 &mut cert,
63 &mut ca,
64 ))?;
65
66 let pkey = (!pkey.is_null()).then(|| PKey::from_ptr(pkey));
67 let cert = (!cert.is_null()).then(|| X509::from_ptr(cert));
68 let ca = (!ca.is_null()).then(|| Stack::from_ptr(ca));
69
70 Ok(ParsedPkcs12_2 { pkey, cert, ca })
71 }
72 }
73}
74
75impl Pkcs12 {
76 from_der! {
77 #[corresponds(d2i_PKCS12)]
79 from_der,
80 Pkcs12,
81 ffi::d2i_PKCS12,
82 ::libc::size_t
83 }
84
85 #[must_use]
94 pub fn builder() -> Pkcs12Builder {
95 ffi::init();
96
97 Pkcs12Builder {
98 nid_key: Nid::UNDEF, nid_cert: Nid::UNDEF, iter: PKCS12_DEFAULT_ITER,
101 mac_iter: PKCS12_DEFAULT_ITER,
102 ca: None,
103 }
104 }
105}
106
107pub struct ParsedPkcs12 {
108 pub pkey: PKey<Private>,
109 pub cert: X509,
110 pub chain: Option<Stack<X509>>,
111}
112
113pub struct ParsedPkcs12_2 {
115 pub pkey: Option<PKey<Private>>,
116 pub cert: Option<X509>,
117 pub ca: Option<Stack<X509>>,
118}
119
120impl ParsedPkcs12_2 {
121 pub fn chain(&self) -> Option<&StackRef<X509>> {
122 self.ca.as_deref()
123 }
124}
125
126pub struct Pkcs12Builder {
127 nid_key: Nid,
128 nid_cert: Nid,
129 iter: c_int,
130 mac_iter: c_int,
131 ca: Option<Stack<X509>>,
132}
133
134impl Pkcs12Builder {
135 pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self {
137 self.nid_key = nid;
138 self
139 }
140
141 pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self {
143 self.nid_cert = nid;
144 self
145 }
146
147 pub fn key_iter(&mut self, iter: u32) -> &mut Self {
149 self.iter = iter as c_int;
150 self
151 }
152
153 pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self {
158 self.mac_iter = mac_iter as c_int;
159 self
160 }
161
162 pub fn ca(&mut self, ca: Stack<X509>) -> &mut Self {
165 self.ca = Some(ca);
166 self
167 }
168
169 pub fn build<T>(
178 self,
179 password: &str,
180 friendly_name: &str,
181 pkey: &PKeyRef<T>,
182 cert: &X509Ref,
183 ) -> Result<Pkcs12, ErrorStack>
184 where
185 T: HasPrivate,
186 {
187 unsafe {
188 let pass = CString::new(password).map_err(ErrorStack::internal_error)?;
189 let friendly_name = CString::new(friendly_name).map_err(ErrorStack::internal_error)?;
190 let pkey = pkey.as_ptr();
191 let cert = cert.as_ptr();
192 let ca = self
193 .ca
194 .as_ref()
195 .map(|ca| ca.as_ptr())
196 .unwrap_or(ptr::null_mut());
197 let nid_key = self.nid_key.as_raw();
198 let nid_cert = self.nid_cert.as_raw();
199
200 let keytype = 0;
204
205 cvt_p(ffi::PKCS12_create(
206 pass.as_ptr(),
207 friendly_name.as_ptr(),
208 pkey,
209 cert,
210 ca,
211 nid_key,
212 nid_cert,
213 self.iter,
214 self.mac_iter,
215 keytype,
216 ))
217 .map(|p| Pkcs12::from_ptr(p))
218 }
219 }
220}
221
222#[cfg(test)]
223mod test {
224 use crate::hash::MessageDigest;
225 use hex;
226
227 use crate::asn1::Asn1Time;
228 use crate::nid::Nid;
229 use crate::pkey::PKey;
230 use crate::rsa::Rsa;
231 use crate::x509::extension::KeyUsage;
232 use crate::x509::{X509Name, X509};
233
234 use super::*;
235
236 #[test]
237 fn parse() {
238 let der = include_bytes!("../test/identity.p12");
239 let pkcs12 = Pkcs12::from_der(der).unwrap();
240 let parsed = pkcs12.parse("mypass").unwrap();
241
242 assert_eq!(
243 hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()),
244 "59172d9313e84459bcff27f967e79e6e9217e584"
245 );
246
247 let chain = parsed.chain.unwrap();
248 assert_eq!(chain.len(), 1);
249 assert_eq!(
250 hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()),
251 "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
252 );
253 }
254
255 #[test]
256 fn parse_empty_chain() {
257 let der = include_bytes!("../test/keystore-empty-chain.p12");
258 let pkcs12 = Pkcs12::from_der(der).unwrap();
259 let parsed = pkcs12.parse("cassandra").unwrap();
260 assert_eq!(parsed.chain.unwrap().len(), 0);
261 }
262
263 #[test]
264 fn create() {
265 let subject_name = "ns.example.com";
266 let rsa = Rsa::generate(2048).unwrap();
267 let pkey = PKey::from_rsa(rsa).unwrap();
268
269 let mut name = X509Name::builder().unwrap();
270 name.append_entry_by_nid(Nid::COMMONNAME, subject_name)
271 .unwrap();
272 let name = name.build();
273
274 let key_usage = KeyUsage::new().digital_signature().build().unwrap();
275
276 let mut builder = X509::builder().unwrap();
277 builder.set_version(2).unwrap();
278 builder
279 .set_not_before(&Asn1Time::days_from_now(0).unwrap())
280 .unwrap();
281 builder
282 .set_not_after(&Asn1Time::days_from_now(365).unwrap())
283 .unwrap();
284 builder.set_subject_name(&name).unwrap();
285 builder.set_issuer_name(&name).unwrap();
286 builder.append_extension(&key_usage).unwrap();
287 builder.set_pubkey(&pkey).unwrap();
288 builder.sign(&pkey, MessageDigest::sha256()).unwrap();
289 let cert = builder.build();
290
291 let pkcs12_builder = Pkcs12::builder();
292 let pkcs12 = pkcs12_builder
293 .build("mypass", subject_name, &pkey, &cert)
294 .unwrap();
295 let der = pkcs12.to_der().unwrap();
296
297 let pkcs12 = Pkcs12::from_der(&der).unwrap();
298 let parsed = pkcs12.parse("mypass").unwrap();
299
300 assert_eq!(
301 &*parsed.cert.digest(MessageDigest::sha1()).unwrap(),
302 &*cert.digest(MessageDigest::sha1()).unwrap()
303 );
304 assert!(parsed.pkey.public_eq(&pkey));
305 }
306}