ids_daps_client/
cert.rs

1//! This module provides functions to work with DAPS certificates.
2
3type SkiAkiPrivateKey<'a> = (std::borrow::Cow<'a, str>, std::borrow::Cow<'a, [u8]>);
4
5/// Reads a .p12 from file, extracts the certificate and returns the SKI:AKI
6pub 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    // Read the .p12 file
13    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    // Read in the .p12 file and parse it
18    let pkcs12 = openssl::pkcs12::Pkcs12::from_der(buf.as_slice())?;
19    let parsed_pkcs12 = pkcs12.parse2(password)?;
20
21    // Extract the SKI:AKI from the certificate
22    let ski_aki_str = ski_aki(
23        &parsed_pkcs12
24            .cert
25            .ok_or("Certificate not found in .p12 file")?,
26    )?;
27    // Extract the private key
28    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
36/**
37 * Extracts the *Subject Key Identifier* and *Authority Key Identifier* from a certificate and creates
38 * a String of the form "`SKI:keyid:AKI`", where SKI and AKI are the hex-encoded values of the
39 * Subject Key Identifier* and *Authority Key Identifier*, respectively.
40 */
41pub 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    /// Loads a certificate and extracts the SKI:AKI
70    #[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}