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
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};
19// Conditionally exported from crate.
20#[allow(unreachable_pub)]
21pub use verify::{ParsedCertificate, verify_identity_signed_by_trust_anchor, verify_server_name};
22pub use verify::{WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature};
23
24/// An error that can occur when building a certificate verifier.
25#[derive(Debug, Clone)]
26#[non_exhaustive]
27pub enum VerifierBuilderError {
28    /// No root trust anchors were provided.
29    NoRootAnchors,
30    /// A provided CRL could not be parsed.
31    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
49#[cfg(feature = "std")]
50impl core::error::Error for VerifierBuilderError {}
51
52fn pki_error(error: webpki::Error) -> Error {
53    use webpki::Error::*;
54    match error {
55        BadDer | BadDerTime | TrailingData(_) => CertificateError::BadEncoding.into(),
56        CertNotValidYet { time, not_before } => {
57            CertificateError::NotValidYetContext { time, not_before }.into()
58        }
59        CertExpired { time, not_after } => {
60            CertificateError::ExpiredContext { time, not_after }.into()
61        }
62        InvalidCertValidity => CertificateError::Expired.into(),
63        UnknownIssuer => CertificateError::UnknownIssuer.into(),
64        CertNotValidForName(InvalidNameContext {
65            expected,
66            presented,
67        }) => CertificateError::NotValidForNameContext {
68            expected,
69            presented,
70        }
71        .into(),
72        CertRevoked => 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        UnsupportedSignatureAlgorithm(cx) => CertificateError::UnsupportedSignatureAlgorithm {
81            signature_algorithm_id: cx.signature_algorithm_id,
82            supported_algorithms: cx.supported_algorithms,
83        }
84        .into(),
85        UnsupportedSignatureAlgorithmForPublicKey(cx) => {
86            CertificateError::UnsupportedSignatureAlgorithmForPublicKey {
87                signature_algorithm_id: cx.signature_algorithm_id,
88                public_key_algorithm_id: cx.public_key_algorithm_id,
89            }
90            .into()
91        }
92
93        InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature.into(),
94        UnsupportedCrlSignatureAlgorithm(cx) => {
95            CertRevocationListError::UnsupportedSignatureAlgorithm {
96                signature_algorithm_id: cx.signature_algorithm_id,
97                supported_algorithms: cx.supported_algorithms,
98            }
99            .into()
100        }
101        UnsupportedCrlSignatureAlgorithmForPublicKey(cx) => {
102            CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
103                signature_algorithm_id: cx.signature_algorithm_id,
104                public_key_algorithm_id: cx.public_key_algorithm_id,
105            }
106            .into()
107        }
108
109        RequiredEkuNotFound(webpki::RequiredEkuNotFoundContext { required, present }) => {
110            CertificateError::InvalidPurposeContext {
111                required: ExtendedKeyPurpose::for_values(required.oid_values()),
112                presented: present
113                    .into_iter()
114                    .map(|eku| ExtendedKeyPurpose::for_values(eku.into_iter()))
115                    .collect(),
116            }
117            .into()
118        }
119
120        _ => CertificateError::Other(OtherError::new(error)).into(),
121    }
122}
123
124fn crl_error(e: webpki::Error) -> CertRevocationListError {
125    use webpki::Error::*;
126    match e {
127        InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature,
128        UnsupportedCrlSignatureAlgorithm(cx) => {
129            CertRevocationListError::UnsupportedSignatureAlgorithm {
130                signature_algorithm_id: cx.signature_algorithm_id,
131                supported_algorithms: cx.supported_algorithms,
132            }
133        }
134        UnsupportedCrlSignatureAlgorithmForPublicKey(cx) => {
135            CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
136                signature_algorithm_id: cx.signature_algorithm_id,
137                public_key_algorithm_id: cx.public_key_algorithm_id,
138            }
139        }
140        InvalidCrlNumber => CertRevocationListError::InvalidCrlNumber,
141        InvalidSerialNumber => CertRevocationListError::InvalidRevokedCertSerialNumber,
142        IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl,
143        MalformedExtensions | BadDer | BadDerTime => CertRevocationListError::ParseError,
144        UnsupportedCriticalExtension => CertRevocationListError::UnsupportedCriticalExtension,
145        UnsupportedCrlVersion => CertRevocationListError::UnsupportedCrlVersion,
146        UnsupportedDeltaCrl => CertRevocationListError::UnsupportedDeltaCrl,
147        UnsupportedIndirectCrl => CertRevocationListError::UnsupportedIndirectCrl,
148        UnsupportedRevocationReason => CertRevocationListError::UnsupportedRevocationReason,
149
150        _ => CertRevocationListError::Other(OtherError::new(e)),
151    }
152}
153
154fn parse_crls(
155    crls: Vec<CertificateRevocationListDer<'_>>,
156) -> Result<Vec<CertRevocationList<'_>>, CertRevocationListError> {
157    crls.iter()
158        .map(|der| OwnedCertRevocationList::from_der(der.as_ref()).map(Into::into))
159        .collect::<Result<Vec<_>, _>>()
160        .map_err(crl_error)
161}
162
163#[cfg(test)]
164mod tests {
165    use alloc::vec;
166
167    use super::*;
168
169    #[test]
170    fn pki_crl_errors() {
171        // CRL signature errors should be turned into BadSignature.
172        assert_eq!(
173            pki_error(webpki::Error::InvalidCrlSignatureForPublicKey),
174            Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
175        );
176
177        assert_eq!(
178            pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm(
179                webpki::UnsupportedSignatureAlgorithmContext {
180                    signature_algorithm_id: vec![],
181                    supported_algorithms: vec![],
182                }
183            )),
184            Error::InvalidCertRevocationList(
185                CertRevocationListError::UnsupportedSignatureAlgorithm {
186                    signature_algorithm_id: vec![],
187                    supported_algorithms: vec![],
188                }
189            )
190        );
191        assert_eq!(
192            pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey(
193                webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
194                    signature_algorithm_id: vec![],
195                    public_key_algorithm_id: vec![],
196                }
197            )),
198            Error::InvalidCertRevocationList(
199                CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
200                    signature_algorithm_id: vec![],
201                    public_key_algorithm_id: vec![],
202                }
203            )
204        );
205
206        // Revoked cert errors should be turned into Revoked.
207        assert_eq!(
208            pki_error(webpki::Error::CertRevoked),
209            Error::InvalidCertificate(CertificateError::Revoked),
210        );
211
212        // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl
213        assert_eq!(
214            pki_error(webpki::Error::IssuerNotCrlSigner),
215            Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl)
216        );
217    }
218
219    #[test]
220    fn crl_error_from_webpki() {
221        use CertRevocationListError::*;
222        let testcases = &[
223            (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature),
224            (
225                webpki::Error::UnsupportedCrlSignatureAlgorithm(
226                    webpki::UnsupportedSignatureAlgorithmContext {
227                        signature_algorithm_id: vec![],
228                        supported_algorithms: vec![],
229                    },
230                ),
231                UnsupportedSignatureAlgorithm {
232                    signature_algorithm_id: vec![],
233                    supported_algorithms: vec![],
234                },
235            ),
236            (
237                webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey(
238                    webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
239                        signature_algorithm_id: vec![],
240                        public_key_algorithm_id: vec![],
241                    },
242                ),
243                UnsupportedSignatureAlgorithmForPublicKey {
244                    signature_algorithm_id: vec![],
245                    public_key_algorithm_id: vec![],
246                },
247            ),
248            (webpki::Error::InvalidCrlNumber, InvalidCrlNumber),
249            (
250                webpki::Error::InvalidSerialNumber,
251                InvalidRevokedCertSerialNumber,
252            ),
253            (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl),
254            (webpki::Error::MalformedExtensions, ParseError),
255            (webpki::Error::BadDer, ParseError),
256            (webpki::Error::BadDerTime, ParseError),
257            (
258                webpki::Error::UnsupportedCriticalExtension,
259                UnsupportedCriticalExtension,
260            ),
261            (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion),
262            (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl),
263            (
264                webpki::Error::UnsupportedIndirectCrl,
265                UnsupportedIndirectCrl,
266            ),
267            (
268                webpki::Error::UnsupportedRevocationReason,
269                UnsupportedRevocationReason,
270            ),
271        ];
272        for t in testcases {
273            std::println!("webpki: {:?}", &t.0);
274            std::println!("rustls: {:?}", &t.1);
275            assert_eq!(crl_error(t.0.clone()), t.1);
276        }
277
278        assert!(matches!(
279            crl_error(webpki::Error::NameConstraintViolation),
280            Other(..)
281        ));
282    }
283}