use btls::{
pkcs12::Pkcs12,
pkey::{PKey, Private},
x509::X509,
};
use crate::Error;
#[derive(Debug, Clone)]
pub struct Identity {
pub(in crate::tls) pkey: PKey<Private>,
pub(in crate::tls) cert: X509,
pub(in crate::tls) chain: Vec<X509>,
}
impl Identity {
pub fn from_pkcs12_der(buf: &[u8], pass: &str) -> crate::Result<Identity> {
let pkcs12 = Pkcs12::from_der(buf).map_err(Error::tls)?;
let parsed = pkcs12.parse(pass).map_err(Error::tls)?;
Ok(Identity {
pkey: parsed.pkey,
cert: parsed.cert,
chain: parsed.chain.into_iter().flatten().rev().collect(),
})
}
pub fn from_pkcs8_pem(buf: &[u8], key: &[u8]) -> crate::Result<Identity> {
if !key.starts_with(b"-----BEGIN PRIVATE KEY-----") {
return Err(Error::builder("expected PKCS#8 PEM"));
}
let pkey = PKey::private_key_from_pem(key).map_err(Error::tls)?;
let mut cert_chain = X509::stack_from_pem(buf).map_err(Error::tls)?.into_iter();
let cert = cert_chain.next().ok_or_else(|| {
Error::builder("at least one certificate must be provided to create an identity")
})?;
let chain = cert_chain.collect();
Ok(Identity { pkey, cert, chain })
}
}
#[cfg(test)]
mod test {
use super::Identity;
#[test]
fn identity_from_pkcs12_der_invalid() {
Identity::from_pkcs12_der(b"not der", "nope").unwrap_err();
}
#[test]
fn identity_from_pkcs8_pem_invalid() {
Identity::from_pkcs8_pem(b"not pem", b"not key").unwrap_err();
}
}