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        CertNotValidForName(InvalidNameContext {
64            expected,
65            presented,
66        }) => CertificateError::NotValidForNameContext {
67            expected,
68            presented,
69        }
70        .into(),
71        CertRevoked => CertificateError::Revoked.into(),
72        UnknownRevocationStatus => CertificateError::UnknownRevocationStatus.into(),
73        CrlExpired { time, next_update } => {
74            CertificateError::ExpiredRevocationListContext { time, next_update }.into()
75        }
76        IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(),
77
78        InvalidSignatureForPublicKey => CertificateError::BadSignature.into(),
79        UnsupportedSignatureAlgorithm(cx) => CertificateError::UnsupportedSignatureAlgorithm {
80            signature_algorithm_id: cx.signature_algorithm_id,
81            supported_algorithms: cx.supported_algorithms,
82        }
83        .into(),
84        UnsupportedSignatureAlgorithmForPublicKey(cx) => {
85            CertificateError::UnsupportedSignatureAlgorithmForPublicKey {
86                signature_algorithm_id: cx.signature_algorithm_id,
87                public_key_algorithm_id: cx.public_key_algorithm_id,
88            }
89            .into()
90        }
91
92        InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature.into(),
93        UnsupportedCrlSignatureAlgorithm(cx) => {
94            CertRevocationListError::UnsupportedSignatureAlgorithm {
95                signature_algorithm_id: cx.signature_algorithm_id,
96                supported_algorithms: cx.supported_algorithms,
97            }
98            .into()
99        }
100        UnsupportedCrlSignatureAlgorithmForPublicKey(cx) => {
101            CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
102                signature_algorithm_id: cx.signature_algorithm_id,
103                public_key_algorithm_id: cx.public_key_algorithm_id,
104            }
105            .into()
106        }
107
108        RequiredEkuNotFound(webpki::RequiredEkuNotFoundContext { required, present }) => {
109            CertificateError::InvalidPurposeContext {
110                required: ExtendedKeyPurpose::for_values(required.oid_values()),
111                presented: present
112                    .into_iter()
113                    .map(|eku| ExtendedKeyPurpose::for_values(eku.into_iter()))
114                    .collect(),
115            }
116            .into()
117        }
118
119        _ => CertificateError::Other(OtherError::new(error)).into(),
120    }
121}
122
123fn crl_error(e: webpki::Error) -> CertRevocationListError {
124    use webpki::Error::*;
125    match e {
126        InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature,
127        UnsupportedCrlSignatureAlgorithm(cx) => {
128            CertRevocationListError::UnsupportedSignatureAlgorithm {
129                signature_algorithm_id: cx.signature_algorithm_id,
130                supported_algorithms: cx.supported_algorithms,
131            }
132        }
133        UnsupportedCrlSignatureAlgorithmForPublicKey(cx) => {
134            CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
135                signature_algorithm_id: cx.signature_algorithm_id,
136                public_key_algorithm_id: cx.public_key_algorithm_id,
137            }
138        }
139        InvalidCrlNumber => CertRevocationListError::InvalidCrlNumber,
140        InvalidSerialNumber => CertRevocationListError::InvalidRevokedCertSerialNumber,
141        IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl,
142        MalformedExtensions | BadDer | BadDerTime => CertRevocationListError::ParseError,
143        UnsupportedCriticalExtension => CertRevocationListError::UnsupportedCriticalExtension,
144        UnsupportedCrlVersion => CertRevocationListError::UnsupportedCrlVersion,
145        UnsupportedDeltaCrl => CertRevocationListError::UnsupportedDeltaCrl,
146        UnsupportedIndirectCrl => CertRevocationListError::UnsupportedIndirectCrl,
147        UnsupportedRevocationReason => CertRevocationListError::UnsupportedRevocationReason,
148
149        _ => CertRevocationListError::Other(OtherError::new(e)),
150    }
151}
152
153fn parse_crls(
154    crls: Vec<CertificateRevocationListDer<'_>>,
155) -> Result<Vec<CertRevocationList<'_>>, CertRevocationListError> {
156    crls.iter()
157        .map(|der| OwnedCertRevocationList::from_der(der.as_ref()).map(Into::into))
158        .collect::<Result<Vec<_>, _>>()
159        .map_err(crl_error)
160}
161
162#[cfg(test)]
163mod tests {
164    use alloc::vec;
165
166    use super::*;
167
168    #[test]
169    fn pki_crl_errors() {
170        // CRL signature errors should be turned into BadSignature.
171        assert_eq!(
172            pki_error(webpki::Error::InvalidCrlSignatureForPublicKey),
173            Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
174        );
175
176        assert_eq!(
177            pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm(
178                webpki::UnsupportedSignatureAlgorithmContext {
179                    signature_algorithm_id: vec![],
180                    supported_algorithms: vec![],
181                }
182            )),
183            Error::InvalidCertRevocationList(
184                CertRevocationListError::UnsupportedSignatureAlgorithm {
185                    signature_algorithm_id: vec![],
186                    supported_algorithms: vec![],
187                }
188            )
189        );
190        assert_eq!(
191            pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey(
192                webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
193                    signature_algorithm_id: vec![],
194                    public_key_algorithm_id: vec![],
195                }
196            )),
197            Error::InvalidCertRevocationList(
198                CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKey {
199                    signature_algorithm_id: vec![],
200                    public_key_algorithm_id: vec![],
201                }
202            )
203        );
204
205        // Revoked cert errors should be turned into Revoked.
206        assert_eq!(
207            pki_error(webpki::Error::CertRevoked),
208            Error::InvalidCertificate(CertificateError::Revoked),
209        );
210
211        // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl
212        assert_eq!(
213            pki_error(webpki::Error::IssuerNotCrlSigner),
214            Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl)
215        );
216    }
217
218    #[test]
219    fn crl_error_from_webpki() {
220        use CertRevocationListError::*;
221        let testcases = &[
222            (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature),
223            (
224                webpki::Error::UnsupportedCrlSignatureAlgorithm(
225                    webpki::UnsupportedSignatureAlgorithmContext {
226                        signature_algorithm_id: vec![],
227                        supported_algorithms: vec![],
228                    },
229                ),
230                UnsupportedSignatureAlgorithm {
231                    signature_algorithm_id: vec![],
232                    supported_algorithms: vec![],
233                },
234            ),
235            (
236                webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey(
237                    webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
238                        signature_algorithm_id: vec![],
239                        public_key_algorithm_id: vec![],
240                    },
241                ),
242                UnsupportedSignatureAlgorithmForPublicKey {
243                    signature_algorithm_id: vec![],
244                    public_key_algorithm_id: vec![],
245                },
246            ),
247            (webpki::Error::InvalidCrlNumber, InvalidCrlNumber),
248            (
249                webpki::Error::InvalidSerialNumber,
250                InvalidRevokedCertSerialNumber,
251            ),
252            (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl),
253            (webpki::Error::MalformedExtensions, ParseError),
254            (webpki::Error::BadDer, ParseError),
255            (webpki::Error::BadDerTime, ParseError),
256            (
257                webpki::Error::UnsupportedCriticalExtension,
258                UnsupportedCriticalExtension,
259            ),
260            (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion),
261            (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl),
262            (
263                webpki::Error::UnsupportedIndirectCrl,
264                UnsupportedIndirectCrl,
265            ),
266            (
267                webpki::Error::UnsupportedRevocationReason,
268                UnsupportedRevocationReason,
269            ),
270        ];
271        for t in testcases {
272            std::println!("webpki: {:?}", &t.0);
273            std::println!("rustls: {:?}", &t.1);
274            assert_eq!(crl_error(t.0.clone()), t.1);
275        }
276
277        assert!(matches!(
278            crl_error(webpki::Error::NameConstraintViolation),
279            Other(..)
280        ));
281    }
282}