structured_cms/attribute_certificate/validation/
authentication.rs1use super::{Check, Profile, Rejection as ProfileRejection, charge};
11use crate::attribute_certificate::AttributeCertificate;
12use crate::{Error, Result};
13use structured_asn1::Span;
14use structured_asn1::digest::Resolution;
15use structured_asn1::memory::{Execution, Work};
16use structured_pkix::path::{Interval, Verified, Verify, WorkingKey};
17use structured_pkix::{AlgorithmIdentifier, Certificate};
18
19pub trait AlgorithmAgreement {
28 type Error;
30 fn algorithms<W: Work>(
32 &self,
33 signed: AlgorithmIdentifier<'_>,
34 outer: AlgorithmIdentifier<'_>,
35 work: &W,
36 ) -> core::result::Result<Resolution<bool>, Self::Error>;
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum Stage {
42 Algorithms,
44 Signature,
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum Failure {
51 Profile(ProfileRejection),
53 Authority(ProfileRejection),
55 KeyBinding,
57 AcValidity,
59 AuthorityValidity,
61 AlgorithmSyntax,
63 AlgorithmMismatch,
65 SignatureEncoding,
67 Signature,
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub struct Rejection {
74 pub reason: Failure,
76 pub source: Span,
78}
79
80#[derive(Debug)]
82pub enum Outcome<T> {
83 Authenticated(T),
85 Rejected(Rejection),
87 Unsupported(Stage),
89}
90
91#[derive(Debug)]
93pub enum AuthenticationError<E> {
94 Processing(Error),
96 UnknownAnswer,
98 Callback {
100 stage: Stage,
102 context: Span,
104 source: E,
106 },
107}
108impl<E> From<Error> for AuthenticationError<E> {
109 fn from(value: Error) -> Self {
110 Self::Processing(value)
111 }
112}
113
114#[derive(Debug)]
122pub struct Authenticated<'r, 'a, 's> {
123 profile: Profile<'r, 'a>,
124 authority: &'r Certificate<'s>,
125 key: WorkingKey<'s>,
126 interval: Interval,
127}
128impl<'r, 'a, 's> Authenticated<'r, 'a, 's> {
129 #[must_use]
131 pub fn certificate(&self) -> &AttributeCertificate<'a> {
132 self.profile.certificate()
133 }
134 #[must_use]
136 pub fn profile(&self) -> &Profile<'r, 'a> {
137 &self.profile
138 }
139 #[must_use]
141 pub fn authority(&self) -> &'r Certificate<'s> {
142 self.authority
143 }
144 #[must_use]
146 pub fn key(&self) -> WorkingKey<'s> {
147 self.key
148 }
149 #[must_use]
151 pub fn interval(&self) -> Interval {
152 self.interval
153 }
154}
155
156fn rejected<T>(reason: Failure, source: Span) -> Outcome<T> {
157 Outcome::Rejected(Rejection { reason, source })
158}
159
160fn key_matches<W: Work>(
161 authority: &Certificate<'_>,
162 key: WorkingKey<'_>,
163 work: &W,
164) -> Result<bool> {
165 let original = key.key().algorithm();
166 let key_work = key.key().execution_in(work);
167 let authority_work = authority.execution_in(work);
168 charge(&key_work, 1, original.offset())?;
169 charge(&authority_work, 1, authority.span().start)?;
170 let supplied = key.key().as_bytes();
171 let actual = authority.tbs().public_key().as_bytes();
172 if supplied.len() != actual.len() {
173 return Ok(false);
174 }
175 if core::ptr::eq(supplied, actual) {
178 return Ok(true);
179 }
180 charge(&key_work, supplied.len() as u64, original.offset())?;
181 charge(&authority_work, actual.len() as u64, authority.span().start)?;
182 Ok(supplied == actual)
183}
184
185impl<'a> AttributeCertificate<'a> {
186 pub fn authenticate<'r, 's, V, W: Work>(
195 &'r self,
196 authority: &'r Certificate<'s>,
197 key: WorkingKey<'s>,
198 interval: Interval,
199 verifier: &V,
200 work: &W,
201 ) -> core::result::Result<
202 Outcome<Authenticated<'r, 'a, 's>>,
203 AuthenticationError<<V as AlgorithmAgreement>::Error>,
204 >
205 where
206 V: AlgorithmAgreement,
207 for<'op> V: Verify<Execution<'op>, Error = <V as AlgorithmAgreement>::Error>,
208 {
209 let execution = work.execution_for(self.parser);
210 let at = self.signed_element().span();
211 let profile = match self.profile(&execution)? {
212 Check::Accepted(profile) => profile,
213 Check::Rejected(cause) => return Ok(rejected(Failure::Profile(cause), at)),
214 };
215 if let Check::Rejected(cause) = self.bind_authority(authority, &execution)? {
216 return Ok(rejected(Failure::Authority(cause), authority.span()));
217 }
218 if !key_matches(authority, key, &execution)? {
219 return Ok(rejected(Failure::KeyBinding, authority.span()));
220 }
221 charge(&execution, 4, at.start)?;
222 let info = self.information();
223 if interval.from_instant() < info.not_before.instant()
224 || interval.to_instant() > info.not_after.instant()
225 {
226 return Ok(rejected(Failure::AcValidity, at));
227 }
228 let authority_work = authority.execution_in(&execution);
229 charge(&authority_work, 4, authority.span().start)?;
230 let validity = authority.tbs().validity();
231 if interval.from_instant() < validity.not_before().instant()
232 || interval.to_instant() > validity.not_after().instant()
233 {
234 return Ok(rejected(Failure::AuthorityValidity, authority.span()));
235 }
236 charge(&execution, 1, at.start)?;
237 if self.signature_value().octets().is_none() {
238 return Ok(rejected(
239 Failure::SignatureEncoding,
240 self.signature_value().span(),
241 ));
242 }
243 match verifier
247 .algorithms(info.signature, self.signature_algorithm(), &execution)
248 .map_err(|source| AuthenticationError::Callback {
249 stage: Stage::Algorithms,
250 context: at,
251 source,
252 })? {
253 Resolution::Supported(true) => {}
254 Resolution::Supported(false) => return Ok(rejected(Failure::AlgorithmMismatch, at)),
255 Resolution::Malformed => return Ok(rejected(Failure::AlgorithmSyntax, at)),
256 Resolution::Unsupported => return Ok(Outcome::Unsupported(Stage::Algorithms)),
257 }
258 charge(&execution, 1, at.start)?;
259 match verifier
260 .verify(
261 &info.signature,
262 key,
263 self.signed_bytes(),
264 self.signature_value(),
265 &execution,
266 )
267 .map_err(|source| AuthenticationError::Callback {
268 stage: Stage::Signature,
269 context: at,
270 source,
271 })? {
272 Verified::Yes => Ok(Outcome::Authenticated(Authenticated {
273 profile,
274 authority,
275 key,
276 interval,
277 })),
278 Verified::No => Ok(rejected(Failure::Signature, self.signature_value().span())),
279 Verified::Unsupported => Ok(Outcome::Unsupported(Stage::Signature)),
280 _ => Err(AuthenticationError::UnknownAnswer),
281 }
282 }
283}