| 1 | use pki_types::{CertificateDer, TrustAnchor}; |
| 2 | |
| 3 | use crate::cert::{Cert, lenient_certificate_serial_number}; |
| 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<'a>| 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 | |