use crate::cert::error::CertificateError;
use crate::cert::Certificate;
use crate::spiffe_id::uri_has_spiffe_scheme;
use crate::SpiffeId;
use x509_parser::certificate::X509Certificate;
use x509_parser::der_parser::oid::Oid;
use x509_parser::error::X509Error;
use x509_parser::extensions::ParsedExtension;
use x509_parser::nom::Err;
use x509_parser::oid_registry;
use x509_parser::prelude::GeneralName;
const MAX_URI_LENGTH: usize = 2048;
const MAX_CERT_CHAIN_LENGTH: usize = 16;
pub(crate) fn to_certificate_vec(
cert_chain_der: &[u8],
) -> Result<Vec<Certificate>, CertificateError> {
let mut rest = cert_chain_der;
let mut certs = Vec::new();
while !rest.is_empty() {
if certs.len() >= MAX_CERT_CHAIN_LENGTH {
return Err(CertificateError::TooManyCertificates {
max: MAX_CERT_CHAIN_LENGTH,
});
}
let (new_rest, cert) = x509_parser::parse_x509_certificate(rest).map_err(|e| match e {
Err::Incomplete(_) => {
CertificateError::ParseX509Certificate(X509Error::InvalidCertificate)
}
Err::Error(err) | Err::Failure(err) => CertificateError::ParseX509Certificate(err),
})?;
certs.push(cert.into());
rest = new_rest;
}
Ok(certs)
}
pub(crate) fn to_certificate_vec_unbounded(
cert_list_der: &[u8],
) -> Result<Vec<Certificate>, CertificateError> {
let mut rest = cert_list_der;
let mut certs = Vec::new();
while !rest.is_empty() {
let (new_rest, cert) = x509_parser::parse_x509_certificate(rest).map_err(|e| match e {
Err::Incomplete(_) => {
CertificateError::ParseX509Certificate(X509Error::InvalidCertificate)
}
Err::Error(err) | Err::Failure(err) => CertificateError::ParseX509Certificate(err),
})?;
certs.push(cert.into());
rest = new_rest;
}
Ok(certs)
}
pub(crate) fn parse_der_encoded_bytes_as_x509_certificate(
der_bytes: &[u8],
) -> Result<X509Certificate<'_>, CertificateError> {
match x509_parser::parse_x509_certificate(der_bytes) {
Ok((rest, cert)) => {
if !rest.is_empty() {
return Err(CertificateError::ParseX509Certificate(
X509Error::InvalidCertificate,
));
}
Ok(cert)
}
Err(Err::Incomplete(_)) => Err(CertificateError::ParseX509Certificate(
X509Error::InvalidCertificate,
)),
Err(Err::Error(e) | Err::Failure(e)) => Err(CertificateError::ParseX509Certificate(e)),
}
}
pub(crate) fn get_x509_extension<'a>(
cert: &'a X509Certificate<'_>,
oid: &Oid<'static>,
) -> Result<&'a ParsedExtension<'a>, CertificateError> {
match cert.tbs_certificate.get_extension_unique(oid)? {
None => Err(CertificateError::MissingX509Extension(oid.clone())),
Some(ext) => Ok(ext.parsed_extension()),
}
}
pub(crate) fn extract_spiffe_ids_from_uri_san(
cert: &X509Certificate<'_>,
) -> Result<Vec<SpiffeId>, CertificateError> {
let ext = get_x509_extension(cert, &oid_registry::OID_X509_EXT_SUBJECT_ALT_NAME)?;
let san = match ext {
ParsedExtension::SubjectAlternativeName(s) => s,
other => return Err(CertificateError::UnexpectedExtension(format!("{other:?}"))),
};
let mut ids = Vec::new();
let mut uri_count = 0usize;
for name in &san.general_names {
let uri = match name {
GeneralName::URI(u) => *u,
_ => continue,
};
uri_count += 1;
if uri_count > 1 {
return Err(CertificateError::MultipleUriSanEntries);
}
if uri.len() > MAX_URI_LENGTH {
continue;
}
if !uri_has_spiffe_scheme(uri) {
continue;
}
ids.push(SpiffeId::new(uri)?);
}
Ok(ids)
}