structured_pkix/ocsp/
authentication.rs1use super::{BasicResponse, ResponderMatch};
4use crate::algorithm::digest::AsnDigest;
5use crate::error::CallbackError;
6use crate::path::{Verified, Verify, WorkingKey};
7use crate::{Certificate, Error};
8use core::fmt;
9use structured_asn1::memory::{MemoryError, Work};
10
11#[derive(Debug)]
13pub enum SignatureError<V, D> {
14 Processing(Error),
16 Verification(V),
18 Digest(D),
20}
21
22impl<V, D> From<Error> for SignatureError<V, D> {
23 fn from(error: Error) -> Self {
24 Self::Processing(error)
25 }
26}
27
28impl<V: fmt::Display, D: fmt::Display> fmt::Display for SignatureError<V, D> {
29 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Self::Processing(error) => error.fmt(formatter),
32 Self::Verification(error) => write!(formatter, "signature verifier: {error}"),
33 Self::Digest(error) => write!(formatter, "digest provider: {error}"),
34 }
35 }
36}
37
38impl<V: core::error::Error + 'static, D: core::error::Error + 'static> core::error::Error
39 for SignatureError<V, D>
40{
41 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
42 match self {
43 Self::Processing(error) => Some(error),
44 Self::Verification(error) => Some(error),
45 Self::Digest(error) => Some(error),
46 }
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum SignatureFailure {
53 KeyBinding,
55 ResponderIdentity,
57 DigestWidth,
59 Signature,
61}
62
63#[derive(Debug, Clone, Copy)]
66pub struct SignedResponse<'r, 'a> {
67 response: &'r BasicResponse<'a>,
68 signer: &'r Certificate<'a>,
69 key: WorkingKey<'a>,
70}
71
72impl<'r, 'a> SignedResponse<'r, 'a> {
73 #[must_use]
75 pub fn response(self) -> &'r BasicResponse<'a> {
76 self.response
77 }
78 #[must_use]
80 pub fn signer(self) -> &'r Certificate<'a> {
81 self.signer
82 }
83 #[must_use]
85 pub fn key(self) -> WorkingKey<'a> {
86 self.key
87 }
88}
89
90#[derive(Debug)]
92pub enum SignatureAuthentication<'r, 'a> {
93 Signed(SignedResponse<'r, 'a>),
95 Rejected(SignatureFailure),
97 UnsupportedDigest,
99 UnsupportedSignature,
101}
102
103impl<'a> BasicResponse<'a> {
104 pub fn authenticate_signature<'r, 'd, V: Verify<E>, D: AsnDigest<'d> + ?Sized, E: Work>(
109 &'r self,
110 signer: &'r Certificate<'a>,
111 key: WorkingKey<'a>,
112 verifier: &V,
113 digest: &'d D,
114 execution: &E,
115 ) -> core::result::Result<SignatureAuthentication<'r, 'a>, SignatureError<V::Error, D::Error>>
116 {
117 const FIELD: &str = "ocspResponse.signature";
118 let charge = |work| {
119 execution
120 .charge_work(work)
121 .map_err(|reason| Error::resource(reason, FIELD, self.span.start))
122 };
123 let encoded = key.key().as_bytes();
124 let actual = signer.tbs().public_key().as_bytes();
125 let work = u64::try_from(encoded.len().max(actual.len()))
126 .ok()
127 .and_then(|n| n.checked_mul(2))
128 .and_then(|n| n.checked_add(1))
129 .ok_or_else(|| Error::resource(MemoryError::WorkExceeded, FIELD, self.span.start))?;
130 charge(work)?;
131 if encoded != actual {
132 return Ok(SignatureAuthentication::Rejected(
133 SignatureFailure::KeyBinding,
134 ));
135 }
136 let identity = self
137 .responder
138 .matches_certificate(signer, digest, execution, FIELD, self.span.start)
139 .map_err(|cause| match cause {
140 CallbackError::Processing(cause) => SignatureError::Processing(cause),
141 CallbackError::Callback(cause) => SignatureError::Digest(cause),
142 })?;
143 match identity {
144 ResponderMatch::Matches => {}
145 ResponderMatch::Differs => {
146 return Ok(SignatureAuthentication::Rejected(
147 SignatureFailure::ResponderIdentity,
148 ));
149 }
150 ResponderMatch::MalformedHashWidth => {
151 return Ok(SignatureAuthentication::Rejected(
152 SignatureFailure::DigestWidth,
153 ));
154 }
155 ResponderMatch::UnsupportedHash => {
156 return Ok(SignatureAuthentication::UnsupportedDigest);
157 }
158 }
159 charge(1)?;
160 match verifier
161 .verify(&self.algorithm, key, self.signed, self.signature, execution)
162 .map_err(SignatureError::Verification)?
163 {
164 Verified::Yes => Ok(SignatureAuthentication::Signed(SignedResponse {
165 response: self,
166 signer,
167 key,
168 })),
169 Verified::No => Ok(SignatureAuthentication::Rejected(
170 SignatureFailure::Signature,
171 )),
172 Verified::Unsupported => Ok(SignatureAuthentication::UnsupportedSignature),
173 }
174 }
175}
176
177#[cfg(test)]
178mod tests;