1use pki_types::{
2 CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
3};
4use webpki::{ExtendedKeyUsage, PathBuilder};
5
6use super::anchors::RootCertStore;
7use super::pki_error;
8use crate::crypto::WebPkiSupportedAlgorithms;
9use crate::error::{ApiMisuse, Error, PeerMisbehaved};
10use crate::verify::{HandshakeSignatureValid, SignatureVerificationInput, SignerPublicKey};
11
12pub fn verify_identity_signed_by_trust_anchor(
24 cert: &ParsedCertificate<'_>,
25 roots: &RootCertStore,
26 intermediates: &[CertificateDer<'_>],
27 now: UnixTime,
28 supported_algs: &[&dyn SignatureVerificationAlgorithm],
29) -> Result<(), Error> {
30 verify_identity_signed_by_trust_anchor_impl(
31 cert,
32 roots,
33 intermediates,
34 None, now,
36 supported_algs,
37 )
38}
39
40pub fn verify_server_name(
45 cert: &ParsedCertificate<'_>,
46 server_name: &ServerName<'_>,
47) -> Result<(), Error> {
48 cert.0
49 .verify_is_valid_for_subject_name(server_name)
50 .map_err(pki_error)
51}
52
53pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
57
58impl ParsedCertificate<'_> {
59 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
61 self.0.subject_public_key_info()
62 }
63}
64
65impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
66 type Error = Error;
67 fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
68 webpki::EndEntityCert::try_from(value)
69 .map_err(pki_error)
70 .map(ParsedCertificate)
71 }
72}
73
74pub fn verify_tls12_signature(
87 input: &SignatureVerificationInput<'_>,
88 supported_schemes: &WebPkiSupportedAlgorithms,
89) -> Result<HandshakeSignatureValid, Error> {
90 if input
91 .signature
92 .scheme
93 .algorithm()
94 .is_none()
95 {
96 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
97 }
98
99 let possible_algs = supported_schemes.convert_scheme(input.signature.scheme)?;
100 let cert = match input.signer {
101 SignerPublicKey::X509(cert_der) => {
102 webpki::EndEntityCert::try_from(*cert_der).map_err(pki_error)?
103 }
104 SignerPublicKey::RawPublicKey(_) => {
105 return Err(ApiMisuse::InvalidSignerForProtocolVersion.into());
106 }
107 };
108
109 let mut error = None;
110 for alg in possible_algs {
111 match cert.verify_signature(*alg, input.message, input.signature.signature()) {
112 Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) => {
113 error = Some(err);
114 continue;
115 }
116 Err(e) => return Err(pki_error(e)),
117 Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
118 }
119 }
120
121 Err(match error {
122 Some(e) => pki_error(e),
123 None => Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms),
124 })
125}
126
127pub fn verify_tls13_signature(
137 input: &SignatureVerificationInput<'_>,
138 supported_schemes: &WebPkiSupportedAlgorithms,
139) -> Result<HandshakeSignatureValid, Error> {
140 if !input
141 .signature
142 .scheme
143 .supported_in_tls13()
144 {
145 return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
146 }
147
148 let &alg = supported_schemes
149 .convert_scheme(input.signature.scheme)?
150 .first()
151 .ok_or(Error::ApiMisuse(
152 ApiMisuse::NoSignatureVerificationAlgorithms,
153 ))?;
154
155 match input.signer {
156 SignerPublicKey::X509(cert_der) => {
157 webpki::EndEntityCert::try_from(*cert_der).and_then(|cert| {
158 cert.verify_signature(alg, input.message, input.signature.signature())
159 })
160 }
161 SignerPublicKey::RawPublicKey(spki) => webpki::RawPublicKeyEntity::try_from(*spki)
162 .and_then(|rpk| rpk.verify_signature(alg, input.message, input.signature.signature())),
163 }
164 .map_err(pki_error)
165 .map(|_| HandshakeSignatureValid::assertion())
166}
167
168pub(crate) fn verify_identity_signed_by_trust_anchor_impl(
182 cert: &ParsedCertificate<'_>,
183 roots: &RootCertStore,
184 intermediates: &[CertificateDer<'_>],
185 revocation: Option<webpki::RevocationOptions<'_>>,
186 now: UnixTime,
187 supported_algs: &[&dyn SignatureVerificationAlgorithm],
188) -> Result<(), Error> {
189 let result = PathBuilder::new(
190 intermediates,
191 revocation,
192 &ExtendedKeyUsage::SERVER_AUTH,
193 supported_algs,
194 &roots.roots,
195 )
196 .build(&cert.0, now);
197 match result {
198 Ok(_) => Ok(()),
199 Err(e) => Err(pki_error(e)),
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use alloc::vec;
206 use std::format;
207
208 use super::*;
209 use crate::crypto::{SignatureScheme, TEST_PROVIDER};
210 use crate::verify::DigitallySignedStruct;
211
212 #[test]
213 fn tls13_empty_signature_mapping_panics() {
214 let supported = WebPkiSupportedAlgorithms {
215 all: TEST_PROVIDER
216 .signature_verification_algorithms
217 .all,
218 mapping: &[(SignatureScheme::ED25519, &[])],
219 };
220
221 let cert = CertificateDer::from(vec![0u8]); let dss = DigitallySignedStruct::new(SignatureScheme::ED25519, vec![]);
223 let signer = SignerPublicKey::X509(&cert);
224 let input = SignatureVerificationInput {
225 message: b"hello",
226 signer: &signer,
227 signature: &dss,
228 };
229
230 assert_eq!(
231 verify_tls13_signature(&input, &supported).unwrap_err(),
232 Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms)
233 );
234 }
235
236 #[test]
237 fn certificate_debug() {
238 assert_eq!(
239 "CertificateDer(0x6162)",
240 format!("{:?}", CertificateDer::from(b"ab".to_vec()))
241 );
242 }
243
244 #[test]
245 fn webpki_supported_algorithms_is_debug() {
246 assert_eq!(
247 "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [] }",
248 format!(
249 "{:?}",
250 WebPkiSupportedAlgorithms {
251 all: &[],
252 mapping: &[]
253 }
254 )
255 );
256 }
257}