1use super::{BasicResponse, Digest, DigestAlgorithm, ResponderId};
4use crate::path::{Verified, Verify, WorkingKey};
5use crate::{Certificate, Error};
6use core::fmt;
7use structured_asn1::memory::{MemoryError, Work};
8
9#[derive(Debug)]
11pub enum SignatureError<V, D> {
12 Processing(Error),
14 Verification(V),
16 Digest(D),
18}
19
20impl<V, D> From<Error> for SignatureError<V, D> {
21 fn from(error: Error) -> Self {
22 Self::Processing(error)
23 }
24}
25
26impl<V: fmt::Display, D: fmt::Display> fmt::Display for SignatureError<V, D> {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 Self::Processing(error) => error.fmt(formatter),
30 Self::Verification(error) => write!(formatter, "signature verifier: {error}"),
31 Self::Digest(error) => write!(formatter, "digest provider: {error}"),
32 }
33 }
34}
35
36#[cfg(feature = "std")]
37impl<V: std::error::Error + 'static, D: std::error::Error + 'static> std::error::Error
38 for SignatureError<V, D>
39{
40 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
41 match self {
42 Self::Processing(error) => Some(error),
43 Self::Verification(error) => Some(error),
44 Self::Digest(error) => Some(error),
45 }
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum SignatureFailure {
52 KeyBinding,
54 ResponderIdentity,
56 DigestWidth,
58 Signature,
60}
61
62#[derive(Debug, Clone, Copy)]
65pub struct SignedResponse<'r, 'a> {
66 response: &'r BasicResponse<'a>,
67 signer: &'r Certificate<'a>,
68 key: WorkingKey<'a>,
69}
70
71impl<'r, 'a> SignedResponse<'r, 'a> {
72 #[must_use]
74 pub fn response(self) -> &'r BasicResponse<'a> {
75 self.response
76 }
77 #[must_use]
79 pub fn signer(self) -> &'r Certificate<'a> {
80 self.signer
81 }
82 #[must_use]
84 pub fn key(self) -> WorkingKey<'a> {
85 self.key
86 }
87}
88
89#[derive(Debug)]
91pub enum SignatureAuthentication<'r, 'a> {
92 Signed(SignedResponse<'r, 'a>),
94 Rejected(SignatureFailure),
96 UnsupportedDigest,
98 UnsupportedSignature,
100}
101
102impl<'a> BasicResponse<'a> {
103 pub fn authenticate_signature<'r, V: Verify<E>, D: Digest<E>, E: Work>(
108 &'r self,
109 signer: &'r Certificate<'a>,
110 key: WorkingKey<'a>,
111 verifier: &V,
112 digest: &D,
113 execution: &E,
114 ) -> core::result::Result<SignatureAuthentication<'r, 'a>, SignatureError<V::Error, D::Error>>
115 {
116 const FIELD: &str = "ocspResponse.signature";
117 let charge = |work| {
118 execution
119 .charge_work(work)
120 .map_err(|reason| Error::resource(reason, FIELD, self.span.start))
121 };
122 let encoded = key.key().as_bytes();
123 let actual = signer.tbs().public_key().as_bytes();
124 let work = u64::try_from(encoded.len().max(actual.len()))
125 .ok()
126 .and_then(|n| n.checked_mul(2))
127 .and_then(|n| n.checked_add(1))
128 .ok_or_else(|| Error::resource(MemoryError::WorkExceeded, FIELD, self.span.start))?;
129 charge(work)?;
130 if encoded != actual {
131 return Ok(SignatureAuthentication::Rejected(
132 SignatureFailure::KeyBinding,
133 ));
134 }
135 let matches = match &self.responder {
136 ResponderId::Name(name) => name.matches(signer.tbs().subject(), execution)?,
137 ResponderId::KeyHash(expected) => {
138 charge(1)?;
139 let Some(resolved) = digest
140 .resolve(DigestAlgorithm::Sha1, execution)
141 .map_err(SignatureError::Digest)?
142 else {
143 return Ok(SignatureAuthentication::UnsupportedDigest);
144 };
145 if resolved.width.get() != 20 || expected.len() != 20 {
148 return Ok(SignatureAuthentication::Rejected(
149 SignatureFailure::DigestWidth,
150 ));
151 }
152 digest
153 .matches(
154 resolved.handle,
155 key.key().key().as_bytes(),
156 expected,
157 execution,
158 )
159 .map_err(SignatureError::Digest)?
160 }
161 };
162 if !matches {
163 return Ok(SignatureAuthentication::Rejected(
164 SignatureFailure::ResponderIdentity,
165 ));
166 }
167 charge(1)?;
168 match verifier
169 .verify(&self.algorithm, key, self.signed, self.signature, execution)
170 .map_err(SignatureError::Verification)?
171 {
172 Verified::Yes => Ok(SignatureAuthentication::Signed(SignedResponse {
173 response: self,
174 signer,
175 key,
176 })),
177 Verified::No => Ok(SignatureAuthentication::Rejected(
178 SignatureFailure::Signature,
179 )),
180 Verified::Unsupported => Ok(SignatureAuthentication::UnsupportedSignature),
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::fixtures::{CertificateParts, bits, context, extension, octets, seq, tlv};
189 use core::{cell::Cell, num::NonZeroUsize};
190 use structured_asn1::memory::Memory;
191 use structured_asn1::{BitString, Parser};
192
193 struct Provider<'a> {
194 key: &'a [u8],
195 signed: &'a [u8],
196 hashes: Cell<usize>,
197 signatures: Cell<usize>,
198 width: usize,
199 digest_answer: Option<bool>,
200 signature_answer: Verified,
201 failure: bool,
202 }
203 impl Digest for Provider<'_> {
204 type Handle = ();
205 type Error = &'static str;
206 fn resolve(
207 &self,
208 algorithm: DigestAlgorithm<'_>,
209 _: &Memory,
210 ) -> Result<Option<super::super::ResolvedDigest<()>>, Self::Error> {
211 assert!(matches!(algorithm, DigestAlgorithm::Sha1));
212 if self.failure {
213 return Err("digest refusal");
214 }
215 Ok(self.digest_answer.map(|_| super::super::ResolvedDigest {
216 handle: (),
217 width: NonZeroUsize::new(self.width).unwrap(),
218 }))
219 }
220 fn matches(
221 &self,
222 (): (),
223 input: &[u8],
224 expected: &[u8],
225 _: &Memory,
226 ) -> Result<bool, Self::Error> {
227 self.hashes.set(self.hashes.get() + 1);
228 assert_eq!(input.as_ptr(), self.key.as_ptr());
229 assert_eq!(input, self.key);
230 assert_eq!(expected, &[0x33; 20]);
231 Ok(self.digest_answer.unwrap())
232 }
233 }
234 impl Verify for Provider<'_> {
235 type Error = &'static str;
236 fn verify(
237 &self,
238 _: &crate::AlgorithmIdentifier<'_>,
239 _: WorkingKey<'_>,
240 signed: &[u8],
241 _: BitString<'_>,
242 _: &Memory,
243 ) -> Result<Verified, Self::Error> {
244 self.signatures.set(self.signatures.get() + 1);
245 assert_eq!(signed.as_ptr(), self.signed.as_ptr());
246 assert_eq!(signed, self.signed);
247 Ok(self.signature_answer)
248 }
249 }
250
251 #[test]
252 fn issuer_binding_enforces_object_signing_key_usage() {
253 for (usage, permitted) in [
256 (None, true),
257 (Some([7, 0x80]), true),
258 (Some([6, 0x40]), true),
259 (Some([1, 0x06]), false),
260 (Some([5, 0x20]), false),
261 ] {
262 let certificate_bytes = CertificateParts {
263 extensions: usage
264 .map(|value| seq(&[extension(crate::oid::KEY_USAGE, true, &tlv(3, &value))])),
265 ..CertificateParts::default()
266 }
267 .build();
268 let execution = crate::fixtures::memory();
269 let parser = Parser::der(execution.clone());
270 let issuer = Certificate::read(&parser, &certificate_bytes, 100).unwrap();
271 let algorithm = issuer.signature_algorithm().as_bytes();
272 let timestamp = tlv(24, b"20261012120000Z");
273 let id = seq(&[
274 algorithm.to_vec(),
275 octets(&[0x11; 20]),
276 octets(&[0x22; 20]),
277 tlv(2, &[1]),
278 ]);
279 let single = seq(&[id, tlv(0x80, &[]), timestamp.clone()]);
280 let data = seq(&[
281 context(2, &[octets(&[0x33; 20])]),
282 timestamp,
283 seq(&[single]),
284 ]);
285 let bytes = seq(&[data, algorithm.to_vec(), bits(&[0xab])]);
286 let mut reader = parser.read(&bytes, 700).unwrap();
287 let root = reader.next_element().unwrap().unwrap();
288 let response = super::super::read_basic(&reader, &root).unwrap();
289 let key = WorkingKey::standing(issuer.tbs().public_key());
290 let provider = Provider {
291 key: issuer.tbs().public_key().key().as_bytes(),
292 signed: response.signed_bytes(),
293 hashes: Cell::new(0),
294 signatures: Cell::new(0),
295 width: 20,
296 digest_answer: Some(true),
297 signature_answer: Verified::Yes,
298 failure: false,
299 };
300 let SignatureAuthentication::Signed(signed) = response
301 .authenticate_signature(&issuer, key, &provider, &provider, &execution)
302 .unwrap()
303 else {
304 panic!("signature fixture rejected");
305 };
306 let result = signed.bind_issuer(&issuer, key, &execution).unwrap();
307 assert_eq!(
308 matches!(result, super::super::AuthorityBinding::Bound(_)),
309 permitted
310 );
311 if !permitted {
312 assert!(matches!(
313 result,
314 super::super::AuthorityBinding::Rejected(
315 super::super::AuthorityFailure::KeyUsage
316 )
317 ));
318 }
319 assert_eq!(provider.signatures.get(), 1);
320 }
321 }
322
323 #[test]
324 fn actual_signer_precedes_hash_and_original_response_data_verification() {
325 let certificate_bytes = CertificateParts::default().build();
328 let execution = crate::fixtures::memory();
329 let parser = Parser::der(execution.clone());
330 let signer = Certificate::read(&parser, &certificate_bytes, 100).unwrap();
331 let algorithm = signer.signature_algorithm().as_bytes();
332 let timestamp = tlv(24, b"20261012120000Z");
333 let id = seq(&[
334 algorithm.to_vec(),
335 octets(&[0x11; 20]),
336 octets(&[0x22; 20]),
337 tlv(2, &[1]),
338 ]);
339 let single = seq(&[id, tlv(0x80, &[]), timestamp.clone()]);
340 let data = seq(&[
341 context(2, &[octets(&[0x33; 20])]),
342 timestamp,
343 seq(&[single]),
344 ]);
345 let bytes = seq(&[data, algorithm.to_vec(), bits(&[0xab])]);
346 let mut reader = parser.read(&bytes, 700).unwrap();
347 let element = reader.next_element().unwrap().unwrap();
348 let response = super::super::read_basic(&reader, &element).unwrap();
349 let key = WorkingKey::standing(signer.tbs().public_key());
350 let mut provider = Provider {
351 key: signer.tbs().public_key().key().as_bytes(),
352 signed: response.signed_bytes(),
353 hashes: Cell::new(0),
354 signatures: Cell::new(0),
355 width: 20,
356 digest_answer: Some(true),
357 signature_answer: Verified::Yes,
358 failure: false,
359 };
360 let retained = execution.used();
361 let SignatureAuthentication::Signed(proof) = response
362 .authenticate_signature(&signer, key, &provider, &provider, &execution)
363 .unwrap()
364 else {
365 panic!("signature not authenticated");
366 };
367 assert!(core::ptr::eq(proof.response(), &raw const response));
368 assert!(core::ptr::eq(proof.signer(), &raw const signer));
369 assert_eq!(provider.signatures.get(), 1);
370 assert_eq!(execution.used(), retained);
371 provider.signatures.set(0);
372 provider.width = 19;
373 assert!(matches!(
374 response
375 .authenticate_signature(&signer, key, &provider, &provider, &execution)
376 .unwrap(),
377 SignatureAuthentication::Rejected(SignatureFailure::DigestWidth)
378 ));
379 assert_eq!(provider.signatures.get(), 0);
380 provider.width = 20;
381 provider.digest_answer = Some(false);
382 assert!(matches!(
383 response
384 .authenticate_signature(&signer, key, &provider, &provider, &execution)
385 .unwrap(),
386 SignatureAuthentication::Rejected(SignatureFailure::ResponderIdentity)
387 ));
388 assert_eq!(provider.signatures.get(), 0);
389 provider.digest_answer = None;
390 assert!(matches!(
391 response
392 .authenticate_signature(&signer, key, &provider, &provider, &execution)
393 .unwrap(),
394 SignatureAuthentication::UnsupportedDigest
395 ));
396 provider.failure = true;
397 assert!(matches!(
398 response.authenticate_signature(&signer, key, &provider, &provider, &execution),
399 Err(SignatureError::Digest("digest refusal"))
400 ));
401 let unfunded = Memory::new(alloc::sync::Arc::new(
402 structured_asn1::memory::MemoryAccount::new(0, 0),
403 ));
404 assert!(
405 matches!(response.authenticate_signature(&signer, key, &provider, &provider, &unfunded), Err(SignatureError::Processing(error)) if error.is_resource() && error.offset() == 700)
406 );
407 }
408}