| 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 | |
| 15 | use core::ops::Deref; |
| 16 | |
| 17 | use pki_types::{ |
| 18 | CertificateDer, ServerName, SignatureVerificationAlgorithm, TrustAnchor, UnixTime, |
| 19 | }; |
| 20 | |
| 21 | use crate::crl::RevocationOptions; |
| 22 | use crate::error::Error; |
| 23 | use crate::subject_name::{verify_dns_names, verify_ip_address_names}; |
| 24 | use crate::verify_cert::{self, KeyUsage, VerifiedPath}; |
| 25 | use 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. |
| 59 | pub struct EndEntityCert<'a> { |
| 60 | inner: cert::Cert<'a>, |
| 61 | } |
| 62 | |
| 63 | impl<'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(cert_der:untrusted::Input::from(bytes:cert.as_ref()))?, |
| 71 | }) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | impl EndEntityCert<'_> { |
| 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(dns_name, &self.inner), |
| 129 | // IP addresses are not compared against the subject field; |
| 130 | // only against Subject Alternative Names. |
| 131 | ServerName::IpAddress(ip_address) => verify_ip_address_names(ip_address, &self.inner), |
| 132 | _ => Err(Error::UnsupportedNameType), |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | /// Verifies the signature `signature` of message `msg` using the |
| 137 | /// certificate's public key. |
| 138 | /// |
| 139 | /// `signature_alg` is the algorithm to use to |
| 140 | /// verify the signature; the certificate's public key is verified to be |
| 141 | /// compatible with this algorithm. |
| 142 | /// |
| 143 | /// For TLS 1.2, `signature` corresponds to TLS's |
| 144 | /// `DigitallySigned.signature` and `signature_alg` corresponds to TLS's |
| 145 | /// `DigitallySigned.algorithm` of TLS type `SignatureAndHashAlgorithm`. In |
| 146 | /// TLS 1.2 a single `SignatureAndHashAlgorithm` may map to multiple |
| 147 | /// `SignatureVerificationAlgorithm`s. For example, a TLS 1.2 |
| 148 | /// `SignatureAndHashAlgorithm` of (ECDSA, SHA-256) may map to any or all |
| 149 | /// of {`ECDSA_P256_SHA256`, `ECDSA_P384_SHA256`}, depending on how the TLS |
| 150 | /// implementation is configured. |
| 151 | /// |
| 152 | /// For current TLS 1.3 drafts, `signature_alg` corresponds to TLS's |
| 153 | /// `algorithm` fields of type `SignatureScheme`. There is (currently) a |
| 154 | /// one-to-one correspondence between TLS 1.3's `SignatureScheme` and |
| 155 | /// `SignatureVerificationAlgorithm`. |
| 156 | pub fn verify_signature( |
| 157 | &self, |
| 158 | signature_alg: &dyn SignatureVerificationAlgorithm, |
| 159 | msg: &[u8], |
| 160 | signature: &[u8], |
| 161 | ) -> Result<(), Error> { |
| 162 | signed_data::verify_signature( |
| 163 | signature_alg, |
| 164 | self.inner.spki, |
| 165 | untrusted::Input::from(msg), |
| 166 | untrusted::Input::from(signature), |
| 167 | ) |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | impl<'a> Deref for EndEntityCert<'a> { |
| 172 | type Target = cert::Cert<'a>; |
| 173 | |
| 174 | fn deref(&self) -> &Self::Target { |
| 175 | &self.inner |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | #[cfg (feature = "alloc" )] |
| 180 | #[cfg (test)] |
| 181 | mod tests { |
| 182 | use super::*; |
| 183 | use crate::test_utils; |
| 184 | use crate::test_utils::RCGEN_SIGNATURE_ALG; |
| 185 | use std::prelude::v1::*; |
| 186 | |
| 187 | // This test reproduces https://github.com/rustls/webpki/issues/167 --- an |
| 188 | // end-entity cert where the common name is a `PrintableString` rather than |
| 189 | // a `UTF8String` cannot iterate over its subject alternative names. |
| 190 | #[test ] |
| 191 | fn printable_string_common_name() { |
| 192 | const DNS_NAME: &str = "test.example.com" ; |
| 193 | |
| 194 | let issuer = test_utils::make_issuer("Test" ); |
| 195 | |
| 196 | let ee_cert = { |
| 197 | let mut params = test_utils::end_entity_params(vec![DNS_NAME.to_string()]); |
| 198 | // construct a certificate that uses `PrintableString` as the |
| 199 | // common name value, rather than `UTF8String`. |
| 200 | params.distinguished_name.push( |
| 201 | rcgen::DnType::CommonName, |
| 202 | rcgen::DnValue::PrintableString( |
| 203 | rcgen::PrintableString::try_from("example.com" ).unwrap(), |
| 204 | ), |
| 205 | ); |
| 206 | params |
| 207 | .signed_by( |
| 208 | &rcgen::KeyPair::generate_for(RCGEN_SIGNATURE_ALG).unwrap(), |
| 209 | &issuer.cert, |
| 210 | &issuer.key_pair, |
| 211 | ) |
| 212 | .expect("failed to make ee cert (this is a test bug)" ) |
| 213 | }; |
| 214 | |
| 215 | expect_dns_name(ee_cert.der(), DNS_NAME); |
| 216 | } |
| 217 | |
| 218 | // This test reproduces https://github.com/rustls/webpki/issues/167 --- an |
| 219 | // end-entity cert where the common name is an empty SEQUENCE. |
| 220 | #[test ] |
| 221 | fn empty_sequence_common_name() { |
| 222 | let ee_cert_der = { |
| 223 | // handcrafted cert DER produced using `ascii2der`, since `rcgen` is |
| 224 | // unwilling to generate this particular weird cert. |
| 225 | let bytes = include_bytes!("../tests/misc/empty_sequence_common_name.der" ); |
| 226 | CertificateDer::from(&bytes[..]) |
| 227 | }; |
| 228 | expect_dns_name(&ee_cert_der, "example.com" ); |
| 229 | } |
| 230 | |
| 231 | fn expect_dns_name(der: &CertificateDer<'_>, name: &str) { |
| 232 | let cert = |
| 233 | EndEntityCert::try_from(der).expect("should parse end entity certificate correctly" ); |
| 234 | |
| 235 | let mut names = cert.valid_dns_names(); |
| 236 | assert_eq!(names.next(), Some(name)); |
| 237 | assert_eq!(names.next(), None); |
| 238 | } |
| 239 | } |
| 240 | |