1use p12_keystore::{Certificate, KeyStore, KeyStoreEntry, Pkcs12ImportPolicy, PrivateKey, PrivateKeyChain};
2
3/// The DER inside a PEM file with the expected label.
4fn pem_der(path: &str, label: &str) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
5 let text = std::fs::read(path)?;
6 let (found, der) = pem_rfc7468::decode_vec(&text)?; // found borrows from text
7 if found != label {
8 return Err(format!("{path}: {found}, expected {label}").into());
9 }
10 Ok(der)
11}
12
13fn main() -> Result<(), Box<dyn std::error::Error>> {
14 let password = std::env::var("P12_PASSWORD")?;
15
16 let key = PrivateKey::from_der(&pem_der("key.pem", "PRIVATE KEY")?)?; // PKCS#8 only
17 let leaf = Certificate::from_der(&pem_der("leaf.pem", "CERTIFICATE")?)?;
18 let intermediate = Certificate::from_der(&pem_der("intermediate.pem", "CERTIFICATE")?)?;
19
20 // One key chain (leaf first); the alias becomes the friendly name
21 let chain = PrivateKeyChain::new(b"api.example.com".to_vec(), key, [leaf, intermediate]);
22 let mut store = KeyStore::new();
23 store.add_entry("api.example.com", KeyStoreEntry::PrivateKeyChain(chain));
24 // Default protection: PBES2 with AES-256-CBC, HMAC-SHA-256, 10 000 iterations
25 std::fs::write("bundle.p12", store.writer(&password).write()?)?;
26
27 // Read it back
28 let data = std::fs::read("bundle.p12")?;
29 let store = KeyStore::from_pkcs12(&data, &password, Pkcs12ImportPolicy::Strict)?;
30 let (alias, chain) = store.private_key_chain().ok_or("no private key in the bundle")?;
31 println!("alias {alias}: key {} bytes of PKCS#8, chain of {}", chain.key().as_der().len(), chain.certs().len());
32 for cert in chain.certs() {
33 println!(" {}", cert.subject());
34 }
35 if let Err(error) = KeyStore::from_pkcs12(&data, "wrong-password", Pkcs12ImportPolicy::Strict) {
36 println!("wrong password: {error}");
37 }
38 Ok(())
39}
40