use crate::{
builder::Error, BasicOcspResponse, OcspGeneralizedTime, OcspResponse, ResponderId,
ResponseData, SingleResponse, Version,
};
use alloc::vec::Vec;
use der::Encode;
use rand_core::CryptoRngCore;
use signature::{RandomizedSigner, Signer};
use spki::{DynSignatureAlgorithmIdentifier, SignatureBitStringEncoding};
use x509_cert::{
ext::{AsExtension, Extensions},
name::Name,
Certificate,
};
#[derive(Clone, Debug)]
pub struct OcspResponseBuilder {
responder_id: ResponderId,
responses: Vec<SingleResponse>,
response_extensions: Option<Extensions>,
}
impl OcspResponseBuilder {
pub fn new(responder_id: impl Into<ResponderId>) -> Self {
let responder_id = responder_id.into();
Self {
responder_id,
responses: Vec::new(),
response_extensions: None,
}
}
pub fn with_single_response(mut self, single_response: SingleResponse) -> Self {
self.responses.push(single_response);
self
}
pub fn with_extension(mut self, ext: impl AsExtension) -> Result<Self, Error> {
let ext = ext.to_extension(&Name::default(), &[])?;
match self.response_extensions {
Some(ref mut exts) => exts.push(ext),
None => self.response_extensions = Some(alloc::vec![ext]),
}
Ok(self)
}
fn into_response_data(self, produced_at: OcspGeneralizedTime) -> ResponseData {
ResponseData {
version: Version::default(),
responder_id: self.responder_id,
produced_at,
responses: self.responses,
response_extensions: self.response_extensions,
}
}
pub fn sign<S, Sig>(
self,
signer: &mut S,
certificate_chain: Option<Vec<Certificate>>,
produced_at: OcspGeneralizedTime,
) -> Result<OcspResponse, Error>
where
S: Signer<Sig> + DynSignatureAlgorithmIdentifier,
Sig: SignatureBitStringEncoding,
{
let tbs_response_data = self.into_response_data(produced_at);
let signature_algorithm = signer.signature_algorithm_identifier()?;
let signature = signer
.try_sign(&tbs_response_data.to_der()?)?
.to_bitstring()?;
Ok(OcspResponse::successful(BasicOcspResponse {
tbs_response_data,
signature_algorithm,
signature,
certs: certificate_chain,
})?)
}
pub fn sign_with_rng<S, Sig>(
self,
signer: &mut S,
rng: &mut impl CryptoRngCore,
certificate_chain: Option<Vec<Certificate>>,
produced_at: OcspGeneralizedTime,
) -> Result<OcspResponse, Error>
where
S: RandomizedSigner<Sig> + DynSignatureAlgorithmIdentifier,
Sig: SignatureBitStringEncoding,
{
let tbs_response_data = self.into_response_data(produced_at);
let signature_algorithm = signer.signature_algorithm_identifier()?;
let signature = signer
.try_sign_with_rng(rng, &tbs_response_data.to_der()?)?
.to_bitstring()?;
Ok(OcspResponse::successful(BasicOcspResponse {
tbs_response_data,
signature_algorithm,
signature,
certs: certificate_chain,
})?)
}
}