1use crate::TlsError;
2use crate::config::{Certificate, TlsCipherSuite, TlsClock, TlsVerifier};
3use crate::extensions::extension_data::signature_algorithms::SignatureScheme;
4use crate::handshake::{
5 certificate::{
6 Certificate as OwnedCertificate, CertificateEntryRef, CertificateRef as ServerCertificate,
7 },
8 certificate_verify::CertificateVerifyRef,
9};
10use core::marker::PhantomData;
11use digest::Digest;
12use heapless::Vec;
13#[cfg(all(not(feature = "alloc"), feature = "webpki"))]
14impl TryInto<&'static webpki::SignatureAlgorithm> for SignatureScheme {
15 type Error = TlsError;
16 fn try_into(self) -> Result<&'static webpki::SignatureAlgorithm, Self::Error> {
17 #[allow(clippy::match_same_arms)] match self {
20 SignatureScheme::RsaPkcs1Sha256
21 | SignatureScheme::RsaPkcs1Sha384
22 | SignatureScheme::RsaPkcs1Sha512 => Err(TlsError::InvalidSignatureScheme),
23
24 SignatureScheme::EcdsaSecp256r1Sha256 => Ok(&webpki::ECDSA_P256_SHA256),
26 SignatureScheme::EcdsaSecp384r1Sha384 => Ok(&webpki::ECDSA_P384_SHA384),
27 SignatureScheme::EcdsaSecp521r1Sha512 => Err(TlsError::InvalidSignatureScheme),
28
29 SignatureScheme::RsaPssRsaeSha256
31 | SignatureScheme::RsaPssRsaeSha384
32 | SignatureScheme::RsaPssRsaeSha512 => Err(TlsError::InvalidSignatureScheme),
33
34 SignatureScheme::Ed25519 => Ok(&webpki::ED25519),
36 SignatureScheme::Ed448
37 | SignatureScheme::Sha224Ecdsa
38 | SignatureScheme::Sha224Rsa
39 | SignatureScheme::Sha224Dsa => Err(TlsError::InvalidSignatureScheme),
40
41 SignatureScheme::RsaPssPssSha256
43 | SignatureScheme::RsaPssPssSha384
44 | SignatureScheme::RsaPssPssSha512 => Err(TlsError::InvalidSignatureScheme),
45
46 SignatureScheme::RsaPkcs1Sha1 | SignatureScheme::EcdsaSha1 => {
48 Err(TlsError::InvalidSignatureScheme)
49 }
50
51 SignatureScheme::MlDsa44 | SignatureScheme::MlDsa65 | SignatureScheme::MlDsa87 => {
53 Err(TlsError::InvalidSignatureScheme)
54 }
55
56 SignatureScheme::Sha256BrainpoolP256r1
58 | SignatureScheme::Sha384BrainpoolP384r1
59 | SignatureScheme::Sha512BrainpoolP512r1 => Err(TlsError::InvalidSignatureScheme),
60 }
61 }
62}
63
64#[cfg(all(feature = "alloc", feature = "webpki"))]
65impl TryInto<&'static webpki::SignatureAlgorithm> for SignatureScheme {
66 type Error = TlsError;
67 fn try_into(self) -> Result<&'static webpki::SignatureAlgorithm, Self::Error> {
68 match self {
69 SignatureScheme::RsaPkcs1Sha256 => Ok(&webpki::RSA_PKCS1_2048_8192_SHA256),
70 SignatureScheme::RsaPkcs1Sha384 => Ok(&webpki::RSA_PKCS1_2048_8192_SHA384),
71 SignatureScheme::RsaPkcs1Sha512 => Ok(&webpki::RSA_PKCS1_2048_8192_SHA512),
72
73 SignatureScheme::EcdsaSecp256r1Sha256 => Ok(&webpki::ECDSA_P256_SHA256),
75 SignatureScheme::EcdsaSecp384r1Sha384 => Ok(&webpki::ECDSA_P384_SHA384),
76 SignatureScheme::EcdsaSecp521r1Sha512 => Err(TlsError::InvalidSignatureScheme),
77
78 SignatureScheme::RsaPssRsaeSha256 => Ok(&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY),
80 SignatureScheme::RsaPssRsaeSha384 => Ok(&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY),
81 SignatureScheme::RsaPssRsaeSha512 => Ok(&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY),
82
83 SignatureScheme::Ed25519 => Ok(&webpki::ED25519),
85 SignatureScheme::Ed448 => Err(TlsError::InvalidSignatureScheme),
86
87 SignatureScheme::Sha224Ecdsa => Err(TlsError::InvalidSignatureScheme),
88 SignatureScheme::Sha224Rsa => Err(TlsError::InvalidSignatureScheme),
89 SignatureScheme::Sha224Dsa => Err(TlsError::InvalidSignatureScheme),
90
91 SignatureScheme::RsaPssPssSha256 => Err(TlsError::InvalidSignatureScheme),
93 SignatureScheme::RsaPssPssSha384 => Err(TlsError::InvalidSignatureScheme),
94 SignatureScheme::RsaPssPssSha512 => Err(TlsError::InvalidSignatureScheme),
95
96 SignatureScheme::RsaPkcs1Sha1 => Err(TlsError::InvalidSignatureScheme),
98 SignatureScheme::EcdsaSha1 => Err(TlsError::InvalidSignatureScheme),
99
100 SignatureScheme::MlDsa44 => Err(TlsError::InvalidSignatureScheme),
102 SignatureScheme::MlDsa65 => Err(TlsError::InvalidSignatureScheme),
103 SignatureScheme::MlDsa87 => Err(TlsError::InvalidSignatureScheme),
104
105 SignatureScheme::Sha256BrainpoolP256r1 => Err(TlsError::InvalidSignatureScheme),
107 SignatureScheme::Sha384BrainpoolP384r1 => Err(TlsError::InvalidSignatureScheme),
108 SignatureScheme::Sha512BrainpoolP512r1 => Err(TlsError::InvalidSignatureScheme),
109 }
110 }
111}
112
113static ALL_SIGALGS: &[&webpki::SignatureAlgorithm] = &[
114 &webpki::ECDSA_P256_SHA256,
115 &webpki::ECDSA_P256_SHA384,
116 &webpki::ECDSA_P384_SHA256,
117 &webpki::ECDSA_P384_SHA384,
118 &webpki::ED25519,
119];
120
121pub struct CertVerifier<'a, CipherSuite, Clock, const CERT_SIZE: usize>
122where
123 Clock: TlsClock,
124 CipherSuite: TlsCipherSuite,
125{
126 ca: Certificate<&'a [u8]>,
127 host: Option<heapless::String<64>>,
128 certificate_transcript: Option<CipherSuite::Hash>,
129 certificate: Option<OwnedCertificate<CERT_SIZE>>,
130 _clock: PhantomData<Clock>,
131}
132
133impl<'a, CipherSuite, Clock, const CERT_SIZE: usize> CertVerifier<'a, CipherSuite, Clock, CERT_SIZE>
134where
135 Clock: TlsClock,
136 CipherSuite: TlsCipherSuite,
137{
138 #[must_use]
139 pub fn new(ca: Certificate<&'a [u8]>) -> Self {
140 Self {
141 ca,
142 host: None,
143 certificate_transcript: None,
144 certificate: None,
145 _clock: PhantomData,
146 }
147 }
148}
149
150impl<CipherSuite, Clock, const CERT_SIZE: usize> TlsVerifier<CipherSuite>
151 for CertVerifier<'_, CipherSuite, Clock, CERT_SIZE>
152where
153 CipherSuite: TlsCipherSuite,
154 Clock: TlsClock,
155{
156 fn set_hostname_verification(&mut self, hostname: &str) -> Result<(), TlsError> {
157 self.host.replace(
158 heapless::String::try_from(hostname).map_err(|_| TlsError::InsufficientSpace)?,
159 );
160 Ok(())
161 }
162
163 fn verify_certificate(
164 &mut self,
165 transcript: &CipherSuite::Hash,
166 cert: ServerCertificate,
167 ) -> Result<(), TlsError> {
168 verify_certificate(self.host.as_deref(), &self.ca, &cert, Clock::now())?;
169 self.certificate.replace(cert.try_into()?);
170 self.certificate_transcript.replace(transcript.clone());
171 Ok(())
172 }
173
174 fn verify_signature(&mut self, verify: CertificateVerifyRef) -> Result<(), TlsError> {
175 let handshake_hash = unwrap!(self.certificate_transcript.take());
176 let ctx_str = b"TLS 1.3, server CertificateVerify\x00";
177 let mut msg: Vec<u8, 130> = Vec::new();
178 msg.resize(64, 0x20).map_err(|_| TlsError::EncodeError)?;
179 msg.extend_from_slice(ctx_str)
180 .map_err(|_| TlsError::EncodeError)?;
181 msg.extend_from_slice(&handshake_hash.finalize())
182 .map_err(|_| TlsError::EncodeError)?;
183
184 let certificate = unwrap!(self.certificate.as_ref()).try_into()?;
185 verify_signature(&msg[..], &certificate, &verify)?;
186 Ok(())
187 }
188}
189
190fn verify_signature(
191 message: &[u8],
192 certificate: &ServerCertificate,
193 verify: &CertificateVerifyRef,
194) -> Result<(), TlsError> {
195 let mut verified = false;
196 if !certificate.entries.is_empty() {
197 if let CertificateEntryRef::X509(certificate) = certificate.entries[0] {
199 let cert = webpki::EndEntityCert::try_from(certificate).map_err(|e| {
200 warn!("Error loading cert: {:?}", e);
201 TlsError::DecodeError
202 })?;
203
204 trace!(
205 "Verifying with signature scheme {:?}",
206 verify.signature_scheme
207 );
208 info!("Signature: {:x?}", verify.signature);
209 let pkisig = verify.signature_scheme.try_into()?;
210 match cert.verify_signature(pkisig, message, verify.signature) {
211 Ok(()) => {
212 verified = true;
213 }
214 Err(e) => {
215 info!("Error verifying signature: {:?}", e);
216 }
217 }
218 }
219 }
220 if !verified {
221 return Err(TlsError::InvalidSignature);
222 }
223 Ok(())
224}
225
226fn verify_certificate(
227 verify_host: Option<&str>,
228 ca: &Certificate<&[u8]>,
229 certificate: &ServerCertificate,
230 now: Option<u64>,
231) -> Result<(), TlsError> {
232 let mut verified = false;
233 let mut host_verified = false;
234 if let Certificate::X509(ca) = ca {
235 let trust = webpki::TrustAnchor::try_from_cert_der(ca).map_err(|e| {
236 warn!("Error loading CA: {:?}", e);
237 TlsError::DecodeError
238 })?;
239
240 trace!("We got {} certificate entries", certificate.entries.len());
241
242 if !certificate.entries.is_empty() {
243 if let CertificateEntryRef::X509(certificate) = certificate.entries[0] {
245 let cert = webpki::EndEntityCert::try_from(certificate).map_err(|e| {
246 warn!("Error loading cert: {:?}", e);
247 TlsError::DecodeError
248 })?;
249
250 let time = if let Some(now) = now {
251 webpki::Time::from_seconds_since_unix_epoch(now)
252 } else {
253 webpki::Time::from_seconds_since_unix_epoch(0)
255 };
256 info!("Certificate is loaded!");
257 match cert.verify_for_usage(
258 ALL_SIGALGS,
259 &[trust],
260 &[],
261 time,
262 webpki::KeyUsage::server_auth(),
263 &[],
264 ) {
265 Ok(()) => verified = true,
266 Err(e) => {
267 warn!("Error verifying certificate: {:?}", e);
268 }
269 }
270
271 if let Some(server_name) = verify_host {
272 match webpki::SubjectNameRef::try_from_ascii(server_name.as_bytes()) {
273 Ok(subject) => match cert.verify_is_valid_for_subject_name(subject) {
274 Ok(()) => host_verified = true,
275 Err(e) => {
276 warn!("Error verifying host: {:?}", e);
277 }
278 },
279 Err(e) => {
280 warn!("Error verifying host: {:?}", e);
281 }
282 }
283 }
284 }
285 }
286 }
287
288 if !verified {
289 return Err(TlsError::InvalidCertificate);
290 }
291
292 if !host_verified && verify_host.is_some() {
293 return Err(TlsError::InvalidCertificate);
294 }
295 Ok(())
296}