Skip to main content

simoom_tls/tls/
mod.rs

1//! TLS 1.3 (RFC 8446): the sans-io handshake engine shared by the record-layer connections and
2//! the QUIC interface, plus the record layer itself.
3
4#[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
83/// TLS alert descriptions (RFC 8446 section 6).
84pub 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    /// The RFC name of an alert.
112    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/// A TLS error.
147#[derive(Clone, Debug, PartialEq, Eq)]
148pub enum Error {
149    /// A protocol violation detected locally; `alert` is sent to the peer.
150    Protocol { alert: u8, reason: std::borrow::Cow<'static, str> },
151    /// The peer sent a fatal alert.
152    PeerAlert(u8),
153    /// The peer's certificate failed validation.
154    Certificate(CertError),
155    /// Invalid configuration or API misuse.
156    Config(String),
157    /// The connection is closed.
158    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    /// The alert this error sends to the peer (or the one the peer sent).
176    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    /// The alert to send for a locally detected error (None for peer alerts).
194    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/// A negotiated protocol version.
225#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
226pub enum ProtocolVersion {
227    /// TLS 1.2 (RFC 5246), only with the `tls12` feature.
228    Tls12,
229    /// TLS 1.3 (RFC 8446).
230    Tls13,
231}
232
233impl ProtocolVersion {
234    /// The name Java and Camel use (`TLSv1.2`, `TLSv1.3`).
235    pub fn name(self) -> &'static str {
236        match self {
237            ProtocolVersion::Tls12 => "TLSv1.2",
238            ProtocolVersion::Tls13 => "TLSv1.3",
239        }
240    }
241    /// Parses `TLSv1.2`, `TLSv1.3`, `1.2`, `TLS1.3` and similar spellings.
242    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/// Encryption level of handshake data (RFC 9001 terms; the record layer uses the same three).
254#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
255pub enum Level {
256    /// Plaintext (QUIC Initial packets).
257    Initial,
258    /// Handshake traffic keys.
259    Handshake,
260    /// Application traffic keys.
261    OneRtt,
262}
263
264/// TLS 1.3 cipher suites.
265#[derive(Clone, Copy, Debug, PartialEq, Eq)]
266pub enum CipherSuite {
267    Aes128GcmSha256,
268    Aes256GcmSha384,
269    #[cfg(feature = "chacha20")]
270    Chacha20Poly1305Sha256,
271}
272
273/// The AEAD of a cipher suite.
274#[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    /// Every suite, in the default server preference when the CPU has AES instructions.
293    #[cfg(feature = "chacha20")]
294    pub const ALL: [CipherSuite; 3] = [CipherSuite::Aes128GcmSha256, CipherSuite::Aes256GcmSha384, CipherSuite::Chacha20Poly1305Sha256];
295    /// Every suite, in the default server preference.
296    #[cfg(not(feature = "chacha20"))]
297    pub const ALL: [CipherSuite; 2] = [CipherSuite::Aes128GcmSha256, CipherSuite::Aes256GcmSha384];
298
299    /// The default preference: AES-GCM first with hardware AES, ChaCha20-Poly1305 first without.
300    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    /// The IANA name, such as `TLS_AES_128_GCM_SHA256`.
319    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/// Key-exchange groups.
344#[derive(Clone, Copy, Debug, PartialEq, Eq)]
345pub enum NamedGroup {
346    X25519,
347    Secp256r1,
348    /// secp384r1 (feature `p384`): not in the default lists; add it to `groups` to offer or
349    /// accept it.
350    #[cfg(feature = "p384")]
351    Secp384r1,
352}
353
354impl NamedGroup {
355    /// The default groups, in preference order.
356    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    /// The IANA name (`x25519`, `secp256r1`, `secp384r1`).
375    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
385/// An ephemeral key pair.
386pub(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    /// The shared secret; fails for invalid peer keys.
434    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/// Signature schemes (RFC 8446 section 4.2.3).
453#[allow(dead_code)] // some are unused without the rsa or ed25519 features
454pub(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    /// What we offer and accept in signature_algorithms. PKCS#1 v1.5 is listed because it
466    /// also covers certificate signatures; it is never accepted in CertificateVerify.
467    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
498/// The signature scheme for `key` among the peer's offered schemes.
499pub(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
513/// Signs a CertificateVerify message.
514pub(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
533/// Verifies a CertificateVerify signature. ECDSA schemes are bound to their curve and PKCS#1
534/// v1.5 is refused, as TLS 1.3 requires.
535pub(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
566/// The content signed in CertificateVerify (RFC 8446 section 4.4.3).
567pub(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
575/// The fixed ServerHello.random of a HelloRetryRequest.
576pub(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
581/// How a peer's certificate chain is checked (shared by both versions and both sides).
582pub(crate) struct PeerCheck<'a> {
583    pub roots: &'a crate::x509::RootStore,
584    /// Unix seconds.
585    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    /// Validates the chain (and its revocation status, when a policy is set) and returns the
595    /// leaf's public key. `host` is an argument rather than a field, so that a server-only build
596    /// (every caller passes `None`) leaves the hostname checks out.
597    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}