1use alloc::vec::Vec;
2use core::fmt;
3
4use pki_types::CertificateRevocationListDer;
5use webpki::{CertRevocationList, InvalidNameContext, OwnedCertRevocationList};
6
7use crate::error::{
8 CertRevocationListError, CertificateError, Error, ExtendedKeyPurpose, OtherError,
9};
10#[cfg(feature = "std")]
11use crate::sync::Arc;
12
13mod anchors;
14mod client_verifier;
15mod server_verifier;
16mod verify;
17
18pub use anchors::RootCertStore;
19pub use client_verifier::{ClientCertVerifierBuilder, WebPkiClientVerifier};
20pub use server_verifier::{ServerCertVerifierBuilder, WebPkiServerVerifier};
21#[allow(unreachable_pub)]
23pub use verify::{
24 ParsedCertificate, verify_server_cert_signed_by_trust_anchor, verify_server_name,
25};
26pub use verify::{
27 WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature,
28 verify_tls13_signature_with_raw_key,
29};
30
31#[derive(Debug, Clone)]
33#[non_exhaustive]
34pub enum VerifierBuilderError {
35 NoRootAnchors,
37 InvalidCrl(CertRevocationListError),
39}
40
41impl From<CertRevocationListError> for VerifierBuilderError {
42 fn from(value: CertRevocationListError) -> Self {
43 Self::InvalidCrl(value)
44 }
45}
46
47impl fmt::Display for VerifierBuilderError {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 Self::NoRootAnchors => write!(f, "no root trust anchors were provided"),
51 Self::InvalidCrl(e) => write!(f, "provided CRL could not be parsed: {e:?}"),
52 }
53 }
54}
55
56#[cfg(feature = "std")]
57impl std::error::Error for VerifierBuilderError {}
58
59fn pki_error(error: webpki::Error) -> Error {
60 use webpki::Error::*;
61 match error {
62 BadDer | BadDerTime | TrailingData(_) => CertificateError::BadEncoding.into(),
63 CertNotValidYet { time, not_before } => {
64 CertificateError::NotValidYetContext { time, not_before }.into()
65 }
66 CertExpired { time, not_after } => {
67 CertificateError::ExpiredContext { time, not_after }.into()
68 }
69 InvalidCertValidity => CertificateError::Expired.into(),
70 UnknownIssuer => CertificateError::UnknownIssuer.into(),
71 CertNotValidForName(InvalidNameContext {
72 expected,
73 presented,
74 }) => CertificateError::NotValidForNameContext {
75 expected,
76 presented,
77 }
78 .into(),
79 CertRevoked => CertificateError::Revoked.into(),
80 UnknownRevocationStatus => CertificateError::UnknownRevocationStatus.into(),
81 CrlExpired { time, next_update } => {
82 CertificateError::ExpiredRevocationListContext { time, next_update }.into()
83 }
84 IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(),
85
86 InvalidSignatureForPublicKey => CertificateError::BadSignature.into(),
87 #[allow(deprecated)]
88 UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => {
89 CertificateError::UnsupportedSignatureAlgorithm.into()
90 }
91 UnsupportedSignatureAlgorithmContext(cx) => {
92 CertificateError::UnsupportedSignatureAlgorithmContext {
93 signature_algorithm_id: cx.signature_algorithm_id,
94 supported_algorithms: cx.supported_algorithms,
95 }
96 .into()
97 }
98 UnsupportedSignatureAlgorithmForPublicKeyContext(cx) => {
99 CertificateError::UnsupportedSignatureAlgorithmForPublicKeyContext {
100 signature_algorithm_id: cx.signature_algorithm_id,
101 public_key_algorithm_id: cx.public_key_algorithm_id,
102 }
103 .into()
104 }
105
106 InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature.into(),
107 #[allow(deprecated)]
108 UnsupportedCrlSignatureAlgorithm | UnsupportedCrlSignatureAlgorithmForPublicKey => {
109 CertRevocationListError::UnsupportedSignatureAlgorithm.into()
110 }
111 UnsupportedCrlSignatureAlgorithmContext(cx) => {
112 CertRevocationListError::UnsupportedSignatureAlgorithmContext {
113 signature_algorithm_id: cx.signature_algorithm_id,
114 supported_algorithms: cx.supported_algorithms,
115 }
116 .into()
117 }
118 UnsupportedCrlSignatureAlgorithmForPublicKeyContext(cx) => {
119 CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext {
120 signature_algorithm_id: cx.signature_algorithm_id,
121 public_key_algorithm_id: cx.public_key_algorithm_id,
122 }
123 .into()
124 }
125
126 #[allow(deprecated)]
127 RequiredEkuNotFound => CertificateError::InvalidPurpose.into(),
128 RequiredEkuNotFoundContext(webpki::RequiredEkuNotFoundContext { required, present }) => {
129 CertificateError::InvalidPurposeContext {
130 required: ExtendedKeyPurpose::for_values(required.oid_values()),
131 presented: present
132 .into_iter()
133 .map(|eku| ExtendedKeyPurpose::for_values(eku.into_iter()))
134 .collect(),
135 }
136 .into()
137 }
138
139 _ => CertificateError::Other(OtherError(
140 #[cfg(feature = "std")]
141 Arc::new(error),
142 ))
143 .into(),
144 }
145}
146
147fn crl_error(e: webpki::Error) -> CertRevocationListError {
148 use webpki::Error::*;
149 match e {
150 InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature,
151 #[allow(deprecated)]
152 UnsupportedCrlSignatureAlgorithm | UnsupportedCrlSignatureAlgorithmForPublicKey => {
153 CertRevocationListError::UnsupportedSignatureAlgorithm
154 }
155 UnsupportedCrlSignatureAlgorithmContext(cx) => {
156 CertRevocationListError::UnsupportedSignatureAlgorithmContext {
157 signature_algorithm_id: cx.signature_algorithm_id,
158 supported_algorithms: cx.supported_algorithms,
159 }
160 }
161 UnsupportedSignatureAlgorithmForPublicKeyContext(cx) => {
162 CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext {
163 signature_algorithm_id: cx.signature_algorithm_id,
164 public_key_algorithm_id: cx.public_key_algorithm_id,
165 }
166 }
167 InvalidCrlNumber => CertRevocationListError::InvalidCrlNumber,
168 InvalidSerialNumber => CertRevocationListError::InvalidRevokedCertSerialNumber,
169 IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl,
170 MalformedExtensions | BadDer | BadDerTime => CertRevocationListError::ParseError,
171 UnsupportedCriticalExtension => CertRevocationListError::UnsupportedCriticalExtension,
172 UnsupportedCrlVersion => CertRevocationListError::UnsupportedCrlVersion,
173 UnsupportedDeltaCrl => CertRevocationListError::UnsupportedDeltaCrl,
174 UnsupportedIndirectCrl => CertRevocationListError::UnsupportedIndirectCrl,
175 UnsupportedRevocationReason => CertRevocationListError::UnsupportedRevocationReason,
176
177 _ => CertRevocationListError::Other(OtherError(
178 #[cfg(feature = "std")]
179 Arc::new(e),
180 )),
181 }
182}
183
184fn parse_crls(
185 crls: Vec<CertificateRevocationListDer<'_>>,
186) -> Result<Vec<CertRevocationList<'_>>, CertRevocationListError> {
187 crls.iter()
188 .map(|der| OwnedCertRevocationList::from_der(der.as_ref()).map(Into::into))
189 .collect::<Result<Vec<_>, _>>()
190 .map_err(crl_error)
191}
192
193#[cfg(test)]
194mod tests {
195 use alloc::vec;
196
197 use super::*;
198
199 #[test]
200 fn pki_crl_errors() {
201 assert_eq!(
203 pki_error(webpki::Error::InvalidCrlSignatureForPublicKey),
204 Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
205 );
206
207 #[allow(deprecated)]
208 {
209 assert_eq!(
210 pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm),
211 Error::InvalidCertRevocationList(
212 CertRevocationListError::UnsupportedSignatureAlgorithm
213 ),
214 );
215 assert_eq!(
216 pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey),
217 Error::InvalidCertRevocationList(
218 CertRevocationListError::UnsupportedSignatureAlgorithm
219 ),
220 );
221 }
222
223 assert_eq!(
224 pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmContext(
225 webpki::UnsupportedSignatureAlgorithmContext {
226 signature_algorithm_id: vec![],
227 supported_algorithms: vec![],
228 }
229 )),
230 Error::InvalidCertRevocationList(
231 CertRevocationListError::UnsupportedSignatureAlgorithmContext {
232 signature_algorithm_id: vec![],
233 supported_algorithms: vec![],
234 }
235 )
236 );
237 assert_eq!(
238 pki_error(
239 webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKeyContext(
240 webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
241 signature_algorithm_id: vec![],
242 public_key_algorithm_id: vec![],
243 }
244 )
245 ),
246 Error::InvalidCertRevocationList(
247 CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext {
248 signature_algorithm_id: vec![],
249 public_key_algorithm_id: vec![],
250 }
251 )
252 );
253
254 assert_eq!(
256 pki_error(webpki::Error::CertRevoked),
257 Error::InvalidCertificate(CertificateError::Revoked),
258 );
259
260 assert_eq!(
262 pki_error(webpki::Error::IssuerNotCrlSigner),
263 Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl)
264 );
265 }
266
267 #[test]
268 fn crl_error_from_webpki() {
269 use CertRevocationListError::*;
270 #[allow(deprecated)]
271 let testcases = &[
272 (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature),
273 (
274 webpki::Error::UnsupportedCrlSignatureAlgorithm,
275 UnsupportedSignatureAlgorithm,
276 ),
277 (
278 webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey,
279 UnsupportedSignatureAlgorithm,
280 ),
281 (webpki::Error::InvalidCrlNumber, InvalidCrlNumber),
282 (
283 webpki::Error::InvalidSerialNumber,
284 InvalidRevokedCertSerialNumber,
285 ),
286 (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl),
287 (webpki::Error::MalformedExtensions, ParseError),
288 (webpki::Error::BadDer, ParseError),
289 (webpki::Error::BadDerTime, ParseError),
290 (
291 webpki::Error::UnsupportedCriticalExtension,
292 UnsupportedCriticalExtension,
293 ),
294 (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion),
295 (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl),
296 (
297 webpki::Error::UnsupportedIndirectCrl,
298 UnsupportedIndirectCrl,
299 ),
300 (
301 webpki::Error::UnsupportedRevocationReason,
302 UnsupportedRevocationReason,
303 ),
304 ];
305 for t in testcases {
306 assert_eq!(crl_error(t.0.clone()), t.1);
307 }
308
309 assert!(matches!(
310 crl_error(webpki::Error::NameConstraintViolation),
311 Other(..)
312 ));
313 }
314}