rustls/webpki/
mod.rs

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// Conditionally exported from crate.
22#[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/// An error that can occur when building a certificate verifier.
32#[derive(Debug, Clone)]
33#[non_exhaustive]
34pub enum VerifierBuilderError {
35    /// No root trust anchors were provided.
36    NoRootAnchors,
37    /// A provided CRL could not be parsed.
38    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        // CRL signature errors should be turned into BadSignature.
202        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        // Revoked cert errors should be turned into Revoked.
255        assert_eq!(
256            pki_error(webpki::Error::CertRevoked),
257            Error::InvalidCertificate(CertificateError::Revoked),
258        );
259
260        // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl
261        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}