x509_ocsp/builder/
request.rs

1//! OCSP request builder
2
3use crate::{builder::Error, OcspRequest, Request, Signature, TbsRequest, Version};
4use alloc::vec::Vec;
5use der::Encode;
6use rand_core::CryptoRngCore;
7use signature::{RandomizedSigner, Signer};
8use spki::{DynSignatureAlgorithmIdentifier, SignatureBitStringEncoding};
9use x509_cert::{
10    ext::{pkix::name::GeneralName, AsExtension},
11    name::Name,
12    Certificate,
13};
14
15/// X509 OCSP Request builder
16///
17/// ```
18/// use der::Decode;
19/// use sha1::Sha1;
20/// use x509_cert::{serial_number::SerialNumber, Certificate};
21/// use x509_ocsp::builder::OcspRequestBuilder;
22/// use x509_ocsp::{ext::Nonce, Request};
23///
24/// # const ISSUER_DER: &[u8] = include_bytes!("../../tests/examples/rsa-2048-sha256-ca.der");
25/// # const CERT_DER: &[u8] = include_bytes!("../../tests/examples/rsa-2048-sha256-crt.der");
26/// # const KEY_DER: &[u8] = include_bytes!("../../tests/examples/rsa-2048-sha256-crt-key.der");
27/// # use rsa::{pkcs1v15::SigningKey, pkcs8::DecodePrivateKey};
28/// # use sha2::Sha256;
29/// # fn rsa_signer() -> SigningKey<Sha256> {
30/// #     let private_key = rsa::RsaPrivateKey::from_pkcs8_der(KEY_DER).unwrap();
31/// #     let signing_key = SigningKey::<Sha256>::new(private_key);
32/// #     signing_key
33/// # }
34/// let issuer = Certificate::from_der(ISSUER_DER).unwrap();
35/// let cert = Certificate::from_der(CERT_DER).unwrap();
36///
37/// let req = OcspRequestBuilder::default()
38///     .with_request(Request::from_cert::<Sha1>(&issuer, &cert).unwrap())
39///     .build();
40///
41/// let mut rng = rand::thread_rng();
42///
43/// let req = OcspRequestBuilder::default()
44///     .with_request(Request::from_issuer::<Sha1>(&issuer, SerialNumber::from(2usize)).unwrap())
45///     .with_request(Request::from_issuer::<Sha1>(&issuer, SerialNumber::from(3usize)).unwrap())
46///     .with_request(Request::from_issuer::<Sha1>(&issuer, SerialNumber::from(4usize)).unwrap())
47///     .with_extension(Nonce::generate(&mut rng, 32).unwrap())
48///     .unwrap()
49///     .build();
50///
51/// let mut signer = rsa_signer();
52/// let signer_cert_chain = vec![cert.clone()];
53/// let req = OcspRequestBuilder::default()
54///     .with_request(Request::from_cert::<Sha1>(&issuer, &cert).unwrap())
55///     .with_extension(Nonce::generate(&mut rng, 32).unwrap())
56///     .unwrap()
57///     .sign(&mut signer, Some(signer_cert_chain))
58///     .unwrap();
59/// ```
60#[derive(Clone, Debug, Default)]
61pub struct OcspRequestBuilder {
62    tbs: TbsRequest,
63}
64
65impl OcspRequestBuilder {
66    /// Returns an `OcspRequestBuilder` with the specified [`Version`]
67    pub fn new(version: Version) -> Self {
68        Self {
69            tbs: TbsRequest {
70                version,
71                requestor_name: None,
72                request_list: Vec::new(),
73                request_extensions: None,
74            },
75        }
76    }
77
78    /// Sets the requestor name as specified in [RFC 6960 Section 4.1.1]
79    ///
80    /// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
81    pub fn with_requestor_name(mut self, requestor_name: GeneralName) -> Self {
82        self.tbs.requestor_name = Some(requestor_name);
83        self
84    }
85
86    /// Adds a [`Request`] to the builder as defined in [RFC 6960 Section 4.1.1].
87    ///
88    /// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
89    pub fn with_request(mut self, request: Request) -> Self {
90        self.tbs.request_list.push(request);
91        self
92    }
93
94    /// Adds a request extension as specified in [RFC 6960 Section 4.4]. Errors when the
95    /// extension encoding fails.
96    ///
97    /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4
98    pub fn with_extension(mut self, ext: impl AsExtension) -> Result<Self, Error> {
99        let ext = ext.to_extension(&Name::default(), &[])?;
100        match self.tbs.request_extensions {
101            Some(ref mut exts) => exts.push(ext),
102            None => self.tbs.request_extensions = Some(alloc::vec![ext]),
103        }
104        Ok(self)
105    }
106
107    /// Consumes the builder and returns an [`OcspRequest`]
108    pub fn build(self) -> OcspRequest {
109        OcspRequest {
110            tbs_request: self.tbs,
111            optional_signature: None,
112        }
113    }
114
115    /// Consumes the builder and returns a signed [`OcspRequest`]. Errors when the algorithm
116    /// identifier encoding, message encoding, or signature generation fails.
117    pub fn sign<S, Sig>(
118        self,
119        signer: &mut S,
120        certificate_chain: Option<Vec<Certificate>>,
121    ) -> Result<OcspRequest, Error>
122    where
123        S: Signer<Sig> + DynSignatureAlgorithmIdentifier,
124        Sig: SignatureBitStringEncoding,
125    {
126        let signature_algorithm = signer.signature_algorithm_identifier()?;
127        let signature = signer.try_sign(&self.tbs.to_der()?)?.to_bitstring()?;
128        let optional_signature = Some(Signature {
129            signature_algorithm,
130            signature,
131            certs: certificate_chain,
132        });
133        Ok(OcspRequest {
134            tbs_request: self.tbs,
135            optional_signature,
136        })
137    }
138
139    /// Consumes the builder and returns a signed [`OcspRequest`]. Errors when the algorithm
140    /// identifier encoding, message encoding, or signature generation fails.
141    pub fn sign_with_rng<S, Sig>(
142        self,
143        signer: &mut S,
144        rng: &mut impl CryptoRngCore,
145        certificate_chain: Option<Vec<Certificate>>,
146    ) -> Result<OcspRequest, Error>
147    where
148        S: RandomizedSigner<Sig> + DynSignatureAlgorithmIdentifier,
149        Sig: SignatureBitStringEncoding,
150    {
151        let signature_algorithm = signer.signature_algorithm_identifier()?;
152        let signature = signer
153            .try_sign_with_rng(rng, &self.tbs.to_der()?)?
154            .to_bitstring()?;
155        let optional_signature = Some(Signature {
156            signature_algorithm,
157            signature,
158            certs: certificate_chain,
159        });
160        Ok(OcspRequest {
161            tbs_request: self.tbs,
162            optional_signature,
163        })
164    }
165}