1type SkiAkiPrivateKey<'a> = (std::borrow::Cow<'a, str>, std::borrow::Cow<'a, [u8]>);
4
5pub fn ski_aki_and_private_key_from_file<'a>(
7 p12_file_path: &std::path::Path,
8 password: &str,
9) -> Result<SkiAkiPrivateKey<'a>, Box<dyn std::error::Error>> {
10 use std::io::Read;
11
12 let mut file = std::fs::File::open(p12_file_path)?;
14 let mut buf = Vec::new();
15 file.read_to_end(&mut buf)?;
16
17 let pkcs12 = openssl::pkcs12::Pkcs12::from_der(buf.as_slice())?;
19 let parsed_pkcs12 = pkcs12.parse2(password)?;
20
21 let ski_aki_str = ski_aki(
23 &parsed_pkcs12
24 .cert
25 .ok_or("Certificate not found in .p12 file")?,
26 )?;
27 let private_key_der = parsed_pkcs12
29 .pkey
30 .ok_or("Private key not found in .p12 file")?
31 .private_key_to_der()?;
32
33 Ok((ski_aki_str, std::borrow::Cow::from(private_key_der)))
34}
35
36pub fn ski_aki<'a>(
42 x509: &openssl::x509::X509,
43) -> Result<std::borrow::Cow<'a, str>, Box<dyn std::error::Error>> {
44 let ski = x509
45 .subject_key_id()
46 .expect("SKI is required to exist in Certificate")
47 .as_slice()
48 .iter()
49 .map(|b| format!("{b:02X}"))
50 .collect::<Vec<String>>()
51 .join(":");
52
53 let aki = x509
54 .authority_key_id()
55 .expect("AKI is required to exist in Certificate")
56 .as_slice()
57 .iter()
58 .map(|b| format!("{b:02X}"))
59 .collect::<Vec<String>>()
60 .join(":");
61
62 Ok(std::borrow::Cow::from([ski, aki].join(":keyid:")))
63}
64
65#[cfg(test)]
66mod test {
67 use super::*;
68
69 #[test]
71 fn test_ski_aki() {
72 let ski_aki = ski_aki_and_private_key_from_file(
73 std::path::Path::new("./testdata/connector-certificate.p12"),
74 "Password1",
75 )
76 .expect("Reading SKI:AKI failed");
77 assert_eq!(ski_aki.0, "65:55:CE:32:79:B4:1A:BD:23:91:D1:27:4A:CE:05:BC:0A:D9:92:E5:keyid:65:55:CE:32:79:B4:1A:BD:23:91:D1:27:4A:CE:05:BC:0A:D9:92:E5");
78 }
79}