1 //! PKCS #12 archives.
2 
3 use foreign_types::{ForeignType, ForeignTypeRef};
4 use libc::c_int;
5 use std::ffi::CString;
6 use std::ptr;
7 
8 use crate::error::ErrorStack;
9 use crate::nid::Nid;
10 use crate::pkey::{HasPrivate, PKey, PKeyRef, Private};
11 use crate::stack::Stack;
12 use crate::util::ForeignTypeExt;
13 use crate::x509::{X509Ref, X509};
14 use crate::{cvt, cvt_p};
15 
16 foreign_type_and_impl_send_sync! {
17     type CType = ffi::PKCS12;
18     fn drop = ffi::PKCS12_free;
19 
20     pub struct Pkcs12;
21     pub struct Pkcs12Ref;
22 }
23 
24 impl Pkcs12Ref {
25     to_der! {
26         /// Serializes the `Pkcs12` to its standard DER encoding.
27         ///
28         /// This corresponds to [`i2d_PKCS12`].
29         ///
30         /// [`i2d_PKCS12`]: https://www.openssl.org/docs/manmaster/man3/i2d_PKCS12.html
31         to_der,
32         ffi::i2d_PKCS12
33     }
34 
35     /// Extracts the contents of the `Pkcs12`.
parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack>36     pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> {
37         unsafe {
38             let pass = CString::new(pass.as_bytes()).unwrap();
39 
40             let mut pkey = ptr::null_mut();
41             let mut cert = ptr::null_mut();
42             let mut chain = ptr::null_mut();
43 
44             cvt(ffi::PKCS12_parse(
45                 self.as_ptr(),
46                 pass.as_ptr(),
47                 &mut pkey,
48                 &mut cert,
49                 &mut chain,
50             ))?;
51 
52             let pkey = PKey::from_ptr(pkey);
53             let cert = X509::from_ptr(cert);
54 
55             let chain = Stack::from_ptr_opt(chain);
56 
57             Ok(ParsedPkcs12 { pkey, cert, chain })
58         }
59     }
60 }
61 
62 impl Pkcs12 {
63     from_der! {
64         /// Deserializes a DER-encoded PKCS#12 archive.
65         ///
66         /// This corresponds to [`d2i_PKCS12`].
67         ///
68         /// [`d2i_PKCS12`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PKCS12.html
69         from_der,
70         Pkcs12,
71         ffi::d2i_PKCS12
72     }
73 
74     /// Creates a new builder for a protected pkcs12 certificate.
75     ///
76     /// This uses the defaults from the OpenSSL library:
77     ///
78     /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC`
79     /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC`
80     /// * `iter` - `2048`
81     /// * `mac_iter` - `2048`
builder() -> Pkcs12Builder82     pub fn builder() -> Pkcs12Builder {
83         ffi::init();
84 
85         Pkcs12Builder {
86             nid_key: Nid::UNDEF,  //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC,
87             nid_cert: Nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC,
88             iter: ffi::PKCS12_DEFAULT_ITER,
89             mac_iter: ffi::PKCS12_DEFAULT_ITER,
90             ca: None,
91         }
92     }
93 }
94 
95 pub struct ParsedPkcs12 {
96     pub pkey: PKey<Private>,
97     pub cert: X509,
98     pub chain: Option<Stack<X509>>,
99 }
100 
101 pub struct Pkcs12Builder {
102     nid_key: Nid,
103     nid_cert: Nid,
104     iter: c_int,
105     mac_iter: c_int,
106     ca: Option<Stack<X509>>,
107 }
108 
109 impl Pkcs12Builder {
110     /// The encryption algorithm that should be used for the key
key_algorithm(&mut self, nid: Nid) -> &mut Self111     pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self {
112         self.nid_key = nid;
113         self
114     }
115 
116     /// The encryption algorithm that should be used for the cert
cert_algorithm(&mut self, nid: Nid) -> &mut Self117     pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self {
118         self.nid_cert = nid;
119         self
120     }
121 
122     /// Key iteration count, default is 2048 as of this writing
key_iter(&mut self, iter: u32) -> &mut Self123     pub fn key_iter(&mut self, iter: u32) -> &mut Self {
124         self.iter = iter as c_int;
125         self
126     }
127 
128     /// MAC iteration count, default is the same as key_iter.
129     ///
130     /// Old implementations don't understand MAC iterations greater than 1, (pre 1.0.1?), if such
131     /// compatibility is required this should be set to 1.
mac_iter(&mut self, mac_iter: u32) -> &mut Self132     pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self {
133         self.mac_iter = mac_iter as c_int;
134         self
135     }
136 
137     /// An additional set of certificates to include in the archive beyond the one provided to
138     /// `build`.
ca(&mut self, ca: Stack<X509>) -> &mut Self139     pub fn ca(&mut self, ca: Stack<X509>) -> &mut Self {
140         self.ca = Some(ca);
141         self
142     }
143 
144     /// Builds the PKCS #12 object
145     ///
146     /// # Arguments
147     ///
148     /// * `password` - the password used to encrypt the key and certificate
149     /// * `friendly_name` - user defined name for the certificate
150     /// * `pkey` - key to store
151     /// * `cert` - certificate to store
build<T>( self, password: &str, friendly_name: &str, pkey: &PKeyRef<T>, cert: &X509Ref, ) -> Result<Pkcs12, ErrorStack> where T: HasPrivate,152     pub fn build<T>(
153         self,
154         password: &str,
155         friendly_name: &str,
156         pkey: &PKeyRef<T>,
157         cert: &X509Ref,
158     ) -> Result<Pkcs12, ErrorStack>
159     where
160         T: HasPrivate,
161     {
162         unsafe {
163             let pass = CString::new(password).unwrap();
164             let friendly_name = CString::new(friendly_name).unwrap();
165             let pkey = pkey.as_ptr();
166             let cert = cert.as_ptr();
167             let ca = self
168                 .ca
169                 .as_ref()
170                 .map(|ca| ca.as_ptr())
171                 .unwrap_or(ptr::null_mut());
172             let nid_key = self.nid_key.as_raw();
173             let nid_cert = self.nid_cert.as_raw();
174 
175             // According to the OpenSSL docs, keytype is a non-standard extension for MSIE,
176             // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information:
177             // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html
178             let keytype = 0;
179 
180             cvt_p(ffi::PKCS12_create(
181                 pass.as_ptr() as *const _ as *mut _,
182                 friendly_name.as_ptr() as *const _ as *mut _,
183                 pkey,
184                 cert,
185                 ca,
186                 nid_key,
187                 nid_cert,
188                 self.iter,
189                 self.mac_iter,
190                 keytype,
191             ))
192             .map(Pkcs12)
193         }
194     }
195 }
196 
197 #[cfg(test)]
198 mod test {
199     use crate::asn1::Asn1Time;
200     use crate::hash::MessageDigest;
201     use crate::nid::Nid;
202     use crate::pkey::PKey;
203     use crate::rsa::Rsa;
204     use crate::x509::extension::KeyUsage;
205     use crate::x509::{X509Name, X509};
206 
207     use super::*;
208 
209     #[test]
210     #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672
parse()211     fn parse() {
212         let der = include_bytes!("../test/identity.p12");
213         let pkcs12 = Pkcs12::from_der(der).unwrap();
214         let parsed = pkcs12.parse("mypass").unwrap();
215 
216         assert_eq!(
217             hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()),
218             "59172d9313e84459bcff27f967e79e6e9217e584"
219         );
220 
221         let chain = parsed.chain.unwrap();
222         assert_eq!(chain.len(), 1);
223         assert_eq!(
224             hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()),
225             "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
226         );
227     }
228 
229     #[test]
230     #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672
parse_empty_chain()231     fn parse_empty_chain() {
232         let der = include_bytes!("../test/keystore-empty-chain.p12");
233         let pkcs12 = Pkcs12::from_der(der).unwrap();
234         let parsed = pkcs12.parse("cassandra").unwrap();
235         assert!(parsed.chain.is_none());
236     }
237 
238     #[test]
239     #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672
create()240     fn create() {
241         let subject_name = "ns.example.com";
242         let rsa = Rsa::generate(2048).unwrap();
243         let pkey = PKey::from_rsa(rsa).unwrap();
244 
245         let mut name = X509Name::builder().unwrap();
246         name.append_entry_by_nid(Nid::COMMONNAME, subject_name)
247             .unwrap();
248         let name = name.build();
249 
250         let key_usage = KeyUsage::new().digital_signature().build().unwrap();
251 
252         let mut builder = X509::builder().unwrap();
253         builder.set_version(2).unwrap();
254         builder
255             .set_not_before(&Asn1Time::days_from_now(0).unwrap())
256             .unwrap();
257         builder
258             .set_not_after(&Asn1Time::days_from_now(365).unwrap())
259             .unwrap();
260         builder.set_subject_name(&name).unwrap();
261         builder.set_issuer_name(&name).unwrap();
262         builder.append_extension(key_usage).unwrap();
263         builder.set_pubkey(&pkey).unwrap();
264         builder.sign(&pkey, MessageDigest::sha256()).unwrap();
265         let cert = builder.build();
266 
267         let pkcs12_builder = Pkcs12::builder();
268         let pkcs12 = pkcs12_builder
269             .build("mypass", subject_name, &pkey, &cert)
270             .unwrap();
271         let der = pkcs12.to_der().unwrap();
272 
273         let pkcs12 = Pkcs12::from_der(&der).unwrap();
274         let parsed = pkcs12.parse("mypass").unwrap();
275 
276         assert_eq!(
277             &*parsed.cert.digest(MessageDigest::sha1()).unwrap(),
278             &*cert.digest(MessageDigest::sha1()).unwrap()
279         );
280         assert!(parsed.pkey.public_eq(&pkey));
281     }
282 }
283