webpki/
end_entity.rs

1// Copyright 2015-2021 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use core::ops::Deref;
16
17use pki_types::{
18    CertificateDer, ServerName, SignatureVerificationAlgorithm, TrustAnchor, UnixTime,
19};
20
21use crate::crl::RevocationOptions;
22use crate::error::Error;
23use crate::subject_name::{verify_dns_names, verify_ip_address_names, NameIterator};
24use crate::verify_cert::{self, KeyUsage, VerifiedPath};
25use crate::{cert, signed_data};
26
27/// An end-entity certificate.
28///
29/// Server certificate processing in a TLS connection consists of several
30/// steps. All of these steps are necessary:
31///
32/// * [`EndEntityCert::verify_for_usage()`]: Verify that the peer's certificate
33///   is valid for the current usage scenario. For server authentication, use
34///   [`KeyUsage::server_auth()`].
35/// * [`EndEntityCert::verify_is_valid_for_subject_name()`]: Verify that the server's
36///   certificate is valid for the host or IP address that is being connected to.
37/// * [`EndEntityCert::verify_signature()`]: Verify that the signature of server's
38///   `ServerKeyExchange` message is valid for the server's certificate.
39///
40/// Client certificate processing in a TLS connection consists of analogous
41/// steps. All of these steps are necessary:
42///
43/// * [`EndEntityCert::verify_for_usage()`]: Verify that the peer's certificate
44///   is valid for the current usage scenario. For client authentication, use
45///   [`KeyUsage::client_auth()`].
46/// * [`EndEntityCert::verify_signature()`]: Verify that the signature of client's
47///   `CertificateVerify` message is valid using the public key from the
48///   client's certificate.
49///
50/// Although it would be less error-prone to combine all these steps into a
51/// single function call, some significant optimizations are possible if the
52/// three steps are processed separately (in parallel). It does not matter much
53/// which order the steps are done in, but **all of these steps must completed
54/// before application data is sent and before received application data is
55/// processed**. The [`TryFrom`] conversion from `&CertificateDer<'_>` is an
56/// inexpensive operation and is deterministic, so if these tasks are done in
57/// multiple threads, it is probably best to just create multiple [`EndEntityCert`]
58/// instances for the same DER-encoded ASN.1 certificate bytes.
59pub struct EndEntityCert<'a> {
60    inner: cert::Cert<'a>,
61}
62
63impl<'a> TryFrom<&'a CertificateDer<'a>> for EndEntityCert<'a> {
64    type Error = Error;
65
66    /// Parse the ASN.1 DER-encoded X.509 encoding of the certificate
67    /// `cert_der`.
68    fn try_from(cert: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
69        Ok(Self {
70            inner: cert::Cert::from_der(untrusted::Input::from(cert.as_ref()))?,
71        })
72    }
73}
74
75impl<'a> EndEntityCert<'a> {
76    /// Verifies that the end-entity certificate is valid for use against the
77    /// specified Extended Key Usage (EKU).
78    ///
79    /// * `supported_sig_algs` is the list of signature algorithms that are
80    ///   trusted for use in certificate signatures; the end-entity certificate's
81    ///   public key is not validated against this list.
82    /// * `trust_anchors` is the list of root CAs to trust in the built path.
83    /// * `intermediate_certs` is the sequence of intermediate certificates that
84    ///   a peer sent for the purpose of path building.
85    /// * `time` is the time for which the validation is effective (usually the
86    ///   current time).
87    /// * `usage` is the intended usage of the certificate, indicating what kind
88    ///   of usage we're verifying the certificate for.
89    /// * `crls` is the list of certificate revocation lists to check
90    ///   the certificate against.
91    /// * `verify_path` is an optional verification function for path candidates.
92    ///
93    /// If successful, yields a `VerifiedPath` type that can be used to inspect a verified chain
94    /// of certificates that leads from the `end_entity` to one of the `self.trust_anchors`.
95    ///
96    /// `verify_path` will only be called for potentially verified paths, that is, paths that
97    /// have been verified up to the trust anchor. As such, `verify_path()` cannot be used to
98    /// verify a path that doesn't satisfy the constraints listed above; it can only be used to
99    /// reject a path that does satisfy the aforementioned constraints. If `verify_path` returns
100    /// an error, path building will continue in order to try other options.
101    #[allow(clippy::too_many_arguments)]
102    pub fn verify_for_usage<'p>(
103        &'p self,
104        supported_sig_algs: &[&dyn SignatureVerificationAlgorithm],
105        trust_anchors: &'p [TrustAnchor<'_>],
106        intermediate_certs: &'p [CertificateDer<'p>],
107        time: UnixTime,
108        usage: KeyUsage,
109        revocation: Option<RevocationOptions<'_>>,
110        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
111    ) -> Result<VerifiedPath<'p>, Error> {
112        verify_cert::ChainOptions {
113            eku: usage,
114            supported_sig_algs,
115            trust_anchors,
116            intermediate_certs,
117            revocation,
118        }
119        .build_chain(self, time, verify_path)
120    }
121
122    /// Verifies that the certificate is valid for the given Subject Name.
123    pub fn verify_is_valid_for_subject_name(
124        &self,
125        server_name: &ServerName<'_>,
126    ) -> Result<(), Error> {
127        match server_name {
128            ServerName::DnsName(dns_name) => verify_dns_names(
129                dns_name,
130                NameIterator::new(Some(self.inner.subject), self.inner.subject_alt_name),
131            ),
132            // IP addresses are not compared against the subject field;
133            // only against Subject Alternative Names.
134            ServerName::IpAddress(ip_address) => verify_ip_address_names(
135                ip_address,
136                NameIterator::new(None, self.inner.subject_alt_name),
137            ),
138            _ => Err(Error::UnsupportedNameType),
139        }
140    }
141
142    /// Verifies the signature `signature` of message `msg` using the
143    /// certificate's public key.
144    ///
145    /// `signature_alg` is the algorithm to use to
146    /// verify the signature; the certificate's public key is verified to be
147    /// compatible with this algorithm.
148    ///
149    /// For TLS 1.2, `signature` corresponds to TLS's
150    /// `DigitallySigned.signature` and `signature_alg` corresponds to TLS's
151    /// `DigitallySigned.algorithm` of TLS type `SignatureAndHashAlgorithm`. In
152    /// TLS 1.2 a single `SignatureAndHashAlgorithm` may map to multiple
153    /// `SignatureVerificationAlgorithm`s. For example, a TLS 1.2
154    /// `SignatureAndHashAlgorithm` of (ECDSA, SHA-256) may map to any or all
155    /// of {`ECDSA_P256_SHA256`, `ECDSA_P384_SHA256`}, depending on how the TLS
156    /// implementation is configured.
157    ///
158    /// For current TLS 1.3 drafts, `signature_alg` corresponds to TLS's
159    /// `algorithm` fields of type `SignatureScheme`. There is (currently) a
160    /// one-to-one correspondence between TLS 1.3's `SignatureScheme` and
161    /// `SignatureVerificationAlgorithm`.
162    pub fn verify_signature(
163        &self,
164        signature_alg: &dyn SignatureVerificationAlgorithm,
165        msg: &[u8],
166        signature: &[u8],
167    ) -> Result<(), Error> {
168        signed_data::verify_signature(
169            signature_alg,
170            self.inner.spki,
171            untrusted::Input::from(msg),
172            untrusted::Input::from(signature),
173        )
174    }
175}
176
177impl<'a> Deref for EndEntityCert<'a> {
178    type Target = cert::Cert<'a>;
179
180    fn deref(&self) -> &Self::Target {
181        &self.inner
182    }
183}
184
185#[cfg(feature = "alloc")]
186#[cfg(test)]
187mod tests {
188    use super::*;
189    use crate::test_utils;
190    use crate::test_utils::RCGEN_SIGNATURE_ALG;
191    use std::prelude::v1::*;
192
193    // This test reproduces https://github.com/rustls/webpki/issues/167 --- an
194    // end-entity cert where the common name is a `PrintableString` rather than
195    // a `UTF8String` cannot iterate over its subject alternative names.
196    #[test]
197    fn printable_string_common_name() {
198        const DNS_NAME: &str = "test.example.com";
199
200        let issuer = test_utils::make_issuer("Test");
201
202        let ee_cert = {
203            let mut params = test_utils::end_entity_params(vec![DNS_NAME.to_string()]);
204            // construct a certificate that uses `PrintableString` as the
205            // common name value, rather than `UTF8String`.
206            params.distinguished_name.push(
207                rcgen::DnType::CommonName,
208                rcgen::DnValue::PrintableString(
209                    rcgen::PrintableString::try_from("example.com").unwrap(),
210                ),
211            );
212            params
213                .signed_by(
214                    &rcgen::KeyPair::generate_for(RCGEN_SIGNATURE_ALG).unwrap(),
215                    &issuer.cert,
216                    &issuer.key_pair,
217                )
218                .expect("failed to make ee cert (this is a test bug)")
219        };
220
221        expect_dns_name(ee_cert.der(), DNS_NAME);
222    }
223
224    // This test reproduces https://github.com/rustls/webpki/issues/167 --- an
225    // end-entity cert where the common name is an empty SEQUENCE.
226    #[test]
227    fn empty_sequence_common_name() {
228        let ee_cert_der = {
229            // handcrafted cert DER produced using `ascii2der`, since `rcgen` is
230            // unwilling to generate this particular weird cert.
231            let bytes = include_bytes!("../tests/misc/empty_sequence_common_name.der");
232            CertificateDer::from(&bytes[..])
233        };
234        expect_dns_name(&ee_cert_der, "example.com");
235    }
236
237    fn expect_dns_name(der: &CertificateDer<'_>, name: &str) {
238        let cert =
239            EndEntityCert::try_from(der).expect("should parse end entity certificate correctly");
240
241        let mut names = cert.valid_dns_names();
242        assert_eq!(names.next(), Some(name));
243        assert_eq!(names.next(), None);
244    }
245}