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