use core::fmt;
use synta::tag::TAG_SEQUENCE;
use synta::{Boolean, Integer, ObjectIdentifier, OctetStringRef, RawDer, Tag};
use crate::crypto::CertificateSigner;
use crate::{Extension, Time, Validity};
#[derive(Debug)]
pub enum BuilderError {
MissingField(&'static str),
EncodeError(String),
SignError(String),
}
impl fmt::Display for BuilderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BuilderError::MissingField(field) => {
write!(f, "required field not set: {field}")
}
BuilderError::EncodeError(msg) => write!(f, "ASN.1 encode error: {msg}"),
BuilderError::SignError(msg) => write!(f, "signing error: {msg}"),
}
}
}
impl std::error::Error for BuilderError {}
impl From<synta::Error> for BuilderError {
fn from(e: synta::Error) -> Self {
BuilderError::EncodeError(e.to_string())
}
}
pub struct CertificateBuilder {
issuer: Option<Vec<u8>>,
subject: Option<Vec<u8>>,
spki: Option<Vec<u8>>,
serial: Option<Integer>,
not_before: Option<Time>,
not_after: Option<Time>,
extensions: Vec<(ObjectIdentifier, bool, Vec<u8>)>,
}
impl Default for CertificateBuilder {
fn default() -> Self {
Self::new()
}
}
impl CertificateBuilder {
pub fn new() -> Self {
Self {
issuer: None,
subject: None,
spki: None,
serial: None,
not_before: None,
not_after: None,
extensions: Vec::new(),
}
}
pub fn issuer_name(mut self, name_der: &[u8]) -> Self {
self.issuer = Some(name_der.to_vec());
self
}
pub fn subject_name(mut self, name_der: &[u8]) -> Self {
self.subject = Some(name_der.to_vec());
self
}
pub fn public_key_der(mut self, spki_der: &[u8]) -> Self {
self.spki = Some(spki_der.to_vec());
self
}
pub fn serial_number(mut self, serial: Integer) -> Self {
self.serial = Some(serial);
self
}
pub fn not_valid_before(mut self, t: Time) -> Self {
self.not_before = Some(t);
self
}
pub fn not_valid_after(mut self, t: Time) -> Self {
self.not_after = Some(t);
self
}
pub fn add_extension(
mut self,
oid: ObjectIdentifier,
critical: bool,
value_der: &[u8],
) -> Self {
self.extensions.push((oid, critical, value_der.to_vec()));
self
}
pub fn add_extension_oid(
self,
oid_components: &[u32],
critical: bool,
value_der: &[u8],
) -> Self {
let oid = ObjectIdentifier::new(oid_components)
.expect("add_extension_oid: invalid OID components");
self.add_extension(oid, critical, value_der)
}
pub fn build_tbs(&self, sig_alg_der: &[u8]) -> Result<Vec<u8>, BuilderError> {
let issuer = self
.issuer
.as_deref()
.ok_or(BuilderError::MissingField("issuer_name"))?;
let subject = self
.subject
.as_deref()
.ok_or(BuilderError::MissingField("subject_name"))?;
let spki = self
.spki
.as_deref()
.ok_or(BuilderError::MissingField("public_key"))?;
let serial = self
.serial
.as_ref()
.ok_or(BuilderError::MissingField("serial_number"))?;
let not_before = self
.not_before
.as_ref()
.ok_or(BuilderError::MissingField("not_valid_before"))?;
let not_after = self
.not_after
.as_ref()
.ok_or(BuilderError::MissingField("not_valid_after"))?;
let mut enc = synta::Encoder::with_capacity(
synta::Encoding::Der,
16 + issuer.len() + subject.len() + spki.len() + 64,
);
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
enc.start_constructed_no_guard(Tag::context_specific_constructed(0))?;
enc.encode(&Integer::from_i64(2))?;
enc.end_constructed()?;
enc.encode(serial)?;
enc.write_bytes(sig_alg_der);
enc.encode(&RawDer(issuer))?;
enc.encode(&Validity {
not_before: not_before.clone(),
not_after: not_after.clone(),
})?;
enc.encode(&RawDer(subject))?;
enc.encode(&RawDer(spki))?;
if !self.extensions.is_empty() {
enc.start_constructed_no_guard(Tag::context_specific_constructed(3))?;
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
for (oid, critical, value_bytes) in &self.extensions {
let ext = Extension {
extn_id: oid.clone(),
critical: if *critical {
Some(Boolean::new(true))
} else {
None
},
extn_value: OctetStringRef::new(value_bytes),
};
enc.encode(&ext)?;
}
enc.end_constructed()?; enc.end_constructed()?; }
enc.end_constructed()?; Ok(enc.finish()?)
}
pub fn assemble(
tbs_der: &[u8],
sig_alg_der: &[u8],
signature: &[u8],
) -> Result<Vec<u8>, BuilderError> {
use synta::BitStringRef;
let mut enc = synta::Encoder::with_capacity(
synta::Encoding::Der,
tbs_der.len() + sig_alg_der.len() + signature.len() + 8,
);
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
enc.write_bytes(tbs_der);
enc.write_bytes(sig_alg_der);
let sig_bstr = BitStringRef::new(signature, 0)
.map_err(|e| BuilderError::EncodeError(e.to_string()))?;
enc.encode(&sig_bstr)?;
enc.end_constructed()?; Ok(enc.finish()?)
}
pub fn sign<S: CertificateSigner>(self, signer: &S) -> Result<Vec<u8>, BuilderError> {
let sig_alg_der = signer
.signature_algorithm_der()
.map_err(|e| BuilderError::SignError(e.to_string()))?;
let tbs_der = self.build_tbs(&sig_alg_der)?;
let signature = signer
.sign_tbs(&tbs_der)
.map_err(|e| BuilderError::SignError(e.to_string()))?;
Self::assemble(&tbs_der, &sig_alg_der, &signature)
}
}