1use crate::{Certificate, Entry, KeyStore, KeyStoreError, PrivateKeyEntry, Result};
10use std::io::Read;
11
12pub const PKCS12_MAGIC: u8 = 0x30;
14
15pub fn is_pkcs12_data(data: &[u8]) -> bool {
17 !data.is_empty() && data[0] == PKCS12_MAGIC
18}
19
20impl KeyStore {
21 pub fn load_pkcs12<R: Read>(&mut self, mut reader: R, password: &[u8]) -> Result<()> {
28 #[cfg(feature = "pkcs12")]
29 {
30 use p12_keystore::{KeyStore as P12KeyStore, KeyStoreEntry as P12Entry};
31
32 let mut buffer = Vec::new();
33 reader.read_to_end(&mut buffer)?;
34
35 let password_str = std::str::from_utf8(password)
36 .map_err(|_| KeyStoreError::Other("Invalid UTF-8 password".to_string()))?;
37
38 let p12_ks = P12KeyStore::from_pkcs12(&buffer, password_str)
40 .map_err(|e| KeyStoreError::Other(format!("PKCS12 parse error: {}", e)))?;
41
42 self.entries.clear();
44
45 for (alias, entry) in p12_ks.entries() {
47 match entry {
48 P12Entry::PrivateKeyChain(chain) => {
49 let private_key = chain.key().as_der().to_vec();
51
52 let cert_chain: Vec<Certificate> = chain
54 .certs()
55 .iter()
56 .map(|cert| Certificate {
57 cert_type: "X509".to_string(),
58 content: cert.as_der().to_vec(),
59 })
60 .collect();
61
62 let entry = PrivateKeyEntry {
63 creation_time: std::time::SystemTime::UNIX_EPOCH,
65 private_key,
66 certificate_chain: cert_chain,
67 };
68
69 self.entries
70 .insert(self.convert_alias(alias), Entry::PrivateKey(entry));
71 }
72 P12Entry::Certificate(cert) => {
73 let tce = crate::TrustedCertificateEntry {
75 creation_time: std::time::SystemTime::UNIX_EPOCH,
77 certificate: Certificate {
78 cert_type: "X509".to_string(),
79 content: cert.as_der().to_vec(),
80 },
81 };
82 self.entries
83 .insert(self.convert_alias(alias), Entry::TrustedCertificate(tce));
84 }
85 P12Entry::Secret(_) => {
86 }
88 }
89 }
90
91 Ok(())
92 }
93
94 #[cfg(not(feature = "pkcs12"))]
95 {
96 let _ = (reader, password);
97 Err(KeyStoreError::Other(
98 "PKCS12 feature not enabled. Enable with: cargo build --features pkcs12"
99 .to_string(),
100 ))
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_is_pkcs12_data() {
111 assert!(is_pkcs12_data(&[0x30, 0x82, 0x00, 0x00]));
113 assert!(!is_pkcs12_data(&[0xFE, 0xED, 0xFE, 0xED])); }
115}
116
117#[cfg(all(test, feature = "pkcs12"))]
118mod integration_tests {
119 use super::*;
120 use std::io::Cursor;
121
122 #[test]
123 fn test_load_pbes2_keystore() {
124 let data = include_bytes!("../p12-keystore-main/tests/assets/pbes2-keystore.p12");
125 let mut ks = KeyStore::new();
126 ks.load_pkcs12(Cursor::new(data.as_slice()), b"changeit").unwrap();
127
128 assert!(!ks.is_empty(), "Keystore should not be empty");
130
131 for alias in ks.aliases() {
133 if ks.is_private_key_entry(&alias) {
134 let entry = ks.get_raw_private_key_entry(&alias).unwrap();
135 assert!(!entry.private_key.is_empty());
136 assert!(!entry.certificate_chain.is_empty());
137 }
138 }
139 }
140
141 #[test]
142 fn test_load_auto_detect_pkcs12() {
143 let data = include_bytes!("../p12-keystore-main/tests/assets/pbes2-keystore.p12");
144 let mut ks = KeyStore::new();
145 ks.load_auto_detect(Cursor::new(data.as_slice()), b"changeit").unwrap();
146
147 assert!(!ks.is_empty(), "Keystore should not be empty after auto-detect load");
148 }
149}