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::{CertRevocationListError, CertificateError, Error, OtherError};
8#[cfg(feature = "std")]
9use crate::sync::Arc;
10
11mod anchors;
12mod client_verifier;
13mod server_verifier;
14mod verify;
15
16pub use anchors::RootCertStore;
17pub use client_verifier::{ClientCertVerifierBuilder, WebPkiClientVerifier};
18pub use server_verifier::{ServerCertVerifierBuilder, WebPkiServerVerifier};
19// Conditionally exported from crate.
20#[allow(unreachable_pub)]
21pub use verify::{
22    ParsedCertificate, verify_server_cert_signed_by_trust_anchor, verify_server_name,
23};
24pub 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]
32pub enum VerifierBuilderError {
33    /// No root trust anchors were provided.
34    NoRootAnchors,
35    /// A provided CRL could not be parsed.
36    InvalidCrl(CertRevocationListError),
37}
38
39impl From<CertRevocationListError> for VerifierBuilderError {
40    fn from(value: CertRevocationListError) -> Self {
41        Self::InvalidCrl(value)
42    }
43}
44
45impl 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) => write!(f, "provided CRL could not be parsed: {:?}", e),
50        }
51    }
52}
53
54#[cfg(feature = "std")]
55impl std::error::Error for VerifierBuilderError {}
56
57fn 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
104fn 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(e),
123        )),
124    }
125}
126
127fn 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(crl_error)
134}
135
136mod 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}