1 | use pki_types::{CertificateDer, TrustAnchor}; |
2 | |
3 | use crate::cert::{lenient_certificate_serial_number, Cert}; |
4 | use crate::der; |
5 | use 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> |
27 | pub fn anchor_from_trusted_cert<'a>( |
28 | cert: &'a CertificateDer<'a>, |
29 | ) -> Result<TrustAnchor<'a>, Error> { |
30 | let cert_der: Input<'_> = untrusted::Input::from(bytes: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: Cert<'_>) => Ok(TrustAnchor::from(cert)), |
39 | Err(Error::UnsupportedCertVersion) => { |
40 | extract_trust_anchor_from_v1_cert_der(cert_der).or(res:Err(Error::BadDer)) |
41 | } |
42 | Err(err: Error) => Err(err), |
43 | } |
44 | } |
45 | |
46 | /// Parses a v1 certificate directly into a TrustAnchor. |
47 | fn 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 | |
89 | impl<'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: certOption> |
95 | .name_constraints |
96 | .map(|nc: Input<'_>| nc.as_slice_less_safe().into()), |
97 | } |
98 | } |
99 | } |
100 | |
101 | fn skip(input: &mut untrusted::Reader, tag: der::Tag) -> Result<(), Error> { |
102 | der::expect_tag(input, tag).map(|_| ()) |
103 | } |
104 | |