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    let possible_algs = supported_schemes.convert_scheme(dss.scheme)?;
162    let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
163
164    let mut error = None;
165    for alg in possible_algs {
166        match cert.verify_signature(*alg, message, dss.signature()) {
167            Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKeyContext(_)) => {
168                error = Some(err);
169                continue;
170            }
171            Err(e) => return Err(pki_error(e)),
172            Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
173        }
174    }
175
176    #[allow(deprecated)] Err(pki_error(error.unwrap_or(
178        webpki::Error::UnsupportedSignatureAlgorithmForPublicKey,
179    )))
180}
181
182pub fn verify_tls13_signature(
189    msg: &[u8],
190    cert: &CertificateDer<'_>,
191    dss: &DigitallySignedStruct,
192    supported_schemes: &WebPkiSupportedAlgorithms,
193) -> Result<HandshakeSignatureValid, Error> {
194    if !dss.scheme.supported_in_tls13() {
195        return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
196    }
197
198    let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
199
200    let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?;
201
202    cert.verify_signature(alg, msg, dss.signature())
203        .map_err(pki_error)
204        .map(|_| HandshakeSignatureValid::assertion())
205}
206
207pub fn verify_tls13_signature_with_raw_key(
210    msg: &[u8],
211    spki: &SubjectPublicKeyInfoDer<'_>,
212    dss: &DigitallySignedStruct,
213    supported_schemes: &WebPkiSupportedAlgorithms,
214) -> Result<HandshakeSignatureValid, Error> {
215    if !dss.scheme.supported_in_tls13() {
216        return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
217    }
218
219    let raw_key = webpki::RawPublicKeyEntity::try_from(spki).map_err(pki_error)?;
220    let alg = supported_schemes.convert_scheme(dss.scheme)?[0];
221
222    raw_key
223        .verify_signature(alg, msg, dss.signature())
224        .map_err(pki_error)
225        .map(|_| HandshakeSignatureValid::assertion())
226}
227
228pub(crate) fn verify_server_cert_signed_by_trust_anchor_impl(
242    cert: &ParsedCertificate<'_>,
243    roots: &RootCertStore,
244    intermediates: &[CertificateDer<'_>],
245    revocation: Option<webpki::RevocationOptions<'_>>,
246    now: UnixTime,
247    supported_algs: &[&dyn SignatureVerificationAlgorithm],
248) -> Result<(), Error> {
249    let result = cert.0.verify_for_usage(
250        supported_algs,
251        &roots.roots,
252        intermediates,
253        now,
254        webpki::KeyUsage::server_auth(),
255        revocation,
256        None,
257    );
258    match result {
259        Ok(_) => Ok(()),
260        Err(e) => Err(pki_error(e)),
261    }
262}
263
264#[cfg(test)]
265mod tests {
266    use std::format;
267
268    use super::*;
269
270    #[test]
271    fn certificate_debug() {
272        assert_eq!(
273            "CertificateDer(0x6162)",
274            format!("{:?}", CertificateDer::from(b"ab".to_vec()))
275        );
276    }
277
278    #[cfg(feature = "ring")]
279    #[test]
280    fn webpki_supported_algorithms_is_debug() {
281        assert_eq!(
282            "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] }",
283            format!(
284                "{:?}",
285                crate::crypto::ring::default_provider().signature_verification_algorithms
286            )
287        );
288    }
289}