x509_ocsp/request.rs
1//! OCSP Request
2
3use crate::{ext::Nonce, CertId, Version};
4use alloc::vec::Vec;
5use const_oid::db::rfc6960::ID_PKIX_OCSP_NONCE;
6use core::{default::Default, option::Option};
7use der::{asn1::BitString, Decode, Sequence};
8use spki::AlgorithmIdentifierOwned;
9use x509_cert::{
10 certificate::Certificate,
11 ext::{pkix::name::GeneralName, Extensions},
12};
13
14/// OCSPRequest structure as defined in [RFC 6960 Section 4.1.1].
15///
16/// ```text
17/// OCSPRequest ::= SEQUENCE {
18/// tbsRequest TBSRequest,
19/// optionalSignature [0] EXPLICIT Signature OPTIONAL }
20/// ```
21///
22/// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
23#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
24#[allow(missing_docs)]
25pub struct OcspRequest {
26 pub tbs_request: TbsRequest,
27
28 #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
29 pub optional_signature: Option<Signature>,
30}
31
32impl OcspRequest {
33 /// Returns the request's nonce value, if any. This method will return `None` if the request
34 /// has no `Nonce` extension or decoding of the `Nonce` extension fails.
35 pub fn nonce(&self) -> Option<Nonce> {
36 self.tbs_request.nonce()
37 }
38}
39
40/// TBSRequest structure as defined in [RFC 6960 Section 4.1.1].
41///
42/// ```text
43/// TBSRequest ::= SEQUENCE {
44/// version [0] EXPLICIT Version DEFAULT v1,
45/// requestorName [1] EXPLICIT GeneralName OPTIONAL,
46/// requestList SEQUENCE OF Request,
47/// requestExtensions [2] EXPLICIT Extensions OPTIONAL }
48/// ```
49///
50/// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
51#[derive(Clone, Debug, Default, Eq, PartialEq, Sequence)]
52#[allow(missing_docs)]
53pub struct TbsRequest {
54 #[asn1(
55 context_specific = "0",
56 default = "Default::default",
57 tag_mode = "EXPLICIT"
58 )]
59 pub version: Version,
60
61 #[asn1(context_specific = "1", optional = "true", tag_mode = "EXPLICIT")]
62 pub requestor_name: Option<GeneralName>,
63
64 pub request_list: Vec<Request>,
65
66 #[asn1(context_specific = "2", optional = "true", tag_mode = "EXPLICIT")]
67 pub request_extensions: Option<Extensions>,
68}
69
70impl TbsRequest {
71 /// Returns the request's nonce value, if any. This method will return `None` if the request
72 /// has no `Nonce` extension or decoding of the `Nonce` extension fails.
73 pub fn nonce(&self) -> Option<Nonce> {
74 match &self.request_extensions {
75 Some(extns) => {
76 let mut filter = extns.iter().filter(|e| e.extn_id == ID_PKIX_OCSP_NONCE);
77 match filter.next() {
78 Some(extn) => Nonce::from_der(extn.extn_value.as_bytes()).ok(),
79 None => None,
80 }
81 }
82 None => None,
83 }
84 }
85}
86
87/// Signature structure as defined in [RFC 6960 Section 4.1.1].
88///
89/// ```text
90/// Signature ::= SEQUENCE {
91/// signatureAlgorithm AlgorithmIdentifier,
92/// signature BIT STRING,
93/// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
94/// ```
95///
96/// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
97#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
98#[allow(missing_docs)]
99pub struct Signature {
100 pub signature_algorithm: AlgorithmIdentifierOwned,
101 pub signature: BitString,
102
103 #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
104 pub certs: Option<Vec<Certificate>>,
105}
106
107/// Request structure as defined in [RFC 6960 Section 4.1.1].
108///
109/// ```text
110/// Request ::= SEQUENCE {
111/// reqCert CertID,
112/// singleRequestExtensions [0] EXPLICIT Extensions OPTIONAL }
113/// ```
114///
115/// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
116#[derive(Clone, Debug, Eq, PartialEq, Sequence)]
117#[allow(missing_docs)]
118pub struct Request {
119 pub req_cert: CertId,
120
121 #[asn1(context_specific = "0", optional = "true", tag_mode = "EXPLICIT")]
122 pub single_request_extensions: Option<Extensions>,
123}
124
125#[cfg(feature = "builder")]
126mod builder {
127 use crate::{builder::Error, CertId, Request};
128 use const_oid::AssociatedOid;
129 use digest::Digest;
130 use x509_cert::{ext::AsExtension, name::Name, serial_number::SerialNumber, Certificate};
131
132 impl Request {
133 /// Returns a new `Request` with the specified `CertID`
134 pub fn new(req_cert: CertId) -> Self {
135 Self {
136 req_cert,
137 single_request_extensions: None,
138 }
139 }
140
141 /// Generates a `CertID` by running the issuer's subject and key through the specified
142 /// [`Digest`].
143 ///
144 /// [RFC 6960 Section 4.1.1]
145 ///
146 /// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
147 pub fn from_issuer<D>(
148 issuer: &Certificate,
149 serial_number: SerialNumber,
150 ) -> Result<Self, Error>
151 where
152 D: Digest + AssociatedOid,
153 {
154 Ok(Self::new(CertId::from_issuer::<D>(issuer, serial_number)?))
155 }
156
157 /// Generates a `CertID` by running the issuer's subject and key through the specified
158 /// [`Digest`] and pulls the serial from `cert`. This does not ensure that `cert` is actually
159 /// issued by `issuer`.
160 ///
161 /// [RFC 6960 Section 4.1.1]
162 ///
163 /// [RFC 6960 Section 4.1.1]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.1.1
164 pub fn from_cert<D>(issuer: &Certificate, cert: &Certificate) -> Result<Self, Error>
165 where
166 D: Digest + AssociatedOid,
167 {
168 Ok(Self::new(CertId::from_cert::<D>(issuer, cert)?))
169 }
170
171 /// Adds a single request extension as specified in [RFC 6960 Section 4.4]. Errors when the
172 /// extension encoding fails.
173 ///
174 /// [RFC 6960 Section 4.4]: https://datatracker.ietf.org/doc/html/rfc6960#section-4.4
175 pub fn with_extension(mut self, ext: impl AsExtension) -> Result<Self, Error> {
176 let ext = ext.to_extension(&Name::default(), &[])?;
177 match self.single_request_extensions {
178 Some(ref mut exts) => exts.push(ext),
179 None => self.single_request_extensions = Some(alloc::vec![ext]),
180 }
181 Ok(self)
182 }
183 }
184}