/rust/registry/src/index.crates.io-6f17d22bba15001f/openssl-0.10.62/src/pkcs12.rs
Line | Count | Source (jump to first uncovered line) |
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 | | #[cfg(not(boringssl))] |
10 | | use crate::hash::MessageDigest; |
11 | | use crate::nid::Nid; |
12 | | use crate::pkey::{HasPrivate, PKey, PKeyRef, Private}; |
13 | | use crate::stack::Stack; |
14 | | use crate::util::ForeignTypeExt; |
15 | | use crate::x509::{X509Ref, X509}; |
16 | | use crate::{cvt, cvt_p}; |
17 | | use openssl_macros::corresponds; |
18 | | |
19 | | foreign_type_and_impl_send_sync! { |
20 | | type CType = ffi::PKCS12; |
21 | | fn drop = ffi::PKCS12_free; |
22 | | |
23 | | pub struct Pkcs12; |
24 | | pub struct Pkcs12Ref; |
25 | | } |
26 | | |
27 | | impl Pkcs12Ref { |
28 | | to_der! { |
29 | | /// Serializes the `Pkcs12` to its standard DER encoding. |
30 | | #[corresponds(i2d_PKCS12)] |
31 | | to_der, |
32 | | ffi::i2d_PKCS12 |
33 | | } |
34 | | |
35 | | /// Deprecated. |
36 | | #[deprecated(note = "Use parse2 instead", since = "0.10.46")] |
37 | | #[allow(deprecated)] |
38 | 0 | pub fn parse(&self, pass: &str) -> Result<ParsedPkcs12, ErrorStack> { |
39 | 0 | let parsed = self.parse2(pass)?; |
40 | | |
41 | 0 | Ok(ParsedPkcs12 { |
42 | 0 | pkey: parsed.pkey.unwrap(), |
43 | 0 | cert: parsed.cert.unwrap(), |
44 | 0 | chain: parsed.ca, |
45 | 0 | }) |
46 | 0 | } |
47 | | |
48 | | /// Extracts the contents of the `Pkcs12`. |
49 | | #[corresponds(PKCS12_parse)] |
50 | 0 | pub fn parse2(&self, pass: &str) -> Result<ParsedPkcs12_2, ErrorStack> { |
51 | 0 | unsafe { |
52 | 0 | let pass = CString::new(pass.as_bytes()).unwrap(); |
53 | 0 |
|
54 | 0 | let mut pkey = ptr::null_mut(); |
55 | 0 | let mut cert = ptr::null_mut(); |
56 | 0 | let mut ca = ptr::null_mut(); |
57 | 0 |
|
58 | 0 | cvt(ffi::PKCS12_parse( |
59 | 0 | self.as_ptr(), |
60 | 0 | pass.as_ptr(), |
61 | 0 | &mut pkey, |
62 | 0 | &mut cert, |
63 | 0 | &mut ca, |
64 | 0 | ))?; |
65 | | |
66 | 0 | let pkey = PKey::from_ptr_opt(pkey); |
67 | 0 | let cert = X509::from_ptr_opt(cert); |
68 | 0 | let ca = Stack::from_ptr_opt(ca); |
69 | 0 |
|
70 | 0 | Ok(ParsedPkcs12_2 { pkey, cert, ca }) |
71 | | } |
72 | 0 | } |
73 | | } |
74 | | |
75 | | impl Pkcs12 { |
76 | | from_der! { |
77 | | /// Deserializes a DER-encoded PKCS#12 archive. |
78 | | #[corresponds(d2i_PKCS12)] |
79 | | from_der, |
80 | | Pkcs12, |
81 | | ffi::d2i_PKCS12 |
82 | | } |
83 | | |
84 | | /// Creates a new builder for a protected pkcs12 certificate. |
85 | | /// |
86 | | /// This uses the defaults from the OpenSSL library: |
87 | | /// |
88 | | /// * `nid_key` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` |
89 | | /// * `nid_cert` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND40BITRC2_CBC` |
90 | | /// * `iter` - `2048` |
91 | | /// * `mac_iter` - `2048` |
92 | | /// * `mac_md` - `SHA-256` (3.0.0+) or `SHA-1` (`SHA-1` only for BoringSSL) |
93 | 0 | pub fn builder() -> Pkcs12Builder { |
94 | 0 | ffi::init(); |
95 | 0 |
|
96 | 0 | Pkcs12Builder { |
97 | 0 | name: None, |
98 | 0 | pkey: None, |
99 | 0 | cert: None, |
100 | 0 | ca: None, |
101 | 0 | nid_key: Nid::UNDEF, |
102 | 0 | nid_cert: Nid::UNDEF, |
103 | 0 | iter: ffi::PKCS12_DEFAULT_ITER, |
104 | 0 | mac_iter: ffi::PKCS12_DEFAULT_ITER, |
105 | 0 | #[cfg(not(boringssl))] |
106 | 0 | mac_md: None, |
107 | 0 | } |
108 | 0 | } |
109 | | } |
110 | | |
111 | | #[deprecated(note = "Use ParsedPkcs12_2 instead", since = "0.10.46")] |
112 | | pub struct ParsedPkcs12 { |
113 | | pub pkey: PKey<Private>, |
114 | | pub cert: X509, |
115 | | pub chain: Option<Stack<X509>>, |
116 | | } |
117 | | |
118 | | pub struct ParsedPkcs12_2 { |
119 | | pub pkey: Option<PKey<Private>>, |
120 | | pub cert: Option<X509>, |
121 | | pub ca: Option<Stack<X509>>, |
122 | | } |
123 | | |
124 | | pub struct Pkcs12Builder { |
125 | | // FIXME borrow |
126 | | name: Option<CString>, |
127 | | pkey: Option<PKey<Private>>, |
128 | | cert: Option<X509>, |
129 | | ca: Option<Stack<X509>>, |
130 | | nid_key: Nid, |
131 | | nid_cert: Nid, |
132 | | iter: c_int, |
133 | | mac_iter: c_int, |
134 | | // FIXME remove |
135 | | #[cfg(not(boringssl))] |
136 | | mac_md: Option<MessageDigest>, |
137 | | } |
138 | | |
139 | | impl Pkcs12Builder { |
140 | | /// The `friendlyName` used for the certificate and private key. |
141 | 0 | pub fn name(&mut self, name: &str) -> &mut Self { |
142 | 0 | self.name = Some(CString::new(name).unwrap()); |
143 | 0 | self |
144 | 0 | } |
145 | | |
146 | | /// The private key. |
147 | 0 | pub fn pkey<T>(&mut self, pkey: &PKeyRef<T>) -> &mut Self |
148 | 0 | where |
149 | 0 | T: HasPrivate, |
150 | 0 | { |
151 | 0 | let new_pkey = unsafe { PKeyRef::from_ptr(pkey.as_ptr()) }; |
152 | 0 | self.pkey = Some(new_pkey.to_owned()); |
153 | 0 | self |
154 | 0 | } |
155 | | |
156 | | /// The certificate. |
157 | 0 | pub fn cert(&mut self, cert: &X509Ref) -> &mut Self { |
158 | 0 | self.cert = Some(cert.to_owned()); |
159 | 0 | self |
160 | 0 | } |
161 | | |
162 | | /// An additional set of certificates to include in the archive beyond the one provided to |
163 | | /// `build`. |
164 | 0 | pub fn ca(&mut self, ca: Stack<X509>) -> &mut Self { |
165 | 0 | self.ca = Some(ca); |
166 | 0 | self |
167 | 0 | } |
168 | | |
169 | | /// The encryption algorithm that should be used for the key |
170 | 0 | pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self { |
171 | 0 | self.nid_key = nid; |
172 | 0 | self |
173 | 0 | } |
174 | | |
175 | | /// The encryption algorithm that should be used for the cert |
176 | 0 | pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self { |
177 | 0 | self.nid_cert = nid; |
178 | 0 | self |
179 | 0 | } |
180 | | |
181 | | /// Key iteration count, default is 2048 as of this writing |
182 | 0 | pub fn key_iter(&mut self, iter: u32) -> &mut Self { |
183 | 0 | self.iter = iter as c_int; |
184 | 0 | self |
185 | 0 | } |
186 | | |
187 | | /// MAC iteration count, default is the same as key_iter. |
188 | | /// |
189 | | /// Old implementations don't understand MAC iterations greater than 1, (pre 1.0.1?), if such |
190 | | /// compatibility is required this should be set to 1. |
191 | 0 | pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self { |
192 | 0 | self.mac_iter = mac_iter as c_int; |
193 | 0 | self |
194 | 0 | } |
195 | | |
196 | | /// MAC message digest type |
197 | | #[cfg(not(boringssl))] |
198 | 0 | pub fn mac_md(&mut self, md: MessageDigest) -> &mut Self { |
199 | 0 | self.mac_md = Some(md); |
200 | 0 | self |
201 | 0 | } |
202 | | |
203 | | /// Deprecated. |
204 | | #[deprecated( |
205 | | note = "Use Self::{name, pkey, cert, build2} instead.", |
206 | | since = "0.10.46" |
207 | | )] |
208 | 0 | pub fn build<T>( |
209 | 0 | mut self, |
210 | 0 | password: &str, |
211 | 0 | friendly_name: &str, |
212 | 0 | pkey: &PKeyRef<T>, |
213 | 0 | cert: &X509Ref, |
214 | 0 | ) -> Result<Pkcs12, ErrorStack> |
215 | 0 | where |
216 | 0 | T: HasPrivate, |
217 | 0 | { |
218 | 0 | self.name(friendly_name) |
219 | 0 | .pkey(pkey) |
220 | 0 | .cert(cert) |
221 | 0 | .build2(password) |
222 | 0 | } |
223 | | |
224 | | /// Builds the PKCS#12 object. |
225 | | #[corresponds(PKCS12_create)] |
226 | 0 | pub fn build2(&self, password: &str) -> Result<Pkcs12, ErrorStack> { |
227 | 0 | unsafe { |
228 | 0 | let pass = CString::new(password).unwrap(); |
229 | 0 | let pass = pass.as_ptr(); |
230 | 0 | let friendly_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr()); |
231 | 0 | let pkey = self.pkey.as_ref().map_or(ptr::null(), |p| p.as_ptr()); |
232 | 0 | let cert = self.cert.as_ref().map_or(ptr::null(), |p| p.as_ptr()); |
233 | 0 | let ca = self |
234 | 0 | .ca |
235 | 0 | .as_ref() |
236 | 0 | .map(|ca| ca.as_ptr()) |
237 | 0 | .unwrap_or(ptr::null_mut()); |
238 | 0 | let nid_key = self.nid_key.as_raw(); |
239 | 0 | let nid_cert = self.nid_cert.as_raw(); |
240 | 0 |
|
241 | 0 | // According to the OpenSSL docs, keytype is a non-standard extension for MSIE, |
242 | 0 | // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information: |
243 | 0 | // https://www.openssl.org/docs/manmaster/crypto/PKCS12_create.html |
244 | 0 | let keytype = 0; |
245 | | |
246 | 0 | let pkcs12 = cvt_p(ffi::PKCS12_create( |
247 | 0 | pass as *mut _, |
248 | 0 | friendly_name as *mut _, |
249 | 0 | pkey as *mut _, |
250 | 0 | cert as *mut _, |
251 | 0 | ca, |
252 | 0 | nid_key, |
253 | 0 | nid_cert, |
254 | 0 | self.iter, |
255 | 0 | self.mac_iter, |
256 | 0 | keytype, |
257 | 0 | )) |
258 | 0 | .map(Pkcs12)?; |
259 | | |
260 | | #[cfg(not(boringssl))] |
261 | | // BoringSSL does not support overriding the MAC and will always |
262 | | // use SHA-1 |
263 | | { |
264 | 0 | let md_type = self |
265 | 0 | .mac_md |
266 | 0 | .map(|md_type| md_type.as_ptr()) |
267 | 0 | .unwrap_or(ptr::null()); |
268 | 0 |
|
269 | 0 | cvt(ffi::PKCS12_set_mac( |
270 | 0 | pkcs12.as_ptr(), |
271 | 0 | pass, |
272 | 0 | -1, |
273 | 0 | ptr::null_mut(), |
274 | 0 | 0, |
275 | 0 | self.mac_iter, |
276 | 0 | md_type, |
277 | 0 | ))?; |
278 | | } |
279 | | |
280 | 0 | Ok(pkcs12) |
281 | | } |
282 | 0 | } |
283 | | } |
284 | | |
285 | | #[cfg(test)] |
286 | | mod test { |
287 | | use crate::asn1::Asn1Time; |
288 | | use crate::hash::MessageDigest; |
289 | | use crate::nid::Nid; |
290 | | use crate::pkey::PKey; |
291 | | use crate::rsa::Rsa; |
292 | | use crate::x509::extension::KeyUsage; |
293 | | use crate::x509::{X509Name, X509}; |
294 | | |
295 | | use super::*; |
296 | | |
297 | | #[test] |
298 | | fn parse() { |
299 | | #[cfg(ossl300)] |
300 | | let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); |
301 | | |
302 | | let der = include_bytes!("../test/identity.p12"); |
303 | | let pkcs12 = Pkcs12::from_der(der).unwrap(); |
304 | | let parsed = pkcs12.parse2("mypass").unwrap(); |
305 | | |
306 | | assert_eq!( |
307 | | hex::encode(parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap()), |
308 | | "59172d9313e84459bcff27f967e79e6e9217e584" |
309 | | ); |
310 | | |
311 | | let chain = parsed.ca.unwrap(); |
312 | | assert_eq!(chain.len(), 1); |
313 | | assert_eq!( |
314 | | hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), |
315 | | "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" |
316 | | ); |
317 | | } |
318 | | |
319 | | #[test] |
320 | | fn parse_empty_chain() { |
321 | | #[cfg(ossl300)] |
322 | | let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); |
323 | | |
324 | | let der = include_bytes!("../test/keystore-empty-chain.p12"); |
325 | | let pkcs12 = Pkcs12::from_der(der).unwrap(); |
326 | | let parsed = pkcs12.parse2("cassandra").unwrap(); |
327 | | if let Some(stack) = parsed.ca { |
328 | | assert_eq!(stack.len(), 0); |
329 | | } |
330 | | } |
331 | | |
332 | | #[test] |
333 | | fn create() { |
334 | | let subject_name = "ns.example.com"; |
335 | | let rsa = Rsa::generate(2048).unwrap(); |
336 | | let pkey = PKey::from_rsa(rsa).unwrap(); |
337 | | |
338 | | let mut name = X509Name::builder().unwrap(); |
339 | | name.append_entry_by_nid(Nid::COMMONNAME, subject_name) |
340 | | .unwrap(); |
341 | | let name = name.build(); |
342 | | |
343 | | let key_usage = KeyUsage::new().digital_signature().build().unwrap(); |
344 | | |
345 | | let mut builder = X509::builder().unwrap(); |
346 | | builder.set_version(2).unwrap(); |
347 | | builder |
348 | | .set_not_before(&Asn1Time::days_from_now(0).unwrap()) |
349 | | .unwrap(); |
350 | | builder |
351 | | .set_not_after(&Asn1Time::days_from_now(365).unwrap()) |
352 | | .unwrap(); |
353 | | builder.set_subject_name(&name).unwrap(); |
354 | | builder.set_issuer_name(&name).unwrap(); |
355 | | builder.append_extension(key_usage).unwrap(); |
356 | | builder.set_pubkey(&pkey).unwrap(); |
357 | | builder.sign(&pkey, MessageDigest::sha256()).unwrap(); |
358 | | let cert = builder.build(); |
359 | | |
360 | | let pkcs12 = Pkcs12::builder() |
361 | | .name(subject_name) |
362 | | .pkey(&pkey) |
363 | | .cert(&cert) |
364 | | .build2("mypass") |
365 | | .unwrap(); |
366 | | let der = pkcs12.to_der().unwrap(); |
367 | | |
368 | | let pkcs12 = Pkcs12::from_der(&der).unwrap(); |
369 | | let parsed = pkcs12.parse2("mypass").unwrap(); |
370 | | |
371 | | assert_eq!( |
372 | | &*parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap(), |
373 | | &*cert.digest(MessageDigest::sha1()).unwrap() |
374 | | ); |
375 | | assert!(parsed.pkey.unwrap().public_eq(&pkey)); |
376 | | } |
377 | | |
378 | | #[test] |
379 | | fn create_only_ca() { |
380 | | let ca = include_bytes!("../test/root-ca.pem"); |
381 | | let ca = X509::from_pem(ca).unwrap(); |
382 | | let mut chain = Stack::new().unwrap(); |
383 | | chain.push(ca).unwrap(); |
384 | | |
385 | | let pkcs12 = Pkcs12::builder().ca(chain).build2("hunter2").unwrap(); |
386 | | let parsed = pkcs12.parse2("hunter2").unwrap(); |
387 | | |
388 | | assert!(parsed.cert.is_none()); |
389 | | assert!(parsed.pkey.is_none()); |
390 | | assert_eq!(parsed.ca.unwrap().len(), 1); |
391 | | } |
392 | | } |