webpki/
trust_anchor.rs

1use pki_types::{CertificateDer, TrustAnchor};
2
3use crate::cert::{Cert, lenient_certificate_serial_number};
4use crate::der;
5use crate::error::{DerTypeId, Error};
6
7/// Interprets the given pre-validated DER-encoded certificate as a `TrustAnchor`.
8///
9/// This function extracts the components of a trust anchor (see [RFC 5280 6.1.1]) from
10/// an X.509 certificate obtained from a source trusted to have appropriately validated
11/// the subject name, public key, and name constraints in the certificate, for example your
12/// operating system's trust store.
13///
14/// No additional checks on the content of the certificate, including whether it is self-signed,
15/// or has a basic constraints extension indicating the `cA` boolean is true, will be performed.
16/// [RFC 5280 6.2] notes:
17/// > Implementations that use self-signed certificates to specify trust
18/// > anchor information are free to process or ignore such information.
19///
20/// This function is intended for users constructing `TrustAnchor`'s from existing trust stores
21/// that express trust anchors as X.509 certificates. It should **not** be used to treat an
22/// end-entity certificate as a `TrustAnchor` in an effort to validate the same end-entity
23/// certificate during path building. Webpki has no support for self-signed certificates.
24///
25/// [RFC 5280 6.1.1]: <https://datatracker.ietf.org/doc/html/rfc5280#section-6.1.1>
26/// [RFC 5280 6.2]: <https://www.rfc-editor.org/rfc/rfc5280#section-6.2>
27pub fn anchor_from_trusted_cert<'a>(
28    cert: &'a CertificateDer<'a>,
29) -> Result<TrustAnchor<'a>, Error> {
30    let cert_der = untrusted::Input::from(cert.as_ref());
31
32    // v1 certificates will result in `Error::BadDer` because `parse_cert` will
33    // expect a version field that isn't there. In that case, try to parse the
34    // certificate using a special parser for v1 certificates. Notably, that
35    // parser doesn't allow extensions, so there's no need to worry about
36    // embedded name constraints in a v1 certificate.
37    match Cert::from_der(cert_der) {
38        Ok(cert) => Ok(TrustAnchor::from(cert)),
39        Err(Error::UnsupportedCertVersion) => {
40            extract_trust_anchor_from_v1_cert_der(cert_der).or(Err(Error::BadDer))
41        }
42        Err(err) => Err(err),
43    }
44}
45
46/// Parses a v1 certificate directly into a TrustAnchor.
47fn extract_trust_anchor_from_v1_cert_der(
48    cert_der: untrusted::Input<'_>,
49) -> Result<TrustAnchor<'_>, Error> {
50    // X.509 Certificate: https://tools.ietf.org/html/rfc5280#section-4.1.
51    cert_der.read_all(Error::BadDer, |cert_der| {
52        der::nested(
53            cert_der,
54            der::Tag::Sequence,
55            Error::TrailingData(DerTypeId::TrustAnchorV1),
56            |cert_der| {
57                let anchor = der::nested(
58                    cert_der,
59                    der::Tag::Sequence,
60                    Error::TrailingData(DerTypeId::TrustAnchorV1TbsCertificate),
61                    |tbs| {
62                        // The version number field does not appear in v1 certificates.
63                        lenient_certificate_serial_number(tbs)?;
64
65                        skip(tbs, der::Tag::Sequence)?; // signature.
66                        skip(tbs, der::Tag::Sequence)?; // issuer.
67                        skip(tbs, der::Tag::Sequence)?; // validity.
68                        let subject = der::expect_tag(tbs, der::Tag::Sequence)?;
69                        let spki = der::expect_tag(tbs, der::Tag::Sequence)?;
70
71                        Ok(TrustAnchor {
72                            subject: subject.as_slice_less_safe().into(),
73                            subject_public_key_info: spki.as_slice_less_safe().into(),
74                            name_constraints: None,
75                        })
76                    },
77                );
78
79                // read and discard signatureAlgorithm + signature
80                skip(cert_der, der::Tag::Sequence)?;
81                skip(cert_der, der::Tag::BitString)?;
82
83                anchor
84            },
85        )
86    })
87}
88
89impl<'a> From<Cert<'a>> for TrustAnchor<'a> {
90    fn from(cert: Cert<'a>) -> Self {
91        Self {
92            subject: cert.subject.as_slice_less_safe().into(),
93            subject_public_key_info: cert.spki.as_slice_less_safe().into(),
94            name_constraints: cert
95                .name_constraints
96                .map(|nc| nc.as_slice_less_safe().into()),
97        }
98    }
99}
100
101fn skip(input: &mut untrusted::Reader<'_>, tag: der::Tag) -> Result<(), Error> {
102    der::expect_tag(input, tag).map(|_| ())
103}