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 | |