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, NameIterator}; |
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_is_valid_tls_server_cert`: Verify that the server's |
33 | /// certificate is currently valid *for use by a TLS server*. |
34 | /// * `EndEntityCert.verify_is_valid_for_subject_name`: Verify that the server's |
35 | /// certificate is valid for the host or IP address that is being connected to. |
36 | /// |
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_is_valid_tls_client_cert`: Verify that the client's |
44 | /// certificate is currently valid *for use by a TLS client*. |
45 | /// * `EndEntityCert.verify_signature`: Verify that the client's signature in |
46 | /// its `CertificateVerify` message is valid using the public key from the |
47 | /// client's certificate. |
48 | /// |
49 | /// Although it would be less error-prone to combine all these steps into a |
50 | /// single function call, some significant optimizations are possible if the |
51 | /// three steps are processed separately (in parallel). It does not matter much |
52 | /// which order the steps are done in, but **all of these steps must completed |
53 | /// before application data is sent and before received application data is |
54 | /// processed**. `EndEntityCert::from` is an inexpensive operation and is |
55 | /// deterministic, so if these tasks are done in multiple threads, it is |
56 | /// probably best to just call `EndEntityCert::from` multiple times (before each |
57 | /// operation) for the same DER-encoded ASN.1 certificate bytes. |
58 | pub struct EndEntityCert<'a> { |
59 | inner: cert::Cert<'a>, |
60 | } |
61 | |
62 | impl<'a> TryFrom<&'a CertificateDer<'a>> for EndEntityCert<'a> { |
63 | type Error = Error; |
64 | |
65 | /// Parse the ASN.1 DER-encoded X.509 encoding of the certificate |
66 | /// `cert_der`. |
67 | fn try_from(cert: &'a CertificateDer<'a>) -> Result<Self, Self::Error> { |
68 | Ok(Self { |
69 | inner: cert::Cert::from_der(cert_der:untrusted::Input::from(bytes:cert.as_ref()))?, |
70 | }) |
71 | } |
72 | } |
73 | |
74 | impl<'a> EndEntityCert<'a> { |
75 | /// Verifies that the end-entity certificate is valid for use against the |
76 | /// specified Extended Key Usage (EKU). |
77 | /// |
78 | /// * `supported_sig_algs` is the list of signature algorithms that are |
79 | /// trusted for use in certificate signatures; the end-entity certificate's |
80 | /// public key is not validated against this list. |
81 | /// * `trust_anchors` is the list of root CAs to trust in the built path. |
82 | /// * `intermediate_certs` is the sequence of intermediate certificates that |
83 | /// a peer sent for the purpose of path building. |
84 | /// * `time` is the time for which the validation is effective (usually the |
85 | /// current time). |
86 | /// * `usage` is the intended usage of the certificate, indicating what kind |
87 | /// of usage we're verifying the certificate for. |
88 | /// * `crls` is the list of certificate revocation lists to check |
89 | /// the certificate against. |
90 | /// * `verify_path` is an optional verification function for path candidates. |
91 | /// |
92 | /// If successful, yields a `VerifiedPath` type that can be used to inspect a verified chain |
93 | /// of certificates that leads from the `end_entity` to one of the `self.trust_anchors`. |
94 | /// |
95 | /// `verify_path` will only be called for potentially verified paths, that is, paths that |
96 | /// have been verified up to the trust anchor. As such, `verify_path()` cannot be used to |
97 | /// verify a path that doesn't satisfy the constraints listed above; it can only be used to |
98 | /// reject a path that does satisfy the aforementioned constraints. If `verify_path` returns |
99 | /// an error, path building will continue in order to try other options. |
100 | #[allow (clippy::too_many_arguments)] |
101 | pub fn verify_for_usage<'p>( |
102 | &'p self, |
103 | supported_sig_algs: &[&dyn SignatureVerificationAlgorithm], |
104 | trust_anchors: &'p [TrustAnchor], |
105 | intermediate_certs: &'p [CertificateDer<'p>], |
106 | time: UnixTime, |
107 | usage: KeyUsage, |
108 | revocation: Option<RevocationOptions<'_>>, |
109 | verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>, |
110 | ) -> Result<VerifiedPath<'p>, Error> { |
111 | verify_cert::ChainOptions { |
112 | eku: usage, |
113 | supported_sig_algs, |
114 | trust_anchors, |
115 | intermediate_certs, |
116 | revocation, |
117 | } |
118 | .build_chain(self, time, verify_path) |
119 | } |
120 | |
121 | /// Verifies that the certificate is valid for the given Subject Name. |
122 | pub fn verify_is_valid_for_subject_name( |
123 | &self, |
124 | server_name: &ServerName<'_>, |
125 | ) -> Result<(), Error> { |
126 | match server_name { |
127 | ServerName::DnsName(dns_name) => verify_dns_names( |
128 | dns_name, |
129 | NameIterator::new(Some(self.inner.subject), self.inner.subject_alt_name), |
130 | ), |
131 | // IP addresses are not compared against the subject field; |
132 | // only against Subject Alternative Names. |
133 | ServerName::IpAddress(ip_address) => verify_ip_address_names( |
134 | ip_address, |
135 | NameIterator::new(None, self.inner.subject_alt_name), |
136 | ), |
137 | _ => Err(Error::UnsupportedNameType), |
138 | } |
139 | } |
140 | |
141 | /// Verifies the signature `signature` of message `msg` using the |
142 | /// certificate's public key. |
143 | /// |
144 | /// `signature_alg` is the algorithm to use to |
145 | /// verify the signature; the certificate's public key is verified to be |
146 | /// compatible with this algorithm. |
147 | /// |
148 | /// For TLS 1.2, `signature` corresponds to TLS's |
149 | /// `DigitallySigned.signature` and `signature_alg` corresponds to TLS's |
150 | /// `DigitallySigned.algorithm` of TLS type `SignatureAndHashAlgorithm`. In |
151 | /// TLS 1.2 a single `SignatureAndHashAlgorithm` may map to multiple |
152 | /// `SignatureVerificationAlgorithm`s. For example, a TLS 1.2 |
153 | /// `SignatureAndHashAlgorithm` of (ECDSA, SHA-256) may map to any or all |
154 | /// of {`ECDSA_P256_SHA256`, `ECDSA_P384_SHA256`}, depending on how the TLS |
155 | /// implementation is configured. |
156 | /// |
157 | /// For current TLS 1.3 drafts, `signature_alg` corresponds to TLS's |
158 | /// `algorithm` fields of type `SignatureScheme`. There is (currently) a |
159 | /// one-to-one correspondence between TLS 1.3's `SignatureScheme` and |
160 | /// `SignatureVerificationAlgorithm`. |
161 | pub fn verify_signature( |
162 | &self, |
163 | signature_alg: &dyn SignatureVerificationAlgorithm, |
164 | msg: &[u8], |
165 | signature: &[u8], |
166 | ) -> Result<(), Error> { |
167 | signed_data::verify_signature( |
168 | signature_alg, |
169 | self.inner.spki, |
170 | untrusted::Input::from(msg), |
171 | untrusted::Input::from(signature), |
172 | ) |
173 | } |
174 | } |
175 | |
176 | impl<'a> Deref for EndEntityCert<'a> { |
177 | type Target = cert::Cert<'a>; |
178 | |
179 | fn deref(&self) -> &Self::Target { |
180 | &self.inner |
181 | } |
182 | } |
183 | |
184 | #[cfg (feature = "alloc" )] |
185 | #[cfg (test)] |
186 | mod tests { |
187 | use super::*; |
188 | use crate::test_utils; |
189 | |
190 | // This test reproduces https://github.com/rustls/webpki/issues/167 --- an |
191 | // end-entity cert where the common name is a `PrintableString` rather than |
192 | // a `UTF8String` cannot iterate over its subject alternative names. |
193 | #[test ] |
194 | fn printable_string_common_name() { |
195 | const DNS_NAME: &str = "test.example.com" ; |
196 | |
197 | let issuer = test_utils::make_issuer("Test" ); |
198 | |
199 | let ee_cert_der = { |
200 | let mut params = test_utils::end_entity_params(vec![DNS_NAME.to_string()]); |
201 | // construct a certificate that uses `PrintableString` as the |
202 | // common name value, rather than `UTF8String`. |
203 | params.distinguished_name.push( |
204 | rcgen::DnType::CommonName, |
205 | rcgen::DnValue::PrintableString("example.com" .to_string()), |
206 | ); |
207 | let cert = rcgen::Certificate::from_params(params) |
208 | .expect("failed to make ee cert (this is a test bug)" ); |
209 | let bytes = cert |
210 | .serialize_der_with_signer(&issuer) |
211 | .expect("failed to serialize signed ee cert (this is a test bug)" ); |
212 | CertificateDer::from(bytes) |
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 | |