use anyhow::{Context, Error};
use der::{DecodePem, EncodePem};
use serde::{Deserialize, Serialize};
use x509_cert::Certificate;
#[derive(Clone, Serialize, Deserialize, Default)]
pub struct TrustAnchorRegistry {
pub anchors: Vec<TrustAnchor>,
}
#[derive(Debug, Clone)]
pub struct TrustAnchor {
pub certificate: Certificate,
pub purpose: TrustPurpose,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum TrustPurpose {
Iaca,
ReaderCa,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PemTrustAnchor {
pub certificate_pem: String,
pub purpose: TrustPurpose,
}
impl TrustAnchorRegistry {
pub fn from_pem_certificates(certs: Vec<PemTrustAnchor>) -> Result<Self, Error> {
Ok(Self {
anchors: certs
.into_iter()
.enumerate()
.map(|(index, t)| {
TrustAnchor::try_from(t)
.context(format!("Failed to build trust anchor for cert no. {index}"))
})
.collect::<Result<_, _>>()?,
})
}
}
impl<'l> TryFrom<&'l TrustAnchor> for PemTrustAnchor {
type Error = Error;
fn try_from(value: &'l TrustAnchor) -> Result<Self, Self::Error> {
Ok(Self {
certificate_pem: value.certificate.to_pem(Default::default())?,
purpose: value.purpose,
})
}
}
impl TryFrom<PemTrustAnchor> for TrustAnchor {
type Error = Error;
fn try_from(value: PemTrustAnchor) -> Result<Self, Self::Error> {
Ok(Self {
certificate: Certificate::from_pem(&value.certificate_pem)?,
purpose: value.purpose,
})
}
}
impl Serialize for TrustAnchor {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::Error;
PemTrustAnchor::try_from(self)
.map_err(S::Error::custom)?
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for TrustAnchor {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
PemTrustAnchor::deserialize(deserializer)?
.try_into()
.map_err(D::Error::custom)
}
}