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