#[cfg(feature = "openssl")]
use openssl::x509::X509;
use super::*;
use crate::firmware::host::{CertTableEntry, CertType};
#[derive(Debug, Clone)]
pub struct Chain {
pub ca: ca::Chain,
pub vek: Certificate,
}
impl<'a> Verifiable for &'a Chain {
type Output = &'a Certificate;
fn verify(self) -> Result<Self::Output> {
let ask = self.ca.verify()?;
(ask, &self.vek).verify()?;
Ok(&self.vek)
}
}
enum ChainEncodingFormat {
Der,
Pem,
}
#[cfg(feature = "openssl")]
impl From<(X509, X509, X509)> for Chain {
fn from(value: (X509, X509, X509)) -> Self {
Self {
ca: ca::Chain {
ark: value.1.into(),
ask: value.0.into(),
},
vek: value.2.into(),
}
}
}
#[cfg(feature = "openssl")]
impl<'a: 'b, 'b> From<&'a Chain> for (&'b X509, &'b X509, &'b X509) {
fn from(value: &'a Chain) -> Self {
(
(&value.ca.ask).into(),
(&value.ca.ark).into(),
(&value.vek).into(),
)
}
}
#[cfg(feature = "openssl")]
impl From<(&X509, &X509, &X509)> for Chain {
fn from(value: (&X509, &X509, &X509)) -> Self {
(value.0.clone(), value.1.clone(), value.2.clone()).into()
}
}
impl<'a: 'b, 'b> From<&'a Chain> for (&'b Certificate, &'b Certificate, &'b Certificate) {
fn from(value: &'a Chain) -> Self {
(&value.ca.ask, &value.ca.ark, &value.vek)
}
}
impl From<(Certificate, Certificate, Certificate)> for Chain {
fn from(value: (Certificate, Certificate, Certificate)) -> Self {
Self {
ca: ca::Chain {
ark: value.1,
ask: value.0,
},
vek: value.2,
}
}
}
impl From<(&Certificate, &Certificate, &Certificate)> for Chain {
fn from(value: (&Certificate, &Certificate, &Certificate)) -> Self {
Self {
ca: ca::Chain {
ark: value.1.clone(),
ask: value.0.clone(),
},
vek: value.2.clone(),
}
}
}
impl From<&Chain> for (Certificate, Certificate, Certificate) {
fn from(value: &Chain) -> Self {
(
value.ca.ask.clone(),
value.ca.ark.clone(),
value.vek.clone(),
)
}
}
impl From<&[Certificate]> for Chain {
fn from(value: &[Certificate]) -> Self {
(value[0].clone(), value[1].clone(), value[2].clone()).into()
}
}
impl Chain {
pub fn from_cert_table_der(entries: Vec<CertTableEntry>) -> Result<Self> {
Self::parse_from_cert_table(entries, ChainEncodingFormat::Der)
}
pub fn from_cert_table_pem(entries: Vec<CertTableEntry>) -> Result<Self> {
Self::parse_from_cert_table(entries, ChainEncodingFormat::Pem)
}
fn parse_from_cert_table(
entries: Vec<CertTableEntry>,
format: ChainEncodingFormat,
) -> Result<Self> {
let mut ark: Option<Certificate> = None;
let mut ask: Option<Certificate> = None;
let mut vcek: Option<Certificate> = None;
let mut vlek: Option<Certificate> = None;
let other = ErrorKind::Other;
for entry in entries {
let cert = match format {
ChainEncodingFormat::Der => Certificate::from_der(entry.data.as_slice())?,
ChainEncodingFormat::Pem => Certificate::from_pem(entry.data.as_slice())?,
};
match entry.cert_type {
CertType::ARK => {
if ark.is_some() {
return Err(Error::new(other, "more than one ARK certificate found"));
}
ark = Some(cert);
}
CertType::ASK => {
if ask.is_some() {
return Err(Error::new(other, "more than one ASK certificate found"));
}
ask = Some(cert);
}
CertType::VCEK => {
if vcek.is_some() {
return Err(Error::new(other, "more than one VCEK certificate found"));
}
vcek = Some(cert);
}
CertType::VLEK => {
if vlek.is_some() {
return Err(Error::new(other, "more than one VLEK certificate found"));
}
vlek = Some(cert);
}
_ => continue,
}
}
if ark.is_none() {
return Err(Error::new(other, "ARK not found"));
} else if ask.is_none() {
return Err(Error::new(other, "ASK not found"));
} else if vcek.is_none() && vlek.is_none() {
return Err(Error::new(other, "VCEK/VLEK not found"));
}
let vek_val = match (vcek, vlek) {
(_, Some(vlek)) => vlek,
(Some(vcek), None) => vcek,
_ => unreachable!(),
};
Ok(Self {
ca: ca::Chain {
ark: ark.unwrap(),
ask: ask.unwrap(),
},
vek: vek_val,
})
}
pub fn from_pem(ark: &[u8], ask: &[u8], vek: &[u8]) -> Result<Self> {
Ok(Self {
ca: ca::Chain::from_pem(ark, ask)?,
vek: Certificate::from_pem(vek)?,
})
}
pub fn from_der(ark: &[u8], ask: &[u8], vek: &[u8]) -> Result<Self> {
Ok(Self {
ca: ca::Chain::from_der(ark, ask)?,
vek: Certificate::from_der(vek)?,
})
}
}