1use alloc::vec::Vec;
2use core::fmt;
3
4use pki_types::{
5 CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
6};
7use webpki::ExtendedKeyUsage;
8
9use super::anchors::RootCertStore;
10use super::pki_error;
11use crate::enums::SignatureScheme;
12use crate::error::{ApiMisuse, Error, PeerMisbehaved};
13use crate::verify::{HandshakeSignatureValid, SignatureVerificationInput, SignerPublicKey};
14
15#[allow(dead_code)]
27pub fn verify_identity_signed_by_trust_anchor(
28 cert: &ParsedCertificate<'_>,
29 roots: &RootCertStore,
30 intermediates: &[CertificateDer<'_>],
31 now: UnixTime,
32 supported_algs: &[&dyn SignatureVerificationAlgorithm],
33) -> Result<(), Error> {
34 verify_identity_signed_by_trust_anchor_impl(
35 cert,
36 roots,
37 intermediates,
38 None, now,
40 supported_algs,
41 )
42}
43
44pub fn verify_server_name(
49 cert: &ParsedCertificate<'_>,
50 server_name: &ServerName<'_>,
51) -> Result<(), Error> {
52 cert.0
53 .verify_is_valid_for_subject_name(server_name)
54 .map_err(pki_error)
55}
56
57#[allow(clippy::exhaustive_structs)]
60#[derive(Clone, Copy)]
61pub struct WebPkiSupportedAlgorithms {
62 pub all: &'static [&'static dyn SignatureVerificationAlgorithm],
68
69 pub mapping: &'static [(
81 SignatureScheme,
82 &'static [&'static dyn SignatureVerificationAlgorithm],
83 )],
84}
85
86impl WebPkiSupportedAlgorithms {
87 pub fn supported_schemes(&self) -> Vec<SignatureScheme> {
89 self.mapping
90 .iter()
91 .map(|item| item.0)
92 .collect()
93 }
94
95 fn convert_scheme(
97 &self,
98 scheme: SignatureScheme,
99 ) -> Result<&[&'static dyn SignatureVerificationAlgorithm], Error> {
100 self.mapping
101 .iter()
102 .filter_map(|item| if item.0 == scheme { Some(item.1) } else { None })
103 .next()
104 .ok_or_else(|| PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into())
105 }
106
107 pub fn fips(&self) -> bool {
109 self.all.iter().all(|alg| alg.fips())
110 && self
111 .mapping
112 .iter()
113 .all(|item| item.1.iter().all(|alg| alg.fips()))
114 }
115}
116
117impl fmt::Debug for WebPkiSupportedAlgorithms {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 write!(f, "WebPkiSupportedAlgorithms {{ all: [ .. ], mapping: ")?;
120 f.debug_list()
121 .entries(self.mapping.iter().map(|item| item.0))
122 .finish()?;
123 write!(f, " }}")
124 }
125}
126
127pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
131
132impl ParsedCertificate<'_> {
133 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
135 self.0.subject_public_key_info()
136 }
137}
138
139impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
140 type Error = Error;
141 fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
142 webpki::EndEntityCert::try_from(value)
143 .map_err(pki_error)
144 .map(ParsedCertificate)
145 }
146}
147
148pub fn verify_tls12_signature(
157 input: &SignatureVerificationInput<'_>,
158 supported_schemes: &WebPkiSupportedAlgorithms,
159) -> Result<HandshakeSignatureValid, Error> {
160 let possible_algs = supported_schemes.convert_scheme(input.signature.scheme)?;
161 let cert = match input.signer {
162 SignerPublicKey::X509(cert_der) => {
163 webpki::EndEntityCert::try_from(*cert_der).map_err(pki_error)?
164 }
165 SignerPublicKey::RawPublicKey(_) => {
166 return Err(ApiMisuse::InvalidSignerForProtocolVersion.into());
167 }
168 };
169
170 let mut error = None;
171 for alg in possible_algs {
172 match cert.verify_signature(*alg, input.message, input.signature.signature()) {
173 Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) => {
174 error = Some(err);
175 continue;
176 }
177 Err(e) => return Err(pki_error(e)),
178 Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
179 }
180 }
181
182 Err(match error {
183 Some(e) => pki_error(e),
184 None => Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms),
185 })
186}
187
188pub fn verify_tls13_signature(
195 input: &SignatureVerificationInput<'_>,
196 supported_schemes: &WebPkiSupportedAlgorithms,
197) -> Result<HandshakeSignatureValid, Error> {
198 if !input
199 .signature
200 .scheme
201 .supported_in_tls13()
202 {
203 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
204 }
205
206 let alg = supported_schemes.convert_scheme(input.signature.scheme)?[0];
207 match input.signer {
208 SignerPublicKey::X509(cert_der) => {
209 webpki::EndEntityCert::try_from(*cert_der).and_then(|cert| {
210 cert.verify_signature(alg, input.message, input.signature.signature())
211 })
212 }
213 SignerPublicKey::RawPublicKey(spki) => webpki::RawPublicKeyEntity::try_from(*spki)
214 .and_then(|rpk| rpk.verify_signature(alg, input.message, input.signature.signature())),
215 }
216 .map_err(pki_error)
217 .map(|_| HandshakeSignatureValid::assertion())
218}
219
220pub(crate) fn verify_identity_signed_by_trust_anchor_impl(
234 cert: &ParsedCertificate<'_>,
235 roots: &RootCertStore,
236 intermediates: &[CertificateDer<'_>],
237 revocation: Option<webpki::RevocationOptions<'_>>,
238 now: UnixTime,
239 supported_algs: &[&dyn SignatureVerificationAlgorithm],
240) -> Result<(), Error> {
241 let result = cert.0.verify_for_usage(
242 supported_algs,
243 &roots.roots,
244 intermediates,
245 now,
246 &ExtendedKeyUsage::server_auth(),
247 revocation,
248 None,
249 );
250 match result {
251 Ok(_) => Ok(()),
252 Err(e) => Err(pki_error(e)),
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use std::format;
259
260 use super::*;
261
262 #[test]
263 fn certificate_debug() {
264 assert_eq!(
265 "CertificateDer(0x6162)",
266 format!("{:?}", CertificateDer::from(b"ab".to_vec()))
267 );
268 }
269
270 #[cfg(feature = "ring")]
271 #[test]
272 fn webpki_supported_algorithms_is_debug() {
273 assert_eq!(
274 "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] }",
275 format!(
276 "{:?}",
277 crate::crypto::ring::DEFAULT_PROVIDER.signature_verification_algorithms
278 )
279 );
280 }
281}