Skip to main content

rustls/webpki/
verify.rs

1use pki_types::{
2    CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
3};
4use webpki::ExtendedKeyUsage;
5
6use super::anchors::RootCertStore;
7use super::pki_error;
8use crate::crypto::WebPkiSupportedAlgorithms;
9use crate::error::{ApiMisuse, Error, PeerMisbehaved};
10use crate::verify::{HandshakeSignatureValid, SignatureVerificationInput, SignerPublicKey};
11
12/// Verify that the end-entity certificate `end_entity` is a valid server cert
13/// and chains to at least one of the trust anchors in the `roots` [RootCertStore].
14///
15/// This function is primarily useful when building a custom certificate verifier. It
16/// performs **no revocation checking**. Implementers must handle this themselves,
17/// along with checking that the server certificate is valid for the subject name
18/// being used (see [`verify_server_name`]).
19///
20/// `intermediates` contains all certificates other than `end_entity` that
21/// were sent as part of the server's `Certificate` message. It is in the
22/// same order that the server sent them and may be empty.
23pub fn verify_identity_signed_by_trust_anchor(
24    cert: &ParsedCertificate<'_>,
25    roots: &RootCertStore,
26    intermediates: &[CertificateDer<'_>],
27    now: UnixTime,
28    supported_algs: &[&dyn SignatureVerificationAlgorithm],
29) -> Result<(), Error> {
30    verify_identity_signed_by_trust_anchor_impl(
31        cert,
32        roots,
33        intermediates,
34        None, // No revocation checking supported with this API.
35        now,
36        supported_algs,
37    )
38}
39
40/// Verify that the `end_entity` has an alternative name matching the `server_name`.
41///
42/// Note: this only verifies the name and should be used in conjunction with more verification
43/// like [verify_identity_signed_by_trust_anchor]
44pub fn verify_server_name(
45    cert: &ParsedCertificate<'_>,
46    server_name: &ServerName<'_>,
47) -> Result<(), Error> {
48    cert.0
49        .verify_is_valid_for_subject_name(server_name)
50        .map_err(pki_error)
51}
52
53/// Wrapper around internal representation of a parsed certificate.
54///
55/// This is used in order to avoid parsing twice when specifying custom verification
56pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
57
58impl ParsedCertificate<'_> {
59    /// Get the parsed certificate's SubjectPublicKeyInfo (SPKI)
60    pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
61        self.0.subject_public_key_info()
62    }
63}
64
65impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
66    type Error = Error;
67    fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
68        webpki::EndEntityCert::try_from(value)
69            .map_err(pki_error)
70            .map(ParsedCertificate)
71    }
72}
73
74/// Verify a message signature using the `cert` public key and any supported scheme.
75///
76/// This function verifies the `dss` signature over `message` using the subject public key from
77/// `cert`. Since TLS 1.2 doesn't provide enough information to map the `dss.scheme` into a single
78/// [`SignatureVerificationAlgorithm`], this function will map to several candidates and try each in
79/// succession until one succeeds or we exhaust all candidates.
80///
81/// See [`WebPkiSupportedAlgorithms::mapping()`] for more information.
82pub fn verify_tls12_signature(
83    input: &SignatureVerificationInput<'_>,
84    supported_schemes: &WebPkiSupportedAlgorithms,
85) -> Result<HandshakeSignatureValid, Error> {
86    let possible_algs = supported_schemes.convert_scheme(input.signature.scheme)?;
87    let cert = match input.signer {
88        SignerPublicKey::X509(cert_der) => {
89            webpki::EndEntityCert::try_from(*cert_der).map_err(pki_error)?
90        }
91        SignerPublicKey::RawPublicKey(_) => {
92            return Err(ApiMisuse::InvalidSignerForProtocolVersion.into());
93        }
94    };
95
96    let mut error = None;
97    for alg in possible_algs {
98        match cert.verify_signature(*alg, input.message, input.signature.signature()) {
99            Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) => {
100                error = Some(err);
101                continue;
102            }
103            Err(e) => return Err(pki_error(e)),
104            Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
105        }
106    }
107
108    Err(match error {
109        Some(e) => pki_error(e),
110        None => Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms),
111    })
112}
113
114/// Verify a message signature using the `cert` public key and the first TLS 1.3 compatible
115/// supported scheme.
116///
117/// This function verifies the `dss` signature over `message` using the subject public key from
118/// `cert`. Unlike [`verify_tls12_signature()`], this function only tries the first matching scheme. See
119/// [`WebPkiSupportedAlgorithms::mapping()`] for more information.
120pub fn verify_tls13_signature(
121    input: &SignatureVerificationInput<'_>,
122    supported_schemes: &WebPkiSupportedAlgorithms,
123) -> Result<HandshakeSignatureValid, Error> {
124    if !input
125        .signature
126        .scheme
127        .supported_in_tls13()
128    {
129        return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
130    }
131
132    let &alg = supported_schemes
133        .convert_scheme(input.signature.scheme)?
134        .first()
135        .ok_or(Error::ApiMisuse(
136            ApiMisuse::NoSignatureVerificationAlgorithms,
137        ))?;
138
139    match input.signer {
140        SignerPublicKey::X509(cert_der) => {
141            webpki::EndEntityCert::try_from(*cert_der).and_then(|cert| {
142                cert.verify_signature(alg, input.message, input.signature.signature())
143            })
144        }
145        SignerPublicKey::RawPublicKey(spki) => webpki::RawPublicKeyEntity::try_from(*spki)
146            .and_then(|rpk| rpk.verify_signature(alg, input.message, input.signature.signature())),
147    }
148    .map_err(pki_error)
149    .map(|_| HandshakeSignatureValid::assertion())
150}
151
152/// Verify that the end-entity certificate `end_entity` is a valid server cert
153/// and chains to at least one of the trust anchors in the `roots` [RootCertStore].
154///
155/// `intermediates` contains all certificates other than `end_entity` that
156/// were sent as part of the server's `Certificate` message. It is in the
157/// same order that the server sent them and may be empty.
158///
159/// `revocation` controls how revocation checking is performed, if at all.
160///
161/// This function exists to be used by [`verify_identity_signed_by_trust_anchor`],
162/// and differs only in providing a `Option<webpki::RevocationOptions>` argument. We
163/// can't include this argument in `verify_identity_signed_by_trust_anchor` because
164/// it will leak the webpki types into Rustls' public API.
165pub(crate) fn verify_identity_signed_by_trust_anchor_impl(
166    cert: &ParsedCertificate<'_>,
167    roots: &RootCertStore,
168    intermediates: &[CertificateDer<'_>],
169    revocation: Option<webpki::RevocationOptions<'_>>,
170    now: UnixTime,
171    supported_algs: &[&dyn SignatureVerificationAlgorithm],
172) -> Result<(), Error> {
173    let result = cert.0.verify_for_usage(
174        supported_algs,
175        &roots.roots,
176        intermediates,
177        now,
178        &ExtendedKeyUsage::server_auth(),
179        revocation,
180        None,
181    );
182    match result {
183        Ok(_) => Ok(()),
184        Err(e) => Err(pki_error(e)),
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use alloc::vec;
191    use std::format;
192
193    use super::*;
194    use crate::crypto::{SignatureScheme, TEST_PROVIDER};
195    use crate::verify::DigitallySignedStruct;
196
197    #[test]
198    fn tls13_empty_signature_mapping_panics() {
199        let supported = WebPkiSupportedAlgorithms {
200            all: TEST_PROVIDER
201                .signature_verification_algorithms
202                .all,
203            mapping: &[(SignatureScheme::ED25519, &[])],
204        };
205
206        let cert = CertificateDer::from(vec![0u8]); // never parsed; panic happens first
207        let dss = DigitallySignedStruct::new(SignatureScheme::ED25519, vec![]);
208        let signer = SignerPublicKey::X509(&cert);
209        let input = SignatureVerificationInput {
210            message: b"hello",
211            signer: &signer,
212            signature: &dss,
213        };
214
215        assert_eq!(
216            verify_tls13_signature(&input, &supported).unwrap_err(),
217            Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms)
218        );
219    }
220
221    #[test]
222    fn certificate_debug() {
223        assert_eq!(
224            "CertificateDer(0x6162)",
225            format!("{:?}", CertificateDer::from(b"ab".to_vec()))
226        );
227    }
228
229    #[test]
230    fn webpki_supported_algorithms_is_debug() {
231        assert_eq!(
232            "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [] }",
233            format!(
234                "{:?}",
235                WebPkiSupportedAlgorithms {
236                    all: &[],
237                    mapping: &[]
238                }
239            )
240        );
241    }
242}