use crate::error::CertKitError;
use der::Encode;
use der::asn1::OctetString;
use x509_cert::Version;
use x509_cert::certificate::TbsCertificateInner;
use x509_cert::serial_number::SerialNumber;
use crate::cert::SignatureAlgorithm;
use crate::cert::params::{DistinguishedName, ExtensionParam};
use crate::key::PublicKey;
pub struct TbsCertificate {
pub serial_number: Vec<u8>,
pub signature_algorithm: SignatureAlgorithm,
pub issuer: DistinguishedName,
pub not_before: time::OffsetDateTime,
pub not_after: time::OffsetDateTime,
pub subject: DistinguishedName,
pub subject_public_key: PublicKey,
pub extensions: Vec<ExtensionParam>,
}
impl TbsCertificate {
pub fn new(
issuer: DistinguishedName,
subject: DistinguishedName,
subject_public_key: PublicKey,
signature_algorithm: SignatureAlgorithm,
extensions: Vec<ExtensionParam>,
) -> Self {
let not_before = time::OffsetDateTime::now_utc();
let not_after = not_before + time::Duration::days(365);
Self {
serial_number: vec![1],
signature_algorithm,
issuer,
not_before,
not_after,
subject,
subject_public_key,
extensions,
}
}
pub fn to_tbs_certificate_inner(&self) -> TbsCertificateInner {
let algorithm_id: x509_cert::spki::AlgorithmIdentifierOwned =
self.signature_algorithm.clone().into();
let extensions = self
.extensions
.iter()
.map(|ext| x509_cert::ext::Extension {
extn_id: ext.oid,
critical: ext.critical,
extn_value: OctetString::new(ext.value.clone()).unwrap(),
})
.collect::<Vec<_>>();
let not_before = x509_cert::time::Time::UtcTime(
der::asn1::UtcTime::from_system_time(self.not_before.into()).unwrap(),
);
let not_after = x509_cert::time::Time::UtcTime(
der::asn1::UtcTime::from_system_time(self.not_after.into()).unwrap(),
);
let validity = x509_cert::time::Validity {
not_before,
not_after,
};
let serial_number = SerialNumber::new(self.serial_number.as_slice()).unwrap();
let subject_public_key_info = match &self.subject_public_key {
PublicKey::Rsa(public) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(public.clone()).unwrap()
}
PublicKey::EcdsaP256(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key).unwrap()
}
PublicKey::EcdsaP384(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key).unwrap()
}
PublicKey::EcdsaP521(verifying_key) => {
x509_cert::spki::SubjectPublicKeyInfoOwned::from_key(*verifying_key).unwrap()
}
PublicKey::Ed25519(verifying_key) => {
let pk_bytes = verifying_key.to_bytes();
x509_cert::spki::SubjectPublicKeyInfoOwned {
algorithm: x509_cert::spki::AlgorithmIdentifierOwned {
oid: const_oid::ObjectIdentifier::new_unwrap("1.3.101.112"),
parameters: None,
},
subject_public_key: der::asn1::BitString::from_bytes(&pk_bytes).unwrap(),
}
}
};
TbsCertificateInner {
version: Version::V3,
serial_number,
signature: algorithm_id,
issuer: self.issuer.as_x509_name(),
validity,
subject: self.subject.as_x509_name(),
subject_public_key_info,
issuer_unique_id: None,
subject_unique_id: None,
extensions: Some(extensions),
}
}
pub fn from_tbs_certificate_inner(inner: TbsCertificateInner) -> Result<Self, CertKitError> {
let issuer = DistinguishedName::from_x509_name(&inner.issuer);
let subject = DistinguishedName::from_x509_name(&inner.subject);
let subject_public_key = PublicKey::from_x509spki(&inner.subject_public_key_info)?;
let extensions = inner
.extensions
.unwrap_or_default()
.iter()
.map(|ext| ExtensionParam {
oid: ext.extn_id,
critical: ext.critical,
value: ext.extn_value.as_bytes().to_vec(),
})
.collect::<Vec<_>>();
let not_before = match inner.validity.not_before {
x509_cert::time::Time::UtcTime(ut) => time::OffsetDateTime::from(ut.to_system_time()),
x509_cert::time::Time::GeneralTime(gt) => {
time::OffsetDateTime::from(gt.to_system_time())
}
};
let not_after = match inner.validity.not_after {
x509_cert::time::Time::UtcTime(ut) => time::OffsetDateTime::from(ut.to_system_time()),
x509_cert::time::Time::GeneralTime(gt) => {
time::OffsetDateTime::from(gt.to_system_time())
}
};
let signature_algorithm = match inner.signature.oid {
const_oid::db::rfc5912::SHA_256_WITH_RSA_ENCRYPTION => {
SignatureAlgorithm::Sha256WithRSA
}
const_oid::db::rfc5912::ECDSA_WITH_SHA_256 => SignatureAlgorithm::Sha256WithECDSA,
const_oid::db::rfc8410::ID_ED_25519 => SignatureAlgorithm::Sha256WithEdDSA,
_ => {
return Err(CertKitError::DecodingError(
"Unsupported signature algorithm".to_string(),
));
}
};
Ok(Self {
serial_number: inner.serial_number.as_bytes().into(),
signature_algorithm,
issuer,
not_before,
not_after,
subject,
subject_public_key,
extensions,
})
}
pub fn to_der(&self) -> Result<Vec<u8>, der::Error> {
self.to_tbs_certificate_inner().to_der()
}
}