Coverage Report

Created: 2026-07-14 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-webpki-0.104.0-alpha.7/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, sct, 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::ExtendedKeyUsage::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::ExtendedKeyUsage::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
2.97k
    fn try_from(cert: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
69
        Ok(Self {
70
2.97k
            inner: cert::Cert::from_der(untrusted::Input::from(cert.as_ref()))?,
71
        })
72
2.97k
    }
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 [`ExtendedKeyUsage`](crate::ExtendedKeyUsage).
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
    #[expect(clippy::too_many_arguments, clippy::type_complexity)]
103
1.67k
    pub fn verify_for_usage<'p>(
104
1.67k
        &'p self,
105
1.67k
        supported_sig_algs: &[&dyn SignatureVerificationAlgorithm],
106
1.67k
        trust_anchors: &'p [TrustAnchor<'_>],
107
1.67k
        intermediate_certs: &'p [CertificateDer<'p>],
108
1.67k
        time: UnixTime,
109
1.67k
        usage: &dyn ExtendedKeyUsageValidator,
110
1.67k
        revocation: Option<RevocationOptions<'_>>,
111
1.67k
        verify_path: Option<&dyn Fn(&VerifiedPath<'_>) -> Result<(), Error>>,
112
1.67k
    ) -> Result<VerifiedPath<'p>, Error> {
113
1.67k
        verify_cert::ChainOptions {
114
1.67k
            eku: usage,
115
1.67k
            supported_sig_algs,
116
1.67k
            trust_anchors,
117
1.67k
            intermediate_certs,
118
1.67k
            revocation,
119
1.67k
        }
120
1.67k
        .build_chain(self, time, verify_path)
121
1.67k
    }
122
123
    /// Verifies that the certificate is valid for the given Subject Name.
124
708
    pub fn verify_is_valid_for_subject_name(
125
708
        &self,
126
708
        server_name: &ServerName<'_>,
127
708
    ) -> Result<(), Error> {
128
708
        match server_name {
129
708
            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
708
    }
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
448
    pub fn verify_signature(
158
448
        &self,
159
448
        signature_alg: &dyn SignatureVerificationAlgorithm,
160
448
        msg: &[u8],
161
448
        signature: &[u8],
162
448
    ) -> Result<(), Error> {
163
448
        signed_data::verify_signature(
164
448
            signature_alg,
165
448
            self.inner.spki,
166
448
            untrusted::Input::from(msg),
167
448
            untrusted::Input::from(signature),
168
        )
169
448
    }
170
171
    /// Returns the CT logs that contributed to the SCTs included in the certificate.
172
    ///
173
    /// Note this method does not verify the SCTs themselves.
174
    ///
175
    /// If the certificate does not contain an SCT extension, this method returns an empty
176
    /// iterator.
177
0
    pub fn sct_log_timestamps<'a>(
178
0
        &'a self,
179
0
    ) -> Result<impl Iterator<Item = Result<sct::LogIdAndTimestamp, sct::Error>> + 'a, sct::Error>
180
    {
181
0
        Ok(sct::SctParser::new(self.scts)?.map(|sct| sct.map(|sct| sct.log_id_and_timestamp())))
182
0
    }
183
}
184
185
impl<'a> Deref for EndEntityCert<'a> {
186
    type Target = cert::Cert<'a>;
187
188
6.89k
    fn deref(&self) -> &Self::Target {
189
6.89k
        &self.inner
190
6.89k
    }
191
}
192
193
#[cfg(feature = "alloc")]
194
#[cfg(test)]
195
mod tests {
196
    use alloc::string::ToString;
197
198
    use super::*;
199
    use crate::test_utils;
200
    use crate::test_utils::RCGEN_SIGNATURE_ALG;
201
202
    // This test reproduces https://github.com/rustls/webpki/issues/167 --- an
203
    // end-entity cert where the common name is a `PrintableString` rather than
204
    // a `UTF8String` cannot iterate over its subject alternative names.
205
    #[test]
206
    fn printable_string_common_name() {
207
        const DNS_NAME: &str = "test.example.com";
208
209
        let issuer = test_utils::make_issuer("Test");
210
211
        let ee_cert = {
212
            let mut params = test_utils::end_entity_params(vec![DNS_NAME.to_string()]);
213
            // construct a certificate that uses `PrintableString` as the
214
            // common name value, rather than `UTF8String`.
215
            params.distinguished_name.push(
216
                rcgen::DnType::CommonName,
217
                rcgen::DnValue::PrintableString(
218
                    rcgen::string::PrintableString::try_from("example.com").unwrap(),
219
                ),
220
            );
221
            params
222
                .signed_by(
223
                    &rcgen::KeyPair::generate_for(RCGEN_SIGNATURE_ALG).unwrap(),
224
                    &issuer,
225
                )
226
                .expect("failed to make ee cert (this is a test bug)")
227
        };
228
229
        expect_dns_name(ee_cert.der(), DNS_NAME);
230
    }
231
232
    // This test reproduces https://github.com/rustls/webpki/issues/167 --- an
233
    // end-entity cert where the common name is an empty SEQUENCE.
234
    #[test]
235
    fn empty_sequence_common_name() {
236
        let ee_cert_der = {
237
            // handcrafted cert DER produced using `ascii2der`, since `rcgen` is
238
            // unwilling to generate this particular weird cert.
239
            let bytes = include_bytes!("../tests/misc/empty_sequence_common_name.der");
240
            CertificateDer::from(&bytes[..])
241
        };
242
        expect_dns_name(&ee_cert_der, "example.com");
243
    }
244
245
    fn expect_dns_name(der: &CertificateDer<'_>, name: &str) {
246
        let cert =
247
            EndEntityCert::try_from(der).expect("should parse end entity certificate correctly");
248
249
        let mut names = cert.valid_dns_names();
250
        assert_eq!(names.next(), Some(name));
251
        assert_eq!(names.next(), None);
252
    }
253
}