1 | use alloc::vec::Vec; |
2 | use core::fmt; |
3 | |
4 | use pki_types::CertificateRevocationListDer; |
5 | use webpki::{CertRevocationList, InvalidNameContext, OwnedCertRevocationList}; |
6 | |
7 | use crate::error::{CertRevocationListError, CertificateError, Error, OtherError}; |
8 | #[cfg (feature = "std" )] |
9 | use crate::sync::Arc; |
10 | |
11 | mod anchors; |
12 | mod client_verifier; |
13 | mod server_verifier; |
14 | mod verify; |
15 | |
16 | pub use anchors::RootCertStore; |
17 | pub use client_verifier::{ClientCertVerifierBuilder, WebPkiClientVerifier}; |
18 | pub use server_verifier::{ServerCertVerifierBuilder, WebPkiServerVerifier}; |
19 | // Conditionally exported from crate. |
20 | #[allow (unreachable_pub)] |
21 | pub use verify::{ |
22 | ParsedCertificate, verify_server_cert_signed_by_trust_anchor, verify_server_name, |
23 | }; |
24 | pub use verify::{ |
25 | WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature, |
26 | verify_tls13_signature_with_raw_key, |
27 | }; |
28 | |
29 | /// An error that can occur when building a certificate verifier. |
30 | #[derive (Debug, Clone)] |
31 | #[non_exhaustive ] |
32 | pub enum VerifierBuilderError { |
33 | /// No root trust anchors were provided. |
34 | NoRootAnchors, |
35 | /// A provided CRL could not be parsed. |
36 | InvalidCrl(CertRevocationListError), |
37 | } |
38 | |
39 | impl From<CertRevocationListError> for VerifierBuilderError { |
40 | fn from(value: CertRevocationListError) -> Self { |
41 | Self::InvalidCrl(value) |
42 | } |
43 | } |
44 | |
45 | impl fmt::Display for VerifierBuilderError { |
46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
47 | match self { |
48 | Self::NoRootAnchors => write!(f, "no root trust anchors were provided" ), |
49 | Self::InvalidCrl(e: &CertRevocationListError) => write!(f, "provided CRL could not be parsed: {:?}" , e), |
50 | } |
51 | } |
52 | } |
53 | |
54 | #[cfg (feature = "std" )] |
55 | impl std::error::Error for VerifierBuilderError {} |
56 | |
57 | fn pki_error(error: webpki::Error) -> Error { |
58 | use webpki::Error::*; |
59 | match error { |
60 | BadDer | BadDerTime | TrailingData(_) => CertificateError::BadEncoding.into(), |
61 | CertNotValidYet { time, not_before } => { |
62 | CertificateError::NotValidYetContext { time, not_before }.into() |
63 | } |
64 | CertExpired { time, not_after } => { |
65 | CertificateError::ExpiredContext { time, not_after }.into() |
66 | } |
67 | InvalidCertValidity => CertificateError::Expired.into(), |
68 | UnknownIssuer => CertificateError::UnknownIssuer.into(), |
69 | CertNotValidForName(InvalidNameContext { |
70 | expected, |
71 | presented, |
72 | }) => CertificateError::NotValidForNameContext { |
73 | expected, |
74 | presented, |
75 | } |
76 | .into(), |
77 | CertRevoked => CertificateError::Revoked.into(), |
78 | UnknownRevocationStatus => CertificateError::UnknownRevocationStatus.into(), |
79 | CrlExpired { time, next_update } => { |
80 | CertificateError::ExpiredRevocationListContext { time, next_update }.into() |
81 | } |
82 | IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(), |
83 | |
84 | InvalidSignatureForPublicKey |
85 | | UnsupportedSignatureAlgorithm |
86 | | UnsupportedSignatureAlgorithmForPublicKey => CertificateError::BadSignature.into(), |
87 | |
88 | InvalidCrlSignatureForPublicKey |
89 | | UnsupportedCrlSignatureAlgorithm |
90 | | UnsupportedCrlSignatureAlgorithmForPublicKey => { |
91 | CertRevocationListError::BadSignature.into() |
92 | } |
93 | |
94 | RequiredEkuNotFound => CertificateError::InvalidPurpose.into(), |
95 | |
96 | _ => CertificateError::Other(OtherError( |
97 | #[cfg (feature = "std" )] |
98 | Arc::new(error), |
99 | )) |
100 | .into(), |
101 | } |
102 | } |
103 | |
104 | fn crl_error(e: webpki::Error) -> CertRevocationListError { |
105 | use webpki::Error::*; |
106 | match e { |
107 | InvalidCrlSignatureForPublicKey |
108 | | UnsupportedCrlSignatureAlgorithm |
109 | | UnsupportedCrlSignatureAlgorithmForPublicKey => CertRevocationListError::BadSignature, |
110 | InvalidCrlNumber => CertRevocationListError::InvalidCrlNumber, |
111 | InvalidSerialNumber => CertRevocationListError::InvalidRevokedCertSerialNumber, |
112 | IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl, |
113 | MalformedExtensions | BadDer | BadDerTime => CertRevocationListError::ParseError, |
114 | UnsupportedCriticalExtension => CertRevocationListError::UnsupportedCriticalExtension, |
115 | UnsupportedCrlVersion => CertRevocationListError::UnsupportedCrlVersion, |
116 | UnsupportedDeltaCrl => CertRevocationListError::UnsupportedDeltaCrl, |
117 | UnsupportedIndirectCrl => CertRevocationListError::UnsupportedIndirectCrl, |
118 | UnsupportedRevocationReason => CertRevocationListError::UnsupportedRevocationReason, |
119 | |
120 | _ => CertRevocationListError::Other(OtherError( |
121 | #[cfg (feature = "std" )] |
122 | Arc::new(data:e), |
123 | )), |
124 | } |
125 | } |
126 | |
127 | fn parse_crls( |
128 | crls: Vec<CertificateRevocationListDer<'_>>, |
129 | ) -> Result<Vec<CertRevocationList<'_>>, CertRevocationListError> { |
130 | crls.iter() |
131 | .map(|der| OwnedCertRevocationList::from_der(der.as_ref()).map(Into::into)) |
132 | .collect::<Result<Vec<_>, _>>() |
133 | .map_err(op:crl_error) |
134 | } |
135 | |
136 | mod tests { |
137 | #[test ] |
138 | fn pki_crl_errors() { |
139 | use super::{CertRevocationListError, CertificateError, Error, pki_error}; |
140 | |
141 | // CRL signature errors should be turned into BadSignature. |
142 | assert_eq!( |
143 | pki_error(webpki::Error::InvalidCrlSignatureForPublicKey), |
144 | Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), |
145 | ); |
146 | assert_eq!( |
147 | pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm), |
148 | Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), |
149 | ); |
150 | assert_eq!( |
151 | pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey), |
152 | Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), |
153 | ); |
154 | |
155 | // Revoked cert errors should be turned into Revoked. |
156 | assert_eq!( |
157 | pki_error(webpki::Error::CertRevoked), |
158 | Error::InvalidCertificate(CertificateError::Revoked), |
159 | ); |
160 | |
161 | // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl |
162 | assert_eq!( |
163 | pki_error(webpki::Error::IssuerNotCrlSigner), |
164 | Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl) |
165 | ); |
166 | } |
167 | |
168 | #[test ] |
169 | fn crl_error_from_webpki() { |
170 | use super::CertRevocationListError::*; |
171 | use super::crl_error; |
172 | |
173 | let testcases = &[ |
174 | (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature), |
175 | ( |
176 | webpki::Error::UnsupportedCrlSignatureAlgorithm, |
177 | BadSignature, |
178 | ), |
179 | ( |
180 | webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey, |
181 | BadSignature, |
182 | ), |
183 | (webpki::Error::InvalidCrlNumber, InvalidCrlNumber), |
184 | ( |
185 | webpki::Error::InvalidSerialNumber, |
186 | InvalidRevokedCertSerialNumber, |
187 | ), |
188 | (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl), |
189 | (webpki::Error::MalformedExtensions, ParseError), |
190 | (webpki::Error::BadDer, ParseError), |
191 | (webpki::Error::BadDerTime, ParseError), |
192 | ( |
193 | webpki::Error::UnsupportedCriticalExtension, |
194 | UnsupportedCriticalExtension, |
195 | ), |
196 | (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion), |
197 | (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl), |
198 | ( |
199 | webpki::Error::UnsupportedIndirectCrl, |
200 | UnsupportedIndirectCrl, |
201 | ), |
202 | ( |
203 | webpki::Error::UnsupportedRevocationReason, |
204 | UnsupportedRevocationReason, |
205 | ), |
206 | ]; |
207 | for t in testcases { |
208 | assert_eq!(crl_error(t.0.clone()), t.1); |
209 | } |
210 | |
211 | assert!(matches!( |
212 | crl_error(webpki::Error::NameConstraintViolation), |
213 | Other(..) |
214 | )); |
215 | } |
216 | } |
217 | |