1use std::{
2 collections::{BTreeMap, btree_map::Iter},
3 fmt,
4};
5
6use crate::codec::{ParsedAuthSafe, secret_to_safe_bag};
7use crate::secret::Secret;
8use crate::{Result, codec, error::Error, oid};
9use cms::content_info::ContentInfo;
10use der::oid::ObjectIdentifier;
11use der::{Any, Decode, Encode, asn1::OctetString};
12use hex::ToHex;
13use pkcs12::{
14 authenticated_safe::AuthenticatedSafe,
15 pfx::{Pfx, Version},
16};
17
18#[derive(Clone, PartialEq, Eq)]
20pub struct Certificate {
21 pub(crate) data: Vec<u8>,
22 pub(crate) subject: String,
23 pub(crate) issuer: String,
24}
25
26impl Certificate {
27 pub fn from_der(der: &[u8]) -> Result<Self> {
29 let (_, cert) = x509_parser::parse_x509_certificate(der)?;
30 Ok(Self {
31 data: der.to_vec(),
32 subject: cert.subject.to_string(),
33 issuer: cert.issuer.to_string(),
34 })
35 }
36
37 pub fn subject(&self) -> &str {
39 &self.subject
40 }
41
42 pub fn issuer(&self) -> &str {
44 &self.issuer
45 }
46
47 pub fn as_der(&self) -> &[u8] {
49 &self.data
50 }
51}
52
53impl fmt::Debug for Certificate {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_struct("Certificate")
56 .field("data", &"<CERT>")
57 .field("subject", &self.subject)
58 .field("issuer", &self.issuer)
59 .finish()
60 }
61}
62
63#[derive(Clone, PartialEq, Eq)]
65pub struct PrivateKeyChain {
66 pub(crate) key: Vec<u8>,
67 pub(crate) local_key_id: Vec<u8>,
68 pub(crate) chain: Vec<Certificate>,
69}
70
71impl PrivateKeyChain {
72 pub fn new<K, D, I>(key: K, local_key_id: D, chain: I) -> Self
75 where
76 K: AsRef<[u8]>,
77 D: AsRef<[u8]>,
78 I: IntoIterator<Item = Certificate>,
79 {
80 Self {
81 key: key.as_ref().to_owned(),
82 local_key_id: local_key_id.as_ref().to_owned(),
83 chain: chain.into_iter().collect(),
84 }
85 }
86
87 pub fn key(&self) -> &[u8] {
89 &self.key
90 }
91
92 pub fn chain(&self) -> &[Certificate] {
94 &self.chain
95 }
96
97 pub fn local_key_id(&self) -> &[u8] {
99 &self.local_key_id
100 }
101}
102
103impl fmt::Debug for PrivateKeyChain {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("PrivateKeyChain")
106 .field("key", &"<KEY>")
107 .field("chain", &self.chain)
108 .field("local_key_id", &hex::encode(&self.local_key_id))
109 .finish()
110 }
111}
112#[derive(Debug, Clone, PartialEq, Eq)]
114pub enum KeyStoreEntry {
115 PrivateKeyChain(PrivateKeyChain),
116 Certificate(Certificate),
117 Secret(Secret),
118}
119
120pub struct Entries<'a> {
122 iter: Iter<'a, String, KeyStoreEntry>,
123}
124
125impl<'a> Iterator for Entries<'a> {
126 type Item = (&'a String, &'a KeyStoreEntry);
127
128 fn next(&mut self) -> Option<Self::Item> {
129 self.iter.next()
130 }
131}
132
133#[derive(Debug, Clone, Default)]
135pub struct KeyStore {
136 entries: BTreeMap<String, KeyStoreEntry>,
137}
138
139impl KeyStore {
140 pub fn new() -> Self {
142 Self::default()
143 }
144
145 pub fn from_pkcs12(data: &[u8], password: &str) -> Result<Self> {
147 let pfx = Pfx::from_der(data)?;
148
149 if pfx.version != Version::V3 {
150 return Err(Error::InvalidVersion);
151 }
152
153 if let Some(mac_data) = pfx.mac_data {
154 codec::verify_mac(&mac_data, password, pfx.auth_safe.content.value())?;
155 }
156
157 let safes: AuthenticatedSafe = if pfx.auth_safe.content_type == oid::CONTENT_TYPE_DATA_OID {
158 AuthenticatedSafe::from_der(&OctetString::from_der(&pfx.auth_safe.content.to_der()?)?.into_bytes())?
159 } else {
160 return Err(Error::UnsupportedContentType);
161 };
162
163 let mut keystore = Self::new();
164
165 let mut parsed_keys = Vec::new();
166 let mut parsed_certs = Vec::new();
167 let mut parsed_secrets = Vec::new();
168
169 for safe in safes.into_iter() {
170 let ParsedAuthSafe { keys, certs, secrets } = codec::parse_auth_safe(&safe, password)?;
171 parsed_keys.extend(keys);
172 parsed_certs.extend(certs);
173 parsed_secrets.extend(secrets);
174 }
175
176 let find_cert_by_key = |key: &[u8]| {
177 parsed_certs
178 .iter()
179 .find(|c| c.local_key_id.as_ref().is_some_and(|k| k.as_slice() == key))
180 };
181
182 let find_issuer = |issuer: &str| parsed_certs.iter().find(|c| c.cert.subject == issuer && !c.trusted);
183
184 for key in parsed_keys {
185 if let Some(mut entry) = find_cert_by_key(&key.key.local_key_id) {
186 let alias = key
187 .friendly_name
188 .as_deref()
189 .unwrap_or_else(|| entry.cert.subject.as_ref());
190
191 let mut key_chain = PrivateKeyChain {
192 key: key.key.key,
193 local_key_id: key.key.local_key_id,
194 chain: vec![entry.cert.clone()],
195 };
196
197 let leaf_cert = &entry.cert;
198
199 while let Some(issuer) = find_issuer(&entry.cert.issuer) {
200 if issuer.cert.subject != leaf_cert.subject {
202 key_chain.chain.push(issuer.cert.clone());
203 }
204 if issuer.cert.issuer == issuer.cert.subject {
205 break;
206 }
207 entry = issuer;
208 }
209 keystore.add_entry(alias, KeyStoreEntry::PrivateKeyChain(key_chain));
210 }
211 }
212
213 for cert in parsed_certs {
214 if cert.local_key_id.is_none() && cert.trusted {
215 let alias = cert.friendly_name.clone().unwrap_or_else(|| cert.cert.subject.clone());
216 keystore.add_entry(&alias, KeyStoreEntry::Certificate(cert.cert));
217 }
218 }
219
220 for secret in parsed_secrets {
221 let alias = secret
222 .friendly_name
223 .clone()
224 .unwrap_or_else(|| secret.key.local_key_id.encode_hex());
225 keystore.add_entry(&alias, KeyStoreEntry::Secret(secret.key));
226 }
227
228 Ok(keystore)
229 }
230
231 pub fn writer<'a, 'b>(&'a self, password: &'b str) -> Pkcs12Writer<'a, 'b> {
233 Pkcs12Writer {
235 keystore: self,
236 password,
237 encryption_algorithm: EncryptionAlgorithm::PbeWithHmacSha256AndAes256,
238 encryption_iterations: 10000,
239 mac_algorithm: MacAlgorithm::HmacSha256,
240 mac_iterations: 10000,
241 }
242 }
243
244 pub fn entries(&self) -> Entries<'_> {
246 let iter = self.entries.iter();
247 Entries { iter }
248 }
249
250 pub fn entry(&self, alias: &str) -> Option<&KeyStoreEntry> {
252 self.entries.get(alias)
253 }
254
255 pub fn entries_count(&self) -> usize {
257 self.entries.len()
258 }
259
260 pub fn add_entry(&mut self, alias: &str, entry: KeyStoreEntry) {
262 self.entries.insert(alias.to_owned(), entry);
263 }
264
265 pub fn delete_entry(&mut self, alias: &str) -> Option<KeyStoreEntry> {
267 self.entries.remove(alias)
268 }
269
270 pub fn rename_entry(&mut self, old_alias: &str, new_alias: &str) -> Option<&KeyStoreEntry> {
272 if let Some(old) = self.entries.remove(old_alias) {
273 self.entries.insert(new_alias.to_owned(), old);
274 self.entry(new_alias)
275 } else {
276 None
277 }
278 }
279
280 pub fn private_key_chain(&self) -> Option<(&str, &PrivateKeyChain)> {
282 self.entries().find_map(|(alias, entry)| match entry {
283 KeyStoreEntry::PrivateKeyChain(chain) => Some((alias.as_str(), chain)),
284 KeyStoreEntry::Certificate(_) => None,
285 KeyStoreEntry::Secret(_) => None,
286 })
287 }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
292#[non_exhaustive]
293pub enum EncryptionAlgorithm {
294 PbeWithHmacSha256AndAes256,
295 PbeWithShaAnd40BitRc4Cbc,
296 PbeWithShaAnd3KeyTripleDesCbc,
297}
298
299impl EncryptionAlgorithm {
300 pub(crate) fn as_oid(&self) -> ObjectIdentifier {
301 match self {
302 EncryptionAlgorithm::PbeWithHmacSha256AndAes256 => oid::PBES2_OID,
303 EncryptionAlgorithm::PbeWithShaAnd40BitRc4Cbc => oid::PBE_WITH_SHA_AND_40BIT_RC2_CBC_OID,
304 EncryptionAlgorithm::PbeWithShaAnd3KeyTripleDesCbc => oid::PBE_WITH_SHA_AND3_KEY_TRIPLE_DES_CBC_OID,
305 }
306 }
307}
308
309#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
311#[non_exhaustive]
312pub enum MacAlgorithm {
313 HmacSha1,
314 HmacSha256,
315}
316
317pub struct Pkcs12Writer<'a, 'b> {
319 keystore: &'a KeyStore,
320 password: &'b str,
321 encryption_algorithm: EncryptionAlgorithm,
322 encryption_iterations: u64,
323 mac_algorithm: MacAlgorithm,
324 mac_iterations: u64,
325}
326
327impl Pkcs12Writer<'_, '_> {
328 pub fn encryption_algorithm(mut self, algorithm: EncryptionAlgorithm) -> Self {
330 self.encryption_algorithm = algorithm;
331 self
332 }
333
334 pub fn encryption_iterations(mut self, iterations: u64) -> Self {
336 self.encryption_iterations = iterations;
337 self
338 }
339
340 pub fn mac_algorithm(mut self, algorithm: MacAlgorithm) -> Self {
342 self.mac_algorithm = algorithm;
343 self
344 }
345
346 pub fn mac_iterations(mut self, iterations: u64) -> Self {
348 self.mac_iterations = iterations;
349 self
350 }
351
352 pub fn write(self) -> Result<Vec<u8>> {
354 let mut cert_bags = Vec::new();
355
356 let certs = self.keystore.entries.iter().filter_map(|(alias, entry)| match entry {
357 KeyStoreEntry::PrivateKeyChain(_) => None,
358 KeyStoreEntry::Certificate(cert) => Some((alias, cert)),
359 KeyStoreEntry::Secret(_) => None,
360 });
361
362 for (alias, cert) in certs {
363 cert_bags.push(codec::certificate_to_safe_bag(cert, alias, None, true)?);
364 }
365
366 let chain_certs = self
367 .keystore
368 .entries
369 .iter()
370 .filter_map(|(_, entry)| match entry {
371 KeyStoreEntry::PrivateKeyChain(chain) => Some(chain.chain.iter().enumerate().map(|(i, c)| {
372 (
373 if i == 0 {
374 Some(chain.local_key_id.as_slice())
375 } else {
376 None
377 },
378 c,
379 )
380 })),
381 KeyStoreEntry::Certificate(_) => None,
382 KeyStoreEntry::Secret(_) => None,
383 })
384 .flatten();
385
386 for (local_key_id, cert) in chain_certs {
387 cert_bags.push(codec::certificate_to_safe_bag(
388 cert,
389 &cert.subject,
390 local_key_id,
391 false,
392 )?);
393 }
394
395 let certs_safe = codec::cert_bags_to_auth_safe(
396 cert_bags,
397 self.encryption_algorithm,
398 self.encryption_iterations,
399 self.password,
400 )?;
401
402 let private_keys = self.keystore.entries.iter().filter_map(|(alias, entry)| match entry {
403 KeyStoreEntry::PrivateKeyChain(chain) => Some((alias, chain)),
404 KeyStoreEntry::Certificate(_) => None,
405 KeyStoreEntry::Secret(_) => None,
406 });
407
408 let mut key_bags = Vec::new();
409
410 for (alias, chain) in private_keys {
411 key_bags.push(codec::private_key_to_safe_bag(
412 chain,
413 alias,
414 self.encryption_algorithm,
415 self.encryption_iterations,
416 self.password,
417 )?);
418 }
419
420 let keys_safe = codec::key_bags_to_auth_safe(key_bags)?;
421
422 let mut safes = vec![certs_safe, keys_safe];
423
424 let secrets = self
425 .keystore
426 .entries
427 .iter()
428 .filter_map(|(alias, entry)| match entry {
429 KeyStoreEntry::PrivateKeyChain(_) => None,
430 KeyStoreEntry::Certificate(_) => None,
431 KeyStoreEntry::Secret(secret) => {
432 let bag = secret_to_safe_bag(
433 secret,
434 self.encryption_algorithm,
435 alias,
436 self.encryption_iterations,
437 self.password,
438 );
439 Some(bag)
440 }
441 })
442 .flatten();
443
444 for secret in secrets {
445 safes.push(codec::key_bags_to_auth_safe(vec![secret])?)
446 }
447
448 let safe_bags = OctetString::new(safes.to_der()?)?;
449 let auth_safe = ContentInfo {
450 content_type: oid::CONTENT_TYPE_DATA_OID,
451 content: Any::from_der(&safe_bags.to_der()?)?,
452 };
453
454 let mac_data = codec::compute_mac(
455 auth_safe.content.value(),
456 self.mac_algorithm,
457 self.mac_iterations,
458 self.password,
459 )?;
460
461 let pfx = Pfx {
462 version: Version::V3,
463 auth_safe,
464 mac_data: Some(mac_data),
465 };
466
467 Ok(pfx.to_der()?)
468 }
469}