structured_pkix/ocsp/request/
authentication.rs1use super::{FIELD, OcspRequest};
4use crate::error::{CallbackError, Error};
5use crate::general_name::{self, GeneralName};
6use crate::path::{Verified, Verify, WorkingKey};
7use crate::{Certificate, revocation::RevocationTarget};
8use core::fmt;
9use structured_asn1::memory::Work;
10
11pub type RequestSignatureError<E> = CallbackError<E>;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum RequestSignatureFailure {
17 KeyBinding,
19 Signature,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum RequestorBinding {
26 Matches,
29 Differs,
32}
33
34#[derive(Debug, Clone, Copy)]
36pub struct SignedRequest<'q, 'a, 'c, 'cert> {
37 request: &'q OcspRequest<'a>,
38 signer: &'c Certificate<'cert>,
39 key: WorkingKey<'cert>,
40 name: RequestorBinding,
41}
42impl<'q, 'a, 'c, 'cert> SignedRequest<'q, 'a, 'c, 'cert> {
43 #[must_use]
45 pub fn request(self) -> &'q OcspRequest<'a> {
46 self.request
47 }
48 #[must_use]
50 pub fn signer(self) -> &'c Certificate<'cert> {
51 self.signer
52 }
53 #[must_use]
55 pub fn key(self) -> WorkingKey<'cert> {
56 self.key
57 }
58 #[must_use]
60 pub fn requestor(self) -> RequestorBinding {
61 self.name
62 }
63}
64
65#[derive(Debug)]
67pub enum RequestAuthentication<'q, 'a, 'c, 'cert> {
68 Unsigned,
70 Signed(SignedRequest<'q, 'a, 'c, 'cert>),
72 Rejected(RequestSignatureFailure),
74 UnsupportedSignature,
76}
77
78impl fmt::Display for RequestSignatureFailure {
79 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
80 formatter.write_str(match self {
81 Self::KeyBinding => "request key differs from signer SPKI",
82 Self::Signature => "request signature rejected",
83 })
84 }
85}
86
87impl<'a> OcspRequest<'a> {
88 pub fn authenticate_signature<'q, 'c, 'cert, V: Verify<E>, E: Work>(
95 &'q self,
96 signer: &'c Certificate<'cert>,
97 key: WorkingKey<'cert>,
98 verifier: &V,
99 execution: &E,
100 ) -> core::result::Result<
101 RequestAuthentication<'q, 'a, 'c, 'cert>,
102 RequestSignatureError<V::Error>,
103 > {
104 let current = self.execution_in(execution);
105 current
106 .charge_work(1)
107 .map_err(|reason| Error::resource(reason, FIELD, self.span.start))?;
108 let Some(signature) = &self.signature else {
109 return Ok(RequestAuthentication::Unsigned);
110 };
111 let actual_work = signer.execution_in(execution);
112 let key_work = key.key().execution_in(execution);
113 if !super::binding::equal(
114 key.key().as_bytes(),
115 &key_work,
116 signer.tbs().public_key().as_bytes(),
117 &actual_work,
118 "ocspRequest.signerKey",
119 key.key().key_offset(),
120 signer.span().start,
121 )? {
122 return Ok(RequestAuthentication::Rejected(
123 RequestSignatureFailure::KeyBinding,
124 ));
125 }
126 let Some(requestor) = self.requestor.as_ref() else {
128 return Err(Error::new(
129 crate::ErrorCode::MissingField,
130 "ocspRequest.requestorName",
131 self.signed.span().start,
132 )
133 .into());
134 };
135 let mut name = RequestorBinding::Differs;
136 if let GeneralName::Directory(requestor) = requestor
137 && requestor.matches_between(
138 signer.tbs().subject(),
139 (¤t, self.parser),
140 (&actual_work, signer.source_parser()),
141 )?
142 {
143 name = RequestorBinding::Matches;
144 }
145 if name == RequestorBinding::Differs
146 && let Some(names) = signer.tbs().extensions().subject_alt_name(execution)?
147 {
148 for candidate in &*names {
149 actual_work.charge_work(1).map_err(|reason| {
150 Error::resource(reason, "ocspRequest.requestorName", signer.span().start)
151 })?;
152 if general_name::matches_between(
153 requestor,
154 candidate,
155 (¤t, self.parser),
156 (&actual_work, signer.source_parser()),
157 self.signed.span().start,
158 "ocspRequest.requestorName",
159 )? {
160 name = RequestorBinding::Matches;
161 break;
162 }
163 }
164 }
165 current
166 .charge_work(1)
167 .map_err(|reason| Error::resource(reason, FIELD, self.span.start))?;
168 match verifier
169 .verify(
170 &signature.algorithm,
171 key,
172 self.signed_bytes(),
173 signature.value,
174 execution,
175 )
176 .map_err(CallbackError::Callback)?
177 {
178 Verified::Yes => Ok(RequestAuthentication::Signed(SignedRequest {
179 request: self,
180 signer,
181 key,
182 name,
183 })),
184 Verified::No => Ok(RequestAuthentication::Rejected(
185 RequestSignatureFailure::Signature,
186 )),
187 Verified::Unsupported => Ok(RequestAuthentication::UnsupportedSignature),
188 }
189 }
190}