use std::fmt;
use bytes::Bytes;
use crate::dtls::Result;
use x509_parser::prelude::*;
use sha2::{Sha256, Digest};
#[derive(Debug, Clone)]
pub struct Certificate {
der: Bytes,
parsed: Option<ParsedCertificate>,
}
impl Certificate {
pub fn new(der: Bytes) -> Self {
Self {
der,
parsed: None,
}
}
pub fn der(&self) -> &Bytes {
&self.der
}
pub fn parse(&mut self) -> Result<&ParsedCertificate> {
if self.parsed.is_none() {
let (_, x509) = X509Certificate::from_der(&self.der)
.map_err(|e| crate::error::Error::CertificateValidationError(
format!("Failed to parse certificate: {}", e)
))?;
let subject = x509.subject().to_string();
let issuer = x509.issuer().to_string();
let serial_number = x509.serial.to_string();
let not_before = x509.validity().not_before.to_string();
let not_after = x509.validity().not_after.to_string();
let mut subject_alt_names = Vec::new();
if let Ok(Some(ext)) = x509.subject_alternative_name() {
for name in ext.value.general_names.iter() {
subject_alt_names.push(name.to_string());
}
}
let tbs = x509.tbs_certificate;
let public_key = match tbs.subject_pki.algorithm.algorithm.to_id_string().as_str() {
"1.2.840.10045.2.1" => {
let curve = match tbs.subject_pki.algorithm.parameters {
Some(ref params) => {
if let Ok(oid) = params.as_oid() {
match oid.to_id_string().as_str() {
"1.2.840.10045.3.1.7" => "P-256".to_string(),
"1.3.132.0.34" => "P-384".to_string(),
"1.3.132.0.35" => "P-521".to_string(),
_ => format!("Unknown curve: {}", oid),
}
} else {
"Unknown curve".to_string()
}
},
None => "Unknown curve".to_string(),
};
CertificatePublicKey::Ecdsa {
curve,
public_key: Bytes::copy_from_slice(&tbs.subject_pki.subject_public_key.data),
}
},
"1.2.840.113549.1.1.1" => {
CertificatePublicKey::Rsa {
modulus: Bytes::new(), exponent: Bytes::new(), }
},
_ => {
return Err(crate::error::Error::UnsupportedFeature(
format!("Unsupported public key algorithm: {}", tbs.subject_pki.algorithm.algorithm)
));
}
};
let signature_algorithm = x509.signature_algorithm.algorithm.to_string();
let signature = Bytes::copy_from_slice(&x509.signature_value.data);
self.parsed = Some(ParsedCertificate {
subject,
issuer,
serial_number,
not_before,
not_after,
subject_alt_names,
public_key,
signature_algorithm,
signature,
});
}
Ok(self.parsed.as_ref().unwrap())
}
pub fn fingerprint(&mut self, algorithm: &str) -> Result<String> {
match algorithm.to_uppercase().as_str() {
"SHA-256" => {
let mut hasher = Sha256::new();
hasher.update(&self.der);
let result = hasher.finalize();
let fingerprint = result.iter()
.map(|b| format!("{:02X}", b))
.collect::<Vec<String>>()
.join(":");
Ok(fingerprint)
}
_ => Err(crate::error::Error::UnsupportedFeature(format!("Unsupported fingerprint algorithm: {}", algorithm))),
}
}
}
#[derive(Debug, Clone)]
pub struct ParsedCertificate {
pub subject: String,
pub issuer: String,
pub serial_number: String,
pub not_before: String,
pub not_after: String,
pub subject_alt_names: Vec<String>,
pub public_key: CertificatePublicKey,
pub signature_algorithm: String,
pub signature: Bytes,
}
#[derive(Debug, Clone)]
pub enum CertificatePublicKey {
Rsa {
modulus: Bytes,
exponent: Bytes,
},
Ecdsa {
curve: String,
public_key: Bytes,
},
}
impl fmt::Display for CertificatePublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CertificatePublicKey::Rsa { .. } => write!(f, "RSA"),
CertificatePublicKey::Ecdsa { curve, .. } => write!(f, "ECDSA ({})", curve),
}
}
}
pub trait CertificateVerifier {
fn verify(&self, cert: &Certificate, trusted_roots: &[Certificate]) -> Result<bool>;
}
pub struct BasicCertificateVerifier;
impl CertificateVerifier for BasicCertificateVerifier {
fn verify(&self, cert: &Certificate, trusted_roots: &[Certificate]) -> Result<bool> {
let mut cert_clone = cert.clone();
let parsed = cert_clone.parse()?;
for root in trusted_roots {
let mut root_clone = root.clone();
let root_parsed = root_clone.parse()?;
if parsed.issuer == root_parsed.subject {
return Ok(true);
}
}
Ok(false)
}
}
pub struct SelfSignedCertificateVerifier;
impl CertificateVerifier for SelfSignedCertificateVerifier {
fn verify(&self, _cert: &Certificate, _trusted_roots: &[Certificate]) -> Result<bool> {
Ok(true)
}
}
pub struct CertificateChainVerifier {
verifier: Box<dyn CertificateVerifier>,
}
impl CertificateChainVerifier {
pub fn new(verifier: Box<dyn CertificateVerifier>) -> Self {
Self {
verifier,
}
}
pub fn verify(&self, certs: &[Certificate], trusted_roots: &[Certificate]) -> Result<bool> {
if certs.is_empty() {
return Err(crate::error::Error::InvalidParameter("Empty certificate chain".to_string()));
}
for (i, cert) in certs.iter().enumerate() {
if i == 0 {
if !self.verifier.verify(cert, trusted_roots)? {
return Ok(false);
}
} else {
let previous_certs = &certs[..i];
if !self.verifier.verify(cert, previous_certs)? {
return Ok(false);
}
}
}
Ok(true)
}
}
pub struct FingerprintVerifier {
algorithm: String,
fingerprint: String,
}
impl FingerprintVerifier {
pub fn new(algorithm: String, fingerprint: String) -> Self {
Self {
algorithm,
fingerprint,
}
}
pub fn verify(&self, cert: &mut Certificate) -> Result<bool> {
let cert_fingerprint = cert.fingerprint(&self.algorithm)?;
Ok(cert_fingerprint.eq_ignore_ascii_case(&self.fingerprint))
}
}
pub fn generate_self_signed_certificate() -> Result<Certificate> {
use rcgen::{Certificate as RcGenCertificate, CertificateParams, PKCS_ECDSA_P256_SHA256};
let mut params = CertificateParams::new(vec!["localhost".to_string()]);
params.alg = &PKCS_ECDSA_P256_SHA256;
let cert = RcGenCertificate::from_params(params)
.map_err(|e| crate::error::Error::CertificateValidationError(
format!("Failed to generate certificate: {}", e)
))?;
let der = cert.serialize_der()
.map_err(|e| crate::error::Error::CertificateValidationError(
format!("Failed to serialize certificate: {}", e)
))?;
Ok(Certificate::new(Bytes::from(der)))
}