use crate::{ext::Nonce, CertId, Version};
use alloc::vec::Vec;
use const_oid::db::rfc6960::ID_PKIX_OCSP_NONCE;
use core::{default::Default, option::Option};
use der::{asn1::BitString, Decode, Sequence};
use spki::AlgorithmIdentifierOwned;
use x509_cert::{
certificate::Certificate,
ext::{pkix::name::GeneralName, Extensions},
};
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[allow(missing_docs)]
pub struct OcspRequest {
pub tbs_request: TbsRequest,
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub optional_signature: Option<Signature>,
}
impl OcspRequest {
pub fn nonce(&self) -> Option<Nonce> {
self.tbs_request.nonce()
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq, Sequence)]
#[allow(missing_docs)]
pub struct TbsRequest {
#[asn1(
context_specific = "0",
default = "Default::default",
tag_mode = "EXPLICIT"
)]
pub version: Version,
#[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")]
pub requestor_name: Option<GeneralName>,
pub request_list: Vec<Request>,
#[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")]
pub request_extensions: Option<Extensions>,
}
impl TbsRequest {
pub fn nonce(&self) -> Option<Nonce> {
match &self.request_extensions {
Some(extns) => {
let mut filter = extns.iter().filter(|e| e.extn_id == ID_PKIX_OCSP_NONCE);
match filter.next() {
Some(extn) => Nonce::from_der(extn.extn_value.as_bytes()).ok(),
None => None,
}
}
None => None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[allow(missing_docs)]
pub struct Signature {
pub signature_algorithm: AlgorithmIdentifierOwned,
pub signature: BitString,
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub certs: Option<Vec<Certificate>>,
}
#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
#[allow(missing_docs)]
pub struct Request {
pub req_cert: CertId,
#[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
pub single_request_extensions: Option<Extensions>,
}
#[cfg(feature = "builder")]
mod builder {
use crate::{builder::Error, CertId, Request};
use const_oid::AssociatedOid;
use digest::Digest;
use x509_cert::{ext::AsExtension, name::Name, serial_number::SerialNumber, Certificate};
impl Request {
pub fn new(req_cert: CertId) -> Self {
Self {
req_cert,
single_request_extensions: None,
}
}
pub fn from_issuer<D>(
issuer: &Certificate,
serial_number: SerialNumber,
) -> Result<Self, Error>
where
D: Digest + AssociatedOid,
{
Ok(Self::new(CertId::from_issuer::<D>(issuer, serial_number)?))
}
pub fn from_cert<D>(issuer: &Certificate, cert: &Certificate) -> Result<Self, Error>
where
D: Digest + AssociatedOid,
{
Ok(Self::new(CertId::from_cert::<D>(issuer, cert)?))
}
pub fn with_extension(mut self, ext: impl AsExtension) -> Result<Self, Error> {
let ext = ext.to_extension(&Name::default(), &[])?;
match self.single_request_extensions {
Some(ref mut exts) => exts.push(ext),
None => self.single_request_extensions = Some(alloc::vec![ext]),
}
Ok(self)
}
}
}