use synta::tag::{TAG_SEQUENCE, TAG_SET};
use synta::{Boolean, Integer, ObjectIdentifier, OctetStringRef, RawDer, Tag};
use crate::builder::BuilderError;
use crate::crypto::CertificateSigner;
use crate::oids::PKCS9_EXTENSION_REQUEST;
use crate::Extension;
pub type CsrBuilderError = BuilderError;
pub struct CsrBuilder {
subject: Option<Vec<u8>>,
spki: Option<Vec<u8>>,
extensions: Vec<(ObjectIdentifier, bool, Vec<u8>)>,
}
impl Default for CsrBuilder {
fn default() -> Self {
Self::new()
}
}
impl CsrBuilder {
pub fn new() -> Self {
Self {
subject: None,
spki: None,
extensions: Vec::new(),
}
}
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 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_cri(&self, sig_alg_der: &[u8]) -> Result<Vec<u8>, CsrBuilderError> {
let subject = self
.subject
.as_deref()
.ok_or(CsrBuilderError::MissingField("subject_name"))?;
let spki = self
.spki
.as_deref()
.ok_or(CsrBuilderError::MissingField("public_key"))?;
let mut enc = synta::Encoder::with_capacity(
synta::Encoding::Der,
16 + subject.len() + spki.len() + sig_alg_der.len() + 64,
);
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
enc.encode(&Integer::from_i64(0))?;
enc.encode(&RawDer(subject))?;
enc.encode(&RawDer(spki))?;
if !self.extensions.is_empty() {
enc.start_constructed_no_guard(Tag::context_specific_constructed(0))?;
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
let ext_req_oid = ObjectIdentifier::new(PKCS9_EXTENSION_REQUEST).map_err(|_| {
CsrBuilderError::EncodeError("invalid PKCS9_EXTENSION_REQUEST OID constant".into())
})?;
enc.encode(&ext_req_oid)?;
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SET))?;
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()?;
enc.end_constructed()?; }
enc.end_constructed()?; Ok(enc.finish()?)
}
pub fn assemble(
cri_der: &[u8],
sig_alg_der: &[u8],
signature: &[u8],
) -> Result<Vec<u8>, CsrBuilderError> {
use synta::BitStringRef;
let mut enc = synta::Encoder::with_capacity(
synta::Encoding::Der,
cri_der.len() + sig_alg_der.len() + signature.len() + 8,
);
enc.start_constructed_no_guard(Tag::universal_constructed(TAG_SEQUENCE))?;
enc.write_bytes(cri_der);
enc.write_bytes(sig_alg_der);
let sig_bstr = BitStringRef::new(signature, 0)
.map_err(|e| CsrBuilderError::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>, CsrBuilderError> {
let sig_alg_der = signer
.signature_algorithm_der()
.map_err(|e| CsrBuilderError::SignError(e.to_string()))?;
let cri_der = self.build_cri(&sig_alg_der)?;
let signature = signer
.sign_tbs(&cri_der)
.map_err(|e| CsrBuilderError::SignError(e.to_string()))?;
Self::assemble(&cri_der, &sig_alg_der, &signature)
}
}