1use alloc::vec::Vec;
2use core::fmt;
3use core::hash::{Hash, Hasher};
4
5use pki_types::{
6 CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
7};
8use webpki::ExtendedKeyUsage;
9
10use super::anchors::RootCertStore;
11use super::pki_error;
12use crate::crypto::SignatureScheme;
13use crate::error::{ApiMisuse, Error, PeerMisbehaved};
14use crate::verify::{HandshakeSignatureValid, SignatureVerificationInput, SignerPublicKey};
15
16pub 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#[expect(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
127impl Hash for WebPkiSupportedAlgorithms {
128 fn hash<H: Hasher>(&self, state: &mut H) {
129 let Self { all, mapping } = self;
130
131 write_algs(state, all);
132 state.write_usize(mapping.len());
133 for (scheme, algs) in *mapping {
134 state.write_u16(u16::from(*scheme));
135 write_algs(state, algs);
136 }
137
138 fn write_algs<H: Hasher>(
139 state: &mut H,
140 algs: &[&'static dyn SignatureVerificationAlgorithm],
141 ) {
142 state.write_usize(algs.len());
143 for alg in algs {
144 state.write(alg.public_key_alg_id().as_ref());
145 state.write(alg.signature_alg_id().as_ref());
146 }
147 }
148 }
149}
150
151pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
155
156impl ParsedCertificate<'_> {
157 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
159 self.0.subject_public_key_info()
160 }
161}
162
163impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
164 type Error = Error;
165 fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
166 webpki::EndEntityCert::try_from(value)
167 .map_err(pki_error)
168 .map(ParsedCertificate)
169 }
170}
171
172pub fn verify_tls12_signature(
181 input: &SignatureVerificationInput<'_>,
182 supported_schemes: &WebPkiSupportedAlgorithms,
183) -> Result<HandshakeSignatureValid, Error> {
184 let possible_algs = supported_schemes.convert_scheme(input.signature.scheme)?;
185 let cert = match input.signer {
186 SignerPublicKey::X509(cert_der) => {
187 webpki::EndEntityCert::try_from(*cert_der).map_err(pki_error)?
188 }
189 SignerPublicKey::RawPublicKey(_) => {
190 return Err(ApiMisuse::InvalidSignerForProtocolVersion.into());
191 }
192 };
193
194 let mut error = None;
195 for alg in possible_algs {
196 match cert.verify_signature(*alg, input.message, input.signature.signature()) {
197 Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) => {
198 error = Some(err);
199 continue;
200 }
201 Err(e) => return Err(pki_error(e)),
202 Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
203 }
204 }
205
206 Err(match error {
207 Some(e) => pki_error(e),
208 None => Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms),
209 })
210}
211
212pub fn verify_tls13_signature(
219 input: &SignatureVerificationInput<'_>,
220 supported_schemes: &WebPkiSupportedAlgorithms,
221) -> Result<HandshakeSignatureValid, Error> {
222 if !input
223 .signature
224 .scheme
225 .supported_in_tls13()
226 {
227 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
228 }
229
230 let alg = supported_schemes.convert_scheme(input.signature.scheme)?[0];
231 match input.signer {
232 SignerPublicKey::X509(cert_der) => {
233 webpki::EndEntityCert::try_from(*cert_der).and_then(|cert| {
234 cert.verify_signature(alg, input.message, input.signature.signature())
235 })
236 }
237 SignerPublicKey::RawPublicKey(spki) => webpki::RawPublicKeyEntity::try_from(*spki)
238 .and_then(|rpk| rpk.verify_signature(alg, input.message, input.signature.signature())),
239 }
240 .map_err(pki_error)
241 .map(|_| HandshakeSignatureValid::assertion())
242}
243
244pub(crate) fn verify_identity_signed_by_trust_anchor_impl(
258 cert: &ParsedCertificate<'_>,
259 roots: &RootCertStore,
260 intermediates: &[CertificateDer<'_>],
261 revocation: Option<webpki::RevocationOptions<'_>>,
262 now: UnixTime,
263 supported_algs: &[&dyn SignatureVerificationAlgorithm],
264) -> Result<(), Error> {
265 let result = cert.0.verify_for_usage(
266 supported_algs,
267 &roots.roots,
268 intermediates,
269 now,
270 &ExtendedKeyUsage::server_auth(),
271 revocation,
272 None,
273 );
274 match result {
275 Ok(_) => Ok(()),
276 Err(e) => Err(pki_error(e)),
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use std::format;
283
284 use super::*;
285
286 #[test]
287 fn certificate_debug() {
288 assert_eq!(
289 "CertificateDer(0x6162)",
290 format!("{:?}", CertificateDer::from(b"ab".to_vec()))
291 );
292 }
293
294 #[test]
295 fn webpki_supported_algorithms_is_debug() {
296 assert_eq!(
297 "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [] }",
298 format!(
299 "{:?}",
300 WebPkiSupportedAlgorithms {
301 all: &[],
302 mapping: &[]
303 }
304 )
305 );
306 }
307}