1#[cfg(feature = "client")]
5pub(crate) mod client;
6pub(crate) mod codec;
7pub mod config;
8pub mod conn;
9pub(crate) mod engine;
10pub(crate) mod keyschedule;
11pub(crate) mod record;
12pub(crate) mod server;
13#[cfg(feature = "tls12")]
14pub mod tls12;
15#[cfg(all(feature = "tls12", feature = "client"))]
16pub(crate) mod client12;
17#[cfg(feature = "tls12")]
18pub(crate) mod server12;
19
20use crate::crypto::sha2::HashAlg;
21use crate::crypto::{p256, rng, x25519};
22use crate::keys::{EcCurve, PrivateKey, PublicKey};
23use crate::x509::CertError;
24use std::fmt;
25
26pub(crate) mod content {
27 pub const CHANGE_CIPHER_SPEC: u8 = 20;
28 pub const ALERT: u8 = 21;
29 pub const HANDSHAKE: u8 = 22;
30 pub const APPLICATION_DATA: u8 = 23;
31}
32
33pub(crate) mod hs {
34 #[cfg(feature = "tls12")]
35 pub const HELLO_REQUEST: u8 = 0;
36 pub const CLIENT_HELLO: u8 = 1;
37 pub const SERVER_HELLO: u8 = 2;
38 pub const NEW_SESSION_TICKET: u8 = 4;
39 pub const END_OF_EARLY_DATA: u8 = 5;
40 pub const ENCRYPTED_EXTENSIONS: u8 = 8;
41 pub const CERTIFICATE: u8 = 11;
42 pub const CERTIFICATE_REQUEST: u8 = 13;
43 pub const CERTIFICATE_VERIFY: u8 = 15;
44 pub const FINISHED: u8 = 20;
45 pub const KEY_UPDATE: u8 = 24;
46 #[cfg(feature = "tls12")]
47 pub const SERVER_KEY_EXCHANGE: u8 = 12;
48 #[cfg(feature = "tls12")]
49 pub const SERVER_HELLO_DONE: u8 = 14;
50 #[cfg(feature = "tls12")]
51 pub const CLIENT_KEY_EXCHANGE: u8 = 16;
52 #[cfg(all(feature = "tls12", any(feature = "client", feature = "revocation")))]
53 pub const CERTIFICATE_STATUS: u8 = 22;
54 pub const MESSAGE_HASH: u8 = 254;
55}
56
57pub(crate) mod ext {
58 pub const SERVER_NAME: u16 = 0;
59 pub const SUPPORTED_GROUPS: u16 = 10;
60 pub const SIGNATURE_ALGORITHMS: u16 = 13;
61 pub const ALPN: u16 = 16;
62 pub const PRE_SHARED_KEY: u16 = 41;
63 pub const EARLY_DATA: u16 = 42;
64 pub const SUPPORTED_VERSIONS: u16 = 43;
65 #[cfg(feature = "client")]
66 pub const COOKIE: u16 = 44;
67 pub const PSK_KEY_EXCHANGE_MODES: u16 = 45;
68 pub const CERTIFICATE_AUTHORITIES: u16 = 47;
69 pub const KEY_SHARE: u16 = 51;
70 pub const QUIC_TRANSPORT_PARAMETERS: u16 = 0x39;
71 #[cfg(any(all(feature = "tls12", feature = "client"), feature = "revocation"))]
72 pub const STATUS_REQUEST: u16 = 5;
73 #[cfg(feature = "tls12")]
74 pub const EC_POINT_FORMATS: u16 = 11;
75 #[cfg(feature = "tls12")]
76 pub const EXTENDED_MASTER_SECRET: u16 = 23;
77 #[cfg(feature = "tls12")]
78 pub const SESSION_TICKET: u16 = 35;
79 #[cfg(feature = "tls12")]
80 pub const RENEGOTIATION_INFO: u16 = 0xff01;
81}
82
83pub mod alert {
85 pub const CLOSE_NOTIFY: u8 = 0;
86 pub const UNEXPECTED_MESSAGE: u8 = 10;
87 pub const BAD_RECORD_MAC: u8 = 20;
88 pub const RECORD_OVERFLOW: u8 = 22;
89 pub const HANDSHAKE_FAILURE: u8 = 40;
90 pub const BAD_CERTIFICATE: u8 = 42;
91 pub const UNSUPPORTED_CERTIFICATE: u8 = 43;
92 pub const CERTIFICATE_REVOKED: u8 = 44;
93 pub const CERTIFICATE_EXPIRED: u8 = 45;
94 pub const CERTIFICATE_UNKNOWN: u8 = 46;
95 pub const ILLEGAL_PARAMETER: u8 = 47;
96 pub const UNKNOWN_CA: u8 = 48;
97 pub const DECODE_ERROR: u8 = 50;
98 pub const DECRYPT_ERROR: u8 = 51;
99 pub const PROTOCOL_VERSION: u8 = 70;
100 pub const INAPPROPRIATE_FALLBACK: u8 = 86;
101 pub const INTERNAL_ERROR: u8 = 80;
102 pub const USER_CANCELED: u8 = 90;
103 pub const NO_RENEGOTIATION: u8 = 100;
104 pub const MISSING_EXTENSION: u8 = 109;
105 pub const UNSUPPORTED_EXTENSION: u8 = 110;
106 pub const UNRECOGNIZED_NAME: u8 = 112;
107 pub const BAD_CERTIFICATE_STATUS_RESPONSE: u8 = 113;
108 pub const CERTIFICATE_REQUIRED: u8 = 116;
109 pub const NO_APPLICATION_PROTOCOL: u8 = 120;
110
111 pub fn name(code: u8) -> &'static str {
113 match code {
114 0 => "close_notify",
115 10 => "unexpected_message",
116 20 => "bad_record_mac",
117 22 => "record_overflow",
118 40 => "handshake_failure",
119 42 => "bad_certificate",
120 43 => "unsupported_certificate",
121 44 => "certificate_revoked",
122 45 => "certificate_expired",
123 46 => "certificate_unknown",
124 47 => "illegal_parameter",
125 48 => "unknown_ca",
126 49 => "access_denied",
127 50 => "decode_error",
128 51 => "decrypt_error",
129 70 => "protocol_version",
130 71 => "insufficient_security",
131 80 => "internal_error",
132 86 => "inappropriate_fallback",
133 90 => "user_canceled",
134 100 => "no_renegotiation",
135 109 => "missing_extension",
136 110 => "unsupported_extension",
137 112 => "unrecognized_name",
138 113 => "bad_certificate_status_response",
139 116 => "certificate_required",
140 120 => "no_application_protocol",
141 _ => "unknown_alert",
142 }
143 }
144}
145
146#[derive(Clone, Debug, PartialEq, Eq)]
148pub enum Error {
149 Protocol { alert: u8, reason: std::borrow::Cow<'static, str> },
151 PeerAlert(u8),
153 Certificate(CertError),
155 Config(String),
157 Closed,
159}
160
161impl Error {
162 pub(crate) fn proto(alert: u8, reason: impl Into<std::borrow::Cow<'static, str>>) -> Error {
163 Error::Protocol { alert, reason: reason.into() }
164 }
165 #[cold]
166 #[inline(never)]
167 pub(crate) fn decode(what: &str) -> Error {
168 Error::proto(alert::DECODE_ERROR, format!("malformed {what}"))
169 }
170 #[cold]
171 #[inline(never)]
172 pub(crate) fn unexpected(what: &str) -> Error {
173 Error::proto(alert::UNEXPECTED_MESSAGE, format!("unexpected {what}"))
174 }
175 pub fn alert(&self) -> Option<u8> {
177 match self {
178 Error::Protocol { alert, .. } => Some(*alert),
179 Error::PeerAlert(a) => Some(*a),
180 Error::Certificate(c) => Some(match c {
181 CertError::Expired { .. } | CertError::NotYetValid { .. } => alert::CERTIFICATE_EXPIRED,
182 CertError::UnknownIssuer { .. } => alert::UNKNOWN_CA,
183 CertError::Parse(_) | CertError::BadSignature { .. } => alert::BAD_CERTIFICATE,
184 CertError::NoCertificates => alert::CERTIFICATE_REQUIRED,
185 CertError::Revoked { .. } => alert::CERTIFICATE_REVOKED,
186 CertError::RevocationUnknown { .. } => alert::BAD_CERTIFICATE_STATUS_RESPONSE,
187 _ => alert::CERTIFICATE_UNKNOWN,
188 }),
189 Error::Config(_) => Some(alert::INTERNAL_ERROR),
190 Error::Closed => None,
191 }
192 }
193 pub(crate) fn alert_to_send(&self) -> Option<u8> {
195 match self {
196 Error::PeerAlert(_) | Error::Closed => None,
197 e => e.alert(),
198 }
199 }
200}
201
202impl fmt::Display for Error {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 match self {
205 Error::Protocol { alert: a, reason } => write!(f, "TLS protocol error: {reason} (alert {})", alert::name(*a)),
206 Error::PeerAlert(a) => write!(f, "TLS alert from peer: {} ({a})", alert::name(*a)),
207 Error::Certificate(c) => write!(f, "TLS certificate error: {c}"),
208 Error::Config(m) => write!(f, "TLS configuration error: {m}"),
209 Error::Closed => f.write_str("TLS connection closed"),
210 }
211 }
212}
213
214impl std::error::Error for Error {}
215
216impl From<CertError> for Error {
217 fn from(e: CertError) -> Error {
218 Error::Certificate(e)
219 }
220}
221
222pub type Result<T> = std::result::Result<T, Error>;
223
224#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
226pub enum ProtocolVersion {
227 Tls12,
229 Tls13,
231}
232
233impl ProtocolVersion {
234 pub fn name(self) -> &'static str {
236 match self {
237 ProtocolVersion::Tls12 => "TLSv1.2",
238 ProtocolVersion::Tls13 => "TLSv1.3",
239 }
240 }
241 pub fn parse(s: &str) -> Option<ProtocolVersion> {
243 let v = s.trim().to_ascii_lowercase();
244 let v = v.trim_start_matches("tlsv").trim_start_matches("tls");
245 match v.trim_start_matches(['v', '_', '-']) {
246 "1.2" | "12" | "1_2" => Some(ProtocolVersion::Tls12),
247 "1.3" | "13" | "1_3" => Some(ProtocolVersion::Tls13),
248 _ => None,
249 }
250 }
251}
252
253#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
255pub enum Level {
256 Initial,
258 Handshake,
260 OneRtt,
262}
263
264#[derive(Clone, Copy, Debug, PartialEq, Eq)]
266pub enum CipherSuite {
267 Aes128GcmSha256,
268 Aes256GcmSha384,
269 #[cfg(feature = "chacha20")]
270 Chacha20Poly1305Sha256,
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq)]
275pub enum AeadAlg {
276 Aes128Gcm,
277 Aes256Gcm,
278 #[cfg(feature = "chacha20")]
279 Chacha20Poly1305,
280}
281
282impl AeadAlg {
283 pub fn key_len(self) -> usize {
284 match self {
285 AeadAlg::Aes128Gcm => 16,
286 _ => 32,
287 }
288 }
289}
290
291impl CipherSuite {
292 #[cfg(feature = "chacha20")]
294 pub const ALL: [CipherSuite; 3] = [CipherSuite::Aes128GcmSha256, CipherSuite::Aes256GcmSha384, CipherSuite::Chacha20Poly1305Sha256];
295 #[cfg(not(feature = "chacha20"))]
297 pub const ALL: [CipherSuite; 2] = [CipherSuite::Aes128GcmSha256, CipherSuite::Aes256GcmSha384];
298
299 pub fn default_order() -> Vec<CipherSuite> {
301 #[cfg(feature = "chacha20")]
302 if !(simoom_sys::arch::has_aes() && simoom_sys::arch::has_clmul()) {
303 return vec![CipherSuite::Chacha20Poly1305Sha256, CipherSuite::Aes128GcmSha256, CipherSuite::Aes256GcmSha384];
304 }
305 CipherSuite::ALL.to_vec()
306 }
307 pub fn id(self) -> u16 {
308 match self {
309 CipherSuite::Aes128GcmSha256 => 0x1301,
310 CipherSuite::Aes256GcmSha384 => 0x1302,
311 #[cfg(feature = "chacha20")]
312 CipherSuite::Chacha20Poly1305Sha256 => 0x1303,
313 }
314 }
315 pub fn from_id(id: u16) -> Option<CipherSuite> {
316 CipherSuite::ALL.into_iter().find(|s| s.id() == id)
317 }
318 pub fn name(self) -> &'static str {
320 match self {
321 CipherSuite::Aes128GcmSha256 => "TLS_AES_128_GCM_SHA256",
322 CipherSuite::Aes256GcmSha384 => "TLS_AES_256_GCM_SHA384",
323 #[cfg(feature = "chacha20")]
324 CipherSuite::Chacha20Poly1305Sha256 => "TLS_CHACHA20_POLY1305_SHA256",
325 }
326 }
327 pub fn hash(self) -> HashAlg {
328 match self {
329 CipherSuite::Aes256GcmSha384 => HashAlg::Sha384,
330 _ => HashAlg::Sha256,
331 }
332 }
333 pub fn aead(self) -> AeadAlg {
334 match self {
335 CipherSuite::Aes128GcmSha256 => AeadAlg::Aes128Gcm,
336 CipherSuite::Aes256GcmSha384 => AeadAlg::Aes256Gcm,
337 #[cfg(feature = "chacha20")]
338 CipherSuite::Chacha20Poly1305Sha256 => AeadAlg::Chacha20Poly1305,
339 }
340 }
341}
342
343#[derive(Clone, Copy, Debug, PartialEq, Eq)]
345pub enum NamedGroup {
346 X25519,
347 Secp256r1,
348 #[cfg(feature = "p384")]
351 Secp384r1,
352}
353
354impl NamedGroup {
355 pub const ALL: [NamedGroup; 2] = [NamedGroup::X25519, NamedGroup::Secp256r1];
357 pub fn id(self) -> u16 {
358 match self {
359 NamedGroup::X25519 => 0x001d,
360 NamedGroup::Secp256r1 => 0x0017,
361 #[cfg(feature = "p384")]
362 NamedGroup::Secp384r1 => 0x0018,
363 }
364 }
365 pub fn from_id(id: u16) -> Option<NamedGroup> {
366 match id {
367 0x001d => Some(NamedGroup::X25519),
368 0x0017 => Some(NamedGroup::Secp256r1),
369 #[cfg(feature = "p384")]
370 0x0018 => Some(NamedGroup::Secp384r1),
371 _ => None,
372 }
373 }
374 pub fn name(self) -> &'static str {
376 match self {
377 NamedGroup::X25519 => "x25519",
378 NamedGroup::Secp256r1 => "secp256r1",
379 #[cfg(feature = "p384")]
380 NamedGroup::Secp384r1 => "secp384r1",
381 }
382 }
383}
384
385pub(crate) struct KeyShare {
387 pub group: NamedGroup,
388 private: [u8; 48],
389 pub public: Vec<u8>,
390}
391
392impl Drop for KeyShare {
393 fn drop(&mut self) {
394 crate::util::zeroize(&mut self.private);
395 }
396}
397
398impl KeyShare {
399 pub fn generate(group: NamedGroup) -> KeyShare {
400 match group {
401 NamedGroup::X25519 => {
402 let mut sk = rng::array::<32>();
403 let public = x25519::x25519_base(&sk).to_vec();
404 let private = Self::pad(&sk);
405 crate::util::zeroize(&mut sk);
406 KeyShare { group, public, private }
407 }
408 NamedGroup::Secp256r1 => {
409 let mut sk = p256::generate_private();
410 let public = p256::public_key(&sk).expect("valid scalar").to_vec();
411 let private = Self::pad(&sk);
412 crate::util::zeroize(&mut sk);
413 KeyShare { group, public, private }
414 }
415 #[cfg(feature = "p384")]
416 NamedGroup::Secp384r1 => {
417 let mut sk = crate::crypto::ec::p384::generate_private();
418 let public = crate::crypto::ec::p384::public_key(&sk).expect("valid scalar");
419 let mut private = [0u8; 48];
420 private.copy_from_slice(&sk);
421 crate::util::zeroize(&mut sk);
422 KeyShare { group, public, private }
423 }
424 }
425 }
426
427 fn pad(sk: &[u8]) -> [u8; 48] {
428 let mut p = [0u8; 48];
429 p[..sk.len()].copy_from_slice(sk);
430 p
431 }
432
433 pub fn agree(&self, peer: &[u8]) -> Result<Vec<u8>> {
435 let bad = || Error::proto(alert::ILLEGAL_PARAMETER, "invalid key share");
436 match self.group {
437 NamedGroup::X25519 => {
438 let p: [u8; 32] = peer.try_into().map_err(|_| bad())?;
439 let sk: &[u8; 32] = self.private[..32].try_into().expect("32 bytes");
440 x25519::agree(sk, &p).map(|s| s.to_vec()).ok_or_else(bad)
441 }
442 NamedGroup::Secp256r1 => {
443 let sk: &[u8; 32] = self.private[..32].try_into().expect("32 bytes");
444 p256::ecdh(sk, peer).map(|s| s.to_vec()).ok_or_else(bad)
445 }
446 #[cfg(feature = "p384")]
447 NamedGroup::Secp384r1 => crate::crypto::ec::p384::ecdh(&self.private, peer).ok_or_else(bad),
448 }
449 }
450}
451
452#[allow(dead_code)] pub(crate) mod sigscheme {
455 pub const RSA_PKCS1_SHA256: u16 = 0x0401;
456 pub const RSA_PKCS1_SHA384: u16 = 0x0501;
457 pub const RSA_PKCS1_SHA512: u16 = 0x0601;
458 pub const ECDSA_SECP256R1_SHA256: u16 = 0x0403;
459 pub const ECDSA_SECP384R1_SHA384: u16 = 0x0503;
460 pub const RSA_PSS_RSAE_SHA256: u16 = 0x0804;
461 pub const RSA_PSS_RSAE_SHA384: u16 = 0x0805;
462 pub const RSA_PSS_RSAE_SHA512: u16 = 0x0806;
463 pub const ED25519: u16 = 0x0807;
464
465 pub const SUPPORTED: &[u16] = &[
468 #[cfg(feature = "ed25519")]
469 ED25519,
470 ECDSA_SECP256R1_SHA256,
471 #[cfg(feature = "p384")]
472 ECDSA_SECP384R1_SHA384,
473 #[cfg(feature = "rsa")]
474 RSA_PSS_RSAE_SHA256,
475 #[cfg(feature = "rsa")]
476 RSA_PSS_RSAE_SHA384,
477 #[cfg(feature = "rsa")]
478 RSA_PSS_RSAE_SHA512,
479 #[cfg(feature = "rsa")]
480 RSA_PKCS1_SHA256,
481 #[cfg(feature = "rsa")]
482 RSA_PKCS1_SHA384,
483 #[cfg(feature = "rsa")]
484 RSA_PKCS1_SHA512,
485 ];
486}
487
488fn scheme_hash(scheme: u16) -> Option<HashAlg> {
489 use sigscheme::*;
490 match scheme {
491 ECDSA_SECP256R1_SHA256 | RSA_PSS_RSAE_SHA256 => Some(HashAlg::Sha256),
492 ECDSA_SECP384R1_SHA384 | RSA_PSS_RSAE_SHA384 => Some(HashAlg::Sha384),
493 RSA_PSS_RSAE_SHA512 => Some(HashAlg::Sha512),
494 _ => None,
495 }
496}
497
498pub(crate) fn choose_scheme(key: &PrivateKey, offered: &[u16]) -> Option<u16> {
500 use sigscheme::*;
501 let candidates: &[u16] = match key {
502 PrivateKey::Ec { curve: EcCurve::P256, .. } => &[ECDSA_SECP256R1_SHA256],
503 #[cfg(feature = "p384")]
504 PrivateKey::Ec { curve: EcCurve::P384, .. } => &[ECDSA_SECP384R1_SHA384],
505 #[cfg(feature = "ed25519")]
506 PrivateKey::Ed25519 { .. } => &[ED25519],
507 #[cfg(feature = "rsa")]
508 PrivateKey::Rsa(_) => &[RSA_PSS_RSAE_SHA256, RSA_PSS_RSAE_SHA384, RSA_PSS_RSAE_SHA512],
509 };
510 candidates.iter().copied().find(|c| offered.contains(c))
511}
512
513pub(crate) fn sign_message(key: &PrivateKey, scheme: u16, message: &[u8]) -> Result<Vec<u8>> {
515 let fail = || Error::proto(alert::INTERNAL_ERROR, "signing failed");
516 #[cfg(feature = "ed25519")]
517 if let PrivateKey::Ed25519 { seed, public } = key {
518 return Ok(crate::crypto::ed25519::sign_with_public(seed, public, message).to_vec());
519 }
520 let h = scheme_hash(scheme).ok_or_else(fail)?;
521 let digest = h.hash(message);
522 match key {
523 PrivateKey::Ec { curve, d, .. } => {
524 curve.sign(d, &digest, h).map(|(r, s)| crate::keys::ecdsa_sig_to_der(&r, &s)).ok_or_else(fail)
525 }
526 #[cfg(feature = "rsa")]
527 PrivateKey::Rsa(k) => k.sign_pss(h, &digest).ok_or_else(fail),
528 #[cfg(feature = "ed25519")]
529 PrivateKey::Ed25519 { .. } => Err(fail()),
530 }
531}
532
533pub(crate) fn verify_message(key: &PublicKey, scheme: u16, message: &[u8], sig: &[u8]) -> Result<()> {
536 use sigscheme::*;
537 let fail = || Error::proto(alert::DECRYPT_ERROR, "handshake signature verification failed");
538 let mismatch = || Error::proto(alert::ILLEGAL_PARAMETER, "signature scheme does not match the key");
539 let ok = match (key, scheme) {
540 #[cfg(feature = "ed25519")]
541 (PublicKey::Ed25519(k), ED25519) => crate::crypto::ed25519::verify(k, message, sig),
542 (PublicKey::Ec { curve, point }, ECDSA_SECP256R1_SHA256 | ECDSA_SECP384R1_SHA384) => {
543 if (scheme == ECDSA_SECP256R1_SHA256) != (*curve == EcCurve::P256) {
544 return Err(mismatch());
545 }
546 let h = scheme_hash(scheme).unwrap();
547 match crate::keys::ecdsa_sig_from_der(sig) {
548 Some((r, s)) => curve.verify(point, &h.hash(message), &r, &s),
549 None => false,
550 }
551 }
552 #[cfg(feature = "rsa")]
553 (PublicKey::Rsa(k), RSA_PSS_RSAE_SHA256 | RSA_PSS_RSAE_SHA384 | RSA_PSS_RSAE_SHA512) => {
554 let h = scheme_hash(scheme).unwrap();
555 k.verify_pss(h, &h.hash(message), sig, Some(h.output_len()))
556 }
557 _ => return Err(mismatch()),
558 };
559 if ok {
560 Ok(())
561 } else {
562 Err(fail())
563 }
564}
565
566pub(crate) fn cv_content(server: bool, transcript_hash: &[u8]) -> Vec<u8> {
568 let mut m = vec![0x20u8; 64];
569 m.extend_from_slice(if server { b"TLS 1.3, server CertificateVerify" } else { b"TLS 1.3, client CertificateVerify" });
570 m.push(0);
571 m.extend_from_slice(transcript_hash);
572 m
573}
574
575pub(crate) const HRR_RANDOM: [u8; 32] = [
577 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a,
578 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
579];
580
581pub(crate) struct PeerCheck<'a> {
583 pub roots: &'a crate::x509::RootStore,
584 pub now: i64,
586 pub eku: &'a str,
587 #[cfg(feature = "revocation")]
588 pub revocation: Option<&'a crate::revocation::RevocationPolicy>,
589 #[cfg(feature = "revocation")]
590 pub staple: Option<&'a [u8]>,
591}
592
593impl PeerCheck<'_> {
594 pub fn verify(&self, certs: &[Vec<u8>], host: Option<&str>) -> Result<PublicKey> {
598 #[cfg(feature = "revocation")]
599 if let Some(policy) = self.revocation {
600 let path = crate::x509::verify_chain_path(certs, host, self.roots, self.now, self.eku)?;
601 crate::revocation::check_path(&path, policy, self.now, self.staple)?;
602 return path
603 .into_iter()
604 .next()
605 .and_then(|leaf| leaf.public_key)
606 .ok_or_else(|| Error::proto(alert::UNSUPPORTED_CERTIFICATE, "unsupported certificate key"));
607 }
608 crate::x509::verify_chain(certs, host, self.roots, self.now, self.eku)?
609 .public_key
610 .ok_or_else(|| Error::proto(alert::UNSUPPORTED_CERTIFICATE, "unsupported certificate key"))
611 }
612}