use std::fmt;
use der::{Decode, Encode};
use sha2::{Digest, Sha256};
use super::{KeyError, PublicKey};
#[derive(Clone)]
pub struct Certificate {
der: Vec<u8>,
parsed: x509_cert::Certificate,
}
impl Certificate {
pub fn from_der(der: &[u8]) -> Result<Self, KeyError> {
let parsed = x509_cert::Certificate::from_der(der).map_err(KeyError::Certificate)?;
Ok(Self { der: der.to_vec(), parsed })
}
pub fn der(&self) -> &[u8] {
&self.der
}
pub fn x509(&self) -> &x509_cert::Certificate {
&self.parsed
}
pub fn sha256_fingerprint(&self) -> [u8; 32] {
Sha256::digest(&self.der).into()
}
pub fn subject(&self) -> String {
self.parsed.tbs_certificate().subject().to_string()
}
pub fn issuer(&self) -> String {
self.parsed.tbs_certificate().issuer().to_string()
}
pub fn serial_number(&self) -> &[u8] {
self.parsed.tbs_certificate().serial_number().as_bytes()
}
pub fn public_key_der(&self) -> Result<Vec<u8>, KeyError> {
self.parsed.tbs_certificate().subject_public_key_info().to_der().map_err(KeyError::Certificate)
}
pub fn public_key(&self) -> Result<PublicKey, KeyError> {
PublicKey::from_spki_der(&self.public_key_der()?)
}
}
impl PartialEq for Certificate {
fn eq(&self, other: &Self) -> bool {
self.der == other.der
}
}
impl Eq for Certificate {}
impl fmt::Debug for Certificate {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Certificate")
.field("subject", &self.subject())
.field("sha256", &hex(&self.sha256_fingerprint()))
.finish()
}
}
pub(crate) fn hex(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{b:02x}")).collect()
}