/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-webpki-0.103.8/src/end_entity.rs
Line | Count | Source |
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, ExtendedKeyUsageValidator, 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 | | /// [`crate::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 | | /// [`crate::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 | 0 | fn try_from(cert: &'a CertificateDer<'a>) -> Result<Self, Self::Error> { |
69 | | Ok(Self { |
70 | 0 | inner: cert::Cert::from_der(untrusted::Input::from(cert.as_ref()))?, |
71 | | }) |
72 | 0 | } Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::convert::TryFrom<&rustls_pki_types::CertificateDer>>::try_from Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::convert::TryFrom<&rustls_pki_types::CertificateDer>>::try_from Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::convert::TryFrom<&rustls_pki_types::CertificateDer>>::try_from |
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. The default [`ExtendedKeyUsageValidator`] |
89 | | /// implementation is [`KeyUsage`](crate::KeyUsage). |
90 | | /// * `crls` is the list of certificate revocation lists to check |
91 | | /// the certificate against. |
92 | | /// * `verify_path` is an optional verification function for path candidates. |
93 | | /// |
94 | | /// If successful, yields a `VerifiedPath` type that can be used to inspect a verified chain |
95 | | /// of certificates that leads from the `end_entity` to one of the `self.trust_anchors`. |
96 | | /// |
97 | | /// `verify_path` will only be called for potentially verified paths, that is, paths that |
98 | | /// have been verified up to the trust anchor. As such, `verify_path()` cannot be used to |
99 | | /// verify a path that doesn't satisfy the constraints listed above; it can only be used to |
100 | | /// reject a path that does satisfy the aforementioned constraints. If `verify_path` returns |
101 | | /// an error, path building will continue in order to try other options. |
102 | | #[allow(clippy::too_many_arguments)] |
103 | 0 | pub fn verify_for_usage<'p>( |
104 | 0 | &'p self, |
105 | 0 | supported_sig_algs: &[&dyn SignatureVerificationAlgorithm], |
106 | 0 | trust_anchors: &'p [TrustAnchor<'_>], |
107 | 0 | intermediate_certs: &'p [CertificateDer<'p>], |
108 | 0 | time: UnixTime, |
109 | 0 | usage: impl ExtendedKeyUsageValidator, |
110 | 0 | revocation: Option<RevocationOptions<'_>>, |
111 | 0 | verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>, |
112 | 0 | ) -> Result<VerifiedPath<'p>, Error> { |
113 | 0 | verify_cert::ChainOptions { |
114 | 0 | eku: usage, |
115 | 0 | supported_sig_algs, |
116 | 0 | trust_anchors, |
117 | 0 | intermediate_certs, |
118 | 0 | revocation, |
119 | 0 | } |
120 | 0 | .build_chain(self, time, verify_path) |
121 | 0 | } Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<webpki::verify_cert::KeyUsage> Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<_> Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<webpki::verify_cert::KeyUsage> Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<_> Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<webpki::verify_cert::KeyUsage> Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_for_usage::<_> |
122 | | |
123 | | /// Verifies that the certificate is valid for the given Subject Name. |
124 | 0 | pub fn verify_is_valid_for_subject_name( |
125 | 0 | &self, |
126 | 0 | server_name: &ServerName<'_>, |
127 | 0 | ) -> Result<(), Error> { |
128 | 0 | match server_name { |
129 | 0 | ServerName::DnsName(dns_name) => verify_dns_names(dns_name, &self.inner), |
130 | | // IP addresses are not compared against the subject field; |
131 | | // only against Subject Alternative Names. |
132 | 0 | ServerName::IpAddress(ip_address) => verify_ip_address_names(ip_address, &self.inner), |
133 | 0 | _ => Err(Error::UnsupportedNameType), |
134 | | } |
135 | 0 | } Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_is_valid_for_subject_name Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_is_valid_for_subject_name Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_is_valid_for_subject_name |
136 | | |
137 | | /// Verifies the signature `signature` of message `msg` using the |
138 | | /// certificate's public key. |
139 | | /// |
140 | | /// `signature_alg` is the algorithm to use to |
141 | | /// verify the signature; the certificate's public key is verified to be |
142 | | /// compatible with this algorithm. |
143 | | /// |
144 | | /// For TLS 1.2, `signature` corresponds to TLS's |
145 | | /// `DigitallySigned.signature` and `signature_alg` corresponds to TLS's |
146 | | /// `DigitallySigned.algorithm` of TLS type `SignatureAndHashAlgorithm`. In |
147 | | /// TLS 1.2 a single `SignatureAndHashAlgorithm` may map to multiple |
148 | | /// `SignatureVerificationAlgorithm`s. For example, a TLS 1.2 |
149 | | /// `SignatureAndHashAlgorithm` of (ECDSA, SHA-256) may map to any or all |
150 | | /// of {`ECDSA_P256_SHA256`, `ECDSA_P384_SHA256`}, depending on how the TLS |
151 | | /// implementation is configured. |
152 | | /// |
153 | | /// For current TLS 1.3 drafts, `signature_alg` corresponds to TLS's |
154 | | /// `algorithm` fields of type `SignatureScheme`. There is (currently) a |
155 | | /// one-to-one correspondence between TLS 1.3's `SignatureScheme` and |
156 | | /// `SignatureVerificationAlgorithm`. |
157 | 0 | pub fn verify_signature( |
158 | 0 | &self, |
159 | 0 | signature_alg: &dyn SignatureVerificationAlgorithm, |
160 | 0 | msg: &[u8], |
161 | 0 | signature: &[u8], |
162 | 0 | ) -> Result<(), Error> { |
163 | 0 | signed_data::verify_signature( |
164 | 0 | signature_alg, |
165 | 0 | self.inner.spki, |
166 | 0 | untrusted::Input::from(msg), |
167 | 0 | untrusted::Input::from(signature), |
168 | | ) |
169 | 0 | } Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_signature Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_signature Unexecuted instantiation: <webpki::end_entity::EndEntityCert>::verify_signature |
170 | | } |
171 | | |
172 | | impl<'a> Deref for EndEntityCert<'a> { |
173 | | type Target = cert::Cert<'a>; |
174 | | |
175 | 0 | fn deref(&self) -> &Self::Target { |
176 | 0 | &self.inner |
177 | 0 | } Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::ops::deref::Deref>::deref Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::ops::deref::Deref>::deref Unexecuted instantiation: <webpki::end_entity::EndEntityCert as core::ops::deref::Deref>::deref |
178 | | } |
179 | | |
180 | | #[cfg(feature = "alloc")] |
181 | | #[cfg(test)] |
182 | | mod tests { |
183 | | use super::*; |
184 | | use crate::test_utils; |
185 | | use crate::test_utils::RCGEN_SIGNATURE_ALG; |
186 | | use std::prelude::v1::*; |
187 | | |
188 | | // This test reproduces https://github.com/rustls/webpki/issues/167 --- an |
189 | | // end-entity cert where the common name is a `PrintableString` rather than |
190 | | // a `UTF8String` cannot iterate over its subject alternative names. |
191 | | #[test] |
192 | | fn printable_string_common_name() { |
193 | | const DNS_NAME: &str = "test.example.com"; |
194 | | |
195 | | let issuer = test_utils::make_issuer("Test"); |
196 | | |
197 | | let ee_cert = { |
198 | | let mut params = test_utils::end_entity_params(vec![DNS_NAME.to_string()]); |
199 | | // construct a certificate that uses `PrintableString` as the |
200 | | // common name value, rather than `UTF8String`. |
201 | | params.distinguished_name.push( |
202 | | rcgen::DnType::CommonName, |
203 | | rcgen::DnValue::PrintableString( |
204 | | rcgen::string::PrintableString::try_from("example.com").unwrap(), |
205 | | ), |
206 | | ); |
207 | | params |
208 | | .signed_by( |
209 | | &rcgen::KeyPair::generate_for(RCGEN_SIGNATURE_ALG).unwrap(), |
210 | | &issuer, |
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 | | } |