extern crate alloc;
use alloc::vec::Vec;
use super::pkix_path::{validate_path, TrustAnchor, ValidationPolicy};
use x509_cert::der::Decode;
use x509_cert::Certificate;
use super::error::{Result, X509Error};
use super::sm2_verifier::TasignSignatureVerifier;
pub fn verify_chain(chain_der: &[&[u8]], trust_roots_pem: &[u8]) -> Result<()> {
verify_chain_at(chain_der, trust_roots_pem, validation_time_secs()?)
}
pub fn verify_chain_at(chain_der: &[&[u8]], trust_roots_pem: &[u8], unix_secs: u64) -> Result<()> {
if chain_der.is_empty() {
return Err(X509Error::InvalidInput);
}
let chain: Vec<Certificate> = chain_der
.iter()
.map(|der| Certificate::from_der(der).map_err(map_der_err))
.collect::<Result<_>>()?;
let anchors = load_trust_anchors(trust_roots_pem)?;
if anchors.is_empty() {
return Err(X509Error::UntrustedRoot);
}
let policy = ValidationPolicy::new(unix_secs);
validate_path(&chain, &anchors, &policy, &TasignSignatureVerifier)
.map_err(map_pkix_err)
.map(|_| ())
}
fn load_trust_anchors(pem: &[u8]) -> Result<Vec<TrustAnchor>> {
let certs = Certificate::load_pem_chain(pem).map_err(map_der_err)?;
Ok(certs.iter().map(TrustAnchor::from).collect())
}
#[cfg(feature = "std")]
fn validation_time_secs() -> Result<u64> {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| X509Error::InternalError)
.map(|d| d.as_secs())
}
#[cfg(not(feature = "std"))]
fn validation_time_secs() -> Result<u64> {
Ok(u64::MAX)
}
fn map_der_err(_e: der::Error) -> X509Error {
X509Error::InvalidCertificate
}
fn map_pkix_err(err: super::pkix_path::Error) -> X509Error {
use super::pkix_path::Error as PkixError;
match err {
PkixError::SignatureInvalid { .. } => X509Error::SignatureVerificationFailed,
PkixError::ValidityPeriod { .. } => X509Error::CertificateExpired,
PkixError::NoTrustedPath | PkixError::ChainBroken { .. } => X509Error::ChainBuildFailed,
PkixError::MalformedCertificate { .. } => X509Error::InvalidCertificate,
PkixError::NotCA { .. }
| PkixError::PathTooLong
| PkixError::KeyUsageMissing { .. }
| PkixError::CrlSignMissing { .. }
| PkixError::UnhandledCriticalExtension { .. } => X509Error::InvalidCertificate,
_ => X509Error::Message(alloc::format!("pkix-path: {err:?}")),
}
}