1use alloc::vec::Vec;
2use core::fmt;
3
4use pki_types::{
5 CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
6};
7
8use super::anchors::RootCertStore;
9use super::pki_error;
10use crate::enums::SignatureScheme;
11use crate::error::{Error, PeerMisbehaved};
12use crate::verify::{DigitallySignedStruct, HandshakeSignatureValid};
13
14#[allow(dead_code)]
26pub fn verify_server_cert_signed_by_trust_anchor(
27 cert: &ParsedCertificate<'_>,
28 roots: &RootCertStore,
29 intermediates: &[CertificateDer<'_>],
30 now: UnixTime,
31 supported_algs: &[&dyn SignatureVerificationAlgorithm],
32) -> Result<(), Error> {
33 verify_server_cert_signed_by_trust_anchor_impl(
34 cert,
35 roots,
36 intermediates,
37 None, now,
39 supported_algs,
40 )
41}
42
43pub fn verify_server_name(
48 cert: &ParsedCertificate<'_>,
49 server_name: &ServerName<'_>,
50) -> Result<(), Error> {
51 cert.0
52 .verify_is_valid_for_subject_name(server_name)
53 .map_err(pki_error)
54}
55
56#[derive(Clone, Copy)]
59#[allow(unreachable_pub)]
60pub struct WebPkiSupportedAlgorithms {
61 pub all: &'static [&'static dyn SignatureVerificationAlgorithm],
67
68 pub mapping: &'static [(
80 SignatureScheme,
81 &'static [&'static dyn SignatureVerificationAlgorithm],
82 )],
83}
84
85impl WebPkiSupportedAlgorithms {
86 pub fn supported_schemes(&self) -> Vec<SignatureScheme> {
88 self.mapping
89 .iter()
90 .map(|item| item.0)
91 .collect()
92 }
93
94 fn convert_scheme(
96 &self,
97 scheme: SignatureScheme,
98 ) -> Result<&[&'static dyn SignatureVerificationAlgorithm], Error> {
99 self.mapping
100 .iter()
101 .filter_map(|item| if item.0 == scheme { Some(item.1) } else { None })
102 .next()
103 .ok_or_else(|| PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into())
104 }
105
106 pub fn fips(&self) -> bool {
108 self.all.iter().all(|alg| alg.fips())
109 && self
110 .mapping
111 .iter()
112 .all(|item| item.1.iter().all(|alg| alg.fips()))
113 }
114}
115
116impl fmt::Debug for WebPkiSupportedAlgorithms {
117 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118 write!(f, "WebPkiSupportedAlgorithms {{ all: [ .. ], mapping: ")?;
119 f.debug_list()
120 .entries(self.mapping.iter().map(|item| item.0))
121 .finish()?;
122 write!(f, " }}")
123 }
124}
125
126pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
130
131impl ParsedCertificate<'_> {
132 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
134 self.0.subject_public_key_info()
135 }
136}
137
138impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
139 type Error = Error;
140 fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
141 webpki::EndEntityCert::try_from(value)
142 .map_err(pki_error)
143 .map(ParsedCertificate)
144 }
145}
146
147pub fn verify_tls12_signature(
156 message: &[u8],
157 cert: &CertificateDer<'_>,
158 dss: &DigitallySignedStruct,
159 supported_schemes: &WebPkiSupportedAlgorithms,
160) -> Result<HandshakeSignatureValid, Error> {
161 if dss.scheme.algorithm().is_none() {
162 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
163 }
164
165 let possible_algs = supported_schemes.convert_scheme(dss.scheme)?;
166 let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
167
168 let mut error = None;
169 for alg in possible_algs {
170 match cert.verify_signature(*alg, message, dss.signature()) {
171 Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKeyContext(_)) => {
172 error = Some(err);
173 continue;
174 }
175 Err(e) => return Err(pki_error(e)),
176 Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
177 }
178 }
179
180 #[allow(deprecated)] Err(pki_error(error.unwrap_or(
182 webpki::Error::UnsupportedSignatureAlgorithmForPublicKey,
183 )))
184}
185
186pub fn verify_tls13_signature(
193 msg: &[u8],
194 cert: &CertificateDer<'_>,
195 dss: &DigitallySignedStruct,
196 supported_schemes: &WebPkiSupportedAlgorithms,
197) -> Result<HandshakeSignatureValid, Error> {
198 if !dss.scheme.supported_in_tls13() {
199 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
200 }
201
202 let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
203
204 let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
205
206 cert.verify_signature(alg, msg, dss.signature())
207 .map_err(pki_error)
208 .map(|_| HandshakeSignatureValid::assertion())
209}
210
211pub fn verify_tls13_signature_with_raw_key(
214 msg: &[u8],
215 spki: &SubjectPublicKeyInfoDer<'_>,
216 dss: &DigitallySignedStruct,
217 supported_schemes: &WebPkiSupportedAlgorithms,
218) -> Result<HandshakeSignatureValid, Error> {
219 if !dss.scheme.supported_in_tls13() {
220 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
221 }
222
223 let raw_key = webpki::RawPublicKeyEntity::try_from(spki).map_err(pki_error)?;
224 let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
225
226 raw_key
227 .verify_signature(alg, msg, dss.signature())
228 .map_err(pki_error)
229 .map(|_| HandshakeSignatureValid::assertion())
230}
231
232pub(crate) fn verify_server_cert_signed_by_trust_anchor_impl(
246 cert: &ParsedCertificate<'_>,
247 roots: &RootCertStore,
248 intermediates: &[CertificateDer<'_>],
249 revocation: Option<webpki::RevocationOptions<'_>>,
250 now: UnixTime,
251 supported_algs: &[&dyn SignatureVerificationAlgorithm],
252) -> Result<(), Error> {
253 let result = cert.0.verify_for_usage(
254 supported_algs,
255 &roots.roots,
256 intermediates,
257 now,
258 webpki::KeyUsage::server_auth(),
259 revocation,
260 None,
261 );
262 match result {
263 Ok(_) => Ok(()),
264 Err(e) => Err(pki_error(e)),
265 }
266}
267
268#[cfg(test)]
269mod tests {
270 use std::format;
271
272 use super::*;
273
274 #[test]
275 fn certificate_debug() {
276 assert_eq!(
277 "CertificateDer(0x6162)",
278 format!("{:?}", CertificateDer::from(b"ab".to_vec()))
279 );
280 }
281
282 #[cfg(feature = "ring")]
283 #[test]
284 fn webpki_supported_algorithms_is_debug() {
285 assert_eq!(
286 "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] }",
287 format!(
288 "{:?}",
289 crate::crypto::ring::default_provider().signature_verification_algorithms
290 )
291 );
292 }
293}