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}