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 super::*;
196    use alloc::vec;
197
198    #[test]
199    fn pki_crl_errors() {
200        // CRL signature errors should be turned into BadSignature.
201        assert_eq!(
202            pki_error(webpki::Error::InvalidCrlSignatureForPublicKey),
203            Error::InvalidCertRevocationList(CertRevocationListError::BadSignature),
204        );
205
206        #[allow(deprecated)]
207        {
208            assert_eq!(
209                pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm),
210                Error::InvalidCertRevocationList(
211                    CertRevocationListError::UnsupportedSignatureAlgorithm
212                ),
213            );
214            assert_eq!(
215                pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey),
216                Error::InvalidCertRevocationList(
217                    CertRevocationListError::UnsupportedSignatureAlgorithm
218                ),
219            );
220        }
221
222        assert_eq!(
223            pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmContext(
224                webpki::UnsupportedSignatureAlgorithmContext {
225                    signature_algorithm_id: vec![],
226                    supported_algorithms: vec![],
227                }
228            )),
229            Error::InvalidCertRevocationList(
230                CertRevocationListError::UnsupportedSignatureAlgorithmContext {
231                    signature_algorithm_id: vec![],
232                    supported_algorithms: vec![],
233                }
234            )
235        );
236        assert_eq!(
237            pki_error(
238                webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKeyContext(
239                    webpki::UnsupportedSignatureAlgorithmForPublicKeyContext {
240                        signature_algorithm_id: vec![],
241                        public_key_algorithm_id: vec![],
242                    }
243                )
244            ),
245            Error::InvalidCertRevocationList(
246                CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext {
247                    signature_algorithm_id: vec![],
248                    public_key_algorithm_id: vec![],
249                }
250            )
251        );
252
253        // Revoked cert errors should be turned into Revoked.
254        assert_eq!(
255            pki_error(webpki::Error::CertRevoked),
256            Error::InvalidCertificate(CertificateError::Revoked),
257        );
258
259        // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl
260        assert_eq!(
261            pki_error(webpki::Error::IssuerNotCrlSigner),
262            Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl)
263        );
264    }
265
266    #[test]
267    fn crl_error_from_webpki() {
268        use CertRevocationListError::*;
269        #[allow(deprecated)]
270        let testcases = &[
271            (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature),
272            (
273                webpki::Error::UnsupportedCrlSignatureAlgorithm,
274                UnsupportedSignatureAlgorithm,
275            ),
276            (
277                webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey,
278                UnsupportedSignatureAlgorithm,
279            ),
280            (webpki::Error::InvalidCrlNumber, InvalidCrlNumber),
281            (
282                webpki::Error::InvalidSerialNumber,
283                InvalidRevokedCertSerialNumber,
284            ),
285            (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl),
286            (webpki::Error::MalformedExtensions, ParseError),
287            (webpki::Error::BadDer, ParseError),
288            (webpki::Error::BadDerTime, ParseError),
289            (
290                webpki::Error::UnsupportedCriticalExtension,
291                UnsupportedCriticalExtension,
292            ),
293            (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion),
294            (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl),
295            (
296                webpki::Error::UnsupportedIndirectCrl,
297                UnsupportedIndirectCrl,
298            ),
299            (
300                webpki::Error::UnsupportedRevocationReason,
301                UnsupportedRevocationReason,
302            ),
303        ];
304        for t in testcases {
305            assert_eq!(crl_error(t.0.clone()), t.1);
306        }
307
308        assert!(matches!(
309            crl_error(webpki::Error::NameConstraintViolation),
310            Other(..)
311        ));
312    }
313}