Coverage Report

Created: 2026-02-14 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.36/src/webpki/verify.rs
Line
Count
Source
1
use alloc::vec::Vec;
2
use core::fmt;
3
4
use pki_types::{
5
    CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
6
};
7
8
use super::anchors::RootCertStore;
9
use super::pki_error;
10
use crate::enums::SignatureScheme;
11
use crate::error::{Error, PeerMisbehaved};
12
use crate::verify::{DigitallySignedStruct, HandshakeSignatureValid};
13
14
/// Verify that the end-entity certificate `end_entity` is a valid server cert
15
/// and chains to at least one of the trust anchors in the `roots` [RootCertStore].
16
///
17
/// This function is primarily useful when building a custom certificate verifier. It
18
/// performs **no revocation checking**. Implementers must handle this themselves,
19
/// along with checking that the server certificate is valid for the subject name
20
/// being used (see [`verify_server_name`]).
21
///
22
/// `intermediates` contains all certificates other than `end_entity` that
23
/// were sent as part of the server's `Certificate` message. It is in the
24
/// same order that the server sent them and may be empty.
25
#[allow(dead_code)]
26
0
pub fn verify_server_cert_signed_by_trust_anchor(
27
0
    cert: &ParsedCertificate<'_>,
28
0
    roots: &RootCertStore,
29
0
    intermediates: &[CertificateDer<'_>],
30
0
    now: UnixTime,
31
0
    supported_algs: &[&dyn SignatureVerificationAlgorithm],
32
0
) -> Result<(), Error> {
33
0
    verify_server_cert_signed_by_trust_anchor_impl(
34
0
        cert,
35
0
        roots,
36
0
        intermediates,
37
0
        None, // No revocation checking supported with this API.
38
0
        now,
39
0
        supported_algs,
40
    )
41
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_server_cert_signed_by_trust_anchor
Unexecuted instantiation: rustls::webpki::verify::verify_server_cert_signed_by_trust_anchor
42
43
/// Verify that the `end_entity` has an alternative name matching the `server_name`.
44
///
45
/// Note: this only verifies the name and should be used in conjunction with more verification
46
/// like [verify_server_cert_signed_by_trust_anchor]
47
0
pub fn verify_server_name(
48
0
    cert: &ParsedCertificate<'_>,
49
0
    server_name: &ServerName<'_>,
50
0
) -> Result<(), Error> {
51
0
    cert.0
52
0
        .verify_is_valid_for_subject_name(server_name)
53
0
        .map_err(pki_error)
54
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_server_name
Unexecuted instantiation: rustls::webpki::verify::verify_server_name
55
56
/// Describes which `webpki` signature verification algorithms are supported and
57
/// how they map to TLS [`SignatureScheme`]s.
58
#[derive(Clone, Copy)]
59
#[allow(unreachable_pub)]
60
pub struct WebPkiSupportedAlgorithms {
61
    /// A list of all supported signature verification algorithms.
62
    ///
63
    /// Used for verifying certificate chains.
64
    ///
65
    /// The order of this list is not significant.
66
    pub all: &'static [&'static dyn SignatureVerificationAlgorithm],
67
68
    /// A mapping from TLS `SignatureScheme`s to matching webpki signature verification algorithms.
69
    ///
70
    /// This is one (`SignatureScheme`) to many ([`SignatureVerificationAlgorithm`]) because
71
    /// (depending on the protocol version) there is not necessary a 1-to-1 mapping.
72
    ///
73
    /// For TLS1.2, all `SignatureVerificationAlgorithm`s are tried in sequence.
74
    ///
75
    /// For TLS1.3, only the first is tried.
76
    ///
77
    /// The supported schemes in this mapping is communicated to the peer and the order is significant.
78
    /// The first mapping is our highest preference.
79
    pub mapping: &'static [(
80
        SignatureScheme,
81
        &'static [&'static dyn SignatureVerificationAlgorithm],
82
    )],
83
}
84
85
impl WebPkiSupportedAlgorithms {
86
    /// Return all the `scheme` items in `mapping`, maintaining order.
87
0
    pub fn supported_schemes(&self) -> Vec<SignatureScheme> {
88
0
        self.mapping
89
0
            .iter()
90
0
            .map(|item| item.0)
91
0
            .collect()
92
0
    }
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::supported_schemes
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::supported_schemes
93
94
    /// Return the first item in `mapping` that matches `scheme`.
95
0
    fn convert_scheme(
96
0
        &self,
97
0
        scheme: SignatureScheme,
98
0
    ) -> Result<&[&'static dyn SignatureVerificationAlgorithm], Error> {
99
0
        self.mapping
100
0
            .iter()
101
0
            .filter_map(|item| if item.0 == scheme { Some(item.1) } else { None })
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme::{closure#0}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme::{closure#0}
102
0
            .next()
103
0
            .ok_or_else(|| PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into())
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme::{closure#1}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme::{closure#1}
104
0
    }
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::convert_scheme
105
106
    /// Return `true` if all cryptography is FIPS-approved.
107
0
    pub fn fips(&self) -> bool {
108
0
        self.all.iter().all(|alg| alg.fips())
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#0}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#0}
109
0
            && self
110
0
                .mapping
111
0
                .iter()
112
0
                .all(|item| item.1.iter().all(|alg| alg.fips()))
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#1}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#1}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#1}::{closure#0}
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips::{closure#1}::{closure#0}
113
0
    }
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms>::fips
114
}
115
116
impl fmt::Debug for WebPkiSupportedAlgorithms {
117
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118
0
        write!(f, "WebPkiSupportedAlgorithms {{ all: [ .. ], mapping: ")?;
119
0
        f.debug_list()
120
0
            .entries(self.mapping.iter().map(|item| item.0))
121
0
            .finish()?;
122
0
        write!(f, " }}")
123
0
    }
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms as core::fmt::Debug>::fmt
Unexecuted instantiation: <rustls::webpki::verify::WebPkiSupportedAlgorithms as core::fmt::Debug>::fmt
124
}
125
126
/// Wrapper around internal representation of a parsed certificate.
127
///
128
/// This is used in order to avoid parsing twice when specifying custom verification
129
pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
130
131
impl ParsedCertificate<'_> {
132
    /// Get the parsed certificate's SubjectPublicKeyInfo (SPKI)
133
0
    pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
134
0
        self.0.subject_public_key_info()
135
0
    }
Unexecuted instantiation: <rustls::webpki::verify::ParsedCertificate>::subject_public_key_info
Unexecuted instantiation: <rustls::webpki::verify::ParsedCertificate>::subject_public_key_info
136
}
137
138
impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
139
    type Error = Error;
140
0
    fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
141
0
        webpki::EndEntityCert::try_from(value)
142
0
            .map_err(pki_error)
143
0
            .map(ParsedCertificate)
144
0
    }
Unexecuted instantiation: <rustls::webpki::verify::ParsedCertificate as core::convert::TryFrom<&rustls_pki_types::CertificateDer>>::try_from
Unexecuted instantiation: <rustls::webpki::verify::ParsedCertificate as core::convert::TryFrom<&rustls_pki_types::CertificateDer>>::try_from
145
}
146
147
/// Verify a message signature using the `cert` public key and any supported scheme.
148
///
149
/// This function verifies the `dss` signature over `message` using the subject public key from
150
/// `cert`. Since TLS 1.2 doesn't provide enough information to map the `dss.scheme` into a single
151
/// [`SignatureVerificationAlgorithm`], this function will map to several candidates and try each in
152
/// succession until one succeeds or we exhaust all candidates.
153
///
154
/// See [WebPkiSupportedAlgorithms::mapping] for more information.
155
0
pub fn verify_tls12_signature(
156
0
    message: &[u8],
157
0
    cert: &CertificateDer<'_>,
158
0
    dss: &DigitallySignedStruct,
159
0
    supported_schemes: &WebPkiSupportedAlgorithms,
160
0
) -> Result<HandshakeSignatureValid, Error> {
161
0
    let possible_algs = supported_schemes.convert_scheme(dss.scheme)?;
162
0
    let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
163
164
0
    let mut error = None;
165
0
    for alg in possible_algs {
166
0
        match cert.verify_signature(*alg, message, dss.signature()) {
167
0
            Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKeyContext(_)) => {
168
0
                error = Some(err);
169
0
                continue;
170
            }
171
0
            Err(e) => return Err(pki_error(e)),
172
0
            Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
173
        }
174
    }
175
176
    #[allow(deprecated)] // The `unwrap_or()` should be statically unreachable
177
0
    Err(pki_error(error.unwrap_or(
178
0
        webpki::Error::UnsupportedSignatureAlgorithmForPublicKey,
179
0
    )))
180
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_tls12_signature
Unexecuted instantiation: rustls::webpki::verify::verify_tls12_signature
181
182
/// Verify a message signature using the `cert` public key and the first TLS 1.3 compatible
183
/// supported scheme.
184
///
185
/// This function verifies the `dss` signature over `message` using the subject public key from
186
/// `cert`. Unlike [verify_tls12_signature], this function only tries the first matching scheme. See
187
/// [WebPkiSupportedAlgorithms::mapping] for more information.
188
0
pub fn verify_tls13_signature(
189
0
    msg: &[u8],
190
0
    cert: &CertificateDer<'_>,
191
0
    dss: &DigitallySignedStruct,
192
0
    supported_schemes: &WebPkiSupportedAlgorithms,
193
0
) -> Result<HandshakeSignatureValid, Error> {
194
0
    if !dss.scheme.supported_in_tls13() {
195
0
        return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
196
0
    }
197
198
0
    let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
199
200
0
    let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
201
202
0
    cert.verify_signature(alg, msg, dss.signature())
203
0
        .map_err(pki_error)
204
0
        .map(|_| HandshakeSignatureValid::assertion())
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature::{closure#0}
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature::{closure#0}
205
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature
206
207
/// Verify a message signature using a raw public key and the first TLS 1.3 compatible
208
/// supported scheme.
209
0
pub fn verify_tls13_signature_with_raw_key(
210
0
    msg: &[u8],
211
0
    spki: &SubjectPublicKeyInfoDer<'_>,
212
0
    dss: &DigitallySignedStruct,
213
0
    supported_schemes: &WebPkiSupportedAlgorithms,
214
0
) -> Result<HandshakeSignatureValid, Error> {
215
0
    if !dss.scheme.supported_in_tls13() {
216
0
        return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
217
0
    }
218
219
0
    let raw_key = webpki::RawPublicKeyEntity::try_from(spki).map_err(pki_error)?;
220
0
    let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
221
222
0
    raw_key
223
0
        .verify_signature(alg, msg, dss.signature())
224
0
        .map_err(pki_error)
225
0
        .map(|_| HandshakeSignatureValid::assertion())
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature_with_raw_key::{closure#0}
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature_with_raw_key::{closure#0}
226
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature_with_raw_key
Unexecuted instantiation: rustls::webpki::verify::verify_tls13_signature_with_raw_key
227
228
/// Verify that the end-entity certificate `end_entity` is a valid server cert
229
/// and chains to at least one of the trust anchors in the `roots` [RootCertStore].
230
///
231
/// `intermediates` contains all certificates other than `end_entity` that
232
/// were sent as part of the server's `Certificate` message. It is in the
233
/// same order that the server sent them and may be empty.
234
///
235
/// `revocation` controls how revocation checking is performed, if at all.
236
///
237
/// This function exists to be used by [`verify_server_cert_signed_by_trust_anchor`],
238
/// and differs only in providing a `Option<webpki::RevocationOptions>` argument. We
239
/// can't include this argument in `verify_server_cert_signed_by_trust_anchor` because
240
/// it will leak the webpki types into Rustls' public API.
241
0
pub(crate) fn verify_server_cert_signed_by_trust_anchor_impl(
242
0
    cert: &ParsedCertificate<'_>,
243
0
    roots: &RootCertStore,
244
0
    intermediates: &[CertificateDer<'_>],
245
0
    revocation: Option<webpki::RevocationOptions<'_>>,
246
0
    now: UnixTime,
247
0
    supported_algs: &[&dyn SignatureVerificationAlgorithm],
248
0
) -> Result<(), Error> {
249
0
    let result = cert.0.verify_for_usage(
250
0
        supported_algs,
251
0
        &roots.roots,
252
0
        intermediates,
253
0
        now,
254
0
        webpki::KeyUsage::server_auth(),
255
0
        revocation,
256
0
        None,
257
    );
258
0
    match result {
259
0
        Ok(_) => Ok(()),
260
0
        Err(e) => Err(pki_error(e)),
261
    }
262
0
}
Unexecuted instantiation: rustls::webpki::verify::verify_server_cert_signed_by_trust_anchor_impl
Unexecuted instantiation: rustls::webpki::verify::verify_server_cert_signed_by_trust_anchor_impl
263
264
#[cfg(test)]
265
mod tests {
266
    use std::format;
267
268
    use super::*;
269
270
    #[test]
271
    fn certificate_debug() {
272
        assert_eq!(
273
            "CertificateDer(0x6162)",
274
            format!("{:?}", CertificateDer::from(b"ab".to_vec()))
275
        );
276
    }
277
278
    #[cfg(feature = "ring")]
279
    #[test]
280
    fn webpki_supported_algorithms_is_debug() {
281
        assert_eq!(
282
            "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [ECDSA_NISTP384_SHA384, ECDSA_NISTP256_SHA256, ED25519, RSA_PSS_SHA512, RSA_PSS_SHA384, RSA_PSS_SHA256, RSA_PKCS1_SHA512, RSA_PKCS1_SHA384, RSA_PKCS1_SHA256] }",
283
            format!(
284
                "{:?}",
285
                crate::crypto::ring::default_provider().signature_verification_algorithms
286
            )
287
        );
288
    }
289
}