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
38#[cfg(feature = "std")]
39impl<V: std::error::Error + 'static, D: std::error::Error + 'static> std::error::Error
40 for SignatureError<V, D>
41{
42 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
43 match self {
44 Self::Processing(error) => Some(error),
45 Self::Verification(error) => Some(error),
46 Self::Digest(error) => Some(error),
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum SignatureFailure {
54 KeyBinding,
56 ResponderIdentity,
58 DigestWidth,
60 Signature,
62}
63
64#[derive(Debug, Clone, Copy)]
67pub struct SignedResponse<'r, 'a> {
68 response: &'r BasicResponse<'a>,
69 signer: &'r Certificate<'a>,
70 key: WorkingKey<'a>,
71}
72
73impl<'r, 'a> SignedResponse<'r, 'a> {
74 #[must_use]
76 pub fn response(self) -> &'r BasicResponse<'a> {
77 self.response
78 }
79 #[must_use]
81 pub fn signer(self) -> &'r Certificate<'a> {
82 self.signer
83 }
84 #[must_use]
86 pub fn key(self) -> WorkingKey<'a> {
87 self.key
88 }
89}
90
91#[derive(Debug)]
93pub enum SignatureAuthentication<'r, 'a> {
94 Signed(SignedResponse<'r, 'a>),
96 Rejected(SignatureFailure),
98 UnsupportedDigest,
100 UnsupportedSignature,
102}
103
104impl<'a> BasicResponse<'a> {
105 pub fn authenticate_signature<'r, 'd, V: Verify<E>, D: AsnDigest<'d> + ?Sized, E: Work>(
110 &'r self,
111 signer: &'r Certificate<'a>,
112 key: WorkingKey<'a>,
113 verifier: &V,
114 digest: &'d D,
115 execution: &E,
116 ) -> core::result::Result<SignatureAuthentication<'r, 'a>, SignatureError<V::Error, D::Error>>
117 {
118 const FIELD: &str = "ocspResponse.signature";
119 let charge = |work| {
120 execution
121 .charge_work(work)
122 .map_err(|reason| Error::resource(reason, FIELD, self.span.start))
123 };
124 let encoded = key.key().as_bytes();
125 let actual = signer.tbs().public_key().as_bytes();
126 let work = u64::try_from(encoded.len().max(actual.len()))
127 .ok()
128 .and_then(|n| n.checked_mul(2))
129 .and_then(|n| n.checked_add(1))
130 .ok_or_else(|| Error::resource(MemoryError::WorkExceeded, FIELD, self.span.start))?;
131 charge(work)?;
132 if encoded != actual {
133 return Ok(SignatureAuthentication::Rejected(
134 SignatureFailure::KeyBinding,
135 ));
136 }
137 let identity = self
138 .responder
139 .matches_certificate(signer, digest, execution, FIELD, self.span.start)
140 .map_err(|cause| match cause {
141 CallbackError::Processing(cause) => SignatureError::Processing(cause),
142 CallbackError::Callback(cause) => SignatureError::Digest(cause),
143 })?;
144 match identity {
145 ResponderMatch::Matches => {}
146 ResponderMatch::Differs => {
147 return Ok(SignatureAuthentication::Rejected(
148 SignatureFailure::ResponderIdentity,
149 ));
150 }
151 ResponderMatch::MalformedHashWidth => {
152 return Ok(SignatureAuthentication::Rejected(
153 SignatureFailure::DigestWidth,
154 ));
155 }
156 ResponderMatch::UnsupportedHash => {
157 return Ok(SignatureAuthentication::UnsupportedDigest);
158 }
159 }
160 charge(1)?;
161 match verifier
162 .verify(&self.algorithm, key, self.signed, self.signature, execution)
163 .map_err(SignatureError::Verification)?
164 {
165 Verified::Yes => Ok(SignatureAuthentication::Signed(SignedResponse {
166 response: self,
167 signer,
168 key,
169 })),
170 Verified::No => Ok(SignatureAuthentication::Rejected(
171 SignatureFailure::Signature,
172 )),
173 Verified::Unsupported => Ok(SignatureAuthentication::UnsupportedSignature),
174 }
175 }
176}
177
178#[cfg(test)]
179mod tests;