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