Skip to main content

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};
19pub use verify::{
20    ParsedCertificate, verify_identity_signed_by_trust_anchor, verify_server_name,
21    verify_tls12_signature, verify_tls13_signature,
22};
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
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        // CRL signature errors should be turned into BadSignature.
189        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        // Revoked cert errors should be turned into Revoked.
224        assert_eq!(
225            pki_error(webpki::Error::CertRevoked),
226            Error::InvalidCertificate(CertificateError::Revoked),
227        );
228
229        // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl
230        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}