Skip to main content

noxtls/protocol/
connection.rs

1// Copyright (c) 2019-2026, Argenox Technologies LLC
2// All rights reserved.
3//
4// SPDX-License-Identifier: GPL-2.0-only OR LicenseRef-Argenox-Commercial-License
5//
6// This file is part of the NoxTLS Library.
7//
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by the
10// Free Software Foundation; version 2 of the License.
11//
12// Alternatively, this file may be used under the terms of a commercial
13// license from Argenox Technologies LLC.
14//
15// See `noxtls/LICENSE` and `noxtls/LICENSE.md` in this repository for full details.
16// CONTACT: info@argenox.com
17
18use super::dtls::{
19    encode_dtls12_handshake_fragments, encode_dtls_record_packet, open_dtls13_aes128gcm_record,
20    parse_dtls_record_packet, reassemble_dtls12_handshake_fragments, seal_dtls13_aes128gcm_record,
21    DtlsEpochReplayTracker, DtlsFlightRetransmitTracker, DtlsRecordHeader, DtlsReplayWindow,
22    DtlsReplayWindowSnapshot,
23};
24use super::handshake::{encode_handshake_message, parse_handshake_message};
25use super::kdf::{
26    finished_hmac_for_hash, hash_bytes_for_algorithm, hkdf_expand_for_hash, hkdf_extract_for_hash,
27    hkdf_extract_with_salt_for_hash, tls13_expand_label_for_hash, HashAlgorithm,
28};
29use super::keyshare::{
30    derive_deterministic_mlkem768_keypair, derive_deterministic_p256_private,
31    derive_deterministic_x25519_private, derive_tls13_mlkem768_shared_secret,
32    derive_tls13_p256_shared_secret, derive_tls13_x25519_shared_secret,
33    tls13_client_hello_offers_supported_key_exchange,
34};
35use super::psk::{ticket_age_matches_policy, ResumptionTicket, TicketStore, TicketUsagePolicy};
36use super::record::{
37    build_record_nonce, decode_tls12_ciphertext_record, decode_tls13_ciphertext_record,
38    decode_tls13_inner_plaintext, encode_tls12_ciphertext_record, encode_tls13_ciphertext_record,
39    encode_tls13_inner_plaintext,
40};
41use super::state::{
42    AlertDescription, AlertLevel, CipherSuite, HandshakeState, RecordContentType, TlsVersion,
43};
44#[cfg(not(feature = "std"))]
45use crate::internal_alloc::ToOwned;
46use crate::internal_alloc::{String, Vec};
47use noxtls_core::{Error, Result};
48use noxtls_crypto::{
49    aes_gcm_decrypt, aes_gcm_encrypt, chacha20_poly1305_decrypt, chacha20_poly1305_encrypt,
50    ed25519_public_key_from_subject_public_key_info, ed25519_verify, hkdf_extract_sha256,
51    mldsa_verify, p256_ecdsa_verify_sha256, rsassa_pss_sha256_verify, rsassa_pss_sha384_verify,
52    sha256, tls12_prf_sha256, tls12_prf_sha384, AesCipher, HmacDrbgSha256, MlDsaPublicKey,
53    MlKemPrivateKey, P256PrivateKey, P256PublicKey, RsaPublicKey, TlsTranscriptSha256,
54    TlsTranscriptSha384, X25519PrivateKey, MLKEM_CIPHERTEXT_LEN,
55};
56use noxtls_x509::{
57    certificate_matches_hostname, parse_certificate, parse_der_node, parse_ecdsa_signature_der,
58    validate_certificate_chain,
59};
60
61/// Holds connection version, handshake state, and transcript bytes.
62#[derive(Debug, Clone)]
63pub struct Connection {
64    pub version: TlsVersion,
65    pub state: HandshakeState,
66    selected_cipher_suite: Option<CipherSuite>,
67    transcript: Vec<u8>,
68    transcript_hash: TranscriptHashState,
69    handshake_secret: Option<Vec<u8>>,
70    tls13_master_secret: Option<Vec<u8>>,
71    tls13_client_handshake_traffic_secret: Option<Vec<u8>>,
72    tls13_server_handshake_traffic_secret: Option<Vec<u8>>,
73    tls13_finished_key: Option<Vec<u8>>,
74    tls13_client_application_traffic_secret: Option<Vec<u8>>,
75    tls13_server_application_traffic_secret: Option<Vec<u8>>,
76    tls13_exporter_master_secret: Option<Vec<u8>>,
77    tls13_resumption_master_secret: Option<Vec<u8>>,
78    tls13_client_x25519_private: Option<X25519PrivateKey>,
79    tls13_client_p256_private: Option<P256PrivateKey>,
80    tls13_client_mlkem768_private: Option<MlKemPrivateKey>,
81    tls13_shared_secret: Option<[u8; 32]>,
82    tls13_hrr_requested_group: Option<u16>,
83    tls13_hrr_seen: bool,
84    /// Holds up to 32 bytes of AEAD key material (AES-128 uses the first 16; AES-256/ChaCha use 32).
85    client_write_key: Option<[u8; 32]>,
86    server_write_key: Option<[u8; 32]>,
87    client_write_iv: Option<[u8; 12]>,
88    server_write_iv: Option<[u8; 12]>,
89    client_sequence: u64,
90    server_sequence: u64,
91    tls13_peer_close_notify_received: bool,
92    tls13_local_close_notify_sent: bool,
93    tls13_require_certificate_auth: bool,
94    tls13_server_trust_anchors_der: Vec<Vec<u8>>,
95    tls13_server_intermediates_der: Vec<Vec<u8>>,
96    tls13_server_validation_time: Option<String>,
97    tls13_server_expected_hostname: Option<String>,
98    tls13_client_server_name: Option<String>,
99    tls13_request_ocsp_stapling: bool,
100    tls13_require_ocsp_staple: bool,
101    tls13_ocsp_staple_verifier: Option<Tls13OcspStapleVerifier>,
102    tls13_server_ocsp_staple: Option<Vec<u8>>,
103    tls13_server_ocsp_staple_verified: bool,
104    tls13_require_server_name_ack: bool,
105    tls13_server_name_acknowledged: bool,
106    tls13_client_alpn_protocols: Vec<Vec<u8>>,
107    tls13_selected_alpn_protocol: Option<Vec<u8>>,
108    tls13_server_leaf_public_key_der: Option<Vec<u8>>,
109    tls13_server_certificate_chain_validated: bool,
110    tls13_early_data_require_acceptance: bool,
111    tls13_early_data_accepted_psk: Option<Vec<u8>>,
112    tls13_early_data_max_bytes: Option<u32>,
113    tls13_early_data_opened_bytes: u64,
114    tls13_early_data_offered_in_client_hello: bool,
115    tls13_early_data_accepted_in_encrypted_extensions: bool,
116    tls13_early_data_anti_replay_enabled: bool,
117    tls13_early_data_replay_window: DtlsReplayWindow,
118    tls13_early_data_telemetry: Tls13EarlyDataTelemetry,
119    tls12_change_cipher_spec_seen: bool,
120    tls12_session_id: Option<Vec<u8>>,
121    tls12_allow_legacy_record_versions: bool,
122    dtls13_client_write_key: Option<[u8; 16]>,
123    dtls13_client_write_iv: Option<[u8; 12]>,
124    dtls13_server_write_key: Option<[u8; 16]>,
125    dtls13_server_write_iv: Option<[u8; 12]>,
126    dtls13_outbound_epoch: u16,
127    dtls13_outbound_sequence: u64,
128    dtls13_inbound_replay_tracker: DtlsEpochReplayTracker,
129    dtls13_client_inbound_replay_tracker: DtlsEpochReplayTracker,
130    dtls13_active_flight: Vec<(u16, u64)>,
131    dtls13_active_flight_started_at_ms: Option<u64>,
132    dtls13_active_flight_timeout_ms: u64,
133    dtls13_active_flight_failed: bool,
134    dtls_retransmit_tracker: DtlsFlightRetransmitTracker,
135    dtls_retransmit_initial_timeout_ms: u64,
136    dtls_max_retransmit_attempts: u8,
137    dtls12_handshake_phase: Dtls12HandshakePhase,
138    dtls12_expected_cookie: Option<Vec<u8>>,
139    dtls12_anti_amplification_enforced: bool,
140    dtls12_inbound_bytes: u64,
141    dtls12_outbound_bytes: u64,
142    max_record_plaintext_len: usize,
143}
144
145/// Represents one protected TLS record carrying ciphertext and authentication tag.
146#[derive(Debug, Clone)]
147pub struct ProtectedRecord {
148    pub sequence: u64,
149    pub ciphertext: Vec<u8>,
150    pub tag: [u8; 16],
151}
152
153/// Captures transport-facing DTLS retry and timeout knobs.
154#[derive(Debug, Copy, Clone, Eq, PartialEq)]
155pub struct DtlsOperationalPolicy {
156    pub retransmit_initial_timeout_ms: u64,
157    pub max_retransmit_attempts: u8,
158    pub active_flight_timeout_ms: u64,
159}
160
161/// Names pre-tuned DTLS operational profiles for common deployment environments.
162#[derive(Debug, Copy, Clone, Eq, PartialEq)]
163pub enum DtlsOperationalProfile {
164    Conservative,
165    LanLowLatency,
166    LossyNetwork,
167}
168
169/// Captures tunable policy controls for TLS 1.3 modeled early-data handling.
170#[derive(Debug, Copy, Clone, Eq, PartialEq)]
171pub struct Tls13EarlyDataOperationalPolicy {
172    pub require_acceptance: bool,
173    pub anti_replay_enabled: bool,
174}
175
176/// Names pre-tuned operational profiles for TLS 1.3 modeled early-data policy.
177#[derive(Debug, Copy, Clone, Eq, PartialEq)]
178pub enum Tls13EarlyDataOperationalProfile {
179    Compatibility,
180    Strict,
181}
182
183/// Tracks counters for modeled TLS 1.3 early-data accept/reject outcomes.
184#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
185pub struct Tls13EarlyDataTelemetry {
186    pub accepted_records: u64,
187    pub rejected_missing_acceptance: u64,
188    pub rejected_psk_mismatch: u64,
189    pub rejected_replay_or_too_old: u64,
190    pub rejected_invalid_input: u64,
191    pub rejected_decrypt_or_policy: u64,
192}
193
194/// Serializable replay-window state for carrying TLS 1.3 early-data anti-replay continuity.
195#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
196pub struct Tls13EarlyDataReplayState {
197    pub latest_sequence: u64,
198    pub bitmap: u64,
199    pub initialized: bool,
200}
201
202/// Captures QUIC Initial secrets derived from destination connection ID.
203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct Tls13QuicInitialSecrets {
205    pub initial_secret: Vec<u8>,
206    pub client_initial_secret: Vec<u8>,
207    pub server_initial_secret: Vec<u8>,
208}
209
210/// Captures one QUIC packet-protection keyset derived from one traffic secret.
211#[derive(Debug, Clone, Eq, PartialEq)]
212pub struct Tls13QuicPacketProtectionKeys {
213    pub key: Vec<u8>,
214    pub iv: Vec<u8>,
215    pub header_protection_key: Vec<u8>,
216}
217
218/// Captures current QUIC handshake and 1-RTT traffic secret snapshots.
219#[derive(Debug, Clone, Eq, PartialEq)]
220pub struct Tls13QuicTrafficSecretSnapshot {
221    pub client_handshake_secret: Vec<u8>,
222    pub server_handshake_secret: Vec<u8>,
223    pub client_application_secret: Vec<u8>,
224    pub server_application_secret: Vec<u8>,
225}
226
227/// Captures next-generation QUIC 1-RTT traffic secrets derived via `quic ku`.
228#[derive(Debug, Clone, Eq, PartialEq)]
229pub struct Tls13QuicNextTrafficSecrets {
230    pub client_next_application_secret: Vec<u8>,
231    pub server_next_application_secret: Vec<u8>,
232}
233
234/// QUIC exporter label for client 1-RTT secret derivations.
235pub const TLS13_QUIC_EXPORTER_LABEL_CLIENT_1RTT: &[u8] = b"EXPORTER-QUIC client 1rtt";
236/// QUIC exporter label for server 1-RTT secret derivations.
237pub const TLS13_QUIC_EXPORTER_LABEL_SERVER_1RTT: &[u8] = b"EXPORTER-QUIC server 1rtt";
238
239const TLS13_QUIC_V1_INITIAL_SALT: [u8; 20] = [
240    0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad,
241    0xcc, 0xbb, 0x7f, 0x0a,
242];
243
244const HANDSHAKE_CLIENT_HELLO: u8 = 0x01;
245const HANDSHAKE_SERVER_HELLO: u8 = 0x02;
246const HANDSHAKE_HELLO_VERIFY_REQUEST: u8 = 0x03;
247const HANDSHAKE_NEW_SESSION_TICKET: u8 = 0x04;
248const HANDSHAKE_ENCRYPTED_EXTENSIONS: u8 = 0x08;
249const HANDSHAKE_CERTIFICATE: u8 = 0x0B;
250const HANDSHAKE_SERVER_KEY_EXCHANGE: u8 = 0x0C;
251const HANDSHAKE_CERTIFICATE_REQUEST: u8 = 0x0D;
252const HANDSHAKE_SERVER_HELLO_DONE: u8 = 0x0E;
253const HANDSHAKE_CLIENT_KEY_EXCHANGE: u8 = 0x10;
254const HANDSHAKE_CERTIFICATE_VERIFY: u8 = 0x0F;
255const HANDSHAKE_FINISHED: u8 = 0x14;
256const HANDSHAKE_KEY_UPDATE: u8 = 0x18;
257const EXT_SERVER_NAME: u16 = 0x0000;
258const EXT_STATUS_REQUEST: u16 = 0x0005;
259const EXT_ALPN: u16 = 0x0010;
260const EXT_SUPPORTED_VERSIONS: u16 = 0x002B;
261const EXT_SIGNATURE_ALGORITHMS: u16 = 0x000D;
262const EXT_KEY_SHARE: u16 = 0x0033;
263const EXT_PSK_KEY_EXCHANGE_MODES: u16 = 0x002D;
264const EXT_PRE_SHARED_KEY: u16 = 0x0029;
265const EXT_EARLY_DATA: u16 = 0x002A;
266const TLS13_KEY_SHARE_GROUP_SECP256R1: u16 = 0x0017;
267const TLS13_KEY_SHARE_GROUP_X25519: u16 = 0x001D;
268const TLS13_KEY_SHARE_GROUP_MLKEM768: u16 = 0x0201;
269const TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID: u16 = 0x11EC;
270const TLS13_PSK_KEY_EXCHANGE_MODE_PSK_DHE_KE: u8 = 0x01;
271const TLS13_SIGALG_ECDSA_SECP256R1_SHA256: u16 = 0x0403;
272const TLS13_SIGALG_RSA_PSS_RSAE_SHA256: u16 = 0x0804;
273const TLS13_SIGALG_RSA_PSS_RSAE_SHA384: u16 = 0x0805;
274const TLS13_SIGALG_ED25519: u16 = 0x0807;
275const TLS13_SIGALG_MLDSA65: u16 = 0x0905;
276const TLS13_MAX_EXTENSION_VALUE_BYTES: usize = 16_384;
277const TLS_MAX_RECORD_PLAINTEXT_LEN: usize = 16_384;
278const DTLS_RETRANSMIT_TRACKER_MAX_RECORDS: usize = 256;
279const DTLS_RETRANSMIT_INITIAL_TIMEOUT_MS: u64 = 1_000;
280const DTLS_MAX_RETRANSMIT_ATTEMPTS: u8 = 4;
281const DTLS13_ACTIVE_FLIGHT_TIMEOUT_MS: u64 = 10_000;
282const DTLS13_MAX_SEQUENCE: u64 = (1_u64 << 48) - 1;
283const DTLS12_MAX_COOKIE_LEN: usize = 255;
284const DTLS12_ANTI_AMPLIFICATION_FACTOR: u64 = 3;
285const TLS13_HRR_RANDOM: [u8; 32] = [
286    0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
287    0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
288];
289
290/// Captures parsed extension data from a minimally-modeled ClientHello.
291#[derive(Debug, Clone, Eq, PartialEq, Default)]
292pub struct ClientHelloExtensions {
293    pub supported_versions: Vec<u16>,
294    pub signature_algorithms: Vec<u16>,
295    pub key_share_groups: Vec<u16>,
296    pub sni_server_name: Option<String>,
297    pub alpn_protocols: Vec<Vec<u8>>,
298    pub status_request_ocsp: bool,
299    pub psk_key_exchange_modes: Vec<u8>,
300    pub psk_identity_count: usize,
301    pub psk_identities: Vec<Vec<u8>>,
302    pub psk_obfuscated_ticket_ages: Vec<u32>,
303    pub psk_binders: Vec<Vec<u8>>,
304    pub early_data_offered: bool,
305}
306
307/// Summarizes parsed suite and extension data from ClientHello.
308#[derive(Debug, Clone, Eq, PartialEq, Default)]
309pub struct ClientHelloInfo {
310    pub offered_cipher_suites: Vec<CipherSuite>,
311    pub extensions: ClientHelloExtensions,
312}
313
314/// Captures one PSK identity entry used in TLS 1.3 pre_shared_key offers.
315struct PskIdentityOffer<'a> {
316    identity: &'a [u8],
317    obfuscated_ticket_age: u32,
318}
319
320/// Carries one or more TLS 1.3 PSK identity+binder offers for ClientHello encoding.
321struct PskClientOffer<'a> {
322    identities: Vec<PskIdentityOffer<'a>>,
323    binders: Vec<&'a [u8]>,
324}
325
326/// Holds TLS 1.3 client `key_share` public material emitted in ClientHello.
327#[derive(Debug, Clone, Eq, PartialEq, Default)]
328struct Tls13ClientPublicKeyShares {
329    x25519: Option<[u8; 32]>,
330    secp256r1_uncompressed: Option<[u8; 65]>,
331    mlkem768: Option<Vec<u8>>,
332    x25519_mlkem768_hybrid: Option<Vec<u8>>,
333}
334
335/// Parsed server `key_share` payload for TLS 1.3 ServerHello (non-HRR).
336#[derive(Debug, Clone, Eq, PartialEq)]
337enum Tls13ServerKeyShareParsed {
338    X25519([u8; 32]),
339    Secp256r1([u8; 65]),
340    MlKem768(Vec<u8>),
341    X25519MlKem768Hybrid { x25519: [u8; 32], mlkem768: Vec<u8> },
342}
343
344/// Summarizes parsed ServerHello/HelloRetryRequest details needed by connection flow.
345struct ParsedServerHello {
346    suite: CipherSuite,
347    key_share: Option<Tls13ServerKeyShareParsed>,
348    hello_retry_request: bool,
349    requested_group: Option<u16>,
350}
351
352/// Captures parsed EncryptedExtensions values required by modeled handshake policy.
353struct ParsedEncryptedExtensions {
354    selected_alpn_protocol: Option<Vec<u8>>,
355    server_name_acknowledged: bool,
356    early_data_accepted: bool,
357}
358
359/// Captures parsed TLS 1.3 Certificate contents and optional leaf stapled OCSP bytes.
360struct ParsedTls13CertificateBody {
361    certificates: Vec<Vec<u8>>,
362    leaf_ocsp_staple: Option<Vec<u8>>,
363}
364
365/// Describes validation outcome for one stapled OCSP response.
366#[derive(Debug, Copy, Clone, Eq, PartialEq)]
367pub enum Tls13OcspStapleVerification {
368    Good,
369    Expired,
370    Revoked,
371}
372
373/// Function-pointer hook used to validate one stapled OCSP response payload.
374pub type Tls13OcspStapleVerifier = fn(&[u8]) -> Result<Tls13OcspStapleVerification>;
375
376/// Models deterministic DTLS1.2 handshake progression for cookie and flight sequencing.
377#[derive(Debug, Copy, Clone, Eq, PartialEq)]
378enum Dtls12HandshakePhase {
379    AwaitingClientHello,
380    AwaitingClientHelloWithCookie,
381    AwaitingClientKeyExchange,
382    AwaitingFinished,
383    Connected,
384}
385
386/// Selects transcript hashing algorithm based on protocol version profile.
387#[derive(Debug, Clone)]
388enum TranscriptHashState {
389    Sha256(TlsTranscriptSha256),
390    Sha384(TlsTranscriptSha384),
391}
392
393impl TranscriptHashState {
394    /// Builds transcript hashing state aligned with connection version defaults.
395    ///
396    /// # Arguments
397    ///
398    /// * `version` — `version: TlsVersion`.
399    ///
400    /// # Returns
401    ///
402    /// A new or updated `Self` value as constructed in the function body.
403    ///
404    /// # Panics
405    ///
406    /// This function does not panic.
407    ///
408    fn for_version(version: TlsVersion) -> Self {
409        match version {
410            TlsVersion::Tls13 | TlsVersion::Dtls13 => Self::Sha384(TlsTranscriptSha384::new()),
411            TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => {
412                Self::Sha256(TlsTranscriptSha256::new())
413            }
414        }
415    }
416
417    /// Feeds handshake bytes into the selected transcript hash implementation.
418    ///
419    /// # Arguments
420    ///
421    /// * `self` — `&mut self`.
422    /// * `message` — `message: &[u8]`.
423    ///
424    /// # Panics
425    ///
426    /// This function does not panic.
427    ///
428    fn update(&mut self, message: &[u8]) {
429        match self {
430            Self::Sha256(hasher) => hasher.update(message),
431            Self::Sha384(hasher) => hasher.update(message),
432        }
433    }
434
435    /// Returns current transcript hash bytes without consuming internal state.
436    ///
437    /// # Arguments
438    ///
439    /// * `&self` — `&self`.
440    ///
441    /// # Returns
442    ///
443    /// The value described by the return type in the function signature.
444    ///
445    /// # Panics
446    ///
447    /// This function does not panic.
448    ///
449    fn snapshot_hash(&self) -> Vec<u8> {
450        match self {
451            Self::Sha256(hasher) => hasher.snapshot_hash().to_vec(),
452            Self::Sha384(hasher) => hasher.snapshot_hash().to_vec(),
453        }
454    }
455
456    /// Returns hash algorithm represented by this transcript state.
457    ///
458    /// # Arguments
459    ///
460    /// * `&self` — `&self`.
461    ///
462    /// # Returns
463    ///
464    /// The value described by the return type in the function signature.
465    ///
466    /// # Panics
467    ///
468    /// This function does not panic.
469    ///
470    fn algorithm(&self) -> HashAlgorithm {
471        match self {
472            Self::Sha256(_) => HashAlgorithm::Sha256,
473            Self::Sha384(_) => HashAlgorithm::Sha384,
474        }
475    }
476}
477
478impl CipherSuite {
479    /// Maps wire two-byte cipher suite identifier into modeled suite variants.
480    ///
481    /// # Arguments
482    ///
483    /// * `codepoint` — `codepoint: u16`.
484    ///
485    /// # Returns
486    ///
487    /// On success, `Some` as described by the return type; see the function body for when `None` is returned.
488    ///
489    /// # Panics
490    ///
491    /// This function does not panic.
492    ///
493    fn from_u16(codepoint: u16) -> Option<Self> {
494        match codepoint {
495            0x1301 => Some(Self::TlsAes128GcmSha256),
496            0x1302 => Some(Self::TlsAes256GcmSha384),
497            0x1303 => Some(Self::TlsChacha20Poly1305Sha256),
498            0xC02F => Some(Self::TlsEcdheRsaWithAes128GcmSha256),
499            0xC030 => Some(Self::TlsEcdheRsaWithAes256GcmSha384),
500            _ => None,
501        }
502    }
503
504    /// Returns transcript hash policy used by this suite.
505    ///
506    /// # Arguments
507    ///
508    /// * `self` — `self`.
509    ///
510    /// # Returns
511    ///
512    /// The value described by the return type in the function signature.
513    ///
514    /// # Panics
515    ///
516    /// This function does not panic.
517    ///
518    fn transcript_hash_state(self) -> TranscriptHashState {
519        match self {
520            Self::TlsAes128GcmSha256
521            | Self::TlsChacha20Poly1305Sha256
522            | Self::TlsEcdheRsaWithAes128GcmSha256 => {
523                TranscriptHashState::Sha256(TlsTranscriptSha256::new())
524            }
525            Self::TlsAes256GcmSha384 | Self::TlsEcdheRsaWithAes256GcmSha384 => {
526                TranscriptHashState::Sha384(TlsTranscriptSha384::new())
527            }
528        }
529    }
530
531    /// Returns key-schedule hash algorithm policy for this suite.
532    ///
533    /// # Arguments
534    ///
535    /// * `self` — `self`.
536    ///
537    /// # Returns
538    ///
539    /// The value described by the return type in the function signature.
540    ///
541    /// # Panics
542    ///
543    /// This function does not panic.
544    ///
545    fn hash_algorithm(self) -> HashAlgorithm {
546        match self {
547            Self::TlsAes128GcmSha256
548            | Self::TlsChacha20Poly1305Sha256
549            | Self::TlsEcdheRsaWithAes128GcmSha256 => HashAlgorithm::Sha256,
550            Self::TlsAes256GcmSha384 | Self::TlsEcdheRsaWithAes256GcmSha384 => {
551                HashAlgorithm::Sha384
552            }
553        }
554    }
555
556    /// Returns TLS 1.3 AEAD traffic key length in bytes when applicable.
557    ///
558    /// # Arguments
559    ///
560    /// * `self` — `self`.
561    ///
562    /// # Returns
563    ///
564    /// On success, `Some` as described by the return type; see the function body for when `None` is returned.
565    ///
566    /// # Panics
567    ///
568    /// This function does not panic.
569    ///
570    fn tls13_traffic_key_len(self) -> Option<usize> {
571        match self {
572            CipherSuite::TlsAes128GcmSha256 => Some(16),
573            CipherSuite::TlsAes256GcmSha384 | CipherSuite::TlsChacha20Poly1305Sha256 => Some(32),
574            CipherSuite::TlsEcdheRsaWithAes128GcmSha256
575            | CipherSuite::TlsEcdheRsaWithAes256GcmSha384 => None,
576        }
577    }
578
579    /// Returns the wire identifier for this cipher suite.
580    ///
581    /// # Arguments
582    ///
583    /// * `self` — `self`.
584    ///
585    /// # Returns
586    ///
587    /// The value described by the return type in the function signature.
588    ///
589    /// # Panics
590    ///
591    /// This function does not panic.
592    ///
593    fn to_u16(self) -> u16 {
594        match self {
595            Self::TlsAes128GcmSha256 => 0x1301,
596            Self::TlsAes256GcmSha384 => 0x1302,
597            Self::TlsChacha20Poly1305Sha256 => 0x1303,
598            Self::TlsEcdheRsaWithAes128GcmSha256 => 0xC02F,
599            Self::TlsEcdheRsaWithAes256GcmSha384 => 0xC030,
600        }
601    }
602}
603
604impl Connection {
605    /// Creates a new connection initialized in the `Idle` handshake state.
606    ///
607    /// # Arguments
608    /// * `version`: Protocol version profile for this connection.
609    ///
610    /// # Returns
611    /// Fresh `Connection` in `Idle` state.
612    /// # Panics
613    ///
614    /// This function does not panic.
615    ///
616    pub fn new(version: TlsVersion) -> Self {
617        Self {
618            version,
619            state: HandshakeState::Idle,
620            selected_cipher_suite: None,
621            transcript: Vec::new(),
622            transcript_hash: TranscriptHashState::for_version(version),
623            handshake_secret: None,
624            tls13_master_secret: None,
625            tls13_client_handshake_traffic_secret: None,
626            tls13_server_handshake_traffic_secret: None,
627            tls13_finished_key: None,
628            tls13_client_application_traffic_secret: None,
629            tls13_server_application_traffic_secret: None,
630            tls13_exporter_master_secret: None,
631            tls13_resumption_master_secret: None,
632            tls13_client_x25519_private: None,
633            tls13_client_p256_private: None,
634            tls13_client_mlkem768_private: None,
635            tls13_shared_secret: None,
636            tls13_hrr_requested_group: None,
637            tls13_hrr_seen: false,
638            client_write_key: None,
639            server_write_key: None,
640            client_write_iv: None,
641            server_write_iv: None,
642            client_sequence: 0,
643            server_sequence: 0,
644            tls13_peer_close_notify_received: false,
645            tls13_local_close_notify_sent: false,
646            tls13_require_certificate_auth: false,
647            tls13_server_trust_anchors_der: Vec::new(),
648            tls13_server_intermediates_der: Vec::new(),
649            tls13_server_validation_time: None,
650            tls13_server_expected_hostname: None,
651            tls13_client_server_name: None,
652            tls13_request_ocsp_stapling: false,
653            tls13_require_ocsp_staple: false,
654            tls13_ocsp_staple_verifier: None,
655            tls13_server_ocsp_staple: None,
656            tls13_server_ocsp_staple_verified: false,
657            tls13_require_server_name_ack: false,
658            tls13_server_name_acknowledged: false,
659            tls13_client_alpn_protocols: Vec::new(),
660            tls13_selected_alpn_protocol: None,
661            tls13_server_leaf_public_key_der: None,
662            tls13_server_certificate_chain_validated: false,
663            tls13_early_data_require_acceptance: false,
664            tls13_early_data_accepted_psk: None,
665            tls13_early_data_max_bytes: None,
666            tls13_early_data_opened_bytes: 0,
667            tls13_early_data_offered_in_client_hello: false,
668            tls13_early_data_accepted_in_encrypted_extensions: false,
669            tls13_early_data_anti_replay_enabled: true,
670            tls13_early_data_replay_window: DtlsReplayWindow::new(),
671            tls13_early_data_telemetry: Tls13EarlyDataTelemetry::default(),
672            tls12_change_cipher_spec_seen: false,
673            tls12_session_id: None,
674            tls12_allow_legacy_record_versions: false,
675            dtls13_client_write_key: None,
676            dtls13_client_write_iv: None,
677            dtls13_server_write_key: None,
678            dtls13_server_write_iv: None,
679            dtls13_outbound_epoch: 0,
680            dtls13_outbound_sequence: 0,
681            dtls13_inbound_replay_tracker: DtlsEpochReplayTracker::new(),
682            dtls13_client_inbound_replay_tracker: DtlsEpochReplayTracker::new(),
683            dtls13_active_flight: Vec::new(),
684            dtls13_active_flight_started_at_ms: None,
685            dtls13_active_flight_timeout_ms: DTLS13_ACTIVE_FLIGHT_TIMEOUT_MS,
686            dtls13_active_flight_failed: false,
687            dtls_retransmit_tracker: DtlsFlightRetransmitTracker::new(
688                DTLS_RETRANSMIT_TRACKER_MAX_RECORDS,
689            ),
690            dtls_retransmit_initial_timeout_ms: DTLS_RETRANSMIT_INITIAL_TIMEOUT_MS,
691            dtls_max_retransmit_attempts: DTLS_MAX_RETRANSMIT_ATTEMPTS,
692            dtls12_handshake_phase: Dtls12HandshakePhase::AwaitingClientHello,
693            dtls12_expected_cookie: None,
694            dtls12_anti_amplification_enforced: true,
695            dtls12_inbound_bytes: 0,
696            dtls12_outbound_bytes: 0,
697            max_record_plaintext_len: TLS_MAX_RECORD_PLAINTEXT_LEN,
698        }
699    }
700
701    /// Returns the currently configured DTLS retry/timeout policy for this connection.
702    ///
703    /// # Returns
704    /// `Some(policy)` for DTLS profiles; `None` for TLS stream profiles.
705    #[must_use]
706    /// # Arguments
707    ///
708    /// * `&self` — `&self`.
709    ///
710    /// # Returns
711    ///
712    /// On success, `Some` as described by the return type; see the function body for when `None` is returned.
713    ///
714    /// # Panics
715    ///
716    /// This function does not panic.
717    ///
718    pub fn dtls_operational_policy(&self) -> Option<DtlsOperationalPolicy> {
719        if !self.version.is_dtls() {
720            return None;
721        }
722        Some(DtlsOperationalPolicy {
723            retransmit_initial_timeout_ms: self.dtls_retransmit_initial_timeout_ms,
724            max_retransmit_attempts: self.dtls_max_retransmit_attempts,
725            active_flight_timeout_ms: self.dtls13_active_flight_timeout_ms,
726        })
727    }
728
729    /// Applies a full DTLS retry/timeout policy in one call.
730    ///
731    /// # Arguments
732    /// * `policy`: DTLS timer/retry settings. Zero values are clamped to 1.
733    ///
734    /// # Returns
735    /// Effective policy after clamping and application.
736    /// # Errors
737    ///
738    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
739    ///
740    /// # Panics
741    ///
742    /// This function does not panic.
743    ///
744    pub fn set_dtls_operational_policy(
745        &mut self,
746        policy: DtlsOperationalPolicy,
747    ) -> Result<DtlsOperationalPolicy> {
748        self.ensure_dtls12_mode()?;
749        let effective = DtlsOperationalPolicy {
750            retransmit_initial_timeout_ms: policy.retransmit_initial_timeout_ms.max(1),
751            max_retransmit_attempts: policy.max_retransmit_attempts.max(1),
752            active_flight_timeout_ms: policy.active_flight_timeout_ms.max(1),
753        };
754        self.dtls_retransmit_initial_timeout_ms = effective.retransmit_initial_timeout_ms;
755        self.dtls_max_retransmit_attempts = effective.max_retransmit_attempts;
756        self.dtls13_active_flight_timeout_ms = effective.active_flight_timeout_ms;
757        Ok(effective)
758    }
759
760    /// Applies one built-in DTLS operational profile and returns the resulting policy.
761    ///
762    /// # Returns
763    ///
764    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
765    ///
766    /// # Arguments
767    /// * `profile`: Built-in profile tuned for a deployment environment.
768    /// # Errors
769    ///
770    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
771    ///
772    /// # Panics
773    ///
774    /// This function does not panic.
775    ///
776    pub fn apply_dtls_operational_profile(
777        &mut self,
778        profile: DtlsOperationalProfile,
779    ) -> Result<DtlsOperationalPolicy> {
780        let policy = match profile {
781            DtlsOperationalProfile::Conservative => DtlsOperationalPolicy {
782                retransmit_initial_timeout_ms: DTLS_RETRANSMIT_INITIAL_TIMEOUT_MS,
783                max_retransmit_attempts: DTLS_MAX_RETRANSMIT_ATTEMPTS,
784                active_flight_timeout_ms: DTLS13_ACTIVE_FLIGHT_TIMEOUT_MS,
785            },
786            DtlsOperationalProfile::LanLowLatency => DtlsOperationalPolicy {
787                retransmit_initial_timeout_ms: 250,
788                max_retransmit_attempts: 3,
789                active_flight_timeout_ms: 3_000,
790            },
791            DtlsOperationalProfile::LossyNetwork => DtlsOperationalPolicy {
792                retransmit_initial_timeout_ms: 1_500,
793                max_retransmit_attempts: 6,
794                active_flight_timeout_ms: 20_000,
795            },
796        };
797        self.set_dtls_operational_policy(policy)
798    }
799
800    /// Enables or disables strict TLS 1.3 certificate-authentication enforcement.
801    ///
802    /// # Arguments
803    /// * `required`: Whether Certificate and CertificateVerify must be validated.
804    /// # Panics
805    ///
806    /// This function does not panic.
807    ///
808    pub fn set_tls13_require_certificate_auth(&mut self, required: bool) {
809        self.tls13_require_certificate_auth = required;
810    }
811
812    /// Configures certificate-chain material used for TLS 1.3 server auth validation.
813    ///
814    /// # Arguments
815    /// * `trust_anchors_der`: Trusted root certificates in DER form.
816    /// * `intermediates_der`: Optional intermediate certificates in DER form.
817    /// * `validation_time`: Validation timestamp in canonical ASN.1 text form.
818    ///
819    /// # Returns
820    /// `Ok(())` when configuration is stored.
821    /// # Errors
822    ///
823    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
824    ///
825    /// # Panics
826    ///
827    /// This function does not panic.
828    ///
829    pub fn configure_tls13_server_auth(
830        &mut self,
831        trust_anchors_der: &[Vec<u8>],
832        intermediates_der: &[Vec<u8>],
833        validation_time: &str,
834    ) -> Result<()> {
835        if trust_anchors_der.is_empty() {
836            return Err(Error::InvalidLength(
837                "tls13 trust anchor list must not be empty",
838            ));
839        }
840        if validation_time.is_empty() {
841            return Err(Error::InvalidLength(
842                "tls13 validation time must not be empty",
843            ));
844        }
845        self.tls13_server_trust_anchors_der = trust_anchors_der.to_vec();
846        self.tls13_server_intermediates_der = intermediates_der.to_vec();
847        self.tls13_server_validation_time = Some(validation_time.to_owned());
848        Ok(())
849    }
850
851    /// Sets or clears expected server hostname for TLS 1.3 certificate authentication.
852    ///
853    /// # Arguments
854    /// * `hostname`: `Some(name)` to enforce hostname matching, or `None` to disable.
855    ///
856    /// # Returns
857    /// `Ok(())` when hostname policy is stored.
858    /// # Errors
859    ///
860    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
861    ///
862    /// # Panics
863    ///
864    /// This function does not panic.
865    ///
866    pub fn set_tls13_server_expected_hostname(&mut self, hostname: Option<&str>) -> Result<()> {
867        match hostname {
868            Some(value) if value.is_empty() => Err(Error::InvalidLength(
869                "tls13 expected hostname must not be empty",
870            )),
871            Some(value) => {
872                self.tls13_server_expected_hostname = Some(value.to_owned());
873                Ok(())
874            }
875            None => {
876                self.tls13_server_expected_hostname = None;
877                Ok(())
878            }
879        }
880    }
881
882    /// Sets or clears TLS 1.2 session-id bytes used in outbound ClientHello.
883    ///
884    /// # Arguments
885    /// * `session_id`: `Some(id)` to advertise a session-id (1..=32 bytes), or `None` to clear.
886    ///
887    /// # Returns
888    /// `Ok(())` when the lifecycle value is stored.
889    /// # Errors
890    ///
891    /// Returns [`noxtls_core::Error`] when size constraints are violated.
892    ///
893    /// # Panics
894    ///
895    /// This function does not panic.
896    pub fn set_tls12_session_id(&mut self, session_id: Option<&[u8]>) -> Result<()> {
897        match session_id {
898            Some(value) if value.is_empty() => Err(Error::InvalidLength(
899                "tls12 session id must not be empty when present",
900            )),
901            Some(value) if value.len() > 32 => Err(Error::InvalidLength(
902                "tls12 session id must not exceed 32 bytes",
903            )),
904            Some(value) => {
905                self.tls12_session_id = Some(value.to_vec());
906                Ok(())
907            }
908            None => {
909                self.tls12_session_id = None;
910                Ok(())
911            }
912        }
913    }
914
915    /// Returns currently configured TLS 1.2 ClientHello session-id bytes.
916    ///
917    /// # Arguments
918    ///
919    /// * `self` — Connection carrying TLS 1.2 session lifecycle state.
920    ///
921    /// # Returns
922    ///
923    /// Configured session-id bytes when present.
924    ///
925    /// # Panics
926    ///
927    /// This function does not panic.
928    #[must_use]
929    pub fn tls12_session_id(&self) -> Option<&[u8]> {
930        self.tls12_session_id.as_deref()
931    }
932
933    /// Enables or disables TLS 1.0/1.1 compatibility record-version acceptance in TLS 1.2 packet APIs.
934    ///
935    /// # Arguments
936    ///
937    /// * `allow` — `true` to accept legacy record versions (`0x0301`, `0x0302`) in addition to `0x0303`.
938    ///
939    /// # Panics
940    ///
941    /// This function does not panic.
942    pub fn set_tls12_allow_legacy_record_versions(&mut self, allow: bool) {
943        self.tls12_allow_legacy_record_versions = allow;
944    }
945
946    /// Configures SNI server_name value offered in TLS 1.3 ClientHello extension data.
947    ///
948    /// # Arguments
949    /// * `server_name`: `Some(name)` to advertise one DNS host_name value, or `None` to disable.
950    ///
951    /// # Returns
952    /// `Ok(())` when SNI offer policy is stored.
953    /// # Errors
954    ///
955    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
956    ///
957    /// # Panics
958    ///
959    /// This function does not panic.
960    ///
961    pub fn set_tls13_server_name(&mut self, server_name: Option<&str>) -> Result<()> {
962        match server_name {
963            Some(name) if name.is_empty() => {
964                Err(Error::InvalidLength("sni server_name must not be empty"))
965            }
966            Some(name) if name.len() > u16::MAX as usize => Err(Error::InvalidLength(
967                "sni server_name length must not exceed 65535 bytes",
968            )),
969            Some(name) => {
970                if !is_valid_sni_dns_name(name) {
971                    return Err(Error::ParseFailure("invalid sni server_name"));
972                }
973                self.tls13_client_server_name = Some(name.to_owned());
974                self.tls13_server_name_acknowledged = false;
975                Ok(())
976            }
977            None => {
978                self.tls13_client_server_name = None;
979                self.tls13_server_name_acknowledged = false;
980                Ok(())
981            }
982        }
983    }
984
985    /// Enables or disables advertising OCSP stapling support via `status_request`.
986    ///
987    /// # Arguments
988    /// * `enabled`: `true` adds `status_request` to generated TLS 1.3 ClientHello extensions.
989    ///
990    /// # Panics
991    ///
992    /// This function does not panic.
993    pub fn set_tls13_request_ocsp_stapling(&mut self, enabled: bool) {
994        self.tls13_request_ocsp_stapling = enabled;
995    }
996
997    /// Requires a stapled OCSP response in the server certificate entry.
998    ///
999    /// # Arguments
1000    /// * `required`: `true` fails handshake when no OCSP staple is present.
1001    ///
1002    /// # Panics
1003    ///
1004    /// This function does not panic.
1005    pub fn set_tls13_require_ocsp_staple(&mut self, required: bool) {
1006        self.tls13_require_ocsp_staple = required;
1007    }
1008
1009    /// Configures one optional verifier hook for stapled OCSP response payloads.
1010    ///
1011    /// # Arguments
1012    /// * `verifier`: Optional function pointer that classifies one OCSP staple.
1013    ///
1014    /// # Panics
1015    ///
1016    /// This function does not panic.
1017    pub fn set_tls13_ocsp_staple_verifier(&mut self, verifier: Option<Tls13OcspStapleVerifier>) {
1018        self.tls13_ocsp_staple_verifier = verifier;
1019    }
1020
1021    /// Returns the most recently parsed server OCSP staple bytes.
1022    #[must_use]
1023    pub fn tls13_server_ocsp_staple(&self) -> Option<&[u8]> {
1024        self.tls13_server_ocsp_staple.as_deref()
1025    }
1026
1027    /// Reports whether the most recently parsed OCSP staple passed verification policy.
1028    #[must_use]
1029    pub fn tls13_server_ocsp_staple_verified(&self) -> bool {
1030        self.tls13_server_ocsp_staple_verified
1031    }
1032
1033    /// Enables strict policy requiring server_name acknowledgment in EncryptedExtensions.
1034    ///
1035    /// # Arguments
1036    /// * `required`: `true` to fail handshake when SNI was offered but not acknowledged.
1037    /// # Panics
1038    ///
1039    /// This function does not panic.
1040    ///
1041    pub fn set_tls13_require_server_name_ack(&mut self, required: bool) {
1042        self.tls13_require_server_name_ack = required;
1043    }
1044
1045    /// Reports whether server_name was acknowledged in parsed EncryptedExtensions.
1046    #[must_use]
1047    /// # Arguments
1048    ///
1049    /// * `&self` — `&self`.
1050    ///
1051    /// # Returns
1052    ///
1053    /// `true` or `false` according to the checks in the function body.
1054    ///
1055    /// # Panics
1056    ///
1057    /// This function does not panic.
1058    ///
1059    pub fn tls13_server_name_acknowledged(&self) -> bool {
1060        self.tls13_server_name_acknowledged
1061    }
1062
1063    /// Configures ALPN protocol IDs offered in TLS 1.3 ClientHello extension data.
1064    ///
1065    /// # Arguments
1066    /// * `protocols`: Ordered ALPN protocol IDs to advertise; empty clears configuration.
1067    ///
1068    /// # Returns
1069    /// `Ok(())` when ALPN offer policy is stored.
1070    /// # Errors
1071    ///
1072    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1073    ///
1074    /// # Panics
1075    ///
1076    /// This function does not panic.
1077    ///
1078    pub fn set_tls13_alpn_protocols(&mut self, protocols: &[&str]) -> Result<()> {
1079        let mut parsed_protocols = Vec::with_capacity(protocols.len());
1080        for protocol in protocols {
1081            if protocol.is_empty() {
1082                return Err(Error::InvalidLength("alpn protocol must not be empty"));
1083            }
1084            if protocol.len() > u8::MAX as usize {
1085                return Err(Error::InvalidLength(
1086                    "alpn protocol length must not exceed 255 bytes",
1087                ));
1088            }
1089            let encoded = protocol.as_bytes().to_vec();
1090            if parsed_protocols.contains(&encoded) {
1091                return Err(Error::ParseFailure("duplicate alpn protocol"));
1092            }
1093            parsed_protocols.push(encoded);
1094        }
1095        self.tls13_client_alpn_protocols = parsed_protocols;
1096        self.tls13_selected_alpn_protocol = None;
1097        Ok(())
1098    }
1099
1100    /// Returns ALPN protocol selected by last parsed TLS 1.3 EncryptedExtensions.
1101    ///
1102    /// # Returns
1103    /// Selected ALPN protocol bytes when negotiated, otherwise `None`.
1104    #[must_use]
1105    /// # Arguments
1106    ///
1107    /// * `&self` — `&self`.
1108    ///
1109    /// # Returns
1110    ///
1111    /// On success, `Some` as described by the return type; see the function body for when `None` is returned.
1112    ///
1113    /// # Panics
1114    ///
1115    /// This function does not panic.
1116    ///
1117    pub fn tls13_selected_alpn_protocol(&self) -> Option<&[u8]> {
1118        self.tls13_selected_alpn_protocol.as_deref()
1119    }
1120
1121    /// Sets maximum accepted record plaintext length for seal/open operations.
1122    ///
1123    /// # Arguments
1124    /// * `max_len`: Plaintext limit in bytes (must be in `1..=16384`).
1125    ///
1126    /// # Returns
1127    /// `Ok(())` when the limit is accepted.
1128    /// # Errors
1129    ///
1130    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1131    ///
1132    /// # Panics
1133    ///
1134    /// This function does not panic.
1135    ///
1136    pub fn set_max_record_plaintext_len(&mut self, max_len: usize) -> Result<()> {
1137        if max_len == 0 || max_len > TLS_MAX_RECORD_PLAINTEXT_LEN {
1138            return Err(Error::InvalidLength(
1139                "record plaintext limit must be between 1 and 16384 bytes",
1140            ));
1141        }
1142        self.max_record_plaintext_len = max_len;
1143        Ok(())
1144    }
1145
1146    /// Enables or disables 0-RTT anti-replay checks for `open_tls13_early_data_record`.
1147    ///
1148    /// # Arguments
1149    /// * `enabled`: `true` to reject replay/too-old sequences, `false` to bypass checks.
1150    /// # Panics
1151    ///
1152    /// This function does not panic.
1153    ///
1154    pub fn set_tls13_early_data_anti_replay_enabled(&mut self, enabled: bool) {
1155        self.tls13_early_data_anti_replay_enabled = enabled;
1156        if enabled {
1157            self.tls13_early_data_replay_window = DtlsReplayWindow::new();
1158        }
1159    }
1160
1161    /// Enables strict 0-RTT acceptance gating before early-data record decryption.
1162    ///
1163    /// # Arguments
1164    /// * `required`: `true` requires prior successful ticket-policy acceptance.
1165    /// # Panics
1166    ///
1167    /// This function does not panic.
1168    ///
1169    pub fn set_tls13_require_early_data_acceptance(&mut self, required: bool) {
1170        self.tls13_early_data_require_acceptance = required;
1171        self.tls13_early_data_accepted_psk = None;
1172        self.tls13_early_data_max_bytes = None;
1173        self.tls13_early_data_opened_bytes = 0;
1174        self.tls13_early_data_accepted_in_encrypted_extensions = false;
1175    }
1176
1177    /// Applies one pre-tuned operational profile for modeled TLS 1.3 early-data policy.
1178    ///
1179    /// # Arguments
1180    /// * `profile`: Desired profile preset.
1181    ///
1182    /// # Returns
1183    /// `()`.
1184    ///
1185    /// # Panics
1186    ///
1187    /// This function does not panic.
1188    pub fn set_tls13_early_data_operational_profile(
1189        &mut self,
1190        profile: Tls13EarlyDataOperationalProfile,
1191    ) {
1192        let policy = match profile {
1193            Tls13EarlyDataOperationalProfile::Compatibility => Tls13EarlyDataOperationalPolicy {
1194                require_acceptance: false,
1195                anti_replay_enabled: false,
1196            },
1197            Tls13EarlyDataOperationalProfile::Strict => Tls13EarlyDataOperationalPolicy {
1198                require_acceptance: true,
1199                anti_replay_enabled: true,
1200            },
1201        };
1202        self.set_tls13_early_data_operational_policy(policy);
1203    }
1204
1205    /// Applies explicit operational policy controls for modeled TLS 1.3 early-data handling.
1206    ///
1207    /// # Arguments
1208    /// * `policy`: Policy values for acceptance and anti-replay checks.
1209    ///
1210    /// # Returns
1211    /// `()`.
1212    ///
1213    /// # Panics
1214    ///
1215    /// This function does not panic.
1216    pub fn set_tls13_early_data_operational_policy(
1217        &mut self,
1218        policy: Tls13EarlyDataOperationalPolicy,
1219    ) {
1220        self.set_tls13_require_early_data_acceptance(policy.require_acceptance);
1221        self.set_tls13_early_data_anti_replay_enabled(policy.anti_replay_enabled);
1222    }
1223
1224    /// Returns currently active operational policy for modeled TLS 1.3 early-data handling.
1225    ///
1226    /// # Returns
1227    /// Current policy values.
1228    ///
1229    /// # Panics
1230    ///
1231    /// This function does not panic.
1232    #[must_use]
1233    pub fn tls13_early_data_operational_policy(&self) -> Tls13EarlyDataOperationalPolicy {
1234        Tls13EarlyDataOperationalPolicy {
1235            require_acceptance: self.tls13_early_data_require_acceptance,
1236            anti_replay_enabled: self.tls13_early_data_anti_replay_enabled,
1237        }
1238    }
1239
1240    /// Returns counters describing modeled TLS 1.3 early-data accept/reject outcomes.
1241    ///
1242    /// # Returns
1243    /// Copy of current early-data telemetry counters.
1244    ///
1245    /// # Panics
1246    ///
1247    /// This function does not panic.
1248    #[must_use]
1249    pub fn tls13_early_data_telemetry(&self) -> Tls13EarlyDataTelemetry {
1250        self.tls13_early_data_telemetry
1251    }
1252
1253    /// Resets modeled TLS 1.3 early-data telemetry counters to zero.
1254    ///
1255    /// # Returns
1256    /// `()`.
1257    ///
1258    /// # Panics
1259    ///
1260    /// This function does not panic.
1261    pub fn reset_tls13_early_data_telemetry(&mut self) {
1262        self.tls13_early_data_telemetry = Tls13EarlyDataTelemetry::default();
1263    }
1264
1265    /// Exports replay-window state for modeled TLS 1.3 early-data anti-replay continuity.
1266    ///
1267    /// # Returns
1268    /// Serializable replay state snapshot.
1269    ///
1270    /// # Panics
1271    ///
1272    /// This function does not panic.
1273    #[must_use]
1274    pub fn export_tls13_early_data_replay_state(&self) -> Tls13EarlyDataReplayState {
1275        let snapshot = self.tls13_early_data_replay_window.snapshot();
1276        Tls13EarlyDataReplayState {
1277            latest_sequence: snapshot.latest_sequence,
1278            bitmap: snapshot.bitmap,
1279            initialized: snapshot.initialized,
1280        }
1281    }
1282
1283    /// Imports replay-window state for modeled TLS 1.3 early-data anti-replay continuity.
1284    ///
1285    /// # Arguments
1286    /// * `state`: Previously exported replay state snapshot.
1287    ///
1288    /// # Returns
1289    /// `Ok(())` when replay state is imported.
1290    ///
1291    /// # Errors
1292    ///
1293    /// Returns [`noxtls_core::Error`] when called on a non-TLS1.3 connection.
1294    ///
1295    /// # Panics
1296    ///
1297    /// This function does not panic.
1298    pub fn import_tls13_early_data_replay_state(
1299        &mut self,
1300        state: Tls13EarlyDataReplayState,
1301    ) -> Result<()> {
1302        if !self.version.uses_tls13_handshake_semantics() {
1303            return Err(Error::StateError(
1304                "tls13 early-data replay state requires TLS 1.3 connection",
1305            ));
1306        }
1307        self.tls13_early_data_replay_window
1308            .restore_from_snapshot(DtlsReplayWindowSnapshot {
1309                latest_sequence: state.latest_sequence,
1310                bitmap: state.bitmap,
1311                initialized: state.initialized,
1312            });
1313        Ok(())
1314    }
1315
1316    /// Builds and records a synthetic client hello message using caller random bytes.
1317    ///
1318    /// # Arguments
1319    /// * `random`: 32-byte ClientHello random value.
1320    ///
1321    /// # Returns
1322    /// Encoded ClientHello handshake message bytes.
1323    /// # Errors
1324    ///
1325    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1326    ///
1327    /// # Panics
1328    ///
1329    /// This function does not panic.
1330    ///
1331    pub fn send_client_hello(&mut self, random: &[u8]) -> Result<Vec<u8>> {
1332        if self.state != HandshakeState::Idle {
1333            return Err(Error::StateError("client hello can only be sent from idle"));
1334        }
1335        if random.len() != 32 {
1336            return Err(Error::InvalidLength("client hello random must be 32 bytes"));
1337        }
1338        self.reset_transcript_for_new_handshake();
1339        self.validate_tls13_hrr_retry_group_support()?;
1340        self.reset_tls13_certificate_auth_state();
1341        let key_shares = self.prepare_client_key_share(random)?;
1342        let client_hello_body = encode_client_hello_body(
1343            self.version,
1344            random,
1345            &default_client_cipher_suites(self.version),
1346            &key_shares,
1347            self.tls13_client_server_name.as_deref(),
1348            &self.tls13_client_alpn_protocols,
1349            self.tls13_request_ocsp_stapling,
1350            false,
1351            None,
1352            self.tls12_session_id.as_deref(),
1353        )?;
1354        let msg = encode_handshake_message(HANDSHAKE_CLIENT_HELLO, &client_hello_body);
1355        self.append_transcript(&msg);
1356        self.state = HandshakeState::ClientHelloSent;
1357        self.tls13_early_data_offered_in_client_hello = false;
1358        self.tls13_early_data_accepted_in_encrypted_extensions = false;
1359        Ok(msg)
1360    }
1361
1362    /// Builds and records a TLS 1.3 ClientHello carrying one PSK identity+binder.
1363    ///
1364    /// # Arguments
1365    /// * `random`: 32-byte ClientHello random value.
1366    /// * `identity`: PSK identity bytes from ticket cache.
1367    /// * `obfuscated_ticket_age`: Encoded ticket age value for the identity.
1368    /// * `psk`: PSK bytes used to compute binder authentication.
1369    ///
1370    /// # Returns
1371    /// Encoded ClientHello handshake message bytes with populated binder.
1372    /// # Errors
1373    ///
1374    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1375    ///
1376    /// # Panics
1377    ///
1378    /// This function does not panic.
1379    ///
1380    pub fn send_client_hello_with_psk(
1381        &mut self,
1382        random: &[u8],
1383        identity: &[u8],
1384        obfuscated_ticket_age: u32,
1385        psk: &[u8],
1386    ) -> Result<Vec<u8>> {
1387        self.send_client_hello_with_psk_internal(
1388            random,
1389            identity,
1390            obfuscated_ticket_age,
1391            psk,
1392            false,
1393        )
1394    }
1395
1396    /// Builds and records a TLS 1.3 ClientHello carrying one PSK identity+binder.
1397    ///
1398    /// # Arguments
1399    /// * `random`: 32-byte ClientHello random value.
1400    /// * `identity`: PSK identity bytes from ticket cache.
1401    /// * `obfuscated_ticket_age`: Encoded ticket age value for the identity.
1402    /// * `psk`: PSK bytes used to compute binder authentication.
1403    /// * `offer_early_data`: `true` emits the empty early_data extension.
1404    ///
1405    /// # Returns
1406    /// Encoded ClientHello handshake message bytes with populated binder.
1407    /// # Errors
1408    ///
1409    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1410    ///
1411    /// # Panics
1412    ///
1413    /// This function does not panic.
1414    ///
1415    fn send_client_hello_with_psk_internal(
1416        &mut self,
1417        random: &[u8],
1418        identity: &[u8],
1419        obfuscated_ticket_age: u32,
1420        psk: &[u8],
1421        offer_early_data: bool,
1422    ) -> Result<Vec<u8>> {
1423        if !self.version.uses_tls13_handshake_semantics() {
1424            return Err(Error::StateError(
1425                "psk client hello is currently only modeled for TLS 1.3",
1426            ));
1427        }
1428        if self.state != HandshakeState::Idle {
1429            return Err(Error::StateError("client hello can only be sent from idle"));
1430        }
1431        if random.len() != 32 {
1432            return Err(Error::InvalidLength("client hello random must be 32 bytes"));
1433        }
1434        if identity.is_empty() {
1435            return Err(Error::InvalidLength("psk identity must not be empty"));
1436        }
1437        if psk.is_empty() {
1438            return Err(Error::InvalidLength("psk must not be empty"));
1439        }
1440        self.reset_transcript_for_new_handshake();
1441        self.validate_tls13_hrr_retry_group_support()?;
1442        self.reset_tls13_certificate_auth_state();
1443        let binder_len = self.negotiated_hash_algorithm().output_len();
1444        let placeholder = vec![0_u8; binder_len];
1445        let placeholder_offer = PskClientOffer {
1446            identities: vec![PskIdentityOffer {
1447                identity,
1448                obfuscated_ticket_age,
1449            }],
1450            binders: vec![placeholder.as_slice()],
1451        };
1452        let key_shares = self.prepare_client_key_share(random)?;
1453        let placeholder_body = encode_client_hello_body(
1454            self.version,
1455            random,
1456            &default_client_cipher_suites(self.version),
1457            &key_shares,
1458            self.tls13_client_server_name.as_deref(),
1459            &self.tls13_client_alpn_protocols,
1460            self.tls13_request_ocsp_stapling,
1461            offer_early_data,
1462            Some(&placeholder_offer),
1463            self.tls12_session_id.as_deref(),
1464        )?;
1465        let placeholder_msg = encode_handshake_message(HANDSHAKE_CLIENT_HELLO, &placeholder_body);
1466        let binder = self.compute_tls13_psk_binder(psk, &placeholder_msg)?;
1467        let final_offer = PskClientOffer {
1468            identities: vec![PskIdentityOffer {
1469                identity,
1470                obfuscated_ticket_age,
1471            }],
1472            binders: vec![binder.as_slice()],
1473        };
1474        let final_body = encode_client_hello_body(
1475            self.version,
1476            random,
1477            &default_client_cipher_suites(self.version),
1478            &key_shares,
1479            self.tls13_client_server_name.as_deref(),
1480            &self.tls13_client_alpn_protocols,
1481            self.tls13_request_ocsp_stapling,
1482            offer_early_data,
1483            Some(&final_offer),
1484            self.tls12_session_id.as_deref(),
1485        )?;
1486        let msg = encode_handshake_message(HANDSHAKE_CLIENT_HELLO, &final_body);
1487        self.append_transcript(&msg);
1488        self.state = HandshakeState::ClientHelloSent;
1489        self.tls13_early_data_offered_in_client_hello = offer_early_data;
1490        self.tls13_early_data_accepted_in_encrypted_extensions = false;
1491        Ok(msg)
1492    }
1493
1494    /// Builds and records a TLS 1.3 ClientHello offering multiple resumption tickets.
1495    ///
1496    /// # Arguments
1497    /// * `random`: 32-byte ClientHello random value.
1498    /// * `tickets`: Ordered resumption tickets to advertise in pre_shared_key.
1499    ///
1500    /// # Returns
1501    /// Encoded ClientHello handshake bytes carrying multiple PSK identities and binders.
1502    /// # Errors
1503    ///
1504    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1505    ///
1506    /// # Panics
1507    ///
1508    /// This function does not panic.
1509    ///
1510    pub fn send_client_hello_with_resumption_tickets(
1511        &mut self,
1512        random: &[u8],
1513        tickets: &[ResumptionTicket],
1514    ) -> Result<Vec<u8>> {
1515        let mut obfuscated_ages = Vec::with_capacity(tickets.len());
1516        for ticket in tickets {
1517            obfuscated_ages.push(ticket.obfuscated_ticket_age);
1518        }
1519        self.send_client_hello_with_resumption_tickets_with_ages(random, tickets, &obfuscated_ages)
1520    }
1521
1522    /// Builds and records a TLS 1.3 ClientHello offering multiple resumption tickets.
1523    ///
1524    /// # Arguments
1525    /// * `random`: 32-byte ClientHello random value.
1526    /// * `tickets`: Ordered resumption tickets to advertise in pre_shared_key.
1527    /// * `current_time_ms`: Client-local timestamp used for obfuscated ticket age values.
1528    ///
1529    /// # Returns
1530    /// Encoded ClientHello handshake bytes carrying multiple PSK identities and binders.
1531    /// # Errors
1532    ///
1533    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1534    ///
1535    /// # Panics
1536    ///
1537    /// This function does not panic.
1538    ///
1539    pub fn send_client_hello_with_resumption_tickets_at(
1540        &mut self,
1541        random: &[u8],
1542        tickets: &[ResumptionTicket],
1543        current_time_ms: u64,
1544    ) -> Result<Vec<u8>> {
1545        if !self.version.uses_tls13_handshake_semantics() {
1546            return Err(Error::StateError(
1547                "psk client hello is currently only modeled for TLS 1.3",
1548            ));
1549        }
1550        if self.state != HandshakeState::Idle {
1551            return Err(Error::StateError("client hello can only be sent from idle"));
1552        }
1553        if random.len() != 32 {
1554            return Err(Error::InvalidLength("client hello random must be 32 bytes"));
1555        }
1556        if tickets.is_empty() {
1557            return Err(Error::InvalidLength("ticket list must not be empty"));
1558        }
1559        let mut obfuscated_ages = Vec::with_capacity(tickets.len());
1560        for ticket in tickets {
1561            let elapsed_ms = current_time_ms.saturating_sub(ticket.issued_at_ms);
1562            let elapsed_u32 = elapsed_ms.min(u64::from(u32::MAX)) as u32;
1563            obfuscated_ages.push(ticket.age_add.wrapping_add(elapsed_u32));
1564        }
1565        self.send_client_hello_with_resumption_tickets_with_ages(random, tickets, &obfuscated_ages)
1566    }
1567
1568    /// Builds multi-ticket ClientHello using caller-selected obfuscated ticket ages.
1569    ///
1570    /// # Arguments
1571    ///
1572    /// * `self` — `&mut self`.
1573    /// * `random` — `random: &[u8]`.
1574    /// * `tickets` — `tickets: &[ResumptionTicket]`.
1575    /// * `obfuscated_ages` — `obfuscated_ages: &[u32]`.
1576    ///
1577    /// # Returns
1578    ///
1579    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
1580    ///
1581    /// # Errors
1582    ///
1583    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1584    ///
1585    /// # Panics
1586    ///
1587    /// This function does not panic.
1588    ///
1589    fn send_client_hello_with_resumption_tickets_with_ages(
1590        &mut self,
1591        random: &[u8],
1592        tickets: &[ResumptionTicket],
1593        obfuscated_ages: &[u32],
1594    ) -> Result<Vec<u8>> {
1595        self.reset_transcript_for_new_handshake();
1596        self.validate_tls13_hrr_retry_group_support()?;
1597        self.reset_tls13_certificate_auth_state();
1598        let hash_len = self.negotiated_hash_algorithm().output_len();
1599        let mut psk_identities = Vec::with_capacity(tickets.len());
1600        let mut psks = Vec::with_capacity(tickets.len());
1601        for (ticket, obfuscated_age) in tickets.iter().zip(obfuscated_ages.iter().copied()) {
1602            psk_identities.push(PskIdentityOffer {
1603                identity: ticket.identity.as_slice(),
1604                obfuscated_ticket_age: obfuscated_age,
1605            });
1606            psks.push(self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?);
1607        }
1608        let zero_binders: Vec<Vec<u8>> = (0..tickets.len()).map(|_| vec![0_u8; hash_len]).collect();
1609        let zero_binder_refs: Vec<&[u8]> = zero_binders.iter().map(Vec::as_slice).collect();
1610        let placeholder_offer = PskClientOffer {
1611            identities: psk_identities,
1612            binders: zero_binder_refs,
1613        };
1614        let key_shares = self.prepare_client_key_share(random)?;
1615        let placeholder_body = encode_client_hello_body(
1616            self.version,
1617            random,
1618            &default_client_cipher_suites(self.version),
1619            &key_shares,
1620            self.tls13_client_server_name.as_deref(),
1621            &self.tls13_client_alpn_protocols,
1622            self.tls13_request_ocsp_stapling,
1623            tickets.iter().any(|ticket| ticket.max_early_data_size > 0),
1624            Some(&placeholder_offer),
1625            self.tls12_session_id.as_deref(),
1626        )?;
1627        let placeholder_msg = encode_handshake_message(HANDSHAKE_CLIENT_HELLO, &placeholder_body);
1628        let mut binders = Vec::with_capacity(psks.len());
1629        for psk in &psks {
1630            binders.push(self.compute_tls13_psk_binder(psk, &placeholder_msg)?);
1631        }
1632        let binder_refs: Vec<&[u8]> = binders.iter().map(Vec::as_slice).collect();
1633        let final_offer = PskClientOffer {
1634            identities: placeholder_offer.identities,
1635            binders: binder_refs,
1636        };
1637        let final_body = encode_client_hello_body(
1638            self.version,
1639            random,
1640            &default_client_cipher_suites(self.version),
1641            &key_shares,
1642            self.tls13_client_server_name.as_deref(),
1643            &self.tls13_client_alpn_protocols,
1644            self.tls13_request_ocsp_stapling,
1645            tickets.iter().any(|ticket| ticket.max_early_data_size > 0),
1646            Some(&final_offer),
1647            self.tls12_session_id.as_deref(),
1648        )?;
1649        let msg = encode_handshake_message(HANDSHAKE_CLIENT_HELLO, &final_body);
1650        self.append_transcript(&msg);
1651        self.state = HandshakeState::ClientHelloSent;
1652        self.tls13_early_data_offered_in_client_hello =
1653            tickets.iter().any(|ticket| ticket.max_early_data_size > 0);
1654        self.tls13_early_data_accepted_in_encrypted_extensions = false;
1655        Ok(msg)
1656    }
1657
1658    /// Builds and records a TLS 1.3 ClientHello from a locally-issued resumption ticket.
1659    ///
1660    /// # Arguments
1661    /// * `random`: 32-byte ClientHello random value.
1662    /// * `ticket`: Resumption ticket metadata used to derive identity and binder.
1663    ///
1664    /// # Returns
1665    /// Encoded ClientHello handshake bytes carrying a pre_shared_key offer.
1666    /// # Errors
1667    ///
1668    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1669    ///
1670    /// # Panics
1671    ///
1672    /// This function does not panic.
1673    ///
1674    pub fn send_client_hello_with_resumption_ticket(
1675        &mut self,
1676        random: &[u8],
1677        ticket: &ResumptionTicket,
1678    ) -> Result<Vec<u8>> {
1679        let psk = self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?;
1680        self.send_client_hello_with_psk_internal(
1681            random,
1682            &ticket.identity,
1683            ticket.obfuscated_ticket_age,
1684            &psk,
1685            ticket.max_early_data_size > 0,
1686        )
1687    }
1688
1689    /// Builds and records a TLS 1.3 ClientHello from a resumption ticket using current age.
1690    ///
1691    /// # Arguments
1692    /// * `random`: 32-byte ClientHello random value.
1693    /// * `ticket`: Resumption ticket metadata used to derive identity and binder.
1694    /// * `current_time_ms`: Client-local timestamp used for obfuscated ticket age.
1695    ///
1696    /// # Returns
1697    /// Encoded ClientHello handshake bytes carrying a pre_shared_key offer.
1698    /// # Errors
1699    ///
1700    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1701    ///
1702    /// # Panics
1703    ///
1704    /// This function does not panic.
1705    ///
1706    pub fn send_client_hello_with_resumption_ticket_at(
1707        &mut self,
1708        random: &[u8],
1709        ticket: &ResumptionTicket,
1710        current_time_ms: u64,
1711    ) -> Result<Vec<u8>> {
1712        let psk = self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?;
1713        let elapsed_ms = current_time_ms.saturating_sub(ticket.issued_at_ms);
1714        let elapsed_u32 = elapsed_ms.min(u64::from(u32::MAX)) as u32;
1715        let obfuscated_age = ticket.age_add.wrapping_add(elapsed_u32);
1716        self.send_client_hello_with_psk_internal(
1717            random,
1718            &ticket.identity,
1719            obfuscated_age,
1720            &psk,
1721            ticket.max_early_data_size > 0,
1722        )
1723    }
1724
1725    /// Builds and records a client hello with randomness sourced from HMAC-DRBG.
1726    ///
1727    /// # Arguments
1728    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1729    ///
1730    /// # Returns
1731    /// Encoded ClientHello handshake message bytes.
1732    /// # Errors
1733    ///
1734    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1735    ///
1736    /// # Panics
1737    ///
1738    /// This function does not panic.
1739    ///
1740    pub fn send_client_hello_auto(&mut self, drbg: &mut HmacDrbgSha256) -> Result<Vec<u8>> {
1741        let random = drbg.generate(32, b"client_hello_random")?;
1742        self.send_client_hello(&random)
1743    }
1744
1745    /// Builds and records a TLS 1.3 PSK ClientHello with DRBG-generated random bytes.
1746    ///
1747    /// # Arguments
1748    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1749    /// * `identity`: PSK identity bytes from ticket cache.
1750    /// * `obfuscated_ticket_age`: Encoded ticket age value for the identity.
1751    /// * `psk`: PSK bytes used to compute binder authentication.
1752    ///
1753    /// # Returns
1754    /// Encoded ClientHello handshake message bytes with populated binder.
1755    /// # Errors
1756    ///
1757    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1758    ///
1759    /// # Panics
1760    ///
1761    /// This function does not panic.
1762    ///
1763    pub fn send_client_hello_with_psk_auto(
1764        &mut self,
1765        drbg: &mut HmacDrbgSha256,
1766        identity: &[u8],
1767        obfuscated_ticket_age: u32,
1768        psk: &[u8],
1769    ) -> Result<Vec<u8>> {
1770        let random = drbg.generate(32, b"client_hello_random")?;
1771        self.send_client_hello_with_psk(&random, identity, obfuscated_ticket_age, psk)
1772    }
1773
1774    /// Builds and records a TLS 1.3 ClientHello from one ticket with DRBG random bytes.
1775    ///
1776    /// # Arguments
1777    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1778    /// * `ticket`: Resumption ticket metadata used to derive identity and binder.
1779    ///
1780    /// # Returns
1781    /// Encoded ClientHello handshake bytes carrying one pre_shared_key offer.
1782    /// # Errors
1783    ///
1784    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1785    ///
1786    /// # Panics
1787    ///
1788    /// This function does not panic.
1789    ///
1790    pub fn send_client_hello_with_resumption_ticket_auto(
1791        &mut self,
1792        drbg: &mut HmacDrbgSha256,
1793        ticket: &ResumptionTicket,
1794    ) -> Result<Vec<u8>> {
1795        let random = drbg.generate(32, b"client_hello_random")?;
1796        self.send_client_hello_with_resumption_ticket(&random, ticket)
1797    }
1798
1799    /// Builds and records a TLS 1.3 ClientHello with ticket age using DRBG random bytes.
1800    ///
1801    /// # Arguments
1802    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1803    /// * `ticket`: Resumption ticket metadata used to derive identity and binder.
1804    /// * `current_time_ms`: Client-local timestamp used for obfuscated ticket age.
1805    ///
1806    /// # Returns
1807    /// Encoded ClientHello handshake bytes carrying one pre_shared_key offer.
1808    /// # Errors
1809    ///
1810    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1811    ///
1812    /// # Panics
1813    ///
1814    /// This function does not panic.
1815    ///
1816    pub fn send_client_hello_with_resumption_ticket_at_auto(
1817        &mut self,
1818        drbg: &mut HmacDrbgSha256,
1819        ticket: &ResumptionTicket,
1820        current_time_ms: u64,
1821    ) -> Result<Vec<u8>> {
1822        let random = drbg.generate(32, b"client_hello_random")?;
1823        self.send_client_hello_with_resumption_ticket_at(&random, ticket, current_time_ms)
1824    }
1825
1826    /// Builds and records a TLS 1.3 multi-ticket ClientHello with DRBG random bytes.
1827    ///
1828    /// # Arguments
1829    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1830    /// * `tickets`: Ordered resumption tickets to advertise in pre_shared_key.
1831    /// * `current_time_ms`: Client-local timestamp used for obfuscated ticket age values.
1832    ///
1833    /// # Returns
1834    /// Encoded ClientHello handshake bytes carrying multiple PSK identities and binders.
1835    /// # Errors
1836    ///
1837    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1838    ///
1839    /// # Panics
1840    ///
1841    /// This function does not panic.
1842    ///
1843    pub fn send_client_hello_with_resumption_tickets_auto(
1844        &mut self,
1845        drbg: &mut HmacDrbgSha256,
1846        tickets: &[ResumptionTicket],
1847    ) -> Result<Vec<u8>> {
1848        let random = drbg.generate(32, b"client_hello_random")?;
1849        self.send_client_hello_with_resumption_tickets(&random, tickets)
1850    }
1851
1852    /// Builds and records a TLS 1.3 multi-ticket ClientHello with DRBG random bytes.
1853    ///
1854    /// # Arguments
1855    /// * `drbg`: DRBG instance used to generate ClientHello random bytes.
1856    /// * `tickets`: Ordered resumption tickets to advertise in pre_shared_key.
1857    /// * `current_time_ms`: Client-local timestamp used for obfuscated ticket age values.
1858    ///
1859    /// # Returns
1860    /// Encoded ClientHello handshake bytes carrying multiple PSK identities and binders.
1861    /// # Errors
1862    ///
1863    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1864    ///
1865    /// # Panics
1866    ///
1867    /// This function does not panic.
1868    ///
1869    pub fn send_client_hello_with_resumption_tickets_at_auto(
1870        &mut self,
1871        drbg: &mut HmacDrbgSha256,
1872        tickets: &[ResumptionTicket],
1873        current_time_ms: u64,
1874    ) -> Result<Vec<u8>> {
1875        let random = drbg.generate(32, b"client_hello_random")?;
1876        self.send_client_hello_with_resumption_tickets_at(&random, tickets, current_time_ms)
1877    }
1878
1879    /// Validates and records server hello bytes for transcript hashing.
1880    ///
1881    /// # Arguments
1882    /// * `msg`: Encoded ServerHello handshake message.
1883    ///
1884    /// # Returns
1885    /// `Ok(())` when ServerHello parses and state advances.
1886    /// # Errors
1887    ///
1888    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1889    ///
1890    /// # Panics
1891    ///
1892    /// This function does not panic.
1893    ///
1894    pub fn recv_server_hello(&mut self, msg: &[u8]) -> Result<()> {
1895        if self.state != HandshakeState::ClientHelloSent {
1896            return Err(Error::StateError(
1897                "server hello can only be processed after client hello",
1898            ));
1899        }
1900        let parsed = parse_server_hello(msg)?;
1901        if parsed.hello_retry_request {
1902            if self.tls13_hrr_seen {
1903                return Err(Error::ParseFailure("duplicate hello retry request"));
1904            }
1905            self.tls13_hrr_seen = true;
1906            self.tls13_hrr_requested_group = parsed.requested_group;
1907            self.reset_transcript_for_hrr();
1908            self.append_transcript(msg);
1909            self.state = HandshakeState::Idle;
1910            return Ok(());
1911        }
1912        let selected_suite = parsed.suite;
1913        self.tls13_hrr_seen = false;
1914        self.tls13_hrr_requested_group = None;
1915        let server_key_share = parsed.key_share;
1916        if let Some(share) = server_key_share {
1917            self.tls13_shared_secret = Some(match share {
1918                Tls13ServerKeyShareParsed::X25519(peer_key_share) => {
1919                    let private = self
1920                        .tls13_client_x25519_private
1921                        .clone()
1922                        .ok_or(Error::StateError(
1923                        "client x25519 key share must be available before server x25519 key share",
1924                    ))?;
1925                    derive_tls13_x25519_shared_secret(private, &peer_key_share)?
1926                }
1927                Tls13ServerKeyShareParsed::Secp256r1(peer_uncompressed) => {
1928                    let private = self.tls13_client_p256_private.as_ref().ok_or(
1929                        Error::StateError(
1930                            "client secp256r1 key share must be available before server secp256r1 key share",
1931                        ),
1932                    )?;
1933                    derive_tls13_p256_shared_secret(private, &peer_uncompressed)?
1934                }
1935                Tls13ServerKeyShareParsed::MlKem768(peer_key_share) => {
1936                    let private =
1937                        self.tls13_client_mlkem768_private
1938                            .as_ref()
1939                            .ok_or(Error::StateError(
1940                                "client mlkem768 key share must be available before server mlkem768 key share",
1941                            ))?;
1942                    derive_tls13_mlkem768_shared_secret(private, &peer_key_share)?
1943                }
1944                Tls13ServerKeyShareParsed::X25519MlKem768Hybrid { x25519, mlkem768 } => {
1945                    let x25519_private = self
1946                        .tls13_client_x25519_private
1947                        .clone()
1948                        .ok_or(Error::StateError(
1949                        "client x25519 key share must be available before server hybrid key share",
1950                    ))?;
1951                    let x25519_shared = derive_tls13_x25519_shared_secret(x25519_private, &x25519)?;
1952                    let mlkem_private =
1953                        self.tls13_client_mlkem768_private
1954                            .as_ref()
1955                            .ok_or(Error::StateError(
1956                                "client mlkem768 key share must be available before server hybrid key share",
1957                            ))?;
1958                    let mlkem_shared =
1959                        derive_tls13_mlkem768_shared_secret(mlkem_private, &mlkem768)?;
1960                    combine_tls13_hybrid_shared_secret(&x25519_shared, &mlkem_shared)
1961                }
1962            });
1963        }
1964        self.append_transcript(msg);
1965        self.selected_cipher_suite = Some(selected_suite);
1966        self.rebuild_transcript_hash_from_selected_suite();
1967        self.state = HandshakeState::ServerHelloReceived;
1968        Ok(())
1969    }
1970
1971    /// Builds a TLS 1.3 HelloRetryRequest (ServerHello form) with requested group.
1972    ///
1973    /// # Arguments
1974    /// * `suite`: Selected cipher suite to advertise.
1975    /// * `requested_group`: Named group requested for retried key share.
1976    ///
1977    /// # Returns
1978    /// Encoded HelloRetryRequest handshake message bytes.
1979    /// # Errors
1980    ///
1981    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
1982    ///
1983    /// # Panics
1984    ///
1985    /// This function does not panic.
1986    ///
1987    pub fn build_hello_retry_request(suite: CipherSuite, requested_group: u16) -> Result<Vec<u8>> {
1988        let mut body = Vec::new();
1989        body.extend_from_slice(&legacy_wire_version(TlsVersion::Tls13));
1990        body.extend_from_slice(&TLS13_HRR_RANDOM);
1991        body.push(0x00); // session_id length
1992        body.extend_from_slice(&suite.to_u16().to_be_bytes());
1993        body.push(0x00); // compression method
1994        let mut extensions = Vec::new();
1995        push_extension(
1996            &mut extensions,
1997            EXT_KEY_SHARE,
1998            &requested_group.to_be_bytes(),
1999        );
2000        body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
2001        body.extend_from_slice(&extensions);
2002        Ok(encode_handshake_message(HANDSHAKE_SERVER_HELLO, &body))
2003    }
2004
2005    /// Parses and records a TLS 1.3 EncryptedExtensions handshake message.
2006    ///
2007    /// # Arguments
2008    /// * `msg`: Encoded EncryptedExtensions handshake message.
2009    ///
2010    /// # Returns
2011    /// `Ok(())` when message type validates and transcript is updated.
2012    /// # Errors
2013    ///
2014    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2015    ///
2016    /// # Panics
2017    ///
2018    /// This function does not panic.
2019    ///
2020    pub fn recv_encrypted_extensions(&mut self, msg: &[u8]) -> Result<()> {
2021        if self.state != HandshakeState::ServerHelloReceived {
2022            return Err(Error::StateError(
2023                "encrypted extensions can only be processed after server hello",
2024            ));
2025        }
2026        let (handshake_type, body) = parse_handshake_message(msg)?;
2027        if handshake_type != HANDSHAKE_ENCRYPTED_EXTENSIONS {
2028            return Err(Error::ParseFailure("invalid encrypted extensions type"));
2029        }
2030        let encrypted_extensions = parse_encrypted_extensions_body(body)?;
2031        if encrypted_extensions.server_name_acknowledged && self.tls13_client_server_name.is_none()
2032        {
2033            return Err(Error::ParseFailure(
2034                "encrypted extensions contains unsolicited server_name acknowledgement",
2035            ));
2036        }
2037        if self.tls13_require_server_name_ack
2038            && self.tls13_client_server_name.is_some()
2039            && !encrypted_extensions.server_name_acknowledged
2040        {
2041            return Err(Error::ParseFailure(
2042                "encrypted extensions missing required server_name acknowledgement",
2043            ));
2044        }
2045        if encrypted_extensions.early_data_accepted
2046            && !self.tls13_early_data_offered_in_client_hello
2047        {
2048            return Err(Error::ParseFailure(
2049                "encrypted extensions contains unsolicited early_data acceptance",
2050            ));
2051        }
2052        self.tls13_early_data_accepted_in_encrypted_extensions =
2053            encrypted_extensions.early_data_accepted;
2054        if self.tls13_early_data_offered_in_client_hello
2055            && !encrypted_extensions.early_data_accepted
2056        {
2057            self.tls13_early_data_accepted_psk = None;
2058            self.tls13_early_data_max_bytes = None;
2059            self.tls13_early_data_opened_bytes = 0;
2060            self.tls13_early_data_replay_window = DtlsReplayWindow::new();
2061        }
2062        self.tls13_server_name_acknowledged = encrypted_extensions.server_name_acknowledged;
2063        if let Some(selected_protocol) = encrypted_extensions.selected_alpn_protocol {
2064            if !self.tls13_client_alpn_protocols.is_empty()
2065                && !self
2066                    .tls13_client_alpn_protocols
2067                    .contains(&selected_protocol)
2068            {
2069                return Err(Error::ParseFailure(
2070                    "encrypted extensions selected unsupported alpn protocol",
2071                ));
2072            }
2073            self.tls13_selected_alpn_protocol = Some(selected_protocol);
2074        } else {
2075            self.tls13_selected_alpn_protocol = None;
2076        }
2077        self.append_transcript(msg);
2078        self.state = HandshakeState::ServerEncryptedExtensionsReceived;
2079        Ok(())
2080    }
2081
2082    /// Builds a minimal TLS 1.3 CertificateRequest handshake message.
2083    ///
2084    /// # Arguments
2085    ///
2086    /// * _(none)_ — This function takes no parameters.
2087    ///
2088    /// # Returns
2089    /// Encoded CertificateRequest bytes.
2090    /// # Panics
2091    ///
2092    /// This function does not panic.
2093    ///
2094    pub fn build_certificate_request_message() -> Vec<u8> {
2095        // Empty request context + signature_algorithms extension.
2096        let mut extensions = Vec::new();
2097        let mut sigalgs = Vec::new();
2098        let requested_sigalgs = [
2099            TLS13_SIGALG_ECDSA_SECP256R1_SHA256,
2100            TLS13_SIGALG_RSA_PSS_RSAE_SHA256,
2101            TLS13_SIGALG_RSA_PSS_RSAE_SHA384,
2102            TLS13_SIGALG_ED25519,
2103            TLS13_SIGALG_MLDSA65,
2104        ];
2105        sigalgs.extend_from_slice(&((requested_sigalgs.len() * 2) as u16).to_be_bytes());
2106        for sigalg in requested_sigalgs {
2107            sigalgs.extend_from_slice(&sigalg.to_be_bytes());
2108        }
2109        push_extension(&mut extensions, EXT_SIGNATURE_ALGORITHMS, &sigalgs);
2110        let mut body = Vec::new();
2111        body.push(0x00); // certificate_request_context length
2112        body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
2113        body.extend_from_slice(&extensions);
2114        encode_handshake_message(HANDSHAKE_CERTIFICATE_REQUEST, &body)
2115    }
2116
2117    /// Parses and records a TLS 1.3 CertificateRequest handshake message.
2118    ///
2119    /// # Arguments
2120    /// * `msg`: Encoded CertificateRequest handshake message.
2121    ///
2122    /// # Returns
2123    /// `Ok(())` when message type validates and transcript is updated.
2124    /// # Errors
2125    ///
2126    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2127    ///
2128    /// # Panics
2129    ///
2130    /// This function does not panic.
2131    ///
2132    pub fn recv_certificate_request(&mut self, msg: &[u8]) -> Result<()> {
2133        if self.state != HandshakeState::ServerEncryptedExtensionsReceived {
2134            return Err(Error::StateError(
2135                "certificate request can only be processed after encrypted extensions",
2136            ));
2137        }
2138        let (handshake_type, body) = parse_handshake_message(msg)?;
2139        if handshake_type != HANDSHAKE_CERTIFICATE_REQUEST {
2140            return Err(Error::ParseFailure("invalid certificate request type"));
2141        }
2142        parse_certificate_request_body(body)?;
2143        self.append_transcript(msg);
2144        self.state = HandshakeState::ServerCertificateRequestReceived;
2145        Ok(())
2146    }
2147
2148    /// Builds a minimal TLS 1.3 EncryptedExtensions handshake message.
2149    ///
2150    /// # Arguments
2151    ///
2152    /// * _(none)_ — This function takes no parameters.
2153    ///
2154    /// # Returns
2155    /// Encoded EncryptedExtensions bytes.
2156    /// # Panics
2157    ///
2158    /// This function does not panic.
2159    ///
2160    pub fn build_encrypted_extensions() -> Vec<u8> {
2161        // Minimal empty extension block.
2162        Self::build_encrypted_extensions_with_policy(None, false, false)
2163            .expect("empty encrypted extensions must always encode")
2164    }
2165
2166    /// Builds a TLS 1.3 EncryptedExtensions handshake message with optional ALPN.
2167    ///
2168    /// # Arguments
2169    /// * `selected_alpn`: Selected ALPN protocol bytes to advertise to client, or `None`.
2170    ///
2171    /// # Returns
2172    /// Encoded EncryptedExtensions bytes.
2173    /// # Errors
2174    ///
2175    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2176    ///
2177    /// # Panics
2178    ///
2179    /// This function does not panic.
2180    ///
2181    pub fn build_encrypted_extensions_with_alpn(selected_alpn: Option<&[u8]>) -> Result<Vec<u8>> {
2182        Self::build_encrypted_extensions_with_policy(selected_alpn, false, false)
2183    }
2184
2185    /// Builds a TLS 1.3 EncryptedExtensions handshake message with optional ALPN and early_data ack.
2186    ///
2187    /// # Arguments
2188    /// * `selected_alpn`: Selected ALPN protocol bytes to advertise to client, or `None`.
2189    /// * `accept_early_data`: `true` emits empty early_data extension.
2190    ///
2191    /// # Returns
2192    /// Encoded EncryptedExtensions bytes.
2193    /// # Errors
2194    ///
2195    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2196    ///
2197    /// # Panics
2198    ///
2199    /// This function does not panic.
2200    pub fn build_encrypted_extensions_with_alpn_and_early_data(
2201        selected_alpn: Option<&[u8]>,
2202        accept_early_data: bool,
2203    ) -> Result<Vec<u8>> {
2204        Self::build_encrypted_extensions_with_policy(selected_alpn, false, accept_early_data)
2205    }
2206
2207    /// Builds a TLS 1.3 EncryptedExtensions handshake message with ALPN and SNI-ack policy.
2208    ///
2209    /// # Arguments
2210    /// * `selected_alpn`: Selected ALPN protocol bytes to advertise to client, or `None`.
2211    /// * `acknowledge_server_name`: `true` emits empty server_name extension as SNI acknowledgment.
2212    ///
2213    /// # Returns
2214    /// Encoded EncryptedExtensions bytes.
2215    /// # Errors
2216    ///
2217    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2218    ///
2219    /// # Panics
2220    ///
2221    /// This function does not panic.
2222    ///
2223    pub fn build_encrypted_extensions_with_policy(
2224        selected_alpn: Option<&[u8]>,
2225        acknowledge_server_name: bool,
2226        accept_early_data: bool,
2227    ) -> Result<Vec<u8>> {
2228        let mut body = Vec::new();
2229        let mut extensions = Vec::new();
2230        if let Some(protocol) = selected_alpn {
2231            if protocol.is_empty() {
2232                return Err(Error::InvalidLength("alpn protocol must not be empty"));
2233            }
2234            if protocol.len() > u8::MAX as usize {
2235                return Err(Error::InvalidLength(
2236                    "alpn protocol length must not exceed 255 bytes",
2237                ));
2238            }
2239            let protocols = vec![protocol.to_vec()];
2240            let extension_data = encode_alpn_extension_data(&protocols)?;
2241            push_extension(&mut extensions, EXT_ALPN, &extension_data);
2242        }
2243        if acknowledge_server_name {
2244            push_extension(&mut extensions, EXT_SERVER_NAME, &[]);
2245        }
2246        if accept_early_data {
2247            push_extension(&mut extensions, EXT_EARLY_DATA, &[]);
2248        }
2249        body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
2250        body.extend_from_slice(&extensions);
2251        Ok(encode_handshake_message(
2252            HANDSHAKE_ENCRYPTED_EXTENSIONS,
2253            &body,
2254        ))
2255    }
2256
2257    /// Parses and records a TLS 1.3 Certificate handshake message.
2258    ///
2259    /// # Arguments
2260    /// * `msg`: Encoded Certificate handshake message.
2261    ///
2262    /// # Returns
2263    /// `Ok(())` when message type validates and transcript is updated.
2264    /// # Errors
2265    ///
2266    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2267    ///
2268    /// # Panics
2269    ///
2270    /// This function does not panic.
2271    ///
2272    pub fn recv_certificate(&mut self, msg: &[u8]) -> Result<()> {
2273        if self.state != HandshakeState::ServerEncryptedExtensionsReceived
2274            && self.state != HandshakeState::ServerCertificateRequestReceived
2275        {
2276            return Err(Error::StateError(
2277                "certificate can only be processed after encrypted extensions/certificate request",
2278            ));
2279        }
2280        let (handshake_type, body) = parse_handshake_message(msg)?;
2281        if handshake_type != HANDSHAKE_CERTIFICATE {
2282            return Err(Error::ParseFailure("invalid certificate type"));
2283        }
2284        let parsed = parse_certificate_body(body)?;
2285        self.tls13_server_ocsp_staple = parsed.leaf_ocsp_staple.clone();
2286        self.tls13_server_ocsp_staple_verified = false;
2287        if self.tls13_require_ocsp_staple && parsed.leaf_ocsp_staple.is_none() {
2288            return Err(Error::ParseFailure(
2289                "certificate message missing required ocsp staple",
2290            ));
2291        }
2292        if let Some(staple) = parsed.leaf_ocsp_staple.as_deref() {
2293            if let Some(verifier) = self.tls13_ocsp_staple_verifier {
2294                match verifier(staple)? {
2295                    Tls13OcspStapleVerification::Good => {
2296                        self.tls13_server_ocsp_staple_verified = true;
2297                    }
2298                    Tls13OcspStapleVerification::Expired => {
2299                        return Err(Error::ParseFailure("ocsp staple expired"));
2300                    }
2301                    Tls13OcspStapleVerification::Revoked => {
2302                        return Err(Error::ParseFailure("ocsp staple revoked"));
2303                    }
2304                }
2305            } else {
2306                self.tls13_server_ocsp_staple_verified = true;
2307            }
2308        }
2309        if self.tls13_require_certificate_auth {
2310            self.validate_tls13_server_certificate_chain(&parsed.certificates)?;
2311        }
2312        self.append_transcript(msg);
2313        self.state = HandshakeState::ServerCertificateReceived;
2314        Ok(())
2315    }
2316
2317    /// Processes a full server handshake flight in expected TLS 1.3 order.
2318    ///
2319    /// Expected sequence:
2320    /// * `ServerHello`
2321    /// * `EncryptedExtensions`
2322    /// * optional `CertificateRequest`
2323    /// * `Certificate`
2324    /// * `CertificateVerify`
2325    /// * `Finished`
2326    ///
2327    /// # Arguments
2328    /// * `messages`: Ordered handshake messages from server.
2329    ///
2330    /// # Returns
2331    /// `Ok(())` when the full flight validates and transitions to `Finished`.
2332    /// # Errors
2333    ///
2334    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2335    ///
2336    /// # Panics
2337    ///
2338    /// This function does not panic.
2339    ///
2340    pub fn process_server_handshake_flight(&mut self, messages: &[Vec<u8>]) -> Result<()> {
2341        if messages.len() < 5 {
2342            return Err(Error::ParseFailure("server handshake flight is too short"));
2343        }
2344        let mut index = 0_usize;
2345        self.recv_server_hello(&messages[index])?;
2346        index += 1;
2347        self.recv_encrypted_extensions(&messages[index])?;
2348        index += 1;
2349        let (next_type, _) = parse_handshake_message(&messages[index])?;
2350        if next_type == HANDSHAKE_CERTIFICATE_REQUEST {
2351            self.recv_certificate_request(&messages[index])?;
2352            index += 1;
2353        }
2354        self.recv_certificate(&messages[index])?;
2355        index += 1;
2356        self.recv_certificate_verify(&messages[index])?;
2357        index += 1;
2358        self.derive_handshake_secret()?;
2359        self.recv_finished_message(&messages[index])?;
2360        index += 1;
2361        if index != messages.len() {
2362            return Err(Error::ParseFailure(
2363                "unexpected trailing server handshake messages",
2364            ));
2365        }
2366        Ok(())
2367    }
2368
2369    /// Processes TLS 1.2 server handshake flight in canonical order.
2370    ///
2371    /// Expected sequence:
2372    /// * `ServerHello`
2373    /// * `Certificate`
2374    /// * optional `ServerKeyExchange`
2375    /// * optional `CertificateRequest`
2376    /// * `ServerHelloDone`
2377    ///
2378    /// # Arguments
2379    /// * `messages`: Ordered handshake messages from server.
2380    ///
2381    /// # Returns
2382    /// `Ok(())` when the full flight validates and transitions to `ServerCertificateVerified`.
2383    /// # Errors
2384    ///
2385    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2386    ///
2387    /// # Panics
2388    ///
2389    /// This function does not panic.
2390    ///
2391    pub fn process_tls12_server_handshake_flight(&mut self, messages: &[Vec<u8>]) -> Result<()> {
2392        if self.version != TlsVersion::Tls12 {
2393            return Err(Error::StateError(
2394                "tls12 server flight processing requires tls1.2 connection version",
2395            ));
2396        }
2397        if self.state != HandshakeState::ClientHelloSent {
2398            return Err(Error::StateError(
2399                "tls12 server flight can only be processed after client hello",
2400            ));
2401        }
2402        if messages.len() < 3 {
2403            return Err(Error::ParseFailure(
2404                "tls12 server handshake flight is too short",
2405            ));
2406        }
2407
2408        let mut index = 0_usize;
2409        self.recv_server_hello(&messages[index])?;
2410        index += 1;
2411        let (next_type, _body) = parse_handshake_message(&messages[index])?;
2412        if next_type != HANDSHAKE_CERTIFICATE {
2413            return Err(Error::ParseFailure(
2414                "tls12 server handshake flight expected certificate after server hello",
2415            ));
2416        }
2417        self.recv_tls12_server_certificate(&messages[index])?;
2418        index += 1;
2419
2420        while index < messages.len() {
2421            let (message_type, _body) = parse_handshake_message(&messages[index])?;
2422            if message_type == HANDSHAKE_SERVER_KEY_EXCHANGE {
2423                self.recv_tls12_server_key_exchange(&messages[index])?;
2424                index += 1;
2425                continue;
2426            }
2427            if message_type == HANDSHAKE_CERTIFICATE_REQUEST {
2428                self.recv_tls12_server_certificate_request(&messages[index])?;
2429                index += 1;
2430                continue;
2431            }
2432            break;
2433        }
2434
2435        if index >= messages.len() {
2436            return Err(Error::ParseFailure(
2437                "tls12 server handshake flight missing server hello done",
2438            ));
2439        }
2440        self.recv_tls12_server_hello_done(&messages[index])?;
2441        index += 1;
2442        if index != messages.len() {
2443            return Err(Error::ParseFailure(
2444                "unexpected trailing tls12 server handshake messages",
2445            ));
2446        }
2447        self.state = HandshakeState::ServerCertificateVerified;
2448        Ok(())
2449    }
2450
2451    /// Records an inbound TLS 1.2 ChangeCipherSpec transition before client Finished.
2452    ///
2453    /// # Arguments
2454    ///
2455    /// * `self` — `&mut self`.
2456    ///
2457    /// # Returns
2458    /// `Ok(())` when the transition is accepted for the current handshake phase.
2459    /// # Errors
2460    ///
2461    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2462    ///
2463    /// # Panics
2464    ///
2465    /// This function does not panic.
2466    ///
2467    pub fn recv_tls12_change_cipher_spec(&mut self) -> Result<()> {
2468        if self.version != TlsVersion::Tls12 {
2469            return Err(Error::StateError(
2470                "tls12 change cipher spec requires tls1.2 connection version",
2471            ));
2472        }
2473        if self.state != HandshakeState::ServerCertificateVerified {
2474            return Err(Error::StateError(
2475                "tls12 change cipher spec can only be processed after server handshake flight",
2476            ));
2477        }
2478        self.tls12_change_cipher_spec_seen = true;
2479        Ok(())
2480    }
2481
2482    /// Processes TLS 1.2 client handshake flight after server has sent `ServerHelloDone`.
2483    ///
2484    /// Expected sequence:
2485    /// * `ClientKeyExchange`
2486    /// * optional `CertificateVerify`
2487    /// * `Finished` (requires prior `ChangeCipherSpec` signal)
2488    ///
2489    /// # Arguments
2490    /// * `messages`: Ordered client handshake messages from the peer.
2491    ///
2492    /// # Returns
2493    /// `Ok(())` when client flight validates and transitions to `Finished`.
2494    /// # Errors
2495    ///
2496    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2497    ///
2498    /// # Panics
2499    ///
2500    /// This function does not panic.
2501    ///
2502    pub fn process_tls12_client_handshake_flight(&mut self, messages: &[Vec<u8>]) -> Result<()> {
2503        if self.version != TlsVersion::Tls12 {
2504            return Err(Error::StateError(
2505                "tls12 client flight processing requires tls1.2 connection version",
2506            ));
2507        }
2508        if self.state != HandshakeState::ServerCertificateVerified {
2509            return Err(Error::StateError(
2510                "tls12 client flight can only be processed after server handshake flight",
2511            ));
2512        }
2513        if messages.len() < 2 {
2514            return Err(Error::ParseFailure(
2515                "tls12 client handshake flight is too short",
2516            ));
2517        }
2518        let mut index = 0_usize;
2519        let (next_type, _body) = parse_handshake_message(&messages[index])?;
2520        if next_type != HANDSHAKE_CLIENT_KEY_EXCHANGE {
2521            return Err(Error::ParseFailure(
2522                "tls12 client handshake flight expected client key exchange first",
2523            ));
2524        }
2525        self.recv_tls12_client_key_exchange(&messages[index])?;
2526        index += 1;
2527
2528        if index < messages.len() {
2529            let (message_type, _body) = parse_handshake_message(&messages[index])?;
2530            if message_type == HANDSHAKE_CERTIFICATE_VERIFY {
2531                self.recv_tls12_client_certificate_verify(&messages[index])?;
2532                index += 1;
2533            }
2534        }
2535
2536        if !self.tls12_change_cipher_spec_seen {
2537            return Err(Error::ParseFailure(
2538                "tls12 expected change cipher spec before finished",
2539            ));
2540        }
2541        if index >= messages.len() {
2542            return Err(Error::ParseFailure(
2543                "tls12 client handshake flight missing finished message",
2544            ));
2545        }
2546        self.recv_tls12_client_finished(&messages[index])?;
2547        index += 1;
2548        if index != messages.len() {
2549            return Err(Error::ParseFailure(
2550                "unexpected trailing tls12 client handshake messages",
2551            ));
2552        }
2553
2554        self.tls12_change_cipher_spec_seen = false;
2555        self.state = HandshakeState::Finished;
2556        Ok(())
2557    }
2558
2559    /// Processes TLS 1.2 server flight and attempts automatic alert emission on failure.
2560    ///
2561    /// # Arguments
2562    /// * `messages`: Ordered handshake messages from server.
2563    ///
2564    /// # Returns
2565    /// `Ok(())` on successful processing, or `Err((error, alert_packet))` where `alert_packet`
2566    /// contains the mapped TLS 1.2 alert packet when emission succeeds on this connection.
2567    /// # Errors
2568    ///
2569    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2570    ///
2571    /// # Panics
2572    ///
2573    /// This function does not panic.
2574    ///
2575    pub fn process_tls12_server_handshake_flight_with_alert(
2576        &mut self,
2577        messages: &[Vec<u8>],
2578    ) -> core::result::Result<(), (Error, Option<Vec<u8>>)> {
2579        match self.process_tls12_server_handshake_flight(messages) {
2580            Ok(()) => Ok(()),
2581            Err(error) => {
2582                let alert_packet = self.send_tls12_alert_for_handshake_error(&error).ok();
2583                Err((error, alert_packet))
2584            }
2585        }
2586    }
2587
2588    /// Processes TLS 1.2 client flight and attempts automatic alert emission on failure.
2589    ///
2590    /// # Arguments
2591    /// * `messages`: Ordered handshake messages from client.
2592    ///
2593    /// # Returns
2594    /// `Ok(())` on successful processing, or `Err((error, alert_packet))` where `alert_packet`
2595    /// contains the mapped TLS 1.2 alert packet when emission succeeds on this connection.
2596    /// # Errors
2597    ///
2598    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2599    ///
2600    /// # Panics
2601    ///
2602    /// This function does not panic.
2603    ///
2604    pub fn process_tls12_client_handshake_flight_with_alert(
2605        &mut self,
2606        messages: &[Vec<u8>],
2607    ) -> core::result::Result<(), (Error, Option<Vec<u8>>)> {
2608        match self.process_tls12_client_handshake_flight(messages) {
2609            Ok(()) => Ok(()),
2610            Err(error) => {
2611                let alert_packet = self.send_tls12_alert_for_handshake_error(&error).ok();
2612                Err((error, alert_packet))
2613            }
2614        }
2615    }
2616
2617    /// Maps a TLS 1.2 handshake processing error into a deterministic fatal alert description.
2618    ///
2619    /// # Arguments
2620    /// * `error`: Handshake processing error returned by TLS 1.2 sequencing/parsing helpers.
2621    ///
2622    /// # Returns
2623    /// `(AlertLevel::Fatal, AlertDescription)` selected for wire-level signaling policy.
2624    #[must_use]
2625    /// # Arguments
2626    ///
2627    /// * `error` — `error: &Error`.
2628    ///
2629    /// # Returns
2630    ///
2631    /// The value described by the return type in the function signature.
2632    ///
2633    /// # Panics
2634    ///
2635    /// This function does not panic.
2636    ///
2637    pub fn tls12_alert_for_handshake_error(error: &Error) -> (AlertLevel, AlertDescription) {
2638        let description = match error {
2639            Error::StateError(message) => {
2640                if message.contains("can only be processed")
2641                    || message.contains("expected")
2642                    || message.contains("missing")
2643                {
2644                    AlertDescription::UnexpectedMessage
2645                } else {
2646                    AlertDescription::InternalError
2647                }
2648            }
2649            Error::ParseFailure(message) | Error::InvalidLength(message) => {
2650                if message.contains("expected")
2651                    || message.contains("missing")
2652                    || message.contains("unexpected trailing")
2653                    || message.contains("invalid")
2654                    || message.contains("malformed")
2655                    || message.contains("must be empty")
2656                    || message.contains("must not be empty")
2657                {
2658                    AlertDescription::UnexpectedMessage
2659                } else {
2660                    AlertDescription::IllegalParameter
2661                }
2662            }
2663            Error::InvalidEncoding(_message) => AlertDescription::IllegalParameter,
2664            Error::UnsupportedFeature(_message) | Error::CryptoFailure(_message) => {
2665                AlertDescription::HandshakeFailure
2666            }
2667        };
2668        (AlertLevel::Fatal, description)
2669    }
2670
2671    /// Parses and records a TLS 1.2 Certificate handshake message with basic structure checks.
2672    ///
2673    /// # Arguments
2674    ///
2675    /// * `self` — `&mut self`.
2676    /// * `msg` — `msg: &[u8]`.
2677    ///
2678    /// # Returns
2679    ///
2680    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2681    ///
2682    /// # Errors
2683    ///
2684    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2685    ///
2686    /// # Panics
2687    ///
2688    /// This function does not panic.
2689    ///
2690    fn recv_tls12_server_certificate(&mut self, msg: &[u8]) -> Result<()> {
2691        if self.state != HandshakeState::ServerHelloReceived {
2692            return Err(Error::StateError(
2693                "tls12 certificate can only be processed after server hello",
2694            ));
2695        }
2696        let (message_type, body) = parse_handshake_message(msg)?;
2697        if message_type != HANDSHAKE_CERTIFICATE {
2698            return Err(Error::ParseFailure(
2699                "invalid tls12 certificate message type",
2700            ));
2701        }
2702        let certificates = parse_tls12_certificate_list(body)?;
2703        if self.tls13_require_certificate_auth {
2704            self.validate_tls13_server_certificate_chain(&certificates)?;
2705        }
2706        self.append_transcript(msg);
2707        self.state = HandshakeState::ServerCertificateReceived;
2708        Ok(())
2709    }
2710
2711    /// Parses and records a TLS 1.2 ServerKeyExchange message when present.
2712    ///
2713    /// # Arguments
2714    ///
2715    /// * `self` — `&mut self`.
2716    /// * `msg` — `msg: &[u8]`.
2717    ///
2718    /// # Returns
2719    ///
2720    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2721    ///
2722    /// # Errors
2723    ///
2724    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2725    ///
2726    /// # Panics
2727    ///
2728    /// This function does not panic.
2729    ///
2730    fn recv_tls12_server_key_exchange(&mut self, msg: &[u8]) -> Result<()> {
2731        if self.state != HandshakeState::ServerCertificateReceived {
2732            return Err(Error::StateError(
2733                "tls12 server key exchange can only be processed after certificate",
2734            ));
2735        }
2736        let (message_type, body) = parse_handshake_message(msg)?;
2737        if message_type != HANDSHAKE_SERVER_KEY_EXCHANGE {
2738            return Err(Error::ParseFailure(
2739                "invalid tls12 server key exchange message type",
2740            ));
2741        }
2742        parse_tls12_server_key_exchange_body(body)?;
2743        self.append_transcript(msg);
2744        Ok(())
2745    }
2746
2747    /// Parses and records a TLS 1.2 CertificateRequest message when server asks for client auth.
2748    ///
2749    /// # Arguments
2750    ///
2751    /// * `self` — `&mut self`.
2752    /// * `msg` — `msg: &[u8]`.
2753    ///
2754    /// # Returns
2755    ///
2756    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2757    ///
2758    /// # Errors
2759    ///
2760    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2761    ///
2762    /// # Panics
2763    ///
2764    /// This function does not panic.
2765    ///
2766    fn recv_tls12_server_certificate_request(&mut self, msg: &[u8]) -> Result<()> {
2767        if self.state != HandshakeState::ServerCertificateReceived {
2768            return Err(Error::StateError(
2769                "tls12 certificate request can only be processed after certificate",
2770            ));
2771        }
2772        let (message_type, body) = parse_handshake_message(msg)?;
2773        if message_type != HANDSHAKE_CERTIFICATE_REQUEST {
2774            return Err(Error::ParseFailure(
2775                "invalid tls12 certificate request message type",
2776            ));
2777        }
2778        if body.is_empty() {
2779            return Err(Error::ParseFailure(
2780                "tls12 certificate request body must not be empty",
2781            ));
2782        }
2783        self.append_transcript(msg);
2784        Ok(())
2785    }
2786
2787    /// Parses and records a TLS 1.2 ServerHelloDone message as end-of-server-flight marker.
2788    ///
2789    /// # Arguments
2790    ///
2791    /// * `self` — `&mut self`.
2792    /// * `msg` — `msg: &[u8]`.
2793    ///
2794    /// # Returns
2795    ///
2796    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2797    ///
2798    /// # Errors
2799    ///
2800    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2801    ///
2802    /// # Panics
2803    ///
2804    /// This function does not panic.
2805    ///
2806    fn recv_tls12_server_hello_done(&mut self, msg: &[u8]) -> Result<()> {
2807        if self.state != HandshakeState::ServerCertificateReceived {
2808            return Err(Error::StateError(
2809                "tls12 server hello done can only be processed after certificate flight",
2810            ));
2811        }
2812        let (message_type, body) = parse_handshake_message(msg)?;
2813        if message_type != HANDSHAKE_SERVER_HELLO_DONE {
2814            return Err(Error::ParseFailure(
2815                "invalid tls12 server hello done message type",
2816            ));
2817        }
2818        if !body.is_empty() {
2819            return Err(Error::ParseFailure(
2820                "tls12 server hello done body must be empty",
2821            ));
2822        }
2823        self.append_transcript(msg);
2824        Ok(())
2825    }
2826
2827    /// Parses and records a TLS 1.2 ClientKeyExchange message as client-flight entrypoint.
2828    ///
2829    /// # Arguments
2830    ///
2831    /// * `self` — `&mut self`.
2832    /// * `msg` — `msg: &[u8]`.
2833    ///
2834    /// # Returns
2835    ///
2836    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2837    ///
2838    /// # Errors
2839    ///
2840    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2841    ///
2842    /// # Panics
2843    ///
2844    /// This function does not panic.
2845    ///
2846    fn recv_tls12_client_key_exchange(&mut self, msg: &[u8]) -> Result<()> {
2847        let (message_type, body) = parse_handshake_message(msg)?;
2848        if message_type != HANDSHAKE_CLIENT_KEY_EXCHANGE {
2849            return Err(Error::ParseFailure(
2850                "invalid tls12 client key exchange message type",
2851            ));
2852        }
2853        if body.is_empty() {
2854            return Err(Error::ParseFailure(
2855                "tls12 client key exchange body must not be empty",
2856            ));
2857        }
2858        self.append_transcript(msg);
2859        Ok(())
2860    }
2861
2862    /// Parses and records an optional TLS 1.2 client CertificateVerify handshake message.
2863    ///
2864    /// # Arguments
2865    ///
2866    /// * `self` — `&mut self`.
2867    /// * `msg` — `msg: &[u8]`.
2868    ///
2869    /// # Returns
2870    ///
2871    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2872    ///
2873    /// # Errors
2874    ///
2875    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2876    ///
2877    /// # Panics
2878    ///
2879    /// This function does not panic.
2880    ///
2881    fn recv_tls12_client_certificate_verify(&mut self, msg: &[u8]) -> Result<()> {
2882        let (message_type, body) = parse_handshake_message(msg)?;
2883        if message_type != HANDSHAKE_CERTIFICATE_VERIFY {
2884            return Err(Error::ParseFailure(
2885                "invalid tls12 client certificate verify message type",
2886            ));
2887        }
2888        parse_tls12_certificate_verify_body(body)?;
2889        self.append_transcript(msg);
2890        Ok(())
2891    }
2892
2893    /// Parses and records TLS 1.2 client Finished handshake message shape.
2894    ///
2895    /// # Arguments
2896    ///
2897    /// * `self` — `&mut self`.
2898    /// * `msg` — `msg: &[u8]`.
2899    ///
2900    /// # Returns
2901    ///
2902    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
2903    ///
2904    /// # Errors
2905    ///
2906    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2907    ///
2908    /// # Panics
2909    ///
2910    /// This function does not panic.
2911    ///
2912    fn recv_tls12_client_finished(&mut self, msg: &[u8]) -> Result<()> {
2913        let (message_type, body) = parse_handshake_message(msg)?;
2914        if message_type != HANDSHAKE_FINISHED {
2915            return Err(Error::ParseFailure("invalid tls12 finished message type"));
2916        }
2917        if body.is_empty() {
2918            return Err(Error::ParseFailure("tls12 finished body must not be empty"));
2919        }
2920        self.append_transcript(msg);
2921        Ok(())
2922    }
2923
2924    /// Builds a minimal TLS 1.3 Certificate handshake message with one certificate entry.
2925    ///
2926    /// # Arguments
2927    /// * `certificate_der`: DER-encoded certificate bytes.
2928    ///
2929    /// # Returns
2930    /// Encoded Certificate message bytes.
2931    /// # Errors
2932    ///
2933    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2934    ///
2935    /// # Panics
2936    ///
2937    /// This function does not panic.
2938    ///
2939    pub fn build_certificate_message(certificate_der: &[u8]) -> Result<Vec<u8>> {
2940        Self::build_certificate_message_with_ocsp_staple(certificate_der, None)
2941    }
2942
2943    /// Builds a TLS 1.3 Certificate handshake message with optional leaf OCSP staple.
2944    ///
2945    /// # Arguments
2946    /// * `certificate_der`: DER-encoded certificate bytes.
2947    /// * `ocsp_staple`: Optional stapled OCSP response bytes for leaf certificate entry.
2948    ///
2949    /// # Returns
2950    /// Encoded Certificate message bytes.
2951    ///
2952    /// # Errors
2953    ///
2954    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2955    pub fn build_certificate_message_with_ocsp_staple(
2956        certificate_der: &[u8],
2957        ocsp_staple: Option<&[u8]>,
2958    ) -> Result<Vec<u8>> {
2959        if certificate_der.is_empty() {
2960            return Err(Error::InvalidLength("certificate der must not be empty"));
2961        }
2962        if certificate_der.len() > 0x00FF_FFFF {
2963            return Err(Error::InvalidLength("certificate der is too large"));
2964        }
2965        let certificate_extensions = if let Some(staple) = ocsp_staple {
2966            encode_certificate_entry_status_request_extension(staple)?
2967        } else {
2968            Vec::new()
2969        };
2970        let mut body = Vec::new();
2971        body.push(0x00); // certificate_request_context length
2972        let cert_entry_len = 3 + certificate_der.len() + 2 + certificate_extensions.len();
2973        let list_len = cert_entry_len as u32;
2974        body.extend_from_slice(&list_len.to_be_bytes()[1..4]);
2975        let cert_len = certificate_der.len() as u32;
2976        body.extend_from_slice(&cert_len.to_be_bytes()[1..4]);
2977        body.extend_from_slice(certificate_der);
2978        body.extend_from_slice(&(certificate_extensions.len() as u16).to_be_bytes());
2979        body.extend_from_slice(&certificate_extensions);
2980        Ok(encode_handshake_message(HANDSHAKE_CERTIFICATE, &body))
2981    }
2982
2983    /// Parses and records a TLS 1.3 CertificateVerify handshake message.
2984    ///
2985    /// # Arguments
2986    /// * `msg`: Encoded CertificateVerify handshake message.
2987    ///
2988    /// # Returns
2989    /// `Ok(())` when message type validates and transcript is updated.
2990    /// # Errors
2991    ///
2992    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
2993    ///
2994    /// # Panics
2995    ///
2996    /// This function does not panic.
2997    ///
2998    pub fn recv_certificate_verify(&mut self, msg: &[u8]) -> Result<()> {
2999        if self.state != HandshakeState::ServerCertificateReceived {
3000            return Err(Error::StateError(
3001                "certificate verify can only be processed after certificate",
3002            ));
3003        }
3004        let (handshake_type, body) = parse_handshake_message(msg)?;
3005        if handshake_type != HANDSHAKE_CERTIFICATE_VERIFY {
3006            return Err(Error::ParseFailure("invalid certificate verify type"));
3007        }
3008        let (signature_scheme, signature) = parse_certificate_verify_fields(body)?;
3009        if signature.is_empty() {
3010            return Err(Error::ParseFailure(
3011                "certificate verify signature must not be empty",
3012            ));
3013        }
3014        if !tls13_supported_certificate_verify_signature_scheme(signature_scheme) {
3015            return Err(Error::UnsupportedFeature(
3016                "unsupported tls13 certificate verify signature scheme",
3017            ));
3018        }
3019        if self.tls13_require_certificate_auth {
3020            if !self.tls13_server_certificate_chain_validated {
3021                return Err(Error::StateError(
3022                    "certificate verify requires validated server certificate chain",
3023                ));
3024            }
3025            self.verify_tls13_server_certificate_verify_signature(signature_scheme, signature)?;
3026        }
3027        self.append_transcript(msg);
3028        self.state = HandshakeState::ServerCertificateVerified;
3029        Ok(())
3030    }
3031
3032    /// Builds a minimal TLS 1.3 CertificateVerify handshake message.
3033    ///
3034    /// # Arguments
3035    /// * `signature_scheme`: Signature scheme identifier.
3036    /// * `signature`: Signature bytes.
3037    ///
3038    /// # Returns
3039    /// Encoded CertificateVerify message bytes.
3040    /// # Errors
3041    ///
3042    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3043    ///
3044    /// # Panics
3045    ///
3046    /// This function does not panic.
3047    ///
3048    pub fn build_certificate_verify_message(
3049        signature_scheme: u16,
3050        signature: &[u8],
3051    ) -> Result<Vec<u8>> {
3052        if signature.is_empty() {
3053            return Err(Error::InvalidLength(
3054                "certificate verify signature must not be empty",
3055            ));
3056        }
3057        if signature.len() > usize::from(u16::MAX) {
3058            return Err(Error::InvalidLength(
3059                "certificate verify signature is too large",
3060            ));
3061        }
3062        let mut body = Vec::new();
3063        body.extend_from_slice(&signature_scheme.to_be_bytes());
3064        body.extend_from_slice(&(signature.len() as u16).to_be_bytes());
3065        body.extend_from_slice(signature);
3066        Ok(encode_handshake_message(
3067            HANDSHAKE_CERTIFICATE_VERIFY,
3068            &body,
3069        ))
3070    }
3071
3072    /// Derives a prototype handshake secret from the selected transcript hash bytes.
3073    ///
3074    /// # Arguments
3075    /// * `self`: Connection with ServerHello already processed.
3076    ///
3077    /// # Returns
3078    /// 32-byte derived handshake secret.
3079    /// # Errors
3080    ///
3081    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3082    ///
3083    /// # Panics
3084    ///
3085    /// This function does not panic.
3086    ///
3087    pub fn derive_handshake_secret(&mut self) -> Result<[u8; 32]> {
3088        if self.state != HandshakeState::ServerHelloReceived
3089            && self.state != HandshakeState::ServerCertificateVerified
3090        {
3091            return Err(Error::StateError(
3092                "cannot derive handshake secret before server hello",
3093            ));
3094        }
3095        let transcript_hash = self.transcript_hash();
3096        let hash_algorithm = self.negotiated_hash_algorithm();
3097        let secret_material = match self.version {
3098            TlsVersion::Tls13 | TlsVersion::Dtls13 => derive_tls13_handshake_secret(
3099                hash_algorithm,
3100                self.tls13_shared_secret
3101                    .as_ref()
3102                    .map_or(&transcript_hash, |secret| secret),
3103                self.selected_cipher_suite,
3104            )?,
3105            TlsVersion::Tls12 | TlsVersion::Dtls12 => {
3106                let prk = hkdf_extract_for_hash(hash_algorithm, &transcript_hash);
3107                tls12_prf_for_hash(
3108                    hash_algorithm,
3109                    &prk,
3110                    b"handshake secret",
3111                    &transcript_hash,
3112                    32,
3113                )?
3114            }
3115            TlsVersion::Tls10 | TlsVersion::Tls11 => {
3116                let prk = hkdf_extract_for_hash(hash_algorithm, &transcript_hash);
3117                hkdf_expand_for_hash(hash_algorithm, &prk, b"handshake secret", 32)?
3118            }
3119        };
3120        self.install_traffic_keys(hash_algorithm, &secret_material, &transcript_hash)?;
3121        self.install_tls13_finished_key(hash_algorithm, &secret_material)?;
3122        self.handshake_secret = Some(secret_material.clone());
3123        let mut secret = [0_u8; 32];
3124        let copy_len = secret_material.len().min(32);
3125        secret[..copy_len].copy_from_slice(&secret_material[..copy_len]);
3126        self.state = HandshakeState::KeysDerived;
3127        Ok(secret)
3128    }
3129
3130    /// Finalizes the handshake and records verify data in transcript history.
3131    ///
3132    /// # Arguments
3133    /// * `verify_data`: Finished verify_data bytes to validate and record.
3134    ///
3135    /// # Returns
3136    /// `Ok(())` when Finished verification succeeds.
3137    /// # Errors
3138    ///
3139    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3140    ///
3141    /// # Panics
3142    ///
3143    /// This function does not panic.
3144    ///
3145    pub fn finish(&mut self, verify_data: &[u8]) -> Result<()> {
3146        if self.state != HandshakeState::KeysDerived
3147            && self.state != HandshakeState::ServerCertificateVerified
3148        {
3149            return Err(Error::StateError("finish must follow key derivation"));
3150        }
3151        let expected = self.compute_expected_finished()?;
3152        if verify_data != expected.as_slice() {
3153            return Err(Error::CryptoFailure("finished verify_data mismatch"));
3154        }
3155        self.append_transcript(verify_data);
3156        self.install_tls13_application_traffic_keys()?;
3157        self.state = HandshakeState::Finished;
3158        Ok(())
3159    }
3160
3161    /// Parses a TLS 1.3 Finished handshake wrapper and validates verify_data.
3162    ///
3163    /// # Arguments
3164    /// * `msg`: Encoded Finished handshake message.
3165    ///
3166    /// # Returns
3167    /// `Ok(())` when Finished verifies and state transitions to `Finished`.
3168    /// # Errors
3169    ///
3170    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3171    ///
3172    /// # Panics
3173    ///
3174    /// This function does not panic.
3175    ///
3176    pub fn recv_finished_message(&mut self, msg: &[u8]) -> Result<()> {
3177        let (handshake_type, body) = parse_handshake_message(msg)?;
3178        if handshake_type != HANDSHAKE_FINISHED {
3179            return Err(Error::ParseFailure("invalid finished type"));
3180        }
3181        if self.state != HandshakeState::KeysDerived
3182            && self.state != HandshakeState::ServerCertificateVerified
3183        {
3184            return Err(Error::StateError("finish must follow key derivation"));
3185        }
3186        let expected_len = self.compute_expected_finished()?.len();
3187        if body.len() != expected_len {
3188            return Err(Error::ParseFailure("finished verify_data length mismatch"));
3189        }
3190        self.finish(body)
3191    }
3192
3193    /// Builds local TLS 1.3 Finished handshake message from current transcript state.
3194    ///
3195    /// # Arguments
3196    ///
3197    /// * `&self` — `&self`.
3198    ///
3199    /// # Returns
3200    /// Encoded Finished handshake message bytes.
3201    /// # Errors
3202    ///
3203    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3204    ///
3205    /// # Panics
3206    ///
3207    /// This function does not panic.
3208    ///
3209    pub fn build_finished_message(&self) -> Result<Vec<u8>> {
3210        let verify_data = self.compute_finished_verify_data()?;
3211        Ok(encode_handshake_message(HANDSHAKE_FINISHED, &verify_data))
3212    }
3213
3214    /// Builds a minimal TLS 1.3 NewSessionTicket handshake message.
3215    ///
3216    /// # Arguments
3217    /// * `ticket_lifetime`: Ticket lifetime in seconds.
3218    /// * `ticket_age_add`: Obfuscation value for ticket age.
3219    /// * `ticket_nonce`: Ticket nonce bytes.
3220    /// * `ticket`: Opaque ticket identity bytes.
3221    ///
3222    /// # Returns
3223    /// Encoded NewSessionTicket message bytes.
3224    /// # Errors
3225    ///
3226    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3227    ///
3228    /// # Panics
3229    ///
3230    /// This function does not panic.
3231    ///
3232    pub fn build_new_session_ticket_message(
3233        ticket_lifetime: u32,
3234        ticket_age_add: u32,
3235        ticket_nonce: &[u8],
3236        ticket: &[u8],
3237    ) -> Result<Vec<u8>> {
3238        if ticket_nonce.len() > usize::from(u8::MAX) {
3239            return Err(Error::InvalidLength("ticket nonce is too large"));
3240        }
3241        if ticket.len() > usize::from(u16::MAX) {
3242            return Err(Error::InvalidLength("ticket identity is too large"));
3243        }
3244        let mut body = Vec::new();
3245        body.extend_from_slice(&ticket_lifetime.to_be_bytes());
3246        body.extend_from_slice(&ticket_age_add.to_be_bytes());
3247        body.push(ticket_nonce.len() as u8);
3248        body.extend_from_slice(ticket_nonce);
3249        body.extend_from_slice(&(ticket.len() as u16).to_be_bytes());
3250        body.extend_from_slice(ticket);
3251        body.extend_from_slice(&0_u16.to_be_bytes()); // extensions length
3252        Ok(encode_handshake_message(
3253            HANDSHAKE_NEW_SESSION_TICKET,
3254            &body,
3255        ))
3256    }
3257
3258    /// Parses and records a TLS 1.3 NewSessionTicket handshake message.
3259    ///
3260    /// # Arguments
3261    /// * `msg`: Encoded NewSessionTicket handshake message.
3262    ///
3263    /// # Returns
3264    /// `Ok(())` when message type validates and transcript is updated.
3265    /// # Errors
3266    ///
3267    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3268    ///
3269    /// # Panics
3270    ///
3271    /// This function does not panic.
3272    ///
3273    pub fn recv_new_session_ticket_message(&mut self, msg: &[u8]) -> Result<()> {
3274        if self.state != HandshakeState::Finished {
3275            return Err(Error::StateError(
3276                "new session ticket requires finished handshake state",
3277            ));
3278        }
3279        let (handshake_type, body) = parse_handshake_message(msg)?;
3280        if handshake_type != HANDSHAKE_NEW_SESSION_TICKET {
3281            return Err(Error::ParseFailure("invalid new session ticket type"));
3282        }
3283        parse_new_session_ticket_body(body)?;
3284        self.append_transcript(msg);
3285        Ok(())
3286    }
3287
3288    /// Builds a TLS 1.3 KeyUpdate handshake message.
3289    ///
3290    /// # Arguments
3291    /// * `request_update`: Whether peer should also update its sending keys.
3292    ///
3293    /// # Returns
3294    /// Encoded KeyUpdate message bytes.
3295    /// # Panics
3296    ///
3297    /// This function does not panic.
3298    ///
3299    pub fn build_key_update_message(request_update: bool) -> Vec<u8> {
3300        let request = if request_update { 1_u8 } else { 0_u8 };
3301        encode_handshake_message(HANDSHAKE_KEY_UPDATE, &[request])
3302    }
3303
3304    /// Parses a TLS 1.3 KeyUpdate handshake message and rotates traffic keys.
3305    ///
3306    /// # Arguments
3307    /// * `msg`: Encoded KeyUpdate handshake message.
3308    ///
3309    /// # Returns
3310    /// `Ok(())` when KeyUpdate parses and local keys rotate successfully.
3311    /// # Errors
3312    ///
3313    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3314    ///
3315    /// # Panics
3316    ///
3317    /// This function does not panic.
3318    ///
3319    pub fn recv_key_update_message(&mut self, msg: &[u8]) -> Result<()> {
3320        if self.state != HandshakeState::Finished {
3321            return Err(Error::StateError(
3322                "key update requires finished handshake state",
3323            ));
3324        }
3325        let (handshake_type, body) = parse_handshake_message(msg)?;
3326        if handshake_type != HANDSHAKE_KEY_UPDATE {
3327            return Err(Error::ParseFailure("invalid key update type"));
3328        }
3329        if body.len() != 1 || body[0] > 1 {
3330            return Err(Error::ParseFailure("invalid key update request value"));
3331        }
3332        self.update_tls13_traffic_keys()?;
3333        self.append_transcript(msg);
3334        Ok(())
3335    }
3336
3337    /// Computes the current transcript hash bytes for post-handshake key schedule use.
3338    ///
3339    /// # Returns
3340    /// Current transcript hash bytes from selected hash algorithm.
3341    #[must_use]
3342    /// # Arguments
3343    ///
3344    /// * `&self` — `&self`.
3345    ///
3346    /// # Returns
3347    ///
3348    /// The value described by the return type in the function signature.
3349    ///
3350    /// # Panics
3351    ///
3352    /// This function does not panic.
3353    ///
3354    pub fn transcript_hash(&self) -> Vec<u8> {
3355        self.transcript_hash.snapshot_hash()
3356    }
3357
3358    /// Returns currently negotiated cipher suite, if known from ServerHello.
3359    ///
3360    /// # Returns
3361    /// Selected cipher suite when negotiation has completed.
3362    #[must_use]
3363    /// # Arguments
3364    ///
3365    /// * `&self` — `&self`.
3366    ///
3367    /// # Returns
3368    ///
3369    /// On success, `Some` as described by the return type; see the function body for when `None` is returned.
3370    ///
3371    /// # Panics
3372    ///
3373    /// This function does not panic.
3374    ///
3375    pub fn selected_cipher_suite(&self) -> Option<CipherSuite> {
3376        self.selected_cipher_suite
3377    }
3378
3379    /// Builds a minimally-encoded TLS ServerHello handshake message.
3380    ///
3381    /// # Arguments
3382    /// * `version`: Protocol version to encode.
3383    /// * `suite`: Selected cipher suite to advertise.
3384    /// * `random`: 32-byte ServerHello random value.
3385    ///
3386    /// # Returns
3387    /// Encoded ServerHello handshake message bytes.
3388    /// # Errors
3389    ///
3390    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3391    ///
3392    /// # Panics
3393    ///
3394    /// This function does not panic.
3395    ///
3396    pub fn build_server_hello(
3397        version: TlsVersion,
3398        suite: CipherSuite,
3399        random: &[u8],
3400    ) -> Result<Vec<u8>> {
3401        if random.len() != 32 {
3402            return Err(Error::InvalidLength("server hello random must be 32 bytes"));
3403        }
3404        let body = encode_server_hello_body(version, suite, random)?;
3405        Ok(encode_handshake_message(HANDSHAKE_SERVER_HELLO, &body))
3406    }
3407
3408    /// Builds a TLS 1.3 ServerHello with an explicit ECDHE `key_share` entry (interop/tests).
3409    ///
3410    /// # Arguments
3411    /// * `version`: Protocol version to encode.
3412    /// * `suite`: Selected cipher suite to advertise.
3413    /// * `random`: 32-byte ServerHello random value.
3414    /// * `named_group`: IANA `NamedGroup` (for example `0x001D` X25519, `0x0017` secp256r1).
3415    /// * `key_exchange`: Raw `KeyExchange` bytes for the selected group.
3416    ///
3417    /// # Returns
3418    /// Encoded ServerHello handshake message bytes.
3419    /// # Errors
3420    ///
3421    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3422    ///
3423    /// # Panics
3424    ///
3425    /// This function does not panic.
3426    ///
3427    pub fn build_server_hello_with_key_share(
3428        version: TlsVersion,
3429        suite: CipherSuite,
3430        random: &[u8],
3431        named_group: u16,
3432        key_exchange: &[u8],
3433    ) -> Result<Vec<u8>> {
3434        if random.len() != 32 {
3435            return Err(Error::InvalidLength("server hello random must be 32 bytes"));
3436        }
3437        let body = encode_server_hello_body_with_key_share(
3438            version,
3439            suite,
3440            random,
3441            Some((named_group, key_exchange)),
3442        )?;
3443        Ok(encode_handshake_message(HANDSHAKE_SERVER_HELLO, &body))
3444    }
3445
3446    /// Builds a TLS ServerHello with randomness sourced from HMAC-DRBG.
3447    ///
3448    /// # Arguments
3449    /// * `version`: Protocol version to encode.
3450    /// * `suite`: Selected cipher suite to advertise.
3451    /// * `drbg`: DRBG instance used to generate ServerHello random bytes.
3452    ///
3453    /// # Returns
3454    /// Encoded ServerHello handshake message bytes.
3455    /// # Errors
3456    ///
3457    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3458    ///
3459    /// # Panics
3460    ///
3461    /// This function does not panic.
3462    ///
3463    pub fn build_server_hello_auto(
3464        version: TlsVersion,
3465        suite: CipherSuite,
3466        drbg: &mut HmacDrbgSha256,
3467    ) -> Result<Vec<u8>> {
3468        let random = drbg.generate(32, b"server_hello_random")?;
3469        Self::build_server_hello(version, suite, &random)
3470    }
3471
3472    /// Parses a ClientHello and returns advertised cipher suites in wire order.
3473    ///
3474    /// # Arguments
3475    /// * `msg`: Encoded ClientHello handshake message.
3476    ///
3477    /// # Returns
3478    /// Supported cipher suites offered by the client.
3479    /// # Errors
3480    ///
3481    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3482    ///
3483    /// # Panics
3484    ///
3485    /// This function does not panic.
3486    ///
3487    pub fn parse_client_hello_cipher_suites(msg: &[u8]) -> Result<Vec<CipherSuite>> {
3488        parse_client_hello_info(msg).map(|hello| hello.offered_cipher_suites)
3489    }
3490
3491    /// Parses a ClientHello into suites and selected extension metadata.
3492    ///
3493    /// # Arguments
3494    /// * `msg`: Encoded ClientHello handshake message.
3495    ///
3496    /// # Returns
3497    /// Parsed `ClientHelloInfo` with suites and extension summary.
3498    /// # Errors
3499    ///
3500    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3501    ///
3502    /// # Panics
3503    ///
3504    /// This function does not panic.
3505    ///
3506    pub fn parse_client_hello_info(msg: &[u8]) -> Result<ClientHelloInfo> {
3507        parse_client_hello_info(msg)
3508    }
3509
3510    /// Builds TLS 1.3 server CertificateVerify signed content from transcript hash.
3511    ///
3512    /// # Arguments
3513    /// * `transcript_hash`: Transcript hash bytes for the signing context.
3514    ///
3515    /// # Returns
3516    /// Byte vector to be signed/verified for server CertificateVerify.
3517    #[must_use]
3518    /// # Arguments
3519    ///
3520    /// * `transcript_hash` — `transcript_hash: &[u8]`.
3521    ///
3522    /// # Returns
3523    ///
3524    /// The value described by the return type in the function signature.
3525    ///
3526    /// # Panics
3527    ///
3528    /// This function does not panic.
3529    ///
3530    pub fn tls13_server_certificate_verify_content(transcript_hash: &[u8]) -> Vec<u8> {
3531        build_tls13_server_certificate_verify_message(transcript_hash)
3532    }
3533
3534    /// Selects one server-preferred suite that is also offered by the client.
3535    ///
3536    /// # Arguments
3537    /// * `client_hello`: Encoded ClientHello bytes.
3538    /// * `server_preferred`: Server preference-ordered suite list.
3539    /// * `version`: Protocol version context for filtering.
3540    ///
3541    /// # Returns
3542    /// Selected mutually-supported cipher suite.
3543    /// # Errors
3544    ///
3545    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3546    ///
3547    /// # Panics
3548    ///
3549    /// This function does not panic.
3550    ///
3551    pub fn select_cipher_suite_from_client_hello(
3552        client_hello: &[u8],
3553        server_preferred: &[CipherSuite],
3554        version: TlsVersion,
3555    ) -> Result<CipherSuite> {
3556        let hello = parse_client_hello_info(client_hello)?;
3557        pick_intersection_suite(&hello, server_preferred, version)
3558    }
3559
3560    /// Builds a ServerHello by negotiating against offered client cipher suites.
3561    ///
3562    /// # Arguments
3563    /// * `version`: Protocol version to encode.
3564    /// * `client_hello`: Encoded ClientHello bytes.
3565    /// * `server_random`: 32-byte ServerHello random value.
3566    /// * `server_preferred`: Server preference-ordered suite list.
3567    ///
3568    /// # Returns
3569    /// Encoded ServerHello handshake message bytes.
3570    /// # Errors
3571    ///
3572    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3573    ///
3574    /// # Panics
3575    ///
3576    /// This function does not panic.
3577    ///
3578    pub fn build_server_hello_for_client(
3579        version: TlsVersion,
3580        client_hello: &[u8],
3581        server_random: &[u8],
3582        server_preferred: &[CipherSuite],
3583    ) -> Result<Vec<u8>> {
3584        let selected =
3585            Self::select_cipher_suite_from_client_hello(client_hello, server_preferred, version)?;
3586        Self::build_server_hello(version, selected, server_random)
3587    }
3588
3589    /// Builds a ServerHello for a parsed ClientHello with DRBG-generated random.
3590    ///
3591    /// # Arguments
3592    /// * `version`: Protocol version to encode.
3593    /// * `client_hello`: Encoded ClientHello bytes.
3594    /// * `server_preferred`: Server preference-ordered suite list.
3595    /// * `drbg`: DRBG instance used to generate ServerHello random bytes.
3596    ///
3597    /// # Returns
3598    /// Encoded ServerHello handshake message bytes.
3599    /// # Errors
3600    ///
3601    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3602    ///
3603    /// # Panics
3604    ///
3605    /// This function does not panic.
3606    ///
3607    pub fn build_server_hello_for_client_auto(
3608        version: TlsVersion,
3609        client_hello: &[u8],
3610        server_preferred: &[CipherSuite],
3611        drbg: &mut HmacDrbgSha256,
3612    ) -> Result<Vec<u8>> {
3613        let random = drbg.generate(32, b"server_hello_random")?;
3614        Self::build_server_hello_for_client(version, client_hello, &random, server_preferred)
3615    }
3616
3617    /// Computes TLS-style Finished verify_data from transcript hash context.
3618    ///
3619    /// # Arguments
3620    ///
3621    /// * `&self` — `&self`.
3622    ///
3623    /// # Returns
3624    /// Expected Finished verify_data bytes for this connection state.
3625    /// # Errors
3626    ///
3627    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3628    ///
3629    /// # Panics
3630    ///
3631    /// This function does not panic.
3632    ///
3633    pub fn compute_finished_verify_data(&self) -> Result<Vec<u8>> {
3634        self.compute_expected_finished()
3635    }
3636
3637    /// Rolls TLS 1.3 application traffic keys to the next key-update generation.
3638    ///
3639    /// # Arguments
3640    /// * `self`: Finished TLS 1.3 connection with installed application secrets.
3641    ///
3642    /// # Returns
3643    /// `Ok(())` when traffic secrets and record protection keys are updated.
3644    /// # Errors
3645    ///
3646    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3647    ///
3648    /// # Panics
3649    ///
3650    /// This function does not panic.
3651    ///
3652    pub fn update_tls13_traffic_keys(&mut self) -> Result<()> {
3653        if !self.version.uses_tls13_handshake_semantics() {
3654            return Err(Error::StateError(
3655                "tls13 traffic key update is only valid for TLS 1.3",
3656            ));
3657        }
3658        if self.state != HandshakeState::Finished {
3659            return Err(Error::StateError(
3660                "tls13 traffic key update requires finished handshake",
3661            ));
3662        }
3663        let hash_algorithm = self.negotiated_hash_algorithm();
3664        let hash_len = hash_algorithm.output_len();
3665        let client_secret = self
3666            .tls13_client_application_traffic_secret
3667            .as_ref()
3668            .ok_or(Error::StateError(
3669                "tls13 application client traffic secret is not installed",
3670            ))?;
3671        let server_secret = self
3672            .tls13_server_application_traffic_secret
3673            .as_ref()
3674            .ok_or(Error::StateError(
3675                "tls13 application server traffic secret is not installed",
3676            ))?;
3677        let next_client_secret = tls13_expand_label_for_hash(
3678            hash_algorithm,
3679            client_secret,
3680            b"traffic upd",
3681            &[],
3682            hash_len,
3683        )?;
3684        let next_server_secret = tls13_expand_label_for_hash(
3685            hash_algorithm,
3686            server_secret,
3687            b"traffic upd",
3688            &[],
3689            hash_len,
3690        )?;
3691        self.install_tls13_record_protection_keys(
3692            hash_algorithm,
3693            &next_client_secret,
3694            &next_server_secret,
3695        )?;
3696        self.tls13_client_application_traffic_secret = Some(next_client_secret);
3697        self.tls13_server_application_traffic_secret = Some(next_server_secret);
3698        self.client_sequence = 0;
3699        self.server_sequence = 0;
3700        Ok(())
3701    }
3702
3703    /// Derives QUIC Initial secrets for QUIC v1 using the destination connection ID.
3704    ///
3705    /// # Arguments
3706    /// * `destination_connection_id`: QUIC destination connection ID from the client's first Initial packet.
3707    ///
3708    /// # Returns
3709    /// QUIC v1 initial secret bundle containing common, client, and server initial secrets.
3710    ///
3711    /// # Errors
3712    ///
3713    /// Returns [`Error::InvalidLength`] when the destination connection ID is empty, or other [`noxtls_core::Error`] values from HKDF label expansion.
3714    ///
3715    /// # Panics
3716    ///
3717    /// This function does not panic.
3718    pub fn derive_tls13_quic_initial_secrets_v1(
3719        destination_connection_id: &[u8],
3720    ) -> Result<Tls13QuicInitialSecrets> {
3721        if destination_connection_id.is_empty() {
3722            return Err(Error::InvalidLength(
3723                "quic destination connection id must not be empty",
3724            ));
3725        }
3726        let initial_secret =
3727            hkdf_extract_sha256(&TLS13_QUIC_V1_INITIAL_SALT, destination_connection_id).to_vec();
3728        let client_initial_secret = tls13_expand_label_for_hash(
3729            HashAlgorithm::Sha256,
3730            &initial_secret,
3731            b"client in",
3732            &[],
3733            32,
3734        )?;
3735        let server_initial_secret = tls13_expand_label_for_hash(
3736            HashAlgorithm::Sha256,
3737            &initial_secret,
3738            b"server in",
3739            &[],
3740            32,
3741        )?;
3742        Ok(Tls13QuicInitialSecrets {
3743            initial_secret,
3744            client_initial_secret,
3745            server_initial_secret,
3746        })
3747    }
3748
3749    /// Derives QUIC packet-protection key material from one traffic secret.
3750    ///
3751    /// # Arguments
3752    /// * `hash_algorithm`: Hash profile used for TLS HKDF label expansion.
3753    /// * `traffic_secret`: QUIC traffic secret at a specific encryption level.
3754    /// * `key_len`: AEAD key length in bytes.
3755    /// * `header_protection_key_len`: Header-protection key length in bytes.
3756    ///
3757    /// # Returns
3758    /// QUIC key, IV, and header-protection key derived from `traffic_secret`.
3759    ///
3760    /// # Errors
3761    ///
3762    /// Returns [`Error::InvalidLength`] when key lengths are zero, or other [`noxtls_core::Error`] values from HKDF label expansion.
3763    ///
3764    /// # Panics
3765    ///
3766    /// This function does not panic.
3767    pub fn derive_tls13_quic_packet_protection_keys(
3768        hash_algorithm: HashAlgorithm,
3769        traffic_secret: &[u8],
3770        key_len: usize,
3771        header_protection_key_len: usize,
3772    ) -> Result<Tls13QuicPacketProtectionKeys> {
3773        if key_len == 0 {
3774            return Err(Error::InvalidLength(
3775                "quic key length must be greater than zero",
3776            ));
3777        }
3778        if header_protection_key_len == 0 {
3779            return Err(Error::InvalidLength(
3780                "quic header protection key length must be greater than zero",
3781            ));
3782        }
3783        let key =
3784            tls13_expand_label_for_hash(hash_algorithm, traffic_secret, b"quic key", &[], key_len)?;
3785        let iv = tls13_expand_label_for_hash(hash_algorithm, traffic_secret, b"quic iv", &[], 12)?;
3786        let header_protection_key = tls13_expand_label_for_hash(
3787            hash_algorithm,
3788            traffic_secret,
3789            b"quic hp",
3790            &[],
3791            header_protection_key_len,
3792        )?;
3793        Ok(Tls13QuicPacketProtectionKeys {
3794            key,
3795            iv,
3796            header_protection_key,
3797        })
3798    }
3799
3800    /// Returns current QUIC handshake and 1-RTT traffic secret snapshots.
3801    ///
3802    /// # Returns
3803    /// Bundle containing client/server handshake and application traffic secrets.
3804    ///
3805    /// # Errors
3806    ///
3807    /// Returns [`noxtls_core::Error`] when called before corresponding TLS 1.3 secrets are installed.
3808    ///
3809    /// # Panics
3810    ///
3811    /// This function does not panic.
3812    pub fn tls13_quic_traffic_secret_snapshot(&self) -> Result<Tls13QuicTrafficSecretSnapshot> {
3813        if !self.version.uses_tls13_handshake_semantics() {
3814            return Err(Error::StateError(
3815                "quic traffic secret snapshot is only defined for TLS 1.3",
3816            ));
3817        }
3818        let client_handshake_secret =
3819            self.tls13_client_handshake_traffic_secret
3820                .clone()
3821                .ok_or(Error::StateError(
3822                    "tls13 client handshake traffic secret is not installed",
3823                ))?;
3824        let server_handshake_secret =
3825            self.tls13_server_handshake_traffic_secret
3826                .clone()
3827                .ok_or(Error::StateError(
3828                    "tls13 server handshake traffic secret is not installed",
3829                ))?;
3830        let client_application_secret = self
3831            .tls13_client_application_traffic_secret
3832            .clone()
3833            .ok_or(Error::StateError(
3834                "tls13 client application traffic secret is not installed",
3835            ))?;
3836        let server_application_secret = self
3837            .tls13_server_application_traffic_secret
3838            .clone()
3839            .ok_or(Error::StateError(
3840                "tls13 server application traffic secret is not installed",
3841            ))?;
3842        Ok(Tls13QuicTrafficSecretSnapshot {
3843            client_handshake_secret,
3844            server_handshake_secret,
3845            client_application_secret,
3846            server_application_secret,
3847        })
3848    }
3849
3850    /// Derives next QUIC 1-RTT traffic secrets from currently installed application secrets.
3851    ///
3852    /// # Returns
3853    /// Next-generation client/server application secrets derived via `quic ku`.
3854    ///
3855    /// # Errors
3856    ///
3857    /// Returns [`noxtls_core::Error`] when called before TLS 1.3 application secrets are installed.
3858    ///
3859    /// # Panics
3860    ///
3861    /// This function does not panic.
3862    pub fn derive_tls13_quic_next_traffic_secrets(&self) -> Result<Tls13QuicNextTrafficSecrets> {
3863        if !self.version.uses_tls13_handshake_semantics() {
3864            return Err(Error::StateError(
3865                "quic key update secrets are only defined for TLS 1.3",
3866            ));
3867        }
3868        let hash_algorithm = self.negotiated_hash_algorithm();
3869        let hash_len = hash_algorithm.output_len();
3870        let client_secret = self
3871            .tls13_client_application_traffic_secret
3872            .as_ref()
3873            .ok_or(Error::StateError(
3874                "tls13 application client traffic secret is not installed",
3875            ))?;
3876        let server_secret = self
3877            .tls13_server_application_traffic_secret
3878            .as_ref()
3879            .ok_or(Error::StateError(
3880                "tls13 application server traffic secret is not installed",
3881            ))?;
3882        let client_next_application_secret =
3883            tls13_expand_label_for_hash(hash_algorithm, client_secret, b"quic ku", &[], hash_len)?;
3884        let server_next_application_secret =
3885            tls13_expand_label_for_hash(hash_algorithm, server_secret, b"quic ku", &[], hash_len)?;
3886        Ok(Tls13QuicNextTrafficSecrets {
3887            client_next_application_secret,
3888            server_next_application_secret,
3889        })
3890    }
3891
3892    /// Exports QUIC-specific keying material using `EXPORTER-QUIC ...` labels.
3893    ///
3894    /// # Arguments
3895    /// * `label`: QUIC exporter label, for example [`TLS13_QUIC_EXPORTER_LABEL_CLIENT_1RTT`].
3896    /// * `context`: Exporter context bytes.
3897    /// * `len`: Requested output length in bytes.
3898    ///
3899    /// # Returns
3900    /// Exported keying material bytes bound to transcript and QUIC exporter label.
3901    ///
3902    /// # Errors
3903    ///
3904    /// Returns [`Error::StateError`] when label namespace is not QUIC, or other exporter errors from [`Self::export_keying_material`].
3905    ///
3906    /// # Panics
3907    ///
3908    /// This function does not panic.
3909    pub fn export_quic_keying_material(
3910        &self,
3911        label: &[u8],
3912        context: &[u8],
3913        len: usize,
3914    ) -> Result<Vec<u8>> {
3915        if !label.starts_with(b"EXPORTER-QUIC ") {
3916            return Err(Error::StateError(
3917                "quic exporter requires label prefix EXPORTER-QUIC ",
3918            ));
3919        }
3920        self.export_keying_material(label, context, len)
3921    }
3922
3923    /// Exports keying material from TLS 1.3 exporter secret for application protocols.
3924    ///
3925    /// # Arguments
3926    /// * `label`: Exporter label namespace chosen by the caller.
3927    /// * `context`: Application-specific exporter context bytes.
3928    /// * `len`: Requested output keying material length.
3929    ///
3930    /// # Returns
3931    /// Exported keying material bytes bound to transcript and context.
3932    /// # Errors
3933    ///
3934    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3935    ///
3936    /// # Panics
3937    ///
3938    /// This function does not panic.
3939    ///
3940    pub fn export_keying_material(
3941        &self,
3942        label: &[u8],
3943        context: &[u8],
3944        len: usize,
3945    ) -> Result<Vec<u8>> {
3946        if !self.version.uses_tls13_handshake_semantics() {
3947            return Err(Error::StateError(
3948                "key exporter is currently only modeled for TLS 1.3",
3949            ));
3950        }
3951        if self.state != HandshakeState::Finished {
3952            return Err(Error::StateError(
3953                "key exporter requires finished handshake state",
3954            ));
3955        }
3956        let hash_algorithm = self.negotiated_hash_algorithm();
3957        let hash_len = hash_algorithm.output_len();
3958        let exporter_master =
3959            self.tls13_exporter_master_secret
3960                .as_ref()
3961                .ok_or(Error::StateError(
3962                    "tls13 exporter master secret is not installed",
3963                ))?;
3964        let context_hash = hash_bytes_for_algorithm(hash_algorithm, context);
3965        let exporter_secret = tls13_expand_label_for_hash(
3966            hash_algorithm,
3967            exporter_master,
3968            b"exporter",
3969            &context_hash,
3970            hash_len,
3971        )?;
3972        tls13_expand_label_for_hash(hash_algorithm, &exporter_secret, label, &context_hash, len)
3973    }
3974
3975    /// Returns TLS 1.3 resumption master secret snapshot for ticket/resumption plumbing.
3976    ///
3977    /// # Arguments
3978    ///
3979    /// * `&self` — `&self`.
3980    ///
3981    /// # Returns
3982    /// Cloned resumption master secret bytes for current handshake epoch.
3983    /// # Errors
3984    ///
3985    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
3986    ///
3987    /// # Panics
3988    ///
3989    /// This function does not panic.
3990    ///
3991    pub fn tls13_resumption_master_secret(&self) -> Result<Vec<u8>> {
3992        if !self.version.uses_tls13_handshake_semantics() {
3993            return Err(Error::StateError(
3994                "resumption master secret is only defined for TLS 1.3",
3995            ));
3996        }
3997        if self.state != HandshakeState::Finished {
3998            return Err(Error::StateError(
3999                "resumption master secret requires finished handshake state",
4000            ));
4001        }
4002        self.tls13_resumption_master_secret
4003            .clone()
4004            .ok_or(Error::StateError(
4005                "tls13 resumption master secret is not installed",
4006            ))
4007    }
4008
4009    /// Derives a TLS 1.3 resumption PSK from resumption master secret and ticket nonce.
4010    ///
4011    /// # Arguments
4012    /// * `ticket_nonce`: NewSessionTicket ticket_nonce bytes.
4013    ///
4014    /// # Returns
4015    /// Resumption PSK bytes sized to the negotiated transcript hash output length.
4016    /// # Errors
4017    ///
4018    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4019    ///
4020    /// # Panics
4021    ///
4022    /// This function does not panic.
4023    ///
4024    pub fn derive_tls13_resumption_psk(&self, ticket_nonce: &[u8]) -> Result<Vec<u8>> {
4025        if !self.version.uses_tls13_handshake_semantics() {
4026            return Err(Error::StateError(
4027                "resumption psk derivation is only defined for TLS 1.3",
4028            ));
4029        }
4030        if ticket_nonce.is_empty() {
4031            return Err(Error::InvalidLength("ticket nonce must not be empty"));
4032        }
4033        let hash_algorithm = self.negotiated_hash_algorithm();
4034        let hash_len = hash_algorithm.output_len();
4035        let resumption_master =
4036            self.tls13_resumption_master_secret
4037                .as_ref()
4038                .ok_or(Error::StateError(
4039                    "tls13 resumption master secret is not installed",
4040                ))?;
4041        tls13_expand_label_for_hash(
4042            hash_algorithm,
4043            resumption_master,
4044            b"resumption",
4045            ticket_nonce,
4046            hash_len,
4047        )
4048    }
4049
4050    /// Issues one local TLS 1.3 resumption ticket from current resumption master secret.
4051    ///
4052    /// # Arguments
4053    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4054    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4055    ///
4056    /// # Returns
4057    /// `ResumptionTicket` containing identity, nonce, and age fields.
4058    /// # Errors
4059    ///
4060    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4061    ///
4062    /// # Panics
4063    ///
4064    /// This function does not panic.
4065    ///
4066    pub fn issue_tls13_resumption_ticket(
4067        &self,
4068        drbg: &mut HmacDrbgSha256,
4069        age_add: u32,
4070    ) -> Result<ResumptionTicket> {
4071        self.issue_tls13_resumption_ticket_with_time(drbg, age_add, 0, u64::MAX)
4072    }
4073
4074    /// Issues one TLS 1.3 ticket and inserts it into a mutable ticket store.
4075    ///
4076    /// # Arguments
4077    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4078    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4079    /// * `ticket_store`: Mutable ticket cache receiving the issued ticket.
4080    ///
4081    /// # Returns
4082    /// Issued `ResumptionTicket` after insertion into `ticket_store`.
4083    /// # Errors
4084    ///
4085    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4086    ///
4087    /// # Panics
4088    ///
4089    /// This function does not panic.
4090    ///
4091    pub fn issue_tls13_resumption_ticket_into_store(
4092        &self,
4093        drbg: &mut HmacDrbgSha256,
4094        age_add: u32,
4095        ticket_store: &mut TicketStore,
4096    ) -> Result<ResumptionTicket> {
4097        let ticket = self.issue_tls13_resumption_ticket(drbg, age_add)?;
4098        ticket_store.insert(ticket.clone());
4099        Ok(ticket)
4100    }
4101
4102    /// Issues one local TLS 1.3 resumption ticket with explicit issuance time and lifetime.
4103    ///
4104    /// # Arguments
4105    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4106    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4107    /// * `issued_at_ms`: Server-local issue timestamp in milliseconds.
4108    /// * `lifetime_ms`: Ticket lifetime window in milliseconds.
4109    ///
4110    /// # Returns
4111    /// `ResumptionTicket` containing identity, nonce, and age policy fields.
4112    /// # Errors
4113    ///
4114    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4115    ///
4116    /// # Panics
4117    ///
4118    /// This function does not panic.
4119    ///
4120    pub fn issue_tls13_resumption_ticket_with_time(
4121        &self,
4122        drbg: &mut HmacDrbgSha256,
4123        age_add: u32,
4124        issued_at_ms: u64,
4125        lifetime_ms: u64,
4126    ) -> Result<ResumptionTicket> {
4127        if !self.version.uses_tls13_handshake_semantics() {
4128            return Err(Error::StateError(
4129                "resumption ticket issuance is only defined for TLS 1.3",
4130            ));
4131        }
4132        if self.state != HandshakeState::Finished {
4133            return Err(Error::StateError(
4134                "resumption ticket issuance requires finished handshake state",
4135            ));
4136        }
4137        let nonce = drbg.generate(16, b"tls13_ticket_nonce")?;
4138        let hash_algorithm = self.negotiated_hash_algorithm();
4139        let identity = tls13_expand_label_for_hash(
4140            hash_algorithm,
4141            &self.tls13_resumption_master_secret()?,
4142            b"ticket",
4143            &nonce,
4144            16,
4145        )?;
4146        Ok(ResumptionTicket {
4147            identity,
4148            ticket_nonce: nonce,
4149            obfuscated_ticket_age: age_add,
4150            age_add,
4151            issued_at_ms,
4152            lifetime_ms,
4153            max_early_data_size: TLS_MAX_RECORD_PLAINTEXT_LEN as u32,
4154            consumed: false,
4155        })
4156    }
4157
4158    /// Issues one local TLS 1.3 resumption ticket with explicit early-data size allowance.
4159    ///
4160    /// # Arguments
4161    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4162    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4163    /// * `issued_at_ms`: Server-local issue timestamp in milliseconds.
4164    /// * `lifetime_ms`: Ticket lifetime window in milliseconds.
4165    /// * `max_early_data_size`: Maximum accepted 0-RTT plaintext bytes for this ticket.
4166    ///
4167    /// # Returns
4168    /// `ResumptionTicket` containing identity, nonce, age policy fields, and early-data limit.
4169    /// # Errors
4170    ///
4171    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4172    ///
4173    /// # Panics
4174    ///
4175    /// This function does not panic.
4176    pub fn issue_tls13_resumption_ticket_with_time_and_early_data(
4177        &self,
4178        drbg: &mut HmacDrbgSha256,
4179        age_add: u32,
4180        issued_at_ms: u64,
4181        lifetime_ms: u64,
4182        max_early_data_size: u32,
4183    ) -> Result<ResumptionTicket> {
4184        let mut ticket =
4185            self.issue_tls13_resumption_ticket_with_time(drbg, age_add, issued_at_ms, lifetime_ms)?;
4186        ticket.max_early_data_size = max_early_data_size;
4187        Ok(ticket)
4188    }
4189
4190    /// Issues one timed TLS 1.3 ticket and inserts it into a mutable ticket store.
4191    ///
4192    /// # Arguments
4193    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4194    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4195    /// * `issued_at_ms`: Server-local issue timestamp in milliseconds.
4196    /// * `lifetime_ms`: Ticket lifetime window in milliseconds.
4197    /// * `ticket_store`: Mutable ticket cache receiving the issued ticket.
4198    ///
4199    /// # Returns
4200    /// Issued `ResumptionTicket` after insertion into `ticket_store`.
4201    /// # Errors
4202    ///
4203    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4204    ///
4205    /// # Panics
4206    ///
4207    /// This function does not panic.
4208    ///
4209    pub fn issue_tls13_resumption_ticket_with_time_into_store(
4210        &self,
4211        drbg: &mut HmacDrbgSha256,
4212        age_add: u32,
4213        issued_at_ms: u64,
4214        lifetime_ms: u64,
4215        ticket_store: &mut TicketStore,
4216    ) -> Result<ResumptionTicket> {
4217        let ticket =
4218            self.issue_tls13_resumption_ticket_with_time(drbg, age_add, issued_at_ms, lifetime_ms)?;
4219        ticket_store.insert(ticket.clone());
4220        Ok(ticket)
4221    }
4222
4223    /// Issues one timed TLS 1.3 ticket with early-data allowance and inserts it into a store.
4224    ///
4225    /// # Arguments
4226    /// * `drbg`: DRBG used to generate per-ticket nonce material.
4227    /// * `age_add`: Ticket age_add value used for obfuscated ticket age encoding.
4228    /// * `issued_at_ms`: Server-local issue timestamp in milliseconds.
4229    /// * `lifetime_ms`: Ticket lifetime window in milliseconds.
4230    /// * `max_early_data_size`: Maximum accepted 0-RTT plaintext bytes for this ticket.
4231    /// * `ticket_store`: Mutable ticket cache receiving the issued ticket.
4232    ///
4233    /// # Returns
4234    /// Issued `ResumptionTicket` after insertion into `ticket_store`.
4235    /// # Errors
4236    ///
4237    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4238    ///
4239    /// # Panics
4240    ///
4241    /// This function does not panic.
4242    pub fn issue_tls13_resumption_ticket_with_time_and_early_data_into_store(
4243        &self,
4244        drbg: &mut HmacDrbgSha256,
4245        age_add: u32,
4246        issued_at_ms: u64,
4247        lifetime_ms: u64,
4248        max_early_data_size: u32,
4249        ticket_store: &mut TicketStore,
4250    ) -> Result<ResumptionTicket> {
4251        let ticket = self.issue_tls13_resumption_ticket_with_time_and_early_data(
4252            drbg,
4253            age_add,
4254            issued_at_ms,
4255            lifetime_ms,
4256            max_early_data_size,
4257        )?;
4258        ticket_store.insert(ticket.clone());
4259        Ok(ticket)
4260    }
4261
4262    /// Computes TLS 1.3 PSK binder bytes for a truncated ClientHello transcript.
4263    ///
4264    /// # Arguments
4265    /// * `psk`: Candidate PSK bytes to validate.
4266    /// * `truncated_client_hello`: ClientHello bytes up to (but excluding) binder list.
4267    ///
4268    /// # Returns
4269    /// Binder bytes using the connection's negotiated hash policy.
4270    /// # Errors
4271    ///
4272    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4273    ///
4274    /// # Panics
4275    ///
4276    /// This function does not panic.
4277    ///
4278    pub fn compute_tls13_psk_binder(
4279        &self,
4280        psk: &[u8],
4281        truncated_client_hello: &[u8],
4282    ) -> Result<Vec<u8>> {
4283        if !self.version.uses_tls13_handshake_semantics() {
4284            return Err(Error::StateError(
4285                "psk binder computation is only defined for TLS 1.3",
4286            ));
4287        }
4288        if psk.is_empty() {
4289            return Err(Error::InvalidLength("psk must not be empty"));
4290        }
4291        if truncated_client_hello.is_empty() {
4292            return Err(Error::InvalidLength(
4293                "truncated client hello must not be empty",
4294            ));
4295        }
4296        let hash_algorithm = self.negotiated_hash_algorithm();
4297        let hash_len = hash_algorithm.output_len();
4298        let early_secret = hkdf_extract_for_hash(hash_algorithm, psk);
4299        let binder_key = tls13_expand_label_for_hash(
4300            hash_algorithm,
4301            &early_secret,
4302            b"res binder",
4303            &[],
4304            hash_len,
4305        )?;
4306        let finished_key =
4307            tls13_expand_label_for_hash(hash_algorithm, &binder_key, b"finished", &[], hash_len)?;
4308        let transcript_hash = hash_bytes_for_algorithm(hash_algorithm, truncated_client_hello);
4309        Ok(finished_hmac_for_hash(
4310            hash_algorithm,
4311            &finished_key,
4312            &transcript_hash,
4313        ))
4314    }
4315
4316    /// Verifies TLS 1.3 PSK binder bytes against provided ClientHello transcript prefix.
4317    ///
4318    /// # Arguments
4319    /// * `psk`: Candidate PSK bytes associated with the binder.
4320    /// * `truncated_client_hello`: ClientHello bytes up to binder list.
4321    /// * `received_binder`: Binder bytes received from peer.
4322    ///
4323    /// # Returns
4324    /// `Ok(true)` when binder matches expected value, `Ok(false)` otherwise.
4325    /// # Errors
4326    ///
4327    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4328    ///
4329    /// # Panics
4330    ///
4331    /// This function does not panic.
4332    ///
4333    pub fn verify_tls13_psk_binder(
4334        &self,
4335        psk: &[u8],
4336        truncated_client_hello: &[u8],
4337        received_binder: &[u8],
4338    ) -> Result<bool> {
4339        let expected = self.compute_tls13_psk_binder(psk, truncated_client_hello)?;
4340        Ok(constant_time_eq(&expected, received_binder))
4341    }
4342
4343    /// Verifies first PSK binder inside a TLS 1.3 ClientHello pre_shared_key extension.
4344    ///
4345    /// # Arguments
4346    /// * `client_hello`: Encoded ClientHello carrying pre_shared_key extension.
4347    /// * `psk`: Candidate PSK bytes associated with first identity.
4348    ///
4349    /// # Returns
4350    /// `Ok(true)` when first binder validates; `Ok(false)` otherwise.
4351    /// # Errors
4352    ///
4353    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4354    ///
4355    /// # Panics
4356    ///
4357    /// This function does not panic.
4358    ///
4359    pub fn verify_client_hello_psk_binder(&self, client_hello: &[u8], psk: &[u8]) -> Result<bool> {
4360        if !self.version.uses_tls13_handshake_semantics() {
4361            return Err(Error::StateError(
4362                "psk binder verification is only defined for TLS 1.3",
4363            ));
4364        }
4365        if psk.is_empty() {
4366            return Err(Error::InvalidLength("psk must not be empty"));
4367        }
4368        let received = extract_first_psk_binder_from_client_hello(client_hello)?;
4369        let normalized = zero_client_hello_psk_binders(client_hello)?;
4370        self.verify_tls13_psk_binder(psk, &normalized, &received)
4371    }
4372
4373    /// Verifies a ClientHello pre_shared_key offer against a locally-issued resumption ticket.
4374    ///
4375    /// # Arguments
4376    /// * `client_hello`: Encoded TLS 1.3 ClientHello.
4377    /// * `ticket`: Ticket metadata expected by the server.
4378    ///
4379    /// # Returns
4380    /// `Ok(true)` when first PSK identity matches and binder validates.
4381    /// # Errors
4382    ///
4383    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4384    ///
4385    /// # Panics
4386    ///
4387    /// This function does not panic.
4388    ///
4389    pub fn verify_client_hello_psk_binder_for_ticket(
4390        &self,
4391        client_hello: &[u8],
4392        ticket: &ResumptionTicket,
4393    ) -> Result<bool> {
4394        self.verify_client_hello_psk_binder_for_ticket_with_age(
4395            client_hello,
4396            ticket,
4397            ticket.issued_at_ms,
4398            u32::MAX,
4399        )
4400    }
4401
4402    /// Verifies ticket identity, binder, and age/skew policy for TLS 1.3 PSK resumption.
4403    ///
4404    /// # Arguments
4405    /// * `client_hello`: Encoded TLS 1.3 ClientHello.
4406    /// * `ticket`: Ticket metadata expected by the server.
4407    /// * `current_time_ms`: Server-local current timestamp in milliseconds.
4408    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4409    ///
4410    /// # Returns
4411    /// `Ok(true)` when identity, age policy, and binder all validate.
4412    /// # Errors
4413    ///
4414    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4415    ///
4416    /// # Panics
4417    ///
4418    /// This function does not panic.
4419    ///
4420    pub fn verify_client_hello_psk_binder_for_ticket_with_age(
4421        &self,
4422        client_hello: &[u8],
4423        ticket: &ResumptionTicket,
4424        current_time_ms: u64,
4425        max_skew_ms: u32,
4426    ) -> Result<bool> {
4427        if !self.version.uses_tls13_handshake_semantics() {
4428            return Err(Error::StateError(
4429                "psk binder verification is only defined for TLS 1.3",
4430            ));
4431        }
4432        let info = parse_client_hello_info(client_hello)?;
4433        let Some(identity) = info.extensions.psk_identities.first() else {
4434            return Ok(false);
4435        };
4436        if identity.as_slice() != ticket.identity.as_slice() {
4437            return Ok(false);
4438        }
4439        let Some(offered_age) = info.extensions.psk_obfuscated_ticket_ages.first().copied() else {
4440            return Ok(false);
4441        };
4442        if ticket.consumed {
4443            return Ok(false);
4444        }
4445        if !ticket_age_matches_policy(ticket, offered_age, current_time_ms, max_skew_ms) {
4446            return Ok(false);
4447        }
4448        let psk = self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?;
4449        self.verify_client_hello_psk_binder(client_hello, &psk)
4450    }
4451
4452    /// Verifies ClientHello PSK binders by scanning all offered identities against ticket set.
4453    ///
4454    /// # Arguments
4455    /// * `client_hello`: Encoded TLS 1.3 ClientHello.
4456    /// * `tickets`: Candidate server tickets allowed for this connection.
4457    /// * `current_time_ms`: Server-local timestamp in milliseconds.
4458    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4459    ///
4460    /// # Returns
4461    /// `Ok(Some(ticket_index))` for first valid ticket match, `Ok(None)` otherwise.
4462    /// # Errors
4463    ///
4464    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4465    ///
4466    /// # Panics
4467    ///
4468    /// This function does not panic.
4469    ///
4470    pub fn verify_client_hello_psk_binder_for_tickets_with_age(
4471        &self,
4472        client_hello: &[u8],
4473        tickets: &[ResumptionTicket],
4474        current_time_ms: u64,
4475        max_skew_ms: u32,
4476    ) -> Result<Option<usize>> {
4477        if !self.version.uses_tls13_handshake_semantics() {
4478            return Err(Error::StateError(
4479                "psk binder verification is only defined for TLS 1.3",
4480            ));
4481        }
4482        if tickets.is_empty() {
4483            return Ok(None);
4484        }
4485        let info = parse_client_hello_info(client_hello)?;
4486        if info.extensions.psk_identities.is_empty() || info.extensions.psk_binders.is_empty() {
4487            return Ok(None);
4488        }
4489        let normalized = zero_client_hello_psk_binders(client_hello)?;
4490        for (identity_idx, identity) in info.extensions.psk_identities.iter().enumerate() {
4491            let Some(offered_age) = info
4492                .extensions
4493                .psk_obfuscated_ticket_ages
4494                .get(identity_idx)
4495                .copied()
4496            else {
4497                continue;
4498            };
4499            let Some(received_binder) = info.extensions.psk_binders.get(identity_idx) else {
4500                continue;
4501            };
4502            for (ticket_idx, ticket) in tickets.iter().enumerate() {
4503                if identity.as_slice() != ticket.identity.as_slice() {
4504                    continue;
4505                }
4506                if ticket.consumed {
4507                    continue;
4508                }
4509                if !ticket_age_matches_policy(ticket, offered_age, current_time_ms, max_skew_ms) {
4510                    continue;
4511                }
4512                let psk = self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?;
4513                let expected_binder = self.compute_tls13_psk_binder(&psk, &normalized)?;
4514                if constant_time_eq(&expected_binder, received_binder) {
4515                    return Ok(Some(ticket_idx));
4516                }
4517            }
4518        }
4519        Ok(None)
4520    }
4521
4522    /// Verifies PSK binders across multiple tickets and applies ticket usage policy.
4523    ///
4524    /// # Arguments
4525    /// * `client_hello`: Encoded TLS 1.3 ClientHello.
4526    /// * `tickets`: Mutable server ticket set considered for PSK resumption.
4527    /// * `current_time_ms`: Server-local timestamp in milliseconds.
4528    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4529    /// * `usage_policy`: Whether accepted tickets remain reusable or are consumed.
4530    ///
4531    /// # Returns
4532    /// `Ok(Some(ticket_index))` for first valid ticket match, `Ok(None)` otherwise.
4533    /// # Errors
4534    ///
4535    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4536    ///
4537    /// # Panics
4538    ///
4539    /// This function does not panic.
4540    ///
4541    pub fn verify_and_apply_client_hello_psk_policy(
4542        &self,
4543        client_hello: &[u8],
4544        tickets: &mut [ResumptionTicket],
4545        current_time_ms: u64,
4546        max_skew_ms: u32,
4547        usage_policy: TicketUsagePolicy,
4548    ) -> Result<Option<usize>> {
4549        let matched = self.verify_client_hello_psk_binder_for_tickets_with_age(
4550            client_hello,
4551            tickets,
4552            current_time_ms,
4553            max_skew_ms,
4554        )?;
4555        if let Some(index) = matched {
4556            if usage_policy == TicketUsagePolicy::SingleUse {
4557                if let Some(ticket) = tickets.get_mut(index) {
4558                    ticket.consumed = true;
4559                }
4560            }
4561        }
4562        Ok(matched)
4563    }
4564
4565    /// Verifies and applies PSK ticket policy against cached ticket store entries.
4566    ///
4567    /// # Arguments
4568    /// * `client_hello`: Encoded TLS 1.3 ClientHello.
4569    /// * `ticket_store`: Mutable ticket cache used for candidate lookup and policy updates.
4570    /// * `current_time_ms`: Server-local timestamp in milliseconds.
4571    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4572    /// * `usage_policy`: Whether accepted tickets remain reusable or are consumed.
4573    ///
4574    /// # Returns
4575    /// `Ok(Some(ticket_index))` for first valid ticket match, `Ok(None)` otherwise.
4576    /// # Errors
4577    ///
4578    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4579    ///
4580    /// # Panics
4581    ///
4582    /// This function does not panic.
4583    ///
4584    pub fn verify_and_apply_client_hello_psk_policy_with_store(
4585        &self,
4586        client_hello: &[u8],
4587        ticket_store: &mut TicketStore,
4588        current_time_ms: u64,
4589        max_skew_ms: u32,
4590        usage_policy: TicketUsagePolicy,
4591    ) -> Result<Option<usize>> {
4592        self.verify_and_apply_client_hello_psk_policy(
4593            client_hello,
4594            ticket_store.tickets_mut(),
4595            current_time_ms,
4596            max_skew_ms,
4597            usage_policy,
4598        )
4599    }
4600
4601    /// Evaluates ClientHello ticket policy and, on success, enables early-data acceptance context.
4602    ///
4603    /// # Arguments
4604    /// * `client_hello`: Encoded TLS 1.3 ClientHello carrying PSK identities.
4605    /// * `tickets`: Mutable server ticket set considered for PSK resumption.
4606    /// * `current_time_ms`: Server-local timestamp in milliseconds.
4607    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4608    /// * `usage_policy`: Whether accepted tickets remain reusable or are consumed.
4609    ///
4610    /// # Returns
4611    /// `Ok(true)` when ticket policy passes and early-data context is installed.
4612    /// # Errors
4613    ///
4614    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4615    ///
4616    /// # Panics
4617    ///
4618    /// This function does not panic.
4619    ///
4620    pub fn accept_tls13_early_data_with_ticket_policy(
4621        &mut self,
4622        client_hello: &[u8],
4623        tickets: &mut [ResumptionTicket],
4624        current_time_ms: u64,
4625        max_skew_ms: u32,
4626        usage_policy: TicketUsagePolicy,
4627    ) -> Result<bool> {
4628        let info = parse_client_hello_info(client_hello)?;
4629        self.tls13_early_data_offered_in_client_hello = info.extensions.early_data_offered;
4630        self.tls13_early_data_accepted_in_encrypted_extensions = false;
4631        self.tls13_early_data_opened_bytes = 0;
4632        self.reset_tls13_early_data_transcript_to_client_hello(client_hello);
4633        let matched = self.verify_and_apply_client_hello_psk_policy(
4634            client_hello,
4635            tickets,
4636            current_time_ms,
4637            max_skew_ms,
4638            usage_policy,
4639        )?;
4640        let Some(ticket_index) = matched else {
4641            self.tls13_early_data_accepted_psk = None;
4642            self.tls13_early_data_max_bytes = None;
4643            return Ok(false);
4644        };
4645        if !self.tls13_early_data_offered_in_client_hello {
4646            self.tls13_early_data_accepted_psk = None;
4647            self.tls13_early_data_max_bytes = None;
4648            return Ok(false);
4649        }
4650        let ticket = tickets
4651            .get(ticket_index)
4652            .ok_or(Error::StateError("matched ticket index is out of range"))?;
4653        if ticket.max_early_data_size == 0 {
4654            self.tls13_early_data_accepted_psk = None;
4655            self.tls13_early_data_max_bytes = None;
4656            return Ok(false);
4657        }
4658        let psk = self.derive_tls13_resumption_psk(&ticket.ticket_nonce)?;
4659        self.tls13_early_data_accepted_psk = Some(psk);
4660        self.tls13_early_data_max_bytes = Some(ticket.max_early_data_size);
4661        self.tls13_early_data_replay_window = DtlsReplayWindow::new();
4662        Ok(true)
4663    }
4664
4665    /// Evaluates ClientHello ticket policy via ticket store and installs early-data context.
4666    ///
4667    /// # Arguments
4668    /// * `client_hello`: Encoded TLS 1.3 ClientHello carrying PSK identities.
4669    /// * `ticket_store`: Mutable ticket cache used for candidate lookup and policy updates.
4670    /// * `current_time_ms`: Server-local timestamp in milliseconds.
4671    /// * `max_skew_ms`: Allowed absolute age skew between expected and offered age.
4672    /// * `usage_policy`: Whether accepted tickets remain reusable or are consumed.
4673    ///
4674    /// # Returns
4675    /// `Ok(true)` when ticket policy passes and early-data context is installed.
4676    /// # Errors
4677    ///
4678    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4679    ///
4680    /// # Panics
4681    ///
4682    /// This function does not panic.
4683    ///
4684    pub fn accept_tls13_early_data_with_ticket_store(
4685        &mut self,
4686        client_hello: &[u8],
4687        ticket_store: &mut TicketStore,
4688        current_time_ms: u64,
4689        max_skew_ms: u32,
4690        usage_policy: TicketUsagePolicy,
4691    ) -> Result<bool> {
4692        self.accept_tls13_early_data_with_ticket_policy(
4693            client_hello,
4694            ticket_store.tickets_mut(),
4695            current_time_ms,
4696            max_skew_ms,
4697            usage_policy,
4698        )
4699    }
4700
4701    /// Seals outbound application data using installed client traffic keys.
4702    ///
4703    /// # Arguments
4704    /// * `plaintext`: Application plaintext bytes to protect.
4705    /// * `aad`: Additional authenticated data for record protection.
4706    ///
4707    /// # Returns
4708    /// `ProtectedRecord` containing sequence, ciphertext, and tag.
4709    /// # Errors
4710    ///
4711    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4712    ///
4713    /// # Panics
4714    ///
4715    /// This function does not panic.
4716    ///
4717    pub fn seal_record(&mut self, plaintext: &[u8], aad: &[u8]) -> Result<ProtectedRecord> {
4718        if self.state != HandshakeState::Finished {
4719            return Err(Error::StateError(
4720                "cannot seal record before handshake finish",
4721            ));
4722        }
4723        if plaintext.len() > self.max_record_plaintext_len {
4724            return Err(Error::InvalidLength(
4725                "record plaintext exceeds configured limit",
4726            ));
4727        }
4728        if self.client_sequence == u64::MAX {
4729            return Err(Error::StateError("client record sequence exhausted"));
4730        }
4731        let suite = self.selected_cipher_suite.ok_or(Error::StateError(
4732            "cipher suite must be selected before sealing records",
4733        ))?;
4734        let key = self
4735            .client_write_key
4736            .ok_or(Error::StateError("client write key is not installed"))?;
4737        let iv = self
4738            .client_write_iv
4739            .ok_or(Error::StateError("client write iv is not installed"))?;
4740        let nonce = build_record_nonce(&iv, self.client_sequence);
4741        let (ciphertext, tag) = match suite {
4742            CipherSuite::TlsChacha20Poly1305Sha256 => {
4743                chacha20_poly1305_encrypt(&key, &nonce, aad, plaintext)?
4744            }
4745            CipherSuite::TlsAes128GcmSha256 | CipherSuite::TlsAes256GcmSha384 => {
4746                let key_len = suite.tls13_traffic_key_len().ok_or(Error::StateError(
4747                    "tls 1.3 aes suites must define traffic key length",
4748                ))?;
4749                let cipher = AesCipher::new(&key[..key_len])?;
4750                aes_gcm_encrypt(&cipher, &nonce, aad, plaintext)?
4751            }
4752            CipherSuite::TlsEcdheRsaWithAes128GcmSha256
4753            | CipherSuite::TlsEcdheRsaWithAes256GcmSha384 => {
4754                let cipher = AesCipher::new(&key[..16])?;
4755                aes_gcm_encrypt(&cipher, &nonce, aad, plaintext)?
4756            }
4757        };
4758        let record = ProtectedRecord {
4759            sequence: self.client_sequence,
4760            ciphertext,
4761            tag,
4762        };
4763        self.client_sequence = self.client_sequence.wrapping_add(1);
4764        Ok(record)
4765    }
4766
4767    /// Seals a modeled TLS 1.3 early-data (0-RTT) record from PSK-derived traffic keys.
4768    ///
4769    /// This is only allowed in [`HandshakeState::ClientHelloSent`], matching the wire protocol
4770    /// rule that 0-RTT application data is sent in the same flight as `ClientHello`.
4771    ///
4772    /// # Arguments
4773    /// * `psk`: Resumption/external PSK bytes used to derive early-data traffic secret.
4774    /// * `plaintext`: Early-data plaintext bytes to protect.
4775    /// * `aad`: Additional authenticated data for record protection.
4776    /// * `sequence`: Record sequence number used for nonce construction.
4777    ///
4778    /// # Returns
4779    /// `ProtectedRecord` carrying encrypted early-data payload.
4780    /// # Errors
4781    ///
4782    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4783    ///
4784    /// # Panics
4785    ///
4786    /// This function does not panic.
4787    ///
4788    pub fn seal_tls13_early_data_record(
4789        &self,
4790        psk: &[u8],
4791        plaintext: &[u8],
4792        aad: &[u8],
4793        sequence: u64,
4794    ) -> Result<ProtectedRecord> {
4795        if !self.version.uses_tls13_handshake_semantics() {
4796            return Err(Error::StateError(
4797                "tls13 early-data records require TLS 1.3 connection",
4798            ));
4799        }
4800        if psk.is_empty() {
4801            return Err(Error::InvalidLength(
4802                "tls13 early-data psk must not be empty",
4803            ));
4804        }
4805        if plaintext.len() > self.max_record_plaintext_len {
4806            return Err(Error::InvalidLength(
4807                "record plaintext exceeds configured limit",
4808            ));
4809        }
4810        if self.state != HandshakeState::ClientHelloSent {
4811            return Err(Error::StateError(
4812                "tls13 early-data may only be sealed in ClientHelloSent state",
4813            ));
4814        }
4815        let (key, iv) = self.derive_tls13_early_data_record_key_iv(psk)?;
4816        let nonce = build_record_nonce(&iv, sequence);
4817        let (ciphertext, tag) = if self.tls13_early_data_uses_chacha20_poly1305() {
4818            let key_32: [u8; 32] = key.as_slice().try_into().map_err(|_| {
4819                Error::InvalidLength("tls13 early-data chacha key must be 32 bytes")
4820            })?;
4821            chacha20_poly1305_encrypt(&key_32, &nonce, aad, plaintext)?
4822        } else {
4823            let cipher = AesCipher::new(&key)?;
4824            aes_gcm_encrypt(&cipher, &nonce, aad, plaintext)?
4825        };
4826        Ok(ProtectedRecord {
4827            sequence,
4828            ciphertext,
4829            tag,
4830        })
4831    }
4832
4833    /// Opens a modeled TLS 1.3 early-data (0-RTT) record from PSK-derived traffic keys.
4834    ///
4835    /// # Arguments
4836    /// * `psk`: Resumption/external PSK bytes used to derive early-data traffic secret.
4837    /// * `record`: Protected early-data record to decrypt.
4838    /// * `aad`: Additional authenticated data used during sealing.
4839    ///
4840    /// # Returns
4841    /// Decrypted early-data plaintext bytes on successful authentication.
4842    /// # Errors
4843    ///
4844    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4845    ///
4846    /// # Panics
4847    ///
4848    /// This function does not panic.
4849    ///
4850    pub fn open_tls13_early_data_record(
4851        &mut self,
4852        psk: &[u8],
4853        record: &ProtectedRecord,
4854        aad: &[u8],
4855    ) -> Result<Vec<u8>> {
4856        if !self.version.uses_tls13_handshake_semantics() {
4857            self.tls13_early_data_telemetry.rejected_invalid_input = self
4858                .tls13_early_data_telemetry
4859                .rejected_invalid_input
4860                .saturating_add(1);
4861            return Err(Error::StateError(
4862                "tls13 early-data records require TLS 1.3 connection",
4863            ));
4864        }
4865        if psk.is_empty() {
4866            self.tls13_early_data_telemetry.rejected_invalid_input = self
4867                .tls13_early_data_telemetry
4868                .rejected_invalid_input
4869                .saturating_add(1);
4870            return Err(Error::InvalidLength(
4871                "tls13 early-data psk must not be empty",
4872            ));
4873        }
4874        if !matches!(
4875            self.state,
4876            HandshakeState::ClientHelloSent
4877                | HandshakeState::ServerHelloReceived
4878                | HandshakeState::Finished
4879        ) {
4880            self.tls13_early_data_telemetry.rejected_decrypt_or_policy = self
4881                .tls13_early_data_telemetry
4882                .rejected_decrypt_or_policy
4883                .saturating_add(1);
4884            return Err(Error::StateError(
4885                "tls13 early-data may only be opened before encrypted extensions",
4886            ));
4887        }
4888        if self.tls13_early_data_require_acceptance {
4889            let Some(accepted_psk) = self.tls13_early_data_accepted_psk.as_deref() else {
4890                self.tls13_early_data_telemetry.rejected_missing_acceptance = self
4891                    .tls13_early_data_telemetry
4892                    .rejected_missing_acceptance
4893                    .saturating_add(1);
4894                return Err(Error::StateError(
4895                    "tls13 early-data requires prior ticket-policy acceptance",
4896                ));
4897            };
4898            if !constant_time_eq(accepted_psk, psk) {
4899                self.tls13_early_data_telemetry.rejected_psk_mismatch = self
4900                    .tls13_early_data_telemetry
4901                    .rejected_psk_mismatch
4902                    .saturating_add(1);
4903                return Err(Error::StateError(
4904                    "tls13 early-data psk does not match accepted ticket context",
4905                ));
4906            }
4907        }
4908        if self.tls13_early_data_anti_replay_enabled
4909            && !self
4910                .tls13_early_data_replay_window
4911                .check_and_mark(record.sequence)
4912        {
4913            self.tls13_early_data_telemetry.rejected_replay_or_too_old = self
4914                .tls13_early_data_telemetry
4915                .rejected_replay_or_too_old
4916                .saturating_add(1);
4917            return Err(Error::StateError(
4918                "tls13 early-data replay detected or sequence is too old",
4919            ));
4920        }
4921        let (key, iv) = self.derive_tls13_early_data_record_key_iv(psk)?;
4922        let nonce = build_record_nonce(&iv, record.sequence);
4923        let plaintext = if self.tls13_early_data_uses_chacha20_poly1305() {
4924            let key_32: [u8; 32] = key.as_slice().try_into().map_err(|_| {
4925                Error::InvalidLength("tls13 early-data chacha key must be 32 bytes")
4926            })?;
4927            chacha20_poly1305_decrypt(&key_32, &nonce, aad, &record.ciphertext, &record.tag)
4928                .map_err(|err| {
4929                    self.tls13_early_data_telemetry.rejected_decrypt_or_policy = self
4930                        .tls13_early_data_telemetry
4931                        .rejected_decrypt_or_policy
4932                        .saturating_add(1);
4933                    err
4934                })?
4935        } else {
4936            let cipher = AesCipher::new(&key)?;
4937            aes_gcm_decrypt(&cipher, &nonce, aad, &record.ciphertext, &record.tag).map_err(
4938                |err| {
4939                    self.tls13_early_data_telemetry.rejected_decrypt_or_policy = self
4940                        .tls13_early_data_telemetry
4941                        .rejected_decrypt_or_policy
4942                        .saturating_add(1);
4943                    err
4944                },
4945            )?
4946        };
4947        if plaintext.len() > self.max_record_plaintext_len {
4948            self.tls13_early_data_telemetry.rejected_decrypt_or_policy = self
4949                .tls13_early_data_telemetry
4950                .rejected_decrypt_or_policy
4951                .saturating_add(1);
4952            return Err(Error::InvalidLength(
4953                "record plaintext exceeds configured limit",
4954            ));
4955        }
4956        if let Some(max_bytes) = self.tls13_early_data_max_bytes {
4957            let next_total = self
4958                .tls13_early_data_opened_bytes
4959                .saturating_add(plaintext.len() as u64);
4960            if next_total > u64::from(max_bytes) {
4961                self.tls13_early_data_telemetry.rejected_decrypt_or_policy = self
4962                    .tls13_early_data_telemetry
4963                    .rejected_decrypt_or_policy
4964                    .saturating_add(1);
4965                return Err(Error::InvalidLength(
4966                    "tls13 early-data exceeds accepted ticket max_early_data_size",
4967                ));
4968            }
4969            self.tls13_early_data_opened_bytes = next_total;
4970        }
4971        self.tls13_early_data_telemetry.accepted_records = self
4972            .tls13_early_data_telemetry
4973            .accepted_records
4974            .saturating_add(1);
4975        Ok(plaintext)
4976    }
4977
4978    /// Seals one TLS 1.3 early-data wire record packet from TLSInnerPlaintext content.
4979    ///
4980    /// Inherits the same [`HandshakeState::ClientHelloSent`] requirement as [`Self::seal_tls13_early_data_record`].
4981    ///
4982    /// # Arguments
4983    /// * `psk`: Resumption/external PSK bytes used to derive early-data traffic secret.
4984    /// * `content`: Inner plaintext content bytes.
4985    /// * `content_type`: Inner content type byte.
4986    /// * `aad`: Additional authenticated data for AEAD.
4987    /// * `sequence`: Record sequence number used for nonce construction.
4988    /// * `padding_len`: Number of trailing zero padding bytes in TLSInnerPlaintext.
4989    ///
4990    /// # Returns
4991    /// Serialized TLSCiphertext packet bytes.
4992    /// # Errors
4993    ///
4994    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
4995    ///
4996    /// # Panics
4997    ///
4998    /// This function does not panic.
4999    ///
5000    pub fn seal_tls13_early_data_record_packet(
5001        &self,
5002        psk: &[u8],
5003        content: &[u8],
5004        content_type: u8,
5005        aad: &[u8],
5006        sequence: u64,
5007        padding_len: usize,
5008    ) -> Result<Vec<u8>> {
5009        let inner = encode_tls13_inner_plaintext(content, content_type, padding_len);
5010        let expected_aad = self.build_tls13_record_aad(inner.len().saturating_add(16))?;
5011        let aad_to_use = if aad.is_empty() {
5012            &expected_aad[..]
5013        } else {
5014            aad
5015        };
5016        let record = self.seal_tls13_early_data_record(psk, &inner, aad_to_use, sequence)?;
5017        self.encode_tls13_record_packet(&record)
5018    }
5019
5020    /// Opens one TLS 1.3 early-data wire record packet and decodes TLSInnerPlaintext.
5021    ///
5022    /// # Arguments
5023    /// * `psk`: Resumption/external PSK bytes used to derive early-data traffic secret.
5024    /// * `packet`: Serialized TLSCiphertext packet bytes.
5025    /// * `aad`: Additional authenticated data used during sealing.
5026    /// * `sequence`: Record sequence number used during sealing.
5027    ///
5028    /// # Returns
5029    /// Tuple `(content, content_type)` decoded from inner plaintext.
5030    /// # Errors
5031    ///
5032    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5033    ///
5034    /// # Panics
5035    ///
5036    /// This function does not panic.
5037    ///
5038    pub fn open_tls13_early_data_record_packet(
5039        &mut self,
5040        psk: &[u8],
5041        packet: &[u8],
5042        aad: &[u8],
5043        sequence: u64,
5044    ) -> Result<(Vec<u8>, u8)> {
5045        let record = self.decode_tls13_record_packet(packet, sequence)?;
5046        let expected_aad =
5047            self.build_tls13_record_aad(record.ciphertext.len().saturating_add(record.tag.len()))?;
5048        let aad_to_use = if aad.is_empty() {
5049            &expected_aad[..]
5050        } else {
5051            aad
5052        };
5053        let inner = self.open_tls13_early_data_record(psk, &record, aad_to_use)?;
5054        decode_tls13_inner_plaintext(&inner)
5055    }
5056
5057    /// Opens a sequence of TLSCiphertext packets as server-side 0-RTT application records.
5058    ///
5059    /// # Arguments
5060    /// * `psk`: Accepted resumption/external PSK bytes for early-data traffic keys.
5061    /// * `packets`: Ordered TLSCiphertext packets from the client first flight.
5062    /// * `first_sequence`: Sequence number corresponding to `packets[0]`.
5063    ///
5064    /// # Returns
5065    /// Ordered decrypted application payloads from early-data records.
5066    /// # Errors
5067    ///
5068    /// Returns [`noxtls_core::Error`] when packet decoding, policy, replay checks, or inner content validation fails.
5069    ///
5070    /// # Panics
5071    ///
5072    /// This function does not panic.
5073    pub fn open_tls13_early_data_client_flight_packets(
5074        &mut self,
5075        psk: &[u8],
5076        packets: &[Vec<u8>],
5077        first_sequence: u64,
5078    ) -> Result<Vec<Vec<u8>>> {
5079        let mut out = Vec::with_capacity(packets.len());
5080        for (idx, packet) in packets.iter().enumerate() {
5081            let sequence = first_sequence.saturating_add(idx as u64);
5082            let (payload, content_type) =
5083                self.open_tls13_early_data_record_packet(psk, packet, &[], sequence)?;
5084            if content_type != RecordContentType::ApplicationData.to_u8() {
5085                return Err(Error::ParseFailure(
5086                    "tls13 early-data packet inner content type must be application_data",
5087                ));
5088            }
5089            out.push(payload);
5090        }
5091        Ok(out)
5092    }
5093
5094    /// Accepts ClientHello ticket policy and opens early-data packets from the same client flight.
5095    ///
5096    /// # Arguments
5097    /// * `client_hello`: Encoded TLS 1.3 ClientHello carrying PSK and early_data offer.
5098    /// * `tickets`: Mutable server ticket set considered for acceptance.
5099    /// * `current_time_ms`: Server-local timestamp in milliseconds.
5100    /// * `max_skew_ms`: Allowed absolute ticket age skew.
5101    /// * `usage_policy`: Whether accepted tickets are reusable or single-use.
5102    /// * `packets`: Ordered TLSCiphertext packets from the client first flight.
5103    /// * `first_sequence`: Sequence number corresponding to `packets[0]`.
5104    ///
5105    /// # Returns
5106    /// Decrypted early-data payloads when accepted; empty vector when ticket policy does not accept.
5107    /// # Errors
5108    ///
5109    /// Returns [`noxtls_core::Error`] when acceptance, key derivation, packet decoding, or policy checks fail.
5110    ///
5111    /// # Panics
5112    ///
5113    /// This function does not panic.
5114    #[allow(clippy::too_many_arguments)]
5115    pub fn accept_and_open_tls13_early_data_client_flight_with_ticket_policy(
5116        &mut self,
5117        client_hello: &[u8],
5118        tickets: &mut [ResumptionTicket],
5119        current_time_ms: u64,
5120        max_skew_ms: u32,
5121        usage_policy: TicketUsagePolicy,
5122        packets: &[Vec<u8>],
5123        first_sequence: u64,
5124    ) -> Result<Vec<Vec<u8>>> {
5125        if !self.accept_tls13_early_data_with_ticket_policy(
5126            client_hello,
5127            tickets,
5128            current_time_ms,
5129            max_skew_ms,
5130            usage_policy,
5131        )? {
5132            return Ok(Vec::new());
5133        }
5134        let accepted_psk = self
5135            .tls13_early_data_accepted_psk
5136            .clone()
5137            .ok_or(Error::StateError(
5138                "tls13 early-data accepted ticket context is not installed",
5139            ))?;
5140        self.open_tls13_early_data_client_flight_packets(&accepted_psk, packets, first_sequence)
5141    }
5142
5143    /// Accepts ClientHello policy from ticket store and opens early-data packets from the client flight.
5144    ///
5145    /// # Arguments
5146    /// * `client_hello`: Encoded TLS 1.3 ClientHello carrying PSK and early_data offer.
5147    /// * `ticket_store`: Mutable server ticket store used for acceptance.
5148    /// * `current_time_ms`: Server-local timestamp in milliseconds.
5149    /// * `max_skew_ms`: Allowed absolute ticket age skew.
5150    /// * `usage_policy`: Whether accepted tickets are reusable or single-use.
5151    /// * `packets`: Ordered TLSCiphertext packets from the client first flight.
5152    /// * `first_sequence`: Sequence number corresponding to `packets[0]`.
5153    ///
5154    /// # Returns
5155    /// Decrypted early-data payloads when accepted; empty vector when ticket policy does not accept.
5156    /// # Errors
5157    ///
5158    /// Returns [`noxtls_core::Error`] when acceptance, key derivation, packet decoding, or policy checks fail.
5159    ///
5160    /// # Panics
5161    ///
5162    /// This function does not panic.
5163    #[allow(clippy::too_many_arguments)]
5164    pub fn accept_and_open_tls13_early_data_client_flight_with_ticket_store(
5165        &mut self,
5166        client_hello: &[u8],
5167        ticket_store: &mut TicketStore,
5168        current_time_ms: u64,
5169        max_skew_ms: u32,
5170        usage_policy: TicketUsagePolicy,
5171        packets: &[Vec<u8>],
5172        first_sequence: u64,
5173    ) -> Result<Vec<Vec<u8>>> {
5174        if !self.accept_tls13_early_data_with_ticket_store(
5175            client_hello,
5176            ticket_store,
5177            current_time_ms,
5178            max_skew_ms,
5179            usage_policy,
5180        )? {
5181            return Ok(Vec::new());
5182        }
5183        let accepted_psk = self
5184            .tls13_early_data_accepted_psk
5185            .clone()
5186            .ok_or(Error::StateError(
5187                "tls13 early-data accepted ticket context is not installed",
5188            ))?;
5189        self.open_tls13_early_data_client_flight_packets(&accepted_psk, packets, first_sequence)
5190    }
5191
5192    /// Opens inbound application data using installed server traffic keys.
5193    ///
5194    /// # Arguments
5195    /// * `record`: Protected record to decrypt and authenticate.
5196    /// * `aad`: Additional authenticated data used when sealing.
5197    ///
5198    /// # Returns
5199    /// Decrypted plaintext bytes on successful authentication.
5200    /// # Errors
5201    ///
5202    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5203    ///
5204    /// # Panics
5205    ///
5206    /// This function does not panic.
5207    ///
5208    pub fn open_record(&mut self, record: &ProtectedRecord, aad: &[u8]) -> Result<Vec<u8>> {
5209        if self.state != HandshakeState::Finished {
5210            return Err(Error::StateError(
5211                "cannot open record before handshake finish",
5212            ));
5213        }
5214        if self.server_sequence == u64::MAX {
5215            return Err(Error::StateError("server record sequence exhausted"));
5216        }
5217        if record.sequence != self.server_sequence {
5218            return Err(Error::StateError(
5219                "unexpected server record sequence number",
5220            ));
5221        }
5222        let suite = self.selected_cipher_suite.ok_or(Error::StateError(
5223            "cipher suite must be selected before opening records",
5224        ))?;
5225        let key = self
5226            .server_write_key
5227            .ok_or(Error::StateError("server write key is not installed"))?;
5228        let iv = self
5229            .server_write_iv
5230            .ok_or(Error::StateError("server write iv is not installed"))?;
5231        let nonce = build_record_nonce(&iv, record.sequence);
5232        let plaintext = match suite {
5233            CipherSuite::TlsChacha20Poly1305Sha256 => {
5234                chacha20_poly1305_decrypt(&key, &nonce, aad, &record.ciphertext, &record.tag)?
5235            }
5236            CipherSuite::TlsAes128GcmSha256 | CipherSuite::TlsAes256GcmSha384 => {
5237                let key_len = suite.tls13_traffic_key_len().ok_or(Error::StateError(
5238                    "tls 1.3 aes suites must define traffic key length",
5239                ))?;
5240                let cipher = AesCipher::new(&key[..key_len])?;
5241                aes_gcm_decrypt(&cipher, &nonce, aad, &record.ciphertext, &record.tag)?
5242            }
5243            CipherSuite::TlsEcdheRsaWithAes128GcmSha256
5244            | CipherSuite::TlsEcdheRsaWithAes256GcmSha384 => {
5245                let cipher = AesCipher::new(&key[..16])?;
5246                aes_gcm_decrypt(&cipher, &nonce, aad, &record.ciphertext, &record.tag)?
5247            }
5248        };
5249        if plaintext.len() > self.max_record_plaintext_len {
5250            return Err(Error::InvalidLength(
5251                "record plaintext exceeds configured limit",
5252            ));
5253        }
5254        self.server_sequence = self.server_sequence.wrapping_add(1);
5255        Ok(plaintext)
5256    }
5257
5258    /// Opens a locally-sealed record using client traffic keys for loopback testing.
5259    ///
5260    /// # Arguments
5261    /// * `record`: Protected record sealed with local client keys.
5262    /// * `aad`: Additional authenticated data used when sealing.
5263    ///
5264    /// # Returns
5265    /// Decrypted plaintext bytes on successful authentication.
5266    /// # Errors
5267    ///
5268    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5269    ///
5270    /// # Panics
5271    ///
5272    /// This function does not panic.
5273    ///
5274    pub fn open_own_record(&self, record: &ProtectedRecord, aad: &[u8]) -> Result<Vec<u8>> {
5275        let suite = self.selected_cipher_suite.ok_or(Error::StateError(
5276            "cipher suite must be selected before opening own records",
5277        ))?;
5278        let key = self
5279            .client_write_key
5280            .ok_or(Error::StateError("client write key is not installed"))?;
5281        let iv = self
5282            .client_write_iv
5283            .ok_or(Error::StateError("client write iv is not installed"))?;
5284        let nonce = build_record_nonce(&iv, record.sequence);
5285        let plaintext = match suite {
5286            CipherSuite::TlsChacha20Poly1305Sha256 => {
5287                chacha20_poly1305_decrypt(&key, &nonce, aad, &record.ciphertext, &record.tag)?
5288            }
5289            CipherSuite::TlsAes128GcmSha256 | CipherSuite::TlsAes256GcmSha384 => {
5290                let key_len = suite.tls13_traffic_key_len().ok_or(Error::StateError(
5291                    "tls 1.3 aes suites must define traffic key length",
5292                ))?;
5293                let cipher = AesCipher::new(&key[..key_len])?;
5294                aes_gcm_decrypt(&cipher, &nonce, aad, &record.ciphertext, &record.tag)?
5295            }
5296            CipherSuite::TlsEcdheRsaWithAes128GcmSha256
5297            | CipherSuite::TlsEcdheRsaWithAes256GcmSha384 => {
5298                let cipher = AesCipher::new(&key[..16])?;
5299                aes_gcm_decrypt(&cipher, &nonce, aad, &record.ciphertext, &record.tag)?
5300            }
5301        };
5302        if plaintext.len() > self.max_record_plaintext_len {
5303            return Err(Error::InvalidLength(
5304                "record plaintext exceeds configured limit",
5305            ));
5306        }
5307        Ok(plaintext)
5308    }
5309
5310    /// Seals one TLS 1.2 wire record packet from plaintext and outer content type.
5311    ///
5312    /// # Arguments
5313    /// * `plaintext`: Application plaintext bytes to protect.
5314    /// * `content_type`: TLS record content type for the outer TLS 1.2 header.
5315    ///
5316    /// # Returns
5317    /// Serialized TLSCiphertext packet bytes (`type || version || len || ciphertext || tag`).
5318    /// # Errors
5319    ///
5320    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5321    ///
5322    /// # Panics
5323    ///
5324    /// This function does not panic.
5325    ///
5326    pub fn seal_tls12_record_packet(
5327        &mut self,
5328        plaintext: &[u8],
5329        content_type: RecordContentType,
5330    ) -> Result<Vec<u8>> {
5331        self.ensure_tls12_wire_mode()?;
5332        let sequence = self.client_sequence;
5333        let aad = self.build_tls12_record_aad(sequence, content_type, plaintext.len())?;
5334        let record = self.seal_record(plaintext, &aad)?;
5335        self.encode_tls12_record_packet(&record, content_type)
5336    }
5337
5338    /// Opens one inbound TLS 1.2 wire record packet using server traffic keys.
5339    ///
5340    /// # Arguments
5341    /// * `packet`: Serialized TLSCiphertext packet bytes.
5342    ///
5343    /// # Returns
5344    /// Tuple `(content_type, plaintext)` after successful authentication.
5345    /// # Errors
5346    ///
5347    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5348    ///
5349    /// # Panics
5350    ///
5351    /// This function does not panic.
5352    ///
5353    pub fn open_tls12_record_packet(
5354        &mut self,
5355        packet: &[u8],
5356    ) -> Result<(RecordContentType, Vec<u8>)> {
5357        self.ensure_tls12_wire_mode()?;
5358        let sequence = self.server_sequence;
5359        let (record, content_type) = self.decode_tls12_record_packet(packet, sequence)?;
5360        let aad = self.build_tls12_record_aad(sequence, content_type, record.ciphertext.len())?;
5361        let plaintext = self.open_record(&record, &aad)?;
5362        Ok((content_type, plaintext))
5363    }
5364
5365    /// Opens one locally-sealed TLS 1.2 wire packet using client traffic keys.
5366    ///
5367    /// # Arguments
5368    /// * `packet`: Serialized TLSCiphertext packet bytes.
5369    /// * `sequence`: Record sequence number used during sealing.
5370    ///
5371    /// # Returns
5372    /// Tuple `(content_type, plaintext)` after successful authentication.
5373    /// # Errors
5374    ///
5375    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5376    ///
5377    /// # Panics
5378    ///
5379    /// This function does not panic.
5380    ///
5381    pub fn open_own_tls12_record_packet(
5382        &self,
5383        packet: &[u8],
5384        sequence: u64,
5385    ) -> Result<(RecordContentType, Vec<u8>)> {
5386        self.ensure_tls12_wire_mode()?;
5387        let (record, content_type) = self.decode_tls12_record_packet(packet, sequence)?;
5388        let aad = self.build_tls12_record_aad(sequence, content_type, record.ciphertext.len())?;
5389        let plaintext = self.open_own_record(&record, &aad)?;
5390        Ok((content_type, plaintext))
5391    }
5392
5393    /// Seals a TLS 1.2 fatal/warning alert into an encrypted TLSCiphertext packet.
5394    ///
5395    /// # Arguments
5396    /// * `level`: TLS alert level byte semantic.
5397    /// * `description`: TLS alert description codepoint semantic.
5398    ///
5399    /// # Returns
5400    /// Serialized TLS 1.2 alert record packet bytes.
5401    /// # Errors
5402    ///
5403    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5404    ///
5405    /// # Panics
5406    ///
5407    /// This function does not panic.
5408    ///
5409    pub fn send_tls12_alert_packet(
5410        &mut self,
5411        level: AlertLevel,
5412        description: AlertDescription,
5413    ) -> Result<Vec<u8>> {
5414        if self.version != TlsVersion::Tls12 {
5415            return Err(Error::StateError(
5416                "tls12 alert records require TLS 1.2 connection",
5417            ));
5418        }
5419        self.seal_tls12_record_packet(
5420            &[level.to_u8(), description.to_u8()],
5421            RecordContentType::Alert,
5422        )
5423    }
5424
5425    /// Maps a TLS 1.2 handshake error and seals the corresponding fatal alert packet.
5426    ///
5427    /// # Arguments
5428    /// * `error`: Handshake processing error to map into alert semantics.
5429    ///
5430    /// # Returns
5431    /// Serialized TLS 1.2 alert record packet bytes.
5432    /// # Errors
5433    ///
5434    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5435    ///
5436    /// # Panics
5437    ///
5438    /// This function does not panic.
5439    ///
5440    pub fn send_tls12_alert_for_handshake_error(&mut self, error: &Error) -> Result<Vec<u8>> {
5441        let (level, description) = Self::tls12_alert_for_handshake_error(error);
5442        self.send_tls12_alert_packet(level, description)
5443    }
5444
5445    /// Opens a peer TLS 1.2 alert packet and parses `(level, description)` semantics.
5446    ///
5447    /// # Arguments
5448    /// * `packet`: Serialized TLSCiphertext packet bytes carrying alert content.
5449    ///
5450    /// # Returns
5451    /// Parsed `(AlertLevel, AlertDescription)` tuple.
5452    /// # Errors
5453    ///
5454    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5455    ///
5456    /// # Panics
5457    ///
5458    /// This function does not panic.
5459    ///
5460    pub fn recv_tls12_alert_packet(
5461        &mut self,
5462        packet: &[u8],
5463    ) -> Result<(AlertLevel, AlertDescription)> {
5464        let (content_type, payload) = self.open_tls12_record_packet(packet)?;
5465        self.parse_tls12_alert_payload(content_type, &payload)
5466    }
5467
5468    /// Opens a locally-sealed TLS 1.2 alert packet for deterministic loopback tests.
5469    ///
5470    /// # Arguments
5471    /// * `packet`: Serialized TLSCiphertext packet bytes from local alert sealing.
5472    /// * `sequence`: Sequence value used when the packet was sealed.
5473    ///
5474    /// # Returns
5475    /// Parsed `(AlertLevel, AlertDescription)` tuple.
5476    /// # Errors
5477    ///
5478    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5479    ///
5480    /// # Panics
5481    ///
5482    /// This function does not panic.
5483    ///
5484    pub fn recv_own_tls12_alert_packet(
5485        &self,
5486        packet: &[u8],
5487        sequence: u64,
5488    ) -> Result<(AlertLevel, AlertDescription)> {
5489        let (content_type, payload) = self.open_own_tls12_record_packet(packet, sequence)?;
5490        self.parse_tls12_alert_payload(content_type, &payload)
5491    }
5492
5493    /// Parses TLS 1.2 alert payload shape from already-authenticated TLS record plaintext bytes.
5494    ///
5495    /// # Arguments
5496    ///
5497    /// * `&self` — `&self`.
5498    /// * `content_type` — `content_type: RecordContentType`.
5499    /// * `payload` — `payload: &[u8]`.
5500    ///
5501    /// # Returns
5502    ///
5503    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
5504    ///
5505    /// # Errors
5506    ///
5507    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5508    ///
5509    /// # Panics
5510    ///
5511    /// This function does not panic.
5512    ///
5513    fn parse_tls12_alert_payload(
5514        &self,
5515        content_type: RecordContentType,
5516        payload: &[u8],
5517    ) -> Result<(AlertLevel, AlertDescription)> {
5518        if content_type != RecordContentType::Alert {
5519            return Err(Error::ParseFailure("record is not an alert content type"));
5520        }
5521        if payload.len() != 2 {
5522            return Err(Error::ParseFailure("tls12 alert payload must be two bytes"));
5523        }
5524        let level =
5525            AlertLevel::from_u8(payload[0]).ok_or(Error::ParseFailure("unknown alert level"))?;
5526        let description = AlertDescription::from_u8(payload[1])
5527            .ok_or(Error::ParseFailure("unknown alert description"))?;
5528        Ok((level, description))
5529    }
5530
5531    /// Encodes a DTLS1.2 datagram record packet from content type, epoch, sequence, and payload.
5532    ///
5533    /// # Arguments
5534    /// * `content_type`: Record content type byte to place in DTLS header.
5535    /// * `epoch`: DTLS epoch value.
5536    /// * `sequence`: 48-bit DTLS record sequence number.
5537    /// * `payload`: Record payload bytes.
5538    ///
5539    /// # Returns
5540    /// Encoded DTLS record datagram bytes (`header || payload`).
5541    /// # Errors
5542    ///
5543    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5544    ///
5545    /// # Panics
5546    ///
5547    /// This function does not panic.
5548    ///
5549    pub fn build_dtls12_record_packet(
5550        &self,
5551        content_type: RecordContentType,
5552        epoch: u16,
5553        sequence: u64,
5554        payload: &[u8],
5555    ) -> Result<Vec<u8>> {
5556        if self.version != TlsVersion::Dtls12 {
5557            return Err(Error::StateError(
5558                "dtls12 record packet builder requires DTLS1.2 connection",
5559            ));
5560        }
5561        encode_dtls_record_packet(content_type, [0xFE, 0xFD], epoch, sequence, payload)
5562    }
5563
5564    /// Parses a DTLS1.2 datagram record packet into header fields and payload bytes.
5565    ///
5566    /// # Arguments
5567    /// * `packet`: Encoded DTLS record datagram bytes.
5568    ///
5569    /// # Returns
5570    /// Tuple of parsed DTLS record header and payload bytes.
5571    /// # Errors
5572    ///
5573    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5574    ///
5575    /// # Panics
5576    ///
5577    /// This function does not panic.
5578    ///
5579    pub fn parse_dtls12_record_packet(&self, packet: &[u8]) -> Result<(DtlsRecordHeader, Vec<u8>)> {
5580        if self.version != TlsVersion::Dtls12 {
5581            return Err(Error::StateError(
5582                "dtls12 record packet parser requires DTLS1.2 connection",
5583            ));
5584        }
5585        let (header, payload) = parse_dtls_record_packet(packet)?;
5586        if header.version != [0xFE, 0xFD] {
5587            return Err(Error::ParseFailure("dtls record version mismatch"));
5588        }
5589        Ok((header, payload))
5590    }
5591
5592    /// Fragments one DTLS1.2 handshake message into transport-sized handshake fragments.
5593    ///
5594    /// # Arguments
5595    /// * `handshake_type`: Handshake message type codepoint.
5596    /// * `message_seq`: DTLS handshake message sequence value.
5597    /// * `body`: Full handshake body bytes to fragment.
5598    /// * `max_fragment_len`: Maximum bytes per fragment payload.
5599    ///
5600    /// # Returns
5601    /// Ordered encoded DTLS handshake fragments.
5602    /// # Errors
5603    ///
5604    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5605    ///
5606    /// # Panics
5607    ///
5608    /// This function does not panic.
5609    ///
5610    pub fn fragment_dtls12_handshake_message(
5611        &self,
5612        handshake_type: u8,
5613        message_seq: u16,
5614        body: &[u8],
5615        max_fragment_len: usize,
5616    ) -> Result<Vec<Vec<u8>>> {
5617        if self.version != TlsVersion::Dtls12 {
5618            return Err(Error::StateError(
5619                "dtls12 handshake fragmentation requires DTLS1.2 connection",
5620            ));
5621        }
5622        encode_dtls12_handshake_fragments(handshake_type, message_seq, body, max_fragment_len)
5623    }
5624
5625    /// Reassembles encoded DTLS1.2 handshake fragments into one complete message.
5626    ///
5627    /// # Arguments
5628    /// * `fragments`: Encoded handshake fragments for one message sequence.
5629    /// * `max_message_len`: Maximum total bytes accepted for one reassembled handshake message.
5630    ///
5631    /// # Returns
5632    /// Tuple of `(handshake_type, message_seq, full_handshake_body)`.
5633    /// # Errors
5634    ///
5635    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5636    ///
5637    /// # Panics
5638    ///
5639    /// This function does not panic.
5640    ///
5641    pub fn reassemble_dtls12_handshake_fragments(
5642        &self,
5643        fragments: &[Vec<u8>],
5644        max_message_len: usize,
5645    ) -> Result<(u8, u16, Vec<u8>)> {
5646        if self.version != TlsVersion::Dtls12 {
5647            return Err(Error::StateError(
5648                "dtls12 handshake reassembly requires DTLS1.2 connection",
5649            ));
5650        }
5651        reassemble_dtls12_handshake_fragments(fragments, max_message_len)
5652    }
5653
5654    /// Enables or disables DTLS1.2 anti-amplification transmit budget enforcement.
5655    ///
5656    /// When enabled, outbound datagrams are capped to `3x` observed inbound bytes until
5657    /// cookie validation succeeds.
5658    /// # Arguments
5659    ///
5660    /// * `self` — `&mut self`.
5661    /// * `enforced` — `enforced: bool`.
5662    ///
5663    /// # Panics
5664    ///
5665    /// This function does not panic.
5666    ///
5667    pub fn set_dtls12_anti_amplification_enforced(&mut self, enforced: bool) {
5668        self.dtls12_anti_amplification_enforced = enforced;
5669    }
5670
5671    /// Records inbound DTLS datagram size for anti-amplification accounting.
5672    ///
5673    /// # Arguments
5674    /// * `bytes`: Number of bytes received from the peer datagram transport.
5675    /// # Panics
5676    ///
5677    /// This function does not panic.
5678    ///
5679    pub fn record_dtls12_inbound_datagram(&mut self, bytes: usize) {
5680        self.dtls12_inbound_bytes = self.dtls12_inbound_bytes.saturating_add(bytes as u64);
5681    }
5682
5683    /// Returns true when sending a datagram of `bytes` would stay within anti-amplification budget.
5684    #[must_use]
5685    /// # Arguments
5686    ///
5687    /// * `&self` — `&self`.
5688    /// * `bytes` — `bytes: usize`.
5689    ///
5690    /// # Returns
5691    ///
5692    /// `true` or `false` according to the checks in the function body.
5693    ///
5694    /// # Panics
5695    ///
5696    /// This function does not panic.
5697    ///
5698    pub fn dtls12_can_send_datagram_bytes(&self, bytes: usize) -> bool {
5699        if !self.dtls12_anti_amplification_enforced {
5700            return true;
5701        }
5702        if matches!(
5703            self.dtls12_handshake_phase,
5704            Dtls12HandshakePhase::AwaitingClientKeyExchange
5705                | Dtls12HandshakePhase::AwaitingFinished
5706                | Dtls12HandshakePhase::Connected
5707        ) {
5708            return true;
5709        }
5710        let budget = self
5711            .dtls12_inbound_bytes
5712            .saturating_mul(DTLS12_ANTI_AMPLIFICATION_FACTOR);
5713        self.dtls12_outbound_bytes.saturating_add(bytes as u64) <= budget
5714    }
5715
5716    /// Records outbound DTLS datagram size after validating anti-amplification budget.
5717    ///
5718    /// # Arguments
5719    /// * `bytes`: Number of bytes intended for outbound datagram transmission.
5720    ///
5721    /// # Returns
5722    /// `Ok(())` when transmission is allowed and accounted.
5723    /// # Errors
5724    ///
5725    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5726    ///
5727    /// # Panics
5728    ///
5729    /// This function does not panic.
5730    ///
5731    pub fn record_dtls12_outbound_datagram(&mut self, bytes: usize) -> Result<()> {
5732        if !self.dtls12_can_send_datagram_bytes(bytes) {
5733            return Err(Error::StateError(
5734                "dtls12 anti-amplification budget exceeded before cookie validation",
5735            ));
5736        }
5737        self.dtls12_outbound_bytes = self.dtls12_outbound_bytes.saturating_add(bytes as u64);
5738        Ok(())
5739    }
5740
5741    /// Processes first DTLS1.2 `ClientHello` and returns a cookie challenge.
5742    ///
5743    /// # Arguments
5744    /// * `client_hello`: Encoded ClientHello handshake message bytes.
5745    /// * `cookie_secret`: Server-local secret used to derive stateless cookie bytes.
5746    ///
5747    /// # Returns
5748    /// Encoded `HelloVerifyRequest` carrying derived cookie.
5749    /// # Errors
5750    ///
5751    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5752    ///
5753    /// # Panics
5754    ///
5755    /// This function does not panic.
5756    ///
5757    pub fn process_dtls12_client_hello_without_cookie(
5758        &mut self,
5759        client_hello: &[u8],
5760        cookie_secret: &[u8],
5761    ) -> Result<Vec<u8>> {
5762        if self.version != TlsVersion::Dtls12 {
5763            return Err(Error::StateError(
5764                "dtls12 cookie exchange requires DTLS1.2 connection",
5765            ));
5766        }
5767        if self.dtls12_handshake_phase != Dtls12HandshakePhase::AwaitingClientHello {
5768            return Err(Error::StateError(
5769                "dtls12 cookie challenge requires initial client-hello phase",
5770            ));
5771        }
5772        let (message_type, _body) = parse_handshake_message(client_hello)?;
5773        if message_type != HANDSHAKE_CLIENT_HELLO {
5774            return Err(Error::ParseFailure(
5775                "dtls12 cookie exchange requires client hello message",
5776            ));
5777        }
5778        let cookie = self.compute_dtls12_cookie(client_hello, cookie_secret)?;
5779        self.dtls12_expected_cookie = Some(cookie.clone());
5780        self.dtls12_handshake_phase = Dtls12HandshakePhase::AwaitingClientHelloWithCookie;
5781        self.build_dtls12_hello_verify_request(&cookie)
5782    }
5783
5784    /// Processes second DTLS1.2 `ClientHello` containing verified cookie bytes.
5785    ///
5786    /// # Returns
5787    ///
5788    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
5789    ///
5790    /// # Arguments
5791    /// * `client_hello`: Encoded retried ClientHello handshake message bytes.
5792    /// * `cookie`: Cookie bytes echoed by the client.
5793    /// * `cookie_secret`: Server-local secret used to derive expected cookie bytes.
5794    /// # Errors
5795    ///
5796    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5797    ///
5798    /// # Panics
5799    ///
5800    /// This function does not panic.
5801    ///
5802    pub fn process_dtls12_client_hello_with_cookie(
5803        &mut self,
5804        client_hello: &[u8],
5805        cookie: &[u8],
5806        cookie_secret: &[u8],
5807    ) -> Result<()> {
5808        if self.version != TlsVersion::Dtls12 {
5809            return Err(Error::StateError(
5810                "dtls12 cookie exchange requires DTLS1.2 connection",
5811            ));
5812        }
5813        if self.dtls12_handshake_phase != Dtls12HandshakePhase::AwaitingClientHelloWithCookie {
5814            return Err(Error::StateError(
5815                "dtls12 cookie verification requires retry client-hello phase",
5816            ));
5817        }
5818        if cookie.is_empty() {
5819            return Err(Error::InvalidLength(
5820                "dtls12 client cookie must not be empty",
5821            ));
5822        }
5823        let (message_type, _body) = parse_handshake_message(client_hello)?;
5824        if message_type != HANDSHAKE_CLIENT_HELLO {
5825            return Err(Error::ParseFailure(
5826                "dtls12 cookie verification requires client hello message",
5827            ));
5828        }
5829        let expected = self.compute_dtls12_cookie(client_hello, cookie_secret)?;
5830        let Some(challenge_cookie) = self.dtls12_expected_cookie.as_ref() else {
5831            return Err(Error::StateError(
5832                "dtls12 cookie challenge must be issued before verification",
5833            ));
5834        };
5835        if !constant_time_eq(challenge_cookie, cookie) || !constant_time_eq(&expected, cookie) {
5836            return Err(Error::ParseFailure("dtls12 client cookie mismatch"));
5837        }
5838        self.dtls12_expected_cookie = None;
5839        self.dtls12_handshake_phase = Dtls12HandshakePhase::AwaitingClientKeyExchange;
5840        self.state = HandshakeState::ClientHelloSent;
5841        Ok(())
5842    }
5843
5844    /// Advances deterministic DTLS1.2 client-flight sequencing after cookie verification.
5845    ///
5846    /// Allowed handshake ordering:
5847    /// * `ClientKeyExchange`
5848    /// * `Finished`
5849    /// # Arguments
5850    ///
5851    /// * `self` — `&mut self`.
5852    /// * `message` — `message: &[u8]`.
5853    ///
5854    /// # Returns
5855    ///
5856    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
5857    ///
5858    /// # Errors
5859    ///
5860    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5861    ///
5862    /// # Panics
5863    ///
5864    /// This function does not panic.
5865    ///
5866    pub fn process_dtls12_client_handshake_message(&mut self, message: &[u8]) -> Result<()> {
5867        if self.version != TlsVersion::Dtls12 {
5868            return Err(Error::StateError(
5869                "dtls12 handshake sequencing requires DTLS1.2 connection",
5870            ));
5871        }
5872        let (message_type, _body) = parse_handshake_message(message)?;
5873        match self.dtls12_handshake_phase {
5874            Dtls12HandshakePhase::AwaitingClientKeyExchange => {
5875                if message_type != HANDSHAKE_CLIENT_KEY_EXCHANGE {
5876                    return Err(Error::ParseFailure(
5877                        "dtls12 expected client key exchange handshake message",
5878                    ));
5879                }
5880                self.dtls12_handshake_phase = Dtls12HandshakePhase::AwaitingFinished;
5881                Ok(())
5882            }
5883            Dtls12HandshakePhase::AwaitingFinished => {
5884                if message_type != HANDSHAKE_FINISHED {
5885                    return Err(Error::ParseFailure(
5886                        "dtls12 expected finished handshake message",
5887                    ));
5888                }
5889                self.dtls12_handshake_phase = Dtls12HandshakePhase::Connected;
5890                self.state = HandshakeState::Finished;
5891                Ok(())
5892            }
5893            _ => Err(Error::StateError(
5894                "dtls12 handshake message received in invalid phase",
5895            )),
5896        }
5897    }
5898
5899    /// Returns current deterministic DTLS1.2 handshake phase label for diagnostics/tests.
5900    #[must_use]
5901    /// # Arguments
5902    ///
5903    /// * `&self` — `&self`.
5904    ///
5905    /// # Returns
5906    ///
5907    /// The value described by the return type in the function signature.
5908    ///
5909    /// # Panics
5910    ///
5911    /// This function does not panic.
5912    ///
5913    pub fn dtls12_handshake_phase(&self) -> &'static str {
5914        match self.dtls12_handshake_phase {
5915            Dtls12HandshakePhase::AwaitingClientHello => "awaiting_client_hello",
5916            Dtls12HandshakePhase::AwaitingClientHelloWithCookie => {
5917                "awaiting_client_hello_with_cookie"
5918            }
5919            Dtls12HandshakePhase::AwaitingClientKeyExchange => "awaiting_client_key_exchange",
5920            Dtls12HandshakePhase::AwaitingFinished => "awaiting_finished",
5921            Dtls12HandshakePhase::Connected => "connected",
5922        }
5923    }
5924
5925    /// Installs DTLS1.3-style traffic keys and static IVs used for protected records.
5926    ///
5927    /// # Returns
5928    ///
5929    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
5930    ///
5931    /// # Arguments
5932    /// * `client_key`: Outbound client write key (AES-128-GCM).
5933    /// * `client_iv`: Outbound client static IV.
5934    /// * `server_key`: Inbound server write key (AES-128-GCM).
5935    /// * `server_iv`: Inbound server static IV.
5936    /// # Errors
5937    ///
5938    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5939    ///
5940    /// # Panics
5941    ///
5942    /// This function does not panic.
5943    ///
5944    pub fn install_dtls13_traffic_keys(
5945        &mut self,
5946        client_key: [u8; 16],
5947        client_iv: [u8; 12],
5948        server_key: [u8; 16],
5949        server_iv: [u8; 12],
5950    ) -> Result<()> {
5951        self.ensure_dtls13_mode()?;
5952        self.dtls13_client_write_key = Some(client_key);
5953        self.dtls13_client_write_iv = Some(client_iv);
5954        self.dtls13_server_write_key = Some(server_key);
5955        self.dtls13_server_write_iv = Some(server_iv);
5956        self.dtls13_inbound_replay_tracker = DtlsEpochReplayTracker::new();
5957        self.dtls13_client_inbound_replay_tracker = DtlsEpochReplayTracker::new();
5958        Ok(())
5959    }
5960
5961    /// Sets the outbound DTLS epoch and resets per-epoch sequence to zero.
5962    ///
5963    /// # Returns
5964    ///
5965    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
5966    ///
5967    /// # Arguments
5968    /// * `epoch`: New outbound epoch value.
5969    /// # Errors
5970    ///
5971    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
5972    ///
5973    /// # Panics
5974    ///
5975    /// This function does not panic.
5976    ///
5977    pub fn set_dtls13_outbound_epoch(&mut self, epoch: u16) -> Result<()> {
5978        self.ensure_dtls13_mode()?;
5979        if !self.dtls13_active_flight.is_empty() && !self.is_dtls13_active_flight_complete()? {
5980            return Err(Error::StateError(
5981                "cannot change dtls13 outbound epoch while active flight is incomplete",
5982            ));
5983        }
5984        if epoch < self.dtls13_outbound_epoch {
5985            return Err(Error::StateError("dtls13 outbound epoch must be monotonic"));
5986        }
5987        self.dtls13_outbound_epoch = epoch;
5988        self.dtls13_outbound_sequence = 0;
5989        Ok(())
5990    }
5991
5992    /// Seals one DTLS1.3 protected record with installed client traffic keys.
5993    ///
5994    /// # Arguments
5995    /// * `plaintext`: Payload bytes to encrypt.
5996    ///
5997    /// # Returns
5998    /// Serialized DTLS packet (`header || ciphertext || tag`).
5999    /// # Errors
6000    ///
6001    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6002    ///
6003    /// # Panics
6004    ///
6005    /// This function does not panic.
6006    ///
6007    pub fn seal_dtls13_record(&mut self, plaintext: &[u8]) -> Result<Vec<u8>> {
6008        self.ensure_dtls13_mode()?;
6009        self.ensure_dtls13_tx_sequence_available()?;
6010        let key = self.dtls13_client_write_key.ok_or(Error::StateError(
6011            "dtls13 client write key is not installed",
6012        ))?;
6013        let iv = self
6014            .dtls13_client_write_iv
6015            .ok_or(Error::StateError("dtls13 client write iv is not installed"))?;
6016        let packet = seal_dtls13_aes128gcm_record(
6017            self.dtls13_outbound_epoch,
6018            self.dtls13_outbound_sequence,
6019            &key,
6020            &iv,
6021            plaintext,
6022        )?;
6023        self.dtls13_outbound_sequence = self.dtls13_outbound_sequence.saturating_add(1);
6024        Ok(packet)
6025    }
6026
6027    /// Seals one DTLS1.3 protected record and schedules it for retransmission.
6028    ///
6029    /// # Arguments
6030    /// * `plaintext`: Payload bytes to encrypt.
6031    /// * `now_ms`: Current monotonic timestamp in milliseconds.
6032    ///
6033    /// # Returns
6034    /// Serialized DTLS packet (`header || ciphertext || tag`) tracked in retransmit state.
6035    /// # Errors
6036    ///
6037    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6038    ///
6039    /// # Panics
6040    ///
6041    /// This function does not panic.
6042    ///
6043    pub fn seal_dtls13_record_for_flight(
6044        &mut self,
6045        plaintext: &[u8],
6046        now_ms: u64,
6047    ) -> Result<Vec<u8>> {
6048        self.ensure_dtls13_mode()?;
6049        let packet = self.seal_dtls13_record(plaintext)?;
6050        let (header, _payload) = parse_dtls_record_packet(&packet)?;
6051        self.dtls_retransmit_tracker.track_outbound_with_schedule(
6052            header.epoch,
6053            header.sequence,
6054            &packet,
6055            now_ms,
6056            self.dtls_retransmit_initial_timeout_ms,
6057        )?;
6058        Ok(packet)
6059    }
6060
6061    /// Seals a DTLS1.3 multi-record flight and schedules each packet for retransmission.
6062    ///
6063    /// # Arguments
6064    /// * `plaintext_records`: Ordered plaintext payloads to seal as individual DTLS packets.
6065    /// * `now_ms`: Current monotonic timestamp in milliseconds.
6066    ///
6067    /// # Returns
6068    /// Ordered serialized DTLS packets tracked in retransmit state.
6069    /// # Errors
6070    ///
6071    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6072    ///
6073    /// # Panics
6074    ///
6075    /// This function does not panic.
6076    ///
6077    pub fn seal_dtls13_record_flight(
6078        &mut self,
6079        plaintext_records: &[&[u8]],
6080        now_ms: u64,
6081    ) -> Result<Vec<Vec<u8>>> {
6082        self.ensure_dtls13_mode()?;
6083        if plaintext_records.is_empty() {
6084            return Err(Error::InvalidLength(
6085                "dtls13 record flight must contain at least one payload",
6086            ));
6087        }
6088        let mut packets = Vec::with_capacity(plaintext_records.len());
6089        for plaintext in plaintext_records {
6090            packets.push(self.seal_dtls13_record_for_flight(plaintext, now_ms)?);
6091        }
6092        Ok(packets)
6093    }
6094
6095    /// Starts a DTLS1.3 active flight and tracks its packet keys for completion checks.
6096    ///
6097    /// # Arguments
6098    /// * `plaintext_records`: Ordered plaintext payloads to seal as one active flight.
6099    /// * `now_ms`: Current monotonic timestamp in milliseconds.
6100    ///
6101    /// # Returns
6102    /// Ordered serialized DTLS packets for immediate transmission.
6103    /// # Errors
6104    ///
6105    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6106    ///
6107    /// # Panics
6108    ///
6109    /// This function does not panic.
6110    ///
6111    pub fn start_dtls13_active_flight(
6112        &mut self,
6113        plaintext_records: &[&[u8]],
6114        now_ms: u64,
6115    ) -> Result<Vec<Vec<u8>>> {
6116        self.ensure_dtls13_mode()?;
6117        if !self.dtls13_active_flight.is_empty() && !self.is_dtls13_active_flight_complete()? {
6118            return Err(Error::StateError(
6119                "cannot start new dtls13 active flight while previous flight is incomplete",
6120            ));
6121        }
6122        let packets = self.seal_dtls13_record_flight(plaintext_records, now_ms)?;
6123        self.dtls13_active_flight.clear();
6124        for packet in &packets {
6125            self.dtls13_active_flight
6126                .push(self.parse_dtls_packet_key(packet)?);
6127        }
6128        self.dtls13_active_flight_started_at_ms = Some(now_ms);
6129        self.dtls13_active_flight_failed = false;
6130        Ok(packets)
6131    }
6132
6133    /// Configures timeout budget for DTLS1.3 active-flight completion.
6134    ///
6135    /// # Returns
6136    ///
6137    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6138    ///
6139    /// # Arguments
6140    /// * `timeout_ms`: Maximum elapsed milliseconds before active flight is considered timed out.
6141    /// # Errors
6142    ///
6143    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6144    ///
6145    /// # Panics
6146    ///
6147    /// This function does not panic.
6148    ///
6149    pub fn set_dtls13_active_flight_timeout_ms(&mut self, timeout_ms: u64) -> Result<()> {
6150        self.ensure_dtls13_mode()?;
6151        self.dtls13_active_flight_timeout_ms = timeout_ms.max(1);
6152        Ok(())
6153    }
6154
6155    /// Opens one DTLS1.3 protected record with installed server traffic keys and replay checks.
6156    ///
6157    /// # Arguments
6158    /// * `packet`: Serialized DTLS protected record.
6159    ///
6160    /// # Returns
6161    /// Parsed DTLS header and decrypted plaintext bytes.
6162    /// # Errors
6163    ///
6164    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6165    ///
6166    /// # Panics
6167    ///
6168    /// This function does not panic.
6169    ///
6170    pub fn open_dtls13_record(&mut self, packet: &[u8]) -> Result<(DtlsRecordHeader, Vec<u8>)> {
6171        self.ensure_dtls13_mode()?;
6172        let key = self.dtls13_server_write_key.ok_or(Error::StateError(
6173            "dtls13 server write key is not installed",
6174        ))?;
6175        let iv = self
6176            .dtls13_server_write_iv
6177            .ok_or(Error::StateError("dtls13 server write iv is not installed"))?;
6178        open_dtls13_aes128gcm_record(packet, &key, &iv, &mut self.dtls13_inbound_replay_tracker)
6179    }
6180
6181    /// Opens one DTLS1.3 protected record using installed client traffic keys.
6182    ///
6183    /// This is intended for server-side validation of encrypted client flights.
6184    ///
6185    /// # Arguments
6186    /// * `packet`: Serialized DTLS protected record.
6187    ///
6188    /// # Returns
6189    /// Parsed DTLS header and decrypted plaintext bytes.
6190    /// # Errors
6191    ///
6192    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6193    ///
6194    /// # Panics
6195    ///
6196    /// This function does not panic.
6197    ///
6198    pub fn open_dtls13_client_record(
6199        &mut self,
6200        packet: &[u8],
6201    ) -> Result<(DtlsRecordHeader, Vec<u8>)> {
6202        self.ensure_dtls13_mode()?;
6203        let key = self.dtls13_client_write_key.ok_or(Error::StateError(
6204            "dtls13 client write key is not installed",
6205        ))?;
6206        let iv = self
6207            .dtls13_client_write_iv
6208            .ok_or(Error::StateError("dtls13 client write iv is not installed"))?;
6209        open_dtls13_aes128gcm_record(
6210            packet,
6211            &key,
6212            &iv,
6213            &mut self.dtls13_client_inbound_replay_tracker,
6214        )
6215    }
6216
6217    /// Processes encrypted DTLS server post-hello handshake flight in strict TLS1.3 message order.
6218    ///
6219    /// Expected decrypted sequence:
6220    /// * `EncryptedExtensions`
6221    /// * optional `CertificateRequest`
6222    /// * `Certificate`
6223    /// * `CertificateVerify`
6224    /// * `Finished`
6225    ///
6226    /// # Arguments
6227    /// * `packets`: Encrypted DTLS packets carrying one handshake message each.
6228    ///
6229    /// # Returns
6230    /// `Ok(())` when decrypted flight validates and transitions to `Finished`.
6231    /// # Errors
6232    ///
6233    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6234    ///
6235    /// # Panics
6236    ///
6237    /// This function does not panic.
6238    ///
6239    pub fn process_dtls13_encrypted_server_flight_after_hello(
6240        &mut self,
6241        packets: &[Vec<u8>],
6242    ) -> Result<()> {
6243        self.ensure_dtls13_mode()?;
6244        if self.state != HandshakeState::ServerHelloReceived {
6245            return Err(Error::StateError(
6246                "dtls13 encrypted server flight requires server hello state",
6247            ));
6248        }
6249        if packets.len() < 4 {
6250            return Err(Error::ParseFailure(
6251                "dtls13 encrypted server flight is too short",
6252            ));
6253        }
6254        let mut messages = Vec::with_capacity(packets.len());
6255        for packet in packets {
6256            let (_header, plaintext) = self.open_dtls13_record(packet)?;
6257            messages.push(plaintext);
6258        }
6259        let mut index = 0_usize;
6260        self.recv_encrypted_extensions(&messages[index])?;
6261        index += 1;
6262        let (next_type, _) = parse_handshake_message(&messages[index])?;
6263        if next_type == HANDSHAKE_CERTIFICATE_REQUEST {
6264            self.recv_certificate_request(&messages[index])?;
6265            index += 1;
6266        }
6267        self.recv_certificate(&messages[index])?;
6268        index += 1;
6269        self.recv_certificate_verify(&messages[index])?;
6270        index += 1;
6271        self.derive_handshake_secret()?;
6272        self.recv_finished_message(&messages[index])?;
6273        index += 1;
6274        if index != messages.len() {
6275            return Err(Error::ParseFailure(
6276                "unexpected trailing dtls13 encrypted server handshake messages",
6277            ));
6278        }
6279        Ok(())
6280    }
6281
6282    /// Processes full DTLS server handshake flight from ServerHello through encrypted post-hello flight.
6283    ///
6284    /// Expected sequence:
6285    /// * `ServerHello` (plaintext handshake wrapper)
6286    /// * encrypted post-hello packets consumed by `process_dtls13_encrypted_server_flight_after_hello`
6287    ///
6288    /// # Arguments
6289    /// * `server_hello`: Encoded ServerHello handshake message.
6290    /// * `encrypted_packets`: Encrypted DTLS packets carrying post-hello server handshake messages.
6291    ///
6292    /// # Returns
6293    /// `Ok(())` when the full flight validates and transitions to `Finished`.
6294    /// # Errors
6295    ///
6296    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6297    ///
6298    /// # Panics
6299    ///
6300    /// This function does not panic.
6301    ///
6302    pub fn process_dtls13_full_server_handshake_flight(
6303        &mut self,
6304        server_hello: &[u8],
6305        encrypted_packets: &[Vec<u8>],
6306    ) -> Result<()> {
6307        self.ensure_dtls13_mode()?;
6308        self.recv_server_hello(server_hello)?;
6309        self.process_dtls13_encrypted_server_flight_after_hello(encrypted_packets)
6310    }
6311
6312    /// Processes encrypted DTLS client post-hello handshake flight with strict message ordering.
6313    ///
6314    /// Allowed decrypted sequence:
6315    /// * `Finished`
6316    /// * `Certificate`, `CertificateVerify`, `Finished`
6317    ///
6318    /// # Arguments
6319    /// * `packets`: Encrypted DTLS packets carrying client post-hello handshake messages.
6320    ///
6321    /// # Returns
6322    /// `Ok(())` when decrypted message ordering is valid.
6323    /// # Errors
6324    ///
6325    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6326    ///
6327    /// # Panics
6328    ///
6329    /// This function does not panic.
6330    ///
6331    pub fn process_dtls13_encrypted_client_flight_after_server_hello(
6332        &mut self,
6333        packets: &[Vec<u8>],
6334    ) -> Result<()> {
6335        self.ensure_dtls13_mode()?;
6336        if packets.is_empty() {
6337            return Err(Error::ParseFailure(
6338                "dtls13 encrypted client flight is too short",
6339            ));
6340        }
6341        let mut message_types = Vec::with_capacity(packets.len());
6342        for packet in packets {
6343            let (_header, plaintext) = self.open_dtls13_client_record(packet)?;
6344            let (handshake_type, _body) = parse_handshake_message(&plaintext)?;
6345            message_types.push(handshake_type);
6346        }
6347        if message_types == [HANDSHAKE_FINISHED] {
6348            return Ok(());
6349        }
6350        if message_types
6351            == [
6352                HANDSHAKE_CERTIFICATE,
6353                HANDSHAKE_CERTIFICATE_VERIFY,
6354                HANDSHAKE_FINISHED,
6355            ]
6356        {
6357            return Ok(());
6358        }
6359        Err(Error::ParseFailure(
6360            "invalid dtls13 encrypted client flight message ordering",
6361        ))
6362    }
6363
6364    /// Builds and schedules one outbound encrypted DTLS1.3 client post-hello handshake flight.
6365    ///
6366    /// Allowed plaintext message ordering:
6367    /// * `Finished`
6368    /// * `Certificate`, `CertificateVerify`, `Finished`
6369    ///
6370    /// # Arguments
6371    /// * `messages`: Ordered encoded handshake messages for one outbound client flight.
6372    /// * `now_ms`: Current monotonic timestamp in milliseconds.
6373    ///
6374    /// # Returns
6375    /// Encrypted DTLS packets tracked as the current active flight.
6376    /// # Errors
6377    ///
6378    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6379    ///
6380    /// # Panics
6381    ///
6382    /// This function does not panic.
6383    ///
6384    pub fn build_dtls13_encrypted_client_flight_after_server_hello(
6385        &mut self,
6386        messages: &[Vec<u8>],
6387        now_ms: u64,
6388    ) -> Result<Vec<Vec<u8>>> {
6389        self.ensure_dtls13_mode()?;
6390        if self.state != HandshakeState::ServerHelloReceived
6391            && self.state != HandshakeState::ServerCertificateVerified
6392            && self.state != HandshakeState::KeysDerived
6393        {
6394            return Err(Error::StateError(
6395                "dtls13 encrypted client flight requires post-server-hello state",
6396            ));
6397        }
6398        self.validate_dtls13_client_post_hello_flight_order(messages)?;
6399        let plaintext_refs: Vec<&[u8]> = messages.iter().map(Vec::as_slice).collect();
6400        self.start_dtls13_active_flight(&plaintext_refs, now_ms)
6401    }
6402
6403    /// Advances outbound DTLS epoch and resets per-epoch record sequence counter.
6404    ///
6405    /// # Arguments
6406    ///
6407    /// * `self` — `&mut self`.
6408    ///
6409    /// # Returns
6410    /// New outbound epoch value.
6411    /// # Errors
6412    ///
6413    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6414    ///
6415    /// # Panics
6416    ///
6417    /// This function does not panic.
6418    ///
6419    pub fn advance_dtls13_outbound_epoch(&mut self) -> Result<u16> {
6420        self.ensure_dtls13_mode()?;
6421        if !self.dtls13_active_flight.is_empty() && !self.is_dtls13_active_flight_complete()? {
6422            return Err(Error::StateError(
6423                "cannot advance dtls13 outbound epoch while active flight is incomplete",
6424            ));
6425        }
6426        if self.dtls13_outbound_epoch == u16::MAX {
6427            return Err(Error::StateError("dtls13 outbound epoch exhausted"));
6428        }
6429        self.dtls13_outbound_epoch = self.dtls13_outbound_epoch.saturating_add(1);
6430        self.dtls13_outbound_sequence = 0;
6431        Ok(self.dtls13_outbound_epoch)
6432    }
6433
6434    /// Opens a locally sealed DTLS1.3 protected record using installed client traffic keys.
6435    ///
6436    /// This loopback helper is intended for local validation paths where records were produced
6437    /// by `seal_dtls13_record` on the same connection instance.
6438    /// # Arguments
6439    ///
6440    /// * `&self` — `&self`.
6441    /// * `packet` — `packet: &[u8]`.
6442    ///
6443    /// # Returns
6444    ///
6445    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6446    ///
6447    /// # Errors
6448    ///
6449    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6450    ///
6451    /// # Panics
6452    ///
6453    /// This function does not panic.
6454    ///
6455    pub fn open_own_dtls13_record(&self, packet: &[u8]) -> Result<(DtlsRecordHeader, Vec<u8>)> {
6456        self.ensure_dtls13_mode()?;
6457        let key = self.dtls13_client_write_key.ok_or(Error::StateError(
6458            "dtls13 client write key is not installed",
6459        ))?;
6460        let iv = self
6461            .dtls13_client_write_iv
6462            .ok_or(Error::StateError("dtls13 client write iv is not installed"))?;
6463        let mut replay_tracker = DtlsEpochReplayTracker::new();
6464        open_dtls13_aes128gcm_record(packet, &key, &iv, &mut replay_tracker)
6465    }
6466
6467    /// Marks a tracked DTLS outbound packet as acknowledged using parsed record header fields.
6468    ///
6469    /// # Arguments
6470    /// * `packet`: DTLS record packet containing epoch/sequence metadata.
6471    ///
6472    /// # Returns
6473    /// `true` when matching tracked packet is found and marked acknowledged.
6474    /// # Errors
6475    ///
6476    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6477    ///
6478    /// # Panics
6479    ///
6480    /// This function does not panic.
6481    ///
6482    pub fn mark_dtls13_record_acked_from_packet(&mut self, packet: &[u8]) -> Result<bool> {
6483        self.ensure_dtls13_mode()?;
6484        let (header, _payload) = parse_dtls_record_packet(packet)?;
6485        if header.version != [0xFE, 0xFD] {
6486            return Err(Error::ParseFailure("dtls record version mismatch"));
6487        }
6488        Ok(self
6489            .dtls_retransmit_tracker
6490            .mark_acked(header.epoch, header.sequence))
6491    }
6492
6493    /// Marks every DTLS packet in one flight as acknowledged using packet headers.
6494    ///
6495    /// # Arguments
6496    /// * `packets`: DTLS packets that belong to one outbound flight.
6497    ///
6498    /// # Returns
6499    /// Count of packets that matched tracked records and were marked acknowledged.
6500    /// # Errors
6501    ///
6502    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6503    ///
6504    /// # Panics
6505    ///
6506    /// This function does not panic.
6507    ///
6508    pub fn mark_dtls13_flight_acked_from_packets(&mut self, packets: &[Vec<u8>]) -> Result<usize> {
6509        self.ensure_dtls13_mode()?;
6510        let mut marked = 0_usize;
6511        for packet in packets {
6512            if self.mark_dtls13_record_acked_from_packet(packet)? {
6513                marked = marked.saturating_add(1);
6514            }
6515        }
6516        Ok(marked)
6517    }
6518
6519    /// Polls retransmit scheduler for due packets belonging to the current active flight.
6520    ///
6521    /// # Arguments
6522    /// * `now_ms`: Current monotonic timestamp in milliseconds.
6523    ///
6524    /// # Returns
6525    /// Due packets that should be resent for active-flight completion.
6526    /// # Errors
6527    ///
6528    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6529    ///
6530    /// # Panics
6531    ///
6532    /// This function does not panic.
6533    ///
6534    pub fn poll_dtls13_active_flight_due_packets(&mut self, now_ms: u64) -> Result<Vec<Vec<u8>>> {
6535        self.ensure_dtls13_mode()?;
6536        if self.dtls13_active_flight.is_empty() {
6537            return Ok(Vec::new());
6538        }
6539        if self.dtls13_active_flight_has_timed_out(now_ms) {
6540            let _ = self.abort_dtls13_active_flight()?;
6541            return Err(Error::StateError(
6542                "dtls13 active flight timed out before completion",
6543            ));
6544        }
6545        if self.dtls13_active_flight_missing_tracked_records() {
6546            self.dtls13_active_flight.clear();
6547            self.dtls13_active_flight_started_at_ms = None;
6548            self.dtls13_active_flight_failed = true;
6549            return Err(Error::StateError(
6550                "dtls13 active flight failed after retransmit budget exhausted",
6551            ));
6552        }
6553        let due_packets = self.poll_dtls12_due_retransmit_packets(now_ms)?;
6554        let mut filtered = Vec::new();
6555        for packet in due_packets {
6556            let key = self.parse_dtls_packet_key(&packet)?;
6557            if self.dtls13_active_flight.contains(&key) {
6558                filtered.push(packet);
6559            }
6560        }
6561        if self.dtls13_active_flight_missing_tracked_records() {
6562            self.dtls13_active_flight.clear();
6563            self.dtls13_active_flight_started_at_ms = None;
6564            self.dtls13_active_flight_failed = true;
6565            return Err(Error::StateError(
6566                "dtls13 active flight failed after retransmit budget exhausted",
6567            ));
6568        }
6569        Ok(filtered)
6570    }
6571
6572    /// Acknowledges packets for the current active DTLS1.3 flight and prunes acked records.
6573    ///
6574    /// # Arguments
6575    /// * `packets`: Acked DTLS packets for this flight.
6576    ///
6577    /// # Returns
6578    /// Number of active-flight packets newly marked acknowledged.
6579    /// # Errors
6580    ///
6581    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6582    ///
6583    /// # Panics
6584    ///
6585    /// This function does not panic.
6586    ///
6587    pub fn acknowledge_dtls13_active_flight_packets(
6588        &mut self,
6589        packets: &[Vec<u8>],
6590    ) -> Result<usize> {
6591        self.ensure_dtls13_mode()?;
6592        if self.dtls13_active_flight.is_empty() {
6593            return Ok(0);
6594        }
6595        let mut marked = 0_usize;
6596        for packet in packets {
6597            let key = self.parse_dtls_packet_key(packet)?;
6598            if !self.dtls13_active_flight.contains(&key) {
6599                continue;
6600            }
6601            if self.mark_dtls12_record_acked(key.0, key.1)? {
6602                marked = marked.saturating_add(1);
6603            }
6604        }
6605        let _ = self.prune_dtls12_acked_records()?;
6606        if self.is_dtls13_active_flight_complete()? {
6607            self.dtls13_active_flight.clear();
6608            self.dtls13_active_flight_started_at_ms = None;
6609            self.dtls13_active_flight_failed = false;
6610        }
6611        Ok(marked)
6612    }
6613
6614    /// Aborts the current active DTLS1.3 flight and removes its retransmit obligations.
6615    ///
6616    /// # Arguments
6617    ///
6618    /// * `self` — `&mut self`.
6619    ///
6620    /// # Returns
6621    /// Number of active-flight records removed from retransmit tracking.
6622    /// # Errors
6623    ///
6624    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6625    ///
6626    /// # Panics
6627    ///
6628    /// This function does not panic.
6629    ///
6630    pub fn abort_dtls13_active_flight(&mut self) -> Result<usize> {
6631        self.ensure_dtls13_mode()?;
6632        if self.dtls13_active_flight.is_empty() {
6633            return Ok(0);
6634        }
6635        for (epoch, sequence) in &self.dtls13_active_flight {
6636            let _ = self.dtls_retransmit_tracker.mark_acked(*epoch, *sequence);
6637        }
6638        let removed = self.prune_dtls12_acked_records()?;
6639        self.dtls13_active_flight.clear();
6640        self.dtls13_active_flight_started_at_ms = None;
6641        self.dtls13_active_flight_failed = false;
6642        Ok(removed)
6643    }
6644
6645    /// Reports whether the most recent active DTLS1.3 flight failed due to retry budget exhaustion.
6646    #[must_use]
6647    /// # Arguments
6648    ///
6649    /// * `&self` — `&self`.
6650    ///
6651    /// # Returns
6652    ///
6653    /// `true` or `false` according to the checks in the function body.
6654    ///
6655    /// # Panics
6656    ///
6657    /// This function does not panic.
6658    ///
6659    pub fn dtls13_active_flight_failed(&self) -> bool {
6660        self.dtls13_active_flight_failed
6661    }
6662
6663    /// Reports whether all packets from the current active DTLS1.3 flight are complete.
6664    ///
6665    /// A flight is complete when no tracked unacknowledged retransmit record remains
6666    /// for any packet key registered in `start_dtls13_active_flight`.
6667    /// # Arguments
6668    ///
6669    /// * `&self` — `&self`.
6670    ///
6671    /// # Returns
6672    ///
6673    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6674    ///
6675    /// # Errors
6676    ///
6677    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6678    ///
6679    /// # Panics
6680    ///
6681    /// This function does not panic.
6682    ///
6683    pub fn is_dtls13_active_flight_complete(&self) -> Result<bool> {
6684        self.ensure_dtls13_mode()?;
6685        if self.dtls13_active_flight.is_empty() {
6686            return Ok(true);
6687        }
6688        for (epoch, sequence) in &self.dtls13_active_flight {
6689            let still_pending = self.dtls_retransmit_tracker.records().iter().any(|record| {
6690                record.epoch == *epoch && record.sequence == *sequence && !record.acknowledged
6691            });
6692            if still_pending {
6693                return Ok(false);
6694            }
6695        }
6696        Ok(true)
6697    }
6698
6699    /// Derives bounded DTLS1.2 cookie bytes from server secret and ClientHello transcript bytes.
6700    ///
6701    /// # Arguments
6702    ///
6703    /// * `&self` — `&self`.
6704    /// * `client_hello` — `client_hello: &[u8]`.
6705    /// * `cookie_secret` — `cookie_secret: &[u8]`.
6706    ///
6707    /// # Returns
6708    ///
6709    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6710    ///
6711    /// # Errors
6712    ///
6713    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6714    ///
6715    /// # Panics
6716    ///
6717    /// This function does not panic.
6718    ///
6719    fn compute_dtls12_cookie(&self, client_hello: &[u8], cookie_secret: &[u8]) -> Result<Vec<u8>> {
6720        if cookie_secret.is_empty() {
6721            return Err(Error::InvalidLength(
6722                "dtls12 cookie secret must not be empty",
6723            ));
6724        }
6725        let mut material = Vec::with_capacity(cookie_secret.len() + client_hello.len());
6726        material.extend_from_slice(cookie_secret);
6727        material.extend_from_slice(client_hello);
6728        let digest = hash_bytes_for_algorithm(HashAlgorithm::Sha256, &material);
6729        let cookie_len = digest.len().min(16);
6730        Ok(digest[..cookie_len].to_vec())
6731    }
6732
6733    /// Encodes DTLS1.2 HelloVerifyRequest carrying one stateless cookie challenge value.
6734    ///
6735    /// # Arguments
6736    ///
6737    /// * `&self` — `&self`.
6738    /// * `cookie` — `cookie: &[u8]`.
6739    ///
6740    /// # Returns
6741    ///
6742    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6743    ///
6744    /// # Errors
6745    ///
6746    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6747    ///
6748    /// # Panics
6749    ///
6750    /// This function does not panic.
6751    ///
6752    fn build_dtls12_hello_verify_request(&self, cookie: &[u8]) -> Result<Vec<u8>> {
6753        if cookie.is_empty() {
6754            return Err(Error::InvalidLength("dtls12 cookie must not be empty"));
6755        }
6756        if cookie.len() > DTLS12_MAX_COOKIE_LEN {
6757            return Err(Error::InvalidLength(
6758                "dtls12 cookie exceeds 8-bit cookie length field",
6759            ));
6760        }
6761        let mut body = Vec::with_capacity(3 + cookie.len());
6762        body.extend_from_slice(&[0xFE, 0xFD]);
6763        body.push(cookie.len() as u8);
6764        body.extend_from_slice(cookie);
6765        Ok(encode_handshake_message(
6766            HANDSHAKE_HELLO_VERIFY_REQUEST,
6767            &body,
6768        ))
6769    }
6770
6771    /// Parses `(epoch, sequence)` key used for DTLS retransmit record correlation.
6772    ///
6773    /// # Arguments
6774    ///
6775    /// * `&self` — `&self`.
6776    /// * `packet` — `packet: &[u8]`.
6777    ///
6778    /// # Returns
6779    ///
6780    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6781    ///
6782    /// # Errors
6783    ///
6784    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6785    ///
6786    /// # Panics
6787    ///
6788    /// This function does not panic.
6789    ///
6790    fn parse_dtls_packet_key(&self, packet: &[u8]) -> Result<(u16, u64)> {
6791        let (header, _payload) = parse_dtls_record_packet(packet)?;
6792        if header.version != [0xFE, 0xFD] {
6793            return Err(Error::ParseFailure("dtls record version mismatch"));
6794        }
6795        Ok((header.epoch, header.sequence))
6796    }
6797
6798    /// Reports whether active-flight elapsed time exceeded configured timeout budget.
6799    ///
6800    /// # Arguments
6801    ///
6802    /// * `&self` — `&self`.
6803    /// * `now_ms` — `now_ms: u64`.
6804    ///
6805    /// # Returns
6806    ///
6807    /// `true` or `false` according to the checks in the function body.
6808    ///
6809    /// # Panics
6810    ///
6811    /// This function does not panic.
6812    ///
6813    fn dtls13_active_flight_has_timed_out(&self, now_ms: u64) -> bool {
6814        let Some(started_at_ms) = self.dtls13_active_flight_started_at_ms else {
6815            return false;
6816        };
6817        now_ms.saturating_sub(started_at_ms) > self.dtls13_active_flight_timeout_ms
6818    }
6819
6820    /// Returns true when active-flight keys no longer exist in retransmit tracker records.
6821    ///
6822    /// # Arguments
6823    ///
6824    /// * `&self` — `&self`.
6825    ///
6826    /// # Returns
6827    ///
6828    /// `true` or `false` according to the checks in the function body.
6829    ///
6830    /// # Panics
6831    ///
6832    /// This function does not panic.
6833    ///
6834    fn dtls13_active_flight_missing_tracked_records(&self) -> bool {
6835        self.dtls13_active_flight.iter().any(|(epoch, sequence)| {
6836            !self
6837                .dtls_retransmit_tracker
6838                .records()
6839                .iter()
6840                .any(|record| record.epoch == *epoch && record.sequence == *sequence)
6841        })
6842    }
6843
6844    /// Validates allowed DTLS1.3 client post-hello flight message ordering.
6845    ///
6846    /// # Arguments
6847    ///
6848    /// * `&self` — `&self`.
6849    /// * `messages` — `messages: &[Vec<u8>]`.
6850    ///
6851    /// # Returns
6852    ///
6853    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6854    ///
6855    /// # Errors
6856    ///
6857    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6858    ///
6859    /// # Panics
6860    ///
6861    /// This function does not panic.
6862    ///
6863    fn validate_dtls13_client_post_hello_flight_order(&self, messages: &[Vec<u8>]) -> Result<()> {
6864        if messages.is_empty() {
6865            return Err(Error::InvalidLength(
6866                "dtls13 encrypted client flight must contain at least one message",
6867            ));
6868        }
6869        let mut message_types = Vec::with_capacity(messages.len());
6870        for message in messages {
6871            let (handshake_type, _body) = parse_handshake_message(message)?;
6872            message_types.push(handshake_type);
6873        }
6874        if message_types == [HANDSHAKE_FINISHED] {
6875            return Ok(());
6876        }
6877        if message_types
6878            == [
6879                HANDSHAKE_CERTIFICATE,
6880                HANDSHAKE_CERTIFICATE_VERIFY,
6881                HANDSHAKE_FINISHED,
6882            ]
6883        {
6884            return Ok(());
6885        }
6886        Err(Error::ParseFailure(
6887            "invalid dtls13 client post-hello flight message ordering",
6888        ))
6889    }
6890
6891    /// Builds TLS 1.2 AEAD additional authenticated data per record sequence and header fields.
6892    ///
6893    /// # Arguments
6894    ///
6895    /// * `&self` — `&self`.
6896    /// * `sequence` — `sequence: u64`.
6897    /// * `content_type` — `content_type: RecordContentType`.
6898    /// * `plaintext_len` — `plaintext_len: usize`.
6899    ///
6900    /// # Returns
6901    ///
6902    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6903    ///
6904    /// # Errors
6905    ///
6906    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6907    ///
6908    /// # Panics
6909    ///
6910    /// This function does not panic.
6911    ///
6912    fn build_tls12_record_aad(
6913        &self,
6914        sequence: u64,
6915        content_type: RecordContentType,
6916        plaintext_len: usize,
6917    ) -> Result<[u8; 13]> {
6918        let len = u16::try_from(plaintext_len)
6919            .map_err(|_| Error::InvalidLength("tls12 plaintext length exceeds 16-bit field"))?;
6920        let mut aad = [0_u8; 13];
6921        aad[..8].copy_from_slice(&sequence.to_be_bytes());
6922        aad[8] = content_type.to_u8();
6923        aad[9..11].copy_from_slice(&legacy_wire_version(self.version));
6924        aad[11..13].copy_from_slice(&len.to_be_bytes());
6925        Ok(aad)
6926    }
6927
6928    /// Builds TLS 1.3 AEAD additional authenticated data from TLSCiphertext header fields.
6929    ///
6930    /// # Arguments
6931    ///
6932    /// * `payload_len` — TLSCiphertext encrypted record payload length (`ciphertext || tag`) in bytes.
6933    ///
6934    /// # Returns
6935    ///
6936    /// 5-byte TLS 1.3 AAD array `(content_type, legacy_version, length)`.
6937    ///
6938    /// # Errors
6939    ///
6940    /// Returns [`Error::InvalidLength`] when `payload_len` exceeds `u16::MAX`.
6941    ///
6942    /// # Panics
6943    ///
6944    /// This function does not panic.
6945    fn build_tls13_record_aad(&self, payload_len: usize) -> Result<[u8; 5]> {
6946        let len = u16::try_from(payload_len)
6947            .map_err(|_| Error::InvalidLength("tls13 record payload length exceeds u16 range"))?;
6948        let mut aad = [0_u8; 5];
6949        aad[0] = RecordContentType::ApplicationData.to_u8();
6950        aad[1..3].copy_from_slice(&0x0303_u16.to_be_bytes());
6951        aad[3..5].copy_from_slice(&len.to_be_bytes());
6952        Ok(aad)
6953    }
6954
6955    /// Encodes protected payload into TLS 1.2 wire packet with version and content type.
6956    ///
6957    /// # Arguments
6958    ///
6959    /// * `&self` — `&self`.
6960    /// * `record` — `record: &ProtectedRecord`.
6961    /// * `content_type` — `content_type: RecordContentType`.
6962    ///
6963    /// # Returns
6964    ///
6965    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
6966    ///
6967    /// # Errors
6968    ///
6969    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
6970    ///
6971    /// # Panics
6972    ///
6973    /// This function does not panic.
6974    ///
6975    fn encode_tls12_record_packet(
6976        &self,
6977        record: &ProtectedRecord,
6978        content_type: RecordContentType,
6979    ) -> Result<Vec<u8>> {
6980        let mut payload = Vec::with_capacity(record.ciphertext.len() + record.tag.len());
6981        payload.extend_from_slice(&record.ciphertext);
6982        payload.extend_from_slice(&record.tag);
6983        encode_tls12_ciphertext_record(
6984            content_type.to_u8(),
6985            legacy_wire_version(self.version),
6986            &payload,
6987        )
6988    }
6989
6990    /// Decodes TLS 1.2 wire packet into protected payload at one sequence number.
6991    ///
6992    /// # Arguments
6993    ///
6994    /// * `&self` — `&self`.
6995    /// * `packet` — `packet: &[u8]`.
6996    /// * `sequence` — `sequence: u64`.
6997    ///
6998    /// # Returns
6999    ///
7000    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7001    ///
7002    /// # Errors
7003    ///
7004    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7005    ///
7006    /// # Panics
7007    ///
7008    /// This function does not panic.
7009    ///
7010    fn decode_tls12_record_packet(
7011        &self,
7012        packet: &[u8],
7013        sequence: u64,
7014    ) -> Result<(ProtectedRecord, RecordContentType)> {
7015        let (content_type_u8, version, payload) = decode_tls12_ciphertext_record(packet)?;
7016        let strict_version = legacy_wire_version(self.version);
7017        let legacy_compat_ok = self.tls12_allow_legacy_record_versions
7018            && (version == [0x03, 0x01] || version == [0x03, 0x02]);
7019        if version != strict_version && !legacy_compat_ok {
7020            return Err(Error::ParseFailure(
7021                "tls12 record has invalid legacy version",
7022            ));
7023        }
7024        let content_type = RecordContentType::from_u8(content_type_u8)
7025            .ok_or(Error::ParseFailure("unknown tls12 record content type"))?;
7026        if payload.len() < 16 {
7027            return Err(Error::ParseFailure("tls12 record payload too short"));
7028        }
7029        let tag_offset = payload.len() - 16;
7030        let mut tag = [0_u8; 16];
7031        tag.copy_from_slice(&payload[tag_offset..]);
7032        Ok((
7033            ProtectedRecord {
7034                sequence,
7035                ciphertext: payload[..tag_offset].to_vec(),
7036                tag,
7037            },
7038            content_type,
7039        ))
7040    }
7041
7042    /// Encodes one protected record into TLS 1.3 TLSCiphertext wire format.
7043    ///
7044    /// # Arguments
7045    ///
7046    /// * `&self` — `&self`.
7047    /// * `record` — `record: &ProtectedRecord`.
7048    ///
7049    /// # Returns
7050    ///
7051    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7052    ///
7053    /// # Errors
7054    ///
7055    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7056    ///
7057    /// # Panics
7058    ///
7059    /// This function does not panic.
7060    ///
7061    fn encode_tls13_record_packet(&self, record: &ProtectedRecord) -> Result<Vec<u8>> {
7062        let mut payload = Vec::with_capacity(record.ciphertext.len() + record.tag.len());
7063        payload.extend_from_slice(&record.ciphertext);
7064        payload.extend_from_slice(&record.tag);
7065        encode_tls13_ciphertext_record(&payload)
7066    }
7067
7068    /// Decodes one TLS 1.3 TLSCiphertext packet into a protected record at one sequence.
7069    ///
7070    /// # Arguments
7071    ///
7072    /// * `&self` — `&self`.
7073    /// * `packet` — `packet: &[u8]`.
7074    /// * `sequence` — `sequence: u64`.
7075    ///
7076    /// # Returns
7077    ///
7078    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7079    ///
7080    /// # Errors
7081    ///
7082    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7083    ///
7084    /// # Panics
7085    ///
7086    /// This function does not panic.
7087    ///
7088    fn decode_tls13_record_packet(&self, packet: &[u8], sequence: u64) -> Result<ProtectedRecord> {
7089        let payload = decode_tls13_ciphertext_record(packet)?;
7090        let tag_offset = payload.len() - 16;
7091        let mut tag = [0_u8; 16];
7092        tag.copy_from_slice(&payload[tag_offset..]);
7093        Ok(ProtectedRecord {
7094            sequence,
7095            ciphertext: payload[..tag_offset].to_vec(),
7096            tag,
7097        })
7098    }
7099
7100    /// Ensures DTLS1.3 sealing has remaining 48-bit sequence space.
7101    ///
7102    /// # Arguments
7103    ///
7104    /// * `&self` — `&self`.
7105    ///
7106    /// # Returns
7107    ///
7108    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7109    ///
7110    /// # Errors
7111    ///
7112    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7113    ///
7114    /// # Panics
7115    ///
7116    /// This function does not panic.
7117    ///
7118    fn ensure_dtls13_tx_sequence_available(&self) -> Result<()> {
7119        if self.dtls13_outbound_sequence > DTLS13_MAX_SEQUENCE {
7120            return Err(Error::StateError(
7121                "dtls13 outbound record sequence exhausted",
7122            ));
7123        }
7124        Ok(())
7125    }
7126
7127    /// Configures the initial DTLS retransmit timeout used for outbound flight scheduling.
7128    ///
7129    /// # Returns
7130    ///
7131    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7132    ///
7133    /// # Arguments
7134    /// * `timeout_ms`: Initial resend delay in milliseconds; values below 1 are clamped.
7135    /// # Errors
7136    ///
7137    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7138    ///
7139    /// # Panics
7140    ///
7141    /// This function does not panic.
7142    ///
7143    pub fn set_dtls12_retransmit_initial_timeout_ms(&mut self, timeout_ms: u64) -> Result<()> {
7144        self.ensure_dtls12_mode()?;
7145        self.dtls_retransmit_initial_timeout_ms = timeout_ms.max(1);
7146        Ok(())
7147    }
7148
7149    /// Configures maximum resend attempts before a DTLS packet is dropped.
7150    ///
7151    /// # Returns
7152    ///
7153    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7154    ///
7155    /// # Arguments
7156    /// * `attempts`: Number of due retransmits allowed before retirement; values below 1 are clamped.
7157    /// # Errors
7158    ///
7159    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7160    ///
7161    /// # Panics
7162    ///
7163    /// This function does not panic.
7164    ///
7165    pub fn set_dtls12_max_retransmit_attempts(&mut self, attempts: u8) -> Result<()> {
7166        self.ensure_dtls12_mode()?;
7167        self.dtls_max_retransmit_attempts = attempts.max(1);
7168        Ok(())
7169    }
7170
7171    /// Builds and schedules one outbound DTLS packet for timer-driven retransmission.
7172    ///
7173    /// # Arguments
7174    /// * `content_type`: DTLS record content type.
7175    /// * `epoch`: DTLS epoch value for this packet.
7176    /// * `sequence`: 48-bit DTLS sequence number.
7177    /// * `payload`: Record payload bytes.
7178    /// * `now_ms`: Current monotonic timestamp in milliseconds.
7179    ///
7180    /// # Returns
7181    /// Serialized DTLS datagram packet ready for immediate transmission.
7182    /// # Errors
7183    ///
7184    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7185    ///
7186    /// # Panics
7187    ///
7188    /// This function does not panic.
7189    ///
7190    pub fn build_dtls12_record_packet_for_flight(
7191        &mut self,
7192        content_type: RecordContentType,
7193        epoch: u16,
7194        sequence: u64,
7195        payload: &[u8],
7196        now_ms: u64,
7197    ) -> Result<Vec<u8>> {
7198        self.ensure_dtls12_mode()?;
7199        let packet = self.build_dtls12_record_packet(content_type, epoch, sequence, payload)?;
7200        self.dtls_retransmit_tracker.track_outbound_with_schedule(
7201            epoch,
7202            sequence,
7203            &packet,
7204            now_ms,
7205            self.dtls_retransmit_initial_timeout_ms,
7206        )?;
7207        Ok(packet)
7208    }
7209
7210    /// Marks one DTLS outbound packet as acknowledged by `(epoch, sequence)`.
7211    ///
7212    /// # Arguments
7213    ///
7214    /// * `self` — `&mut self`.
7215    /// * `epoch` — `epoch: u16`.
7216    /// * `sequence` — `sequence: u64`.
7217    ///
7218    /// # Returns
7219    /// `true` if a tracked packet matched and was marked acknowledged.
7220    /// # Errors
7221    ///
7222    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7223    ///
7224    /// # Panics
7225    ///
7226    /// This function does not panic.
7227    ///
7228    pub fn mark_dtls12_record_acked(&mut self, epoch: u16, sequence: u64) -> Result<bool> {
7229        self.ensure_dtls12_mode()?;
7230        Ok(self.dtls_retransmit_tracker.mark_acked(epoch, sequence))
7231    }
7232
7233    /// Returns due retransmit packets and updates their backoff schedule.
7234    ///
7235    /// # Arguments
7236    /// * `now_ms`: Current monotonic timestamp used to decide due timers.
7237    ///
7238    /// # Returns
7239    /// DTLS packets that should be retransmitted now.
7240    /// # Errors
7241    ///
7242    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7243    ///
7244    /// # Panics
7245    ///
7246    /// This function does not panic.
7247    ///
7248    pub fn poll_dtls12_due_retransmit_packets(&mut self, now_ms: u64) -> Result<Vec<Vec<u8>>> {
7249        self.ensure_dtls12_mode()?;
7250        Ok(self
7251            .dtls_retransmit_tracker
7252            .collect_due_retransmit_packets(now_ms, self.dtls_max_retransmit_attempts))
7253    }
7254
7255    /// Returns currently unacknowledged DTLS packets regardless of timer state.
7256    #[must_use]
7257    /// # Arguments
7258    ///
7259    /// * `&self` — `&self`.
7260    ///
7261    /// # Returns
7262    ///
7263    /// The value described by the return type in the function signature.
7264    ///
7265    /// # Panics
7266    ///
7267    /// This function does not panic.
7268    ///
7269    pub fn dtls12_pending_retransmit_packets(&self) -> Vec<Vec<u8>> {
7270        if !self.version.is_dtls() {
7271            return Vec::new();
7272        }
7273        self.dtls_retransmit_tracker.pending_retransmit_packets()
7274    }
7275
7276    /// Prunes acknowledged DTLS packets from retransmit tracking.
7277    ///
7278    /// # Arguments
7279    ///
7280    /// * `self` — `&mut self`.
7281    ///
7282    /// # Returns
7283    /// Number of pruned packet records.
7284    /// # Errors
7285    ///
7286    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7287    ///
7288    /// # Panics
7289    ///
7290    /// This function does not panic.
7291    ///
7292    pub fn prune_dtls12_acked_records(&mut self) -> Result<usize> {
7293        self.ensure_dtls12_mode()?;
7294        Ok(self.dtls_retransmit_tracker.prune_acked())
7295    }
7296
7297    /// Ensures DTLS-specific packet scheduler APIs are used only for DTLS profiles.
7298    ///
7299    /// # Arguments
7300    ///
7301    /// * `&self` — `&self`.
7302    ///
7303    /// # Returns
7304    ///
7305    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7306    ///
7307    /// # Errors
7308    ///
7309    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7310    ///
7311    /// # Panics
7312    ///
7313    /// This function does not panic.
7314    ///
7315    fn ensure_dtls12_mode(&self) -> Result<()> {
7316        if !self.version.is_dtls() {
7317            return Err(Error::StateError(
7318                "dtls retransmit scheduler requires DTLS connection",
7319            ));
7320        }
7321        Ok(())
7322    }
7323
7324    /// Ensures DTLS1.3 packet APIs are used only for DTLS profiles.
7325    ///
7326    /// # Arguments
7327    ///
7328    /// * `&self` — `&self`.
7329    ///
7330    /// # Returns
7331    ///
7332    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7333    ///
7334    /// # Errors
7335    ///
7336    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7337    ///
7338    /// # Panics
7339    ///
7340    /// This function does not panic.
7341    ///
7342    fn ensure_dtls13_mode(&self) -> Result<()> {
7343        if !self.version.is_dtls() {
7344            return Err(Error::StateError("dtls13 APIs require DTLS connection"));
7345        }
7346        Ok(())
7347    }
7348
7349    /// Ensures TLS1.2 wire-packet APIs are used only on TLS 1.0/1.1/1.2 connections.
7350    ///
7351    /// # Arguments
7352    ///
7353    /// * `&self` — `&self`.
7354    ///
7355    /// # Returns
7356    ///
7357    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7358    ///
7359    /// # Errors
7360    ///
7361    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7362    ///
7363    /// # Panics
7364    ///
7365    /// This function does not panic.
7366    ///
7367    fn ensure_tls12_wire_mode(&self) -> Result<()> {
7368        if self.version == TlsVersion::Tls10
7369            || self.version == TlsVersion::Tls11
7370            || self.version == TlsVersion::Tls12
7371        {
7372            return Ok(());
7373        }
7374        Err(Error::StateError(
7375            "tls12 record packets require TLS 1.0/1.1/1.2 connection",
7376        ))
7377    }
7378
7379    /// Seals plaintext into multiple records using caller-selected fragment size.
7380    ///
7381    /// # Arguments
7382    /// * `plaintext`: Full plaintext payload to fragment and seal.
7383    /// * `aad`: Additional authenticated data reused for each fragment.
7384    /// * `fragment_len`: Maximum plaintext bytes per sealed record fragment.
7385    ///
7386    /// # Returns
7387    /// Ordered protected-record fragments covering the full plaintext.
7388    /// # Errors
7389    ///
7390    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7391    ///
7392    /// # Panics
7393    ///
7394    /// This function does not panic.
7395    ///
7396    pub fn seal_record_fragments(
7397        &mut self,
7398        plaintext: &[u8],
7399        aad: &[u8],
7400        fragment_len: usize,
7401    ) -> Result<Vec<ProtectedRecord>> {
7402        if fragment_len == 0 {
7403            return Err(Error::InvalidLength(
7404                "fragment length must be greater than zero",
7405            ));
7406        }
7407        if fragment_len > self.max_record_plaintext_len {
7408            return Err(Error::InvalidLength(
7409                "fragment length exceeds configured record plaintext limit",
7410            ));
7411        }
7412        if plaintext.is_empty() {
7413            return Ok(Vec::new());
7414        }
7415        let fragment_count = plaintext.len().div_ceil(fragment_len);
7416        let required_sequences = u64::try_from(fragment_count)
7417            .map_err(|_| Error::InvalidLength("too many record fragments requested"))?;
7418        let highest_sequence = self
7419            .client_sequence
7420            .checked_add(required_sequences.saturating_sub(1));
7421        if highest_sequence.is_none() {
7422            return Err(Error::StateError(
7423                "insufficient record sequence space for all fragments",
7424            ));
7425        }
7426
7427        let mut out = Vec::with_capacity(fragment_count);
7428        let mut offset = 0_usize;
7429        while offset < plaintext.len() {
7430            let end = (offset + fragment_len).min(plaintext.len());
7431            out.push(self.seal_record(&plaintext[offset..end], aad)?);
7432            offset = end;
7433        }
7434        Ok(out)
7435    }
7436
7437    /// Opens and reassembles a sequence of protected record fragments.
7438    ///
7439    /// # Arguments
7440    /// * `records`: Ordered record fragments to decrypt and concatenate.
7441    /// * `aad`: Additional authenticated data reused for each fragment.
7442    ///
7443    /// # Returns
7444    /// Reassembled plaintext payload.
7445    /// # Errors
7446    ///
7447    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7448    ///
7449    /// # Panics
7450    ///
7451    /// This function does not panic.
7452    ///
7453    pub fn open_record_fragments(
7454        &mut self,
7455        records: &[ProtectedRecord],
7456        aad: &[u8],
7457    ) -> Result<Vec<u8>> {
7458        if records.is_empty() {
7459            return Ok(Vec::new());
7460        }
7461        let base_sequence = self.server_sequence;
7462        for (index, record) in records.iter().enumerate() {
7463            let expected_sequence = base_sequence
7464                .checked_add(index as u64)
7465                .ok_or(Error::ParseFailure("record fragment sequence overflow"))?;
7466            if record.sequence != expected_sequence {
7467                return Err(Error::ParseFailure(
7468                    "record fragments must be contiguous sequences",
7469                ));
7470            }
7471        }
7472        let mut out = Vec::new();
7473        for record in records {
7474            out.extend_from_slice(&self.open_record(record, aad)?);
7475        }
7476        Ok(out)
7477    }
7478
7479    /// Opens locally-sealed fragments with client keys and reassembles plaintext.
7480    ///
7481    /// # Arguments
7482    /// * `records`: Ordered local record fragments produced by `seal_record_fragments`.
7483    /// * `aad`: Additional authenticated data reused for each fragment.
7484    ///
7485    /// # Returns
7486    /// Reassembled plaintext payload.
7487    /// # Errors
7488    ///
7489    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7490    ///
7491    /// # Panics
7492    ///
7493    /// This function does not panic.
7494    ///
7495    pub fn open_own_record_fragments(
7496        &self,
7497        records: &[ProtectedRecord],
7498        aad: &[u8],
7499    ) -> Result<Vec<u8>> {
7500        if records.is_empty() {
7501            return Ok(Vec::new());
7502        }
7503        let base_sequence = records[0].sequence;
7504        for (index, record) in records.iter().enumerate() {
7505            let expected_sequence = base_sequence
7506                .checked_add(index as u64)
7507                .ok_or(Error::ParseFailure("record fragment sequence overflow"))?;
7508            if record.sequence != expected_sequence {
7509                return Err(Error::ParseFailure(
7510                    "record fragments must be contiguous sequences",
7511                ));
7512            }
7513        }
7514        let mut out = Vec::new();
7515        for record in records {
7516            out.extend_from_slice(&self.open_own_record(record, aad)?);
7517        }
7518        Ok(out)
7519    }
7520
7521    /// Seals a TLS 1.3 record by encoding TLSInnerPlaintext with content type and padding.
7522    ///
7523    /// # Arguments
7524    /// * `content`: Inner plaintext content bytes.
7525    /// * `content_type`: TLS content type byte encoded at end of inner plaintext.
7526    /// * `aad`: Additional authenticated data for AEAD.
7527    /// * `padding_len`: Number of trailing zero padding bytes.
7528    ///
7529    /// # Returns
7530    /// Protected record carrying encrypted TLSInnerPlaintext.
7531    /// # Errors
7532    ///
7533    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7534    ///
7535    /// # Panics
7536    ///
7537    /// This function does not panic.
7538    ///
7539    pub fn seal_tls13_inner_record(
7540        &mut self,
7541        content: &[u8],
7542        content_type: u8,
7543        aad: &[u8],
7544        padding_len: usize,
7545    ) -> Result<ProtectedRecord> {
7546        if !self.version.uses_tls13_handshake_semantics() {
7547            return Err(Error::StateError(
7548                "tls13 inner plaintext records require TLS 1.3 connection",
7549            ));
7550        }
7551        let inner = encode_tls13_inner_plaintext(content, content_type, padding_len);
7552        self.seal_record(&inner, aad)
7553    }
7554
7555    /// Opens a TLS 1.3 record and decodes TLSInnerPlaintext into content and content type.
7556    ///
7557    /// # Arguments
7558    /// * `record`: Protected record sealed with peer TLS 1.3 traffic keys.
7559    /// * `aad`: Additional authenticated data used during sealing.
7560    ///
7561    /// # Returns
7562    /// Tuple `(content, content_type)` extracted from decoded inner plaintext.
7563    /// # Errors
7564    ///
7565    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7566    ///
7567    /// # Panics
7568    ///
7569    /// This function does not panic.
7570    ///
7571    pub fn open_tls13_inner_record(
7572        &mut self,
7573        record: &ProtectedRecord,
7574        aad: &[u8],
7575    ) -> Result<(Vec<u8>, u8)> {
7576        if !self.version.uses_tls13_handshake_semantics() {
7577            return Err(Error::StateError(
7578                "tls13 inner plaintext records require TLS 1.3 connection",
7579            ));
7580        }
7581        let inner = self.open_record(record, aad)?;
7582        decode_tls13_inner_plaintext(&inner)
7583    }
7584
7585    /// Opens a locally-sealed TLS 1.3 record and decodes TLSInnerPlaintext for tests.
7586    ///
7587    /// # Arguments
7588    /// * `record`: Protected record sealed via `seal_tls13_inner_record`.
7589    /// * `aad`: Additional authenticated data used during sealing.
7590    ///
7591    /// # Returns
7592    /// Tuple `(content, content_type)` extracted from decoded inner plaintext.
7593    /// # Errors
7594    ///
7595    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7596    ///
7597    /// # Panics
7598    ///
7599    /// This function does not panic.
7600    ///
7601    pub fn open_own_tls13_inner_record(
7602        &self,
7603        record: &ProtectedRecord,
7604        aad: &[u8],
7605    ) -> Result<(Vec<u8>, u8)> {
7606        if !self.version.uses_tls13_handshake_semantics() {
7607            return Err(Error::StateError(
7608                "tls13 inner plaintext records require TLS 1.3 connection",
7609            ));
7610        }
7611        let inner = self.open_own_record(record, aad)?;
7612        decode_tls13_inner_plaintext(&inner)
7613    }
7614
7615    /// Seals one TLS 1.3 wire record packet from TLSInnerPlaintext content.
7616    ///
7617    /// # Arguments
7618    /// * `content`: Inner plaintext content bytes.
7619    /// * `content_type`: Inner content type byte.
7620    /// * `aad`: Additional authenticated data for AEAD.
7621    /// * `padding_len`: Number of trailing zero padding bytes.
7622    ///
7623    /// # Returns
7624    /// Serialized TLSCiphertext packet bytes.
7625    /// # Errors
7626    ///
7627    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7628    ///
7629    /// # Panics
7630    ///
7631    /// This function does not panic.
7632    ///
7633    pub fn seal_tls13_record_packet(
7634        &mut self,
7635        content: &[u8],
7636        content_type: u8,
7637        aad: &[u8],
7638        padding_len: usize,
7639    ) -> Result<Vec<u8>> {
7640        if !self.version.uses_tls13_handshake_semantics() {
7641            return Err(Error::StateError(
7642                "tls13 record packets require TLS 1.3 connection",
7643            ));
7644        }
7645        let record = self.seal_tls13_inner_record(content, content_type, aad, padding_len)?;
7646        self.encode_tls13_record_packet(&record)
7647    }
7648
7649    /// Opens one inbound TLS 1.3 wire record packet and decodes TLSInnerPlaintext.
7650    ///
7651    /// # Arguments
7652    /// * `packet`: Serialized TLSCiphertext packet bytes.
7653    /// * `aad`: Additional authenticated data used during sealing.
7654    ///
7655    /// # Returns
7656    /// Tuple `(content, content_type)` decoded from inner plaintext.
7657    /// # Errors
7658    ///
7659    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7660    ///
7661    /// # Panics
7662    ///
7663    /// This function does not panic.
7664    ///
7665    pub fn open_tls13_record_packet(&mut self, packet: &[u8], aad: &[u8]) -> Result<(Vec<u8>, u8)> {
7666        if !self.version.uses_tls13_handshake_semantics() {
7667            return Err(Error::StateError(
7668                "tls13 record packets require TLS 1.3 connection",
7669            ));
7670        }
7671        let record = self.decode_tls13_record_packet(packet, self.server_sequence)?;
7672        self.open_tls13_inner_record(&record, aad)
7673    }
7674
7675    /// Opens one locally-sealed TLS 1.3 wire packet using client traffic keys.
7676    ///
7677    /// # Arguments
7678    /// * `packet`: Serialized TLSCiphertext packet bytes.
7679    /// * `sequence`: Record sequence number used during sealing.
7680    /// * `aad`: Additional authenticated data used during sealing.
7681    ///
7682    /// # Returns
7683    /// Tuple `(content, content_type)` decoded from inner plaintext.
7684    /// # Errors
7685    ///
7686    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7687    ///
7688    /// # Panics
7689    ///
7690    /// This function does not panic.
7691    ///
7692    pub fn open_own_tls13_record_packet(
7693        &self,
7694        packet: &[u8],
7695        sequence: u64,
7696        aad: &[u8],
7697    ) -> Result<(Vec<u8>, u8)> {
7698        if !self.version.uses_tls13_handshake_semantics() {
7699            return Err(Error::StateError(
7700                "tls13 record packets require TLS 1.3 connection",
7701            ));
7702        }
7703        let record = self.decode_tls13_record_packet(packet, sequence)?;
7704        self.open_own_tls13_inner_record(&record, aad)
7705    }
7706
7707    /// Seals a TLS 1.3 alert as TLSInnerPlaintext with alert content type.
7708    ///
7709    /// # Arguments
7710    /// * `level`: Alert severity level.
7711    /// * `description`: Alert description codepoint.
7712    /// * `aad`: Additional authenticated data used for AEAD.
7713    ///
7714    /// # Returns
7715    /// Protected record containing encoded alert bytes.
7716    /// # Errors
7717    ///
7718    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7719    ///
7720    /// # Panics
7721    ///
7722    /// This function does not panic.
7723    ///
7724    pub fn send_tls13_alert(
7725        &mut self,
7726        level: AlertLevel,
7727        description: AlertDescription,
7728        aad: &[u8],
7729    ) -> Result<ProtectedRecord> {
7730        if !self.version.uses_tls13_handshake_semantics() {
7731            return Err(Error::StateError(
7732                "tls13 alert records require TLS 1.3 connection",
7733            ));
7734        }
7735        let payload = [level.to_u8(), description.to_u8()];
7736        let record =
7737            self.seal_tls13_inner_record(&payload, RecordContentType::Alert.to_u8(), aad, 0)?;
7738        self.apply_tls13_alert_effects(level, description, true);
7739        Ok(record)
7740    }
7741
7742    /// Seals a TLS 1.3 alert and encodes it into TLSCiphertext packet wire format.
7743    ///
7744    /// # Arguments
7745    /// * `level`: Alert severity level.
7746    /// * `description`: Alert description codepoint.
7747    /// * `aad`: Additional authenticated data used for AEAD.
7748    ///
7749    /// # Returns
7750    /// Serialized TLSCiphertext packet bytes carrying an alert inner record.
7751    /// # Errors
7752    ///
7753    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7754    ///
7755    /// # Panics
7756    ///
7757    /// This function does not panic.
7758    ///
7759    pub fn send_tls13_alert_packet(
7760        &mut self,
7761        level: AlertLevel,
7762        description: AlertDescription,
7763        aad: &[u8],
7764    ) -> Result<Vec<u8>> {
7765        if !self.version.uses_tls13_handshake_semantics() {
7766            return Err(Error::StateError(
7767                "tls13 alert records require TLS 1.3 connection",
7768            ));
7769        }
7770        let record = self.send_tls13_alert(level, description, aad)?;
7771        self.encode_tls13_record_packet(&record)
7772    }
7773
7774    /// Opens and parses a peer TLS 1.3 alert record.
7775    ///
7776    /// # Arguments
7777    /// * `record`: Protected record carrying peer alert payload.
7778    /// * `aad`: Additional authenticated data used during sealing.
7779    ///
7780    /// # Returns
7781    /// Parsed `(AlertLevel, AlertDescription)` tuple.
7782    /// # Errors
7783    ///
7784    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7785    ///
7786    /// # Panics
7787    ///
7788    /// This function does not panic.
7789    ///
7790    pub fn recv_tls13_alert(
7791        &mut self,
7792        record: &ProtectedRecord,
7793        aad: &[u8],
7794    ) -> Result<(AlertLevel, AlertDescription)> {
7795        if !self.version.uses_tls13_handshake_semantics() {
7796            return Err(Error::StateError(
7797                "tls13 alert records require TLS 1.3 connection",
7798            ));
7799        }
7800        let (payload, content_type) = self.open_tls13_inner_record(record, aad)?;
7801        self.process_parsed_tls13_alert(payload, content_type)
7802    }
7803
7804    /// Opens and parses a locally-sealed TLS 1.3 alert record for loopback tests.
7805    ///
7806    /// # Arguments
7807    /// * `record`: Protected record sealed via `send_tls13_alert`.
7808    /// * `aad`: Additional authenticated data used during sealing.
7809    ///
7810    /// # Returns
7811    /// Parsed `(AlertLevel, AlertDescription)` tuple.
7812    /// # Errors
7813    ///
7814    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7815    ///
7816    /// # Panics
7817    ///
7818    /// This function does not panic.
7819    ///
7820    pub fn recv_own_tls13_alert(
7821        &mut self,
7822        record: &ProtectedRecord,
7823        aad: &[u8],
7824    ) -> Result<(AlertLevel, AlertDescription)> {
7825        if !self.version.uses_tls13_handshake_semantics() {
7826            return Err(Error::StateError(
7827                "tls13 alert records require TLS 1.3 connection",
7828            ));
7829        }
7830        let (payload, content_type) = self.open_own_tls13_inner_record(record, aad)?;
7831        self.process_parsed_tls13_alert(payload, content_type)
7832    }
7833
7834    /// Opens and parses a peer TLS 1.3 alert TLSCiphertext packet.
7835    ///
7836    /// # Arguments
7837    /// * `packet`: Serialized TLSCiphertext packet bytes carrying an alert inner record.
7838    /// * `aad`: Additional authenticated data used during sealing.
7839    ///
7840    /// # Returns
7841    /// Parsed `(AlertLevel, AlertDescription)` tuple.
7842    /// # Errors
7843    ///
7844    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7845    ///
7846    /// # Panics
7847    ///
7848    /// This function does not panic.
7849    ///
7850    pub fn recv_tls13_alert_packet(
7851        &mut self,
7852        packet: &[u8],
7853        aad: &[u8],
7854    ) -> Result<(AlertLevel, AlertDescription)> {
7855        if !self.version.uses_tls13_handshake_semantics() {
7856            return Err(Error::StateError(
7857                "tls13 alert records require TLS 1.3 connection",
7858            ));
7859        }
7860        let (payload, content_type) = self.open_tls13_record_packet(packet, aad)?;
7861        self.process_parsed_tls13_alert(payload, content_type)
7862    }
7863
7864    /// Opens and parses a locally-sealed TLS 1.3 alert TLSCiphertext packet for loopback tests.
7865    ///
7866    /// # Arguments
7867    /// * `packet`: Serialized TLSCiphertext packet bytes from local alert sealing.
7868    /// * `sequence`: Record sequence number used during sealing.
7869    /// * `aad`: Additional authenticated data used during sealing.
7870    ///
7871    /// # Returns
7872    /// Parsed `(AlertLevel, AlertDescription)` tuple.
7873    /// # Errors
7874    ///
7875    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7876    ///
7877    /// # Panics
7878    ///
7879    /// This function does not panic.
7880    ///
7881    pub fn recv_own_tls13_alert_packet(
7882        &mut self,
7883        packet: &[u8],
7884        sequence: u64,
7885        aad: &[u8],
7886    ) -> Result<(AlertLevel, AlertDescription)> {
7887        if !self.version.uses_tls13_handshake_semantics() {
7888            return Err(Error::StateError(
7889                "tls13 alert records require TLS 1.3 connection",
7890            ));
7891        }
7892        let (payload, content_type) = self.open_own_tls13_record_packet(packet, sequence, aad)?;
7893        self.process_parsed_tls13_alert(payload, content_type)
7894    }
7895
7896    /// Applies decoded alert payload semantics to connection state.
7897    ///
7898    /// # Arguments
7899    ///
7900    /// * `self` — `&mut self`.
7901    /// * `payload` — `payload: Vec<u8>`.
7902    /// * `content_type` — `content_type: u8`.
7903    ///
7904    /// # Returns
7905    ///
7906    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
7907    ///
7908    /// # Errors
7909    ///
7910    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
7911    ///
7912    /// # Panics
7913    ///
7914    /// This function does not panic.
7915    ///
7916    fn process_parsed_tls13_alert(
7917        &mut self,
7918        payload: Vec<u8>,
7919        content_type: u8,
7920    ) -> Result<(AlertLevel, AlertDescription)> {
7921        if RecordContentType::from_u8(content_type) != Some(RecordContentType::Alert) {
7922            return Err(Error::ParseFailure("record is not an alert content type"));
7923        }
7924        if payload.len() != 2 {
7925            return Err(Error::ParseFailure("tls13 alert payload must be two bytes"));
7926        }
7927        let level =
7928            AlertLevel::from_u8(payload[0]).ok_or(Error::ParseFailure("unknown alert level"))?;
7929        let description = AlertDescription::from_u8(payload[1])
7930            .ok_or(Error::ParseFailure("unknown alert description"))?;
7931        self.apply_tls13_alert_effects(level, description, false);
7932        Ok((level, description))
7933    }
7934
7935    /// Applies modeled TLS 1.3 alert mapping effects for local-send and peer-receive paths.
7936    ///
7937    /// # Arguments
7938    ///
7939    /// * `self` — `&mut self`.
7940    /// * `level` — `level: AlertLevel`.
7941    /// * `description` — `description: AlertDescription`.
7942    /// * `from_local_send` — `from_local_send: bool`.
7943    ///
7944    /// # Panics
7945    ///
7946    /// This function does not panic.
7947    ///
7948    fn apply_tls13_alert_effects(
7949        &mut self,
7950        level: AlertLevel,
7951        description: AlertDescription,
7952        from_local_send: bool,
7953    ) {
7954        if description == AlertDescription::CloseNotify {
7955            if from_local_send {
7956                self.tls13_local_close_notify_sent = true;
7957            } else {
7958                self.tls13_peer_close_notify_received = true;
7959            }
7960        }
7961        if level == AlertLevel::Fatal {
7962            self.state = HandshakeState::Idle;
7963        }
7964    }
7965
7966    /// Reports whether a peer close_notify alert has been processed.
7967    #[must_use]
7968    /// # Arguments
7969    ///
7970    /// * `&self` — `&self`.
7971    ///
7972    /// # Returns
7973    ///
7974    /// `true` or `false` according to the checks in the function body.
7975    ///
7976    /// # Panics
7977    ///
7978    /// This function does not panic.
7979    ///
7980    pub fn tls13_peer_close_notify_received(&self) -> bool {
7981        self.tls13_peer_close_notify_received
7982    }
7983
7984    /// Reports whether this endpoint has sent a close_notify alert.
7985    #[must_use]
7986    /// # Arguments
7987    ///
7988    /// * `&self` — `&self`.
7989    ///
7990    /// # Returns
7991    ///
7992    /// `true` or `false` according to the checks in the function body.
7993    ///
7994    /// # Panics
7995    ///
7996    /// This function does not panic.
7997    ///
7998    pub fn tls13_local_close_notify_sent(&self) -> bool {
7999        self.tls13_local_close_notify_sent
8000    }
8001
8002    /// Resets per-handshake certificate-auth tracking before a new ClientHello.
8003    ///
8004    /// # Arguments
8005    ///
8006    /// * `self` — `&mut self`.
8007    ///
8008    /// # Panics
8009    ///
8010    /// This function does not panic.
8011    ///
8012    fn reset_tls13_certificate_auth_state(&mut self) {
8013        self.tls13_server_leaf_public_key_der = None;
8014        self.tls13_server_certificate_chain_validated = false;
8015        self.tls13_server_name_acknowledged = false;
8016        self.tls13_selected_alpn_protocol = None;
8017        self.tls13_server_ocsp_staple = None;
8018        self.tls13_server_ocsp_staple_verified = false;
8019    }
8020
8021    /// Validates modeled HRR retry-group support before sending a second ClientHello.
8022    ///
8023    /// # Arguments
8024    ///
8025    /// * `&self` — `&self`.
8026    ///
8027    /// # Returns
8028    ///
8029    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8030    ///
8031    /// # Errors
8032    ///
8033    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8034    ///
8035    /// # Panics
8036    ///
8037    /// This function does not panic.
8038    ///
8039    fn validate_tls13_hrr_retry_group_support(&self) -> Result<()> {
8040        if !self.version.uses_tls13_handshake_semantics() || !self.tls13_hrr_seen {
8041            return Ok(());
8042        }
8043        let requested_group = self.tls13_hrr_requested_group.ok_or(Error::ParseFailure(
8044            "hello retry request is missing requested key_share group",
8045        ))?;
8046        if !super::keyshare::tls13_key_share_group_supported(requested_group) {
8047            return Err(Error::StateError(
8048                "hello retry request requested unsupported key_share group",
8049            ));
8050        }
8051        Ok(())
8052    }
8053
8054    /// Derives TLS 1.3 modeled client early-data record key+iv from PSK and transcript context.
8055    ///
8056    /// # Arguments
8057    ///
8058    /// * `&self` — `&self`.
8059    /// * `psk` — `psk: &[u8]`.
8060    ///
8061    /// # Returns
8062    ///
8063    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8064    ///
8065    /// # Errors
8066    ///
8067    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8068    ///
8069    /// # Panics
8070    ///
8071    /// This function does not panic.
8072    ///
8073    fn derive_tls13_early_data_record_key_iv(&self, psk: &[u8]) -> Result<(Vec<u8>, [u8; 12])> {
8074        let hash_algorithm = self.negotiated_hash_algorithm();
8075        let hash_len = hash_algorithm.output_len();
8076        let transcript_hash = hash_bytes_for_algorithm(hash_algorithm, &self.transcript);
8077        let early_secret = hkdf_extract_for_hash(hash_algorithm, psk);
8078        let client_early_traffic_secret = tls13_expand_label_for_hash(
8079            hash_algorithm,
8080            &early_secret,
8081            b"c e traffic",
8082            &transcript_hash,
8083            hash_len,
8084        )?;
8085        let key_len = self.tls13_early_data_key_len();
8086        let key = tls13_expand_label_for_hash(
8087            hash_algorithm,
8088            &client_early_traffic_secret,
8089            b"key",
8090            &[],
8091            key_len,
8092        )?;
8093        let iv: [u8; 12] = tls13_expand_label_for_hash(
8094            hash_algorithm,
8095            &client_early_traffic_secret,
8096            b"iv",
8097            &[],
8098            12,
8099        )?
8100        .try_into()
8101        .expect("tls13 early-data iv should be 12 bytes");
8102        Ok((key, iv))
8103    }
8104
8105    /// Returns TLS 1.3 early-data traffic-key length based on active modeled suite policy.
8106    ///
8107    /// # Returns
8108    ///
8109    /// AES-128 uses 16 bytes; AES-256 and ChaCha20-Poly1305 use 32 bytes.
8110    ///
8111    /// # Panics
8112    ///
8113    /// This function does not panic.
8114    fn tls13_early_data_key_len(&self) -> usize {
8115        match self.selected_cipher_suite {
8116            Some(CipherSuite::TlsAes256GcmSha384 | CipherSuite::TlsChacha20Poly1305Sha256) => 32,
8117            _ => 16,
8118        }
8119    }
8120
8121    /// Returns whether modeled early-data record protection uses ChaCha20-Poly1305.
8122    ///
8123    /// # Returns
8124    ///
8125    /// `true` when current modeled suite policy selects ChaCha20-Poly1305.
8126    ///
8127    /// # Panics
8128    ///
8129    /// This function does not panic.
8130    fn tls13_early_data_uses_chacha20_poly1305(&self) -> bool {
8131        matches!(
8132            self.selected_cipher_suite,
8133            Some(CipherSuite::TlsChacha20Poly1305Sha256)
8134        )
8135    }
8136
8137    /// Validates server certificate chain and caches leaf SPKI for CertificateVerify.
8138    ///
8139    /// # Arguments
8140    ///
8141    /// * `self` — `&mut self`.
8142    /// * `certificates` — `certificates: &[Vec<u8>]`.
8143    ///
8144    /// # Returns
8145    ///
8146    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8147    ///
8148    /// # Errors
8149    ///
8150    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8151    ///
8152    /// # Panics
8153    ///
8154    /// This function does not panic.
8155    ///
8156    fn validate_tls13_server_certificate_chain(&mut self, certificates: &[Vec<u8>]) -> Result<()> {
8157        if certificates.is_empty() {
8158            return Err(Error::ParseFailure(
8159                "certificate list must include leaf certificate",
8160            ));
8161        }
8162        if self.tls13_server_trust_anchors_der.is_empty() {
8163            return Err(Error::StateError(
8164                "tls13 server trust anchors are not configured",
8165            ));
8166        }
8167        let validation_time =
8168            self.tls13_server_validation_time
8169                .as_deref()
8170                .ok_or(Error::StateError(
8171                    "tls13 server validation time is not configured",
8172                ))?;
8173        let leaf = parse_certificate(&certificates[0])
8174            .map_err(|_| Error::ParseFailure("failed to parse server leaf certificate"))?;
8175        if let Some(expected_hostname) = self.tls13_server_expected_hostname.as_deref() {
8176            if !certificate_matches_hostname(&leaf, expected_hostname) {
8177                return Err(Error::CryptoFailure(
8178                    "server certificate hostname validation failed",
8179                ));
8180            }
8181        }
8182
8183        let mut parsed_intermediates = Vec::new();
8184        for der in &certificates[1..] {
8185            let parsed = parse_certificate(der).map_err(|_| {
8186                Error::ParseFailure("failed to parse server intermediate certificate")
8187            })?;
8188            parsed_intermediates.push(parsed);
8189        }
8190        for der in &self.tls13_server_intermediates_der {
8191            let parsed = parse_certificate(der).map_err(|_| {
8192                Error::ParseFailure("failed to parse configured server intermediate certificate")
8193            })?;
8194            parsed_intermediates.push(parsed);
8195        }
8196
8197        let mut parsed_anchors = Vec::new();
8198        for der in &self.tls13_server_trust_anchors_der {
8199            let parsed = parse_certificate(der).map_err(|_| {
8200                Error::ParseFailure("failed to parse configured trust anchor certificate")
8201            })?;
8202            parsed_anchors.push(parsed);
8203        }
8204
8205        validate_certificate_chain(
8206            &leaf,
8207            &parsed_intermediates,
8208            &parsed_anchors,
8209            validation_time,
8210        )
8211        .map_err(|_| Error::CryptoFailure("server certificate chain validation failed"))?;
8212        self.tls13_server_leaf_public_key_der = Some(leaf.subject_public_key.clone());
8213        self.tls13_server_certificate_chain_validated = true;
8214        Ok(())
8215    }
8216
8217    /// Verifies TLS 1.3 CertificateVerify signature over transcript-based context bytes.
8218    ///
8219    /// # Arguments
8220    ///
8221    /// * `&self` — `&self`.
8222    /// * `signature_scheme` — `signature_scheme: u16`.
8223    /// * `signature` — `signature: &[u8]`.
8224    ///
8225    /// # Returns
8226    ///
8227    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8228    ///
8229    /// # Errors
8230    ///
8231    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8232    ///
8233    /// # Panics
8234    ///
8235    /// This function does not panic.
8236    ///
8237    fn verify_tls13_server_certificate_verify_signature(
8238        &self,
8239        signature_scheme: u16,
8240        signature: &[u8],
8241    ) -> Result<()> {
8242        let leaf_spki =
8243            self.tls13_server_leaf_public_key_der
8244                .as_deref()
8245                .ok_or(Error::StateError(
8246                    "server leaf public key is unavailable for certificate verify",
8247                ))?;
8248        let signed_message = build_tls13_server_certificate_verify_message(&self.transcript_hash());
8249        match signature_scheme {
8250            TLS13_SIGALG_ECDSA_SECP256R1_SHA256 => {
8251                let public_key = P256PublicKey::from_uncompressed(leaf_spki)?;
8252                let (r, s) = parse_ecdsa_signature_der(signature)?;
8253                p256_ecdsa_verify_sha256(&public_key, &signed_message, &r, &s).map_err(|_| {
8254                    Error::CryptoFailure("tls13 certificate verify signature validation failed")
8255                })
8256            }
8257            TLS13_SIGALG_RSA_PSS_RSAE_SHA256 => {
8258                let public_key = parse_rsa_public_key_der(leaf_spki)?;
8259                rsassa_pss_sha256_verify(&public_key, &signed_message, signature, 32).map_err(
8260                    |_| {
8261                        Error::CryptoFailure("tls13 certificate verify signature validation failed")
8262                    },
8263                )
8264            }
8265            TLS13_SIGALG_RSA_PSS_RSAE_SHA384 => {
8266                let public_key = parse_rsa_public_key_der(leaf_spki)?;
8267                rsassa_pss_sha384_verify(&public_key, &signed_message, signature, 48).map_err(
8268                    |_| {
8269                        Error::CryptoFailure("tls13 certificate verify signature validation failed")
8270                    },
8271                )
8272            }
8273            TLS13_SIGALG_ED25519 => {
8274                let public_key = ed25519_public_key_from_subject_public_key_info(leaf_spki)?;
8275                ed25519_verify(&public_key, &signed_message, signature).map_err(|_| {
8276                    Error::CryptoFailure("tls13 certificate verify signature validation failed")
8277                })
8278            }
8279            TLS13_SIGALG_MLDSA65 => {
8280                let public_key = MlDsaPublicKey::from_bytes(leaf_spki).map_err(|_| {
8281                    Error::ParseFailure("failed to parse mldsa server public key bytes")
8282                })?;
8283                mldsa_verify(&public_key, &signed_message, signature).map_err(|_| {
8284                    Error::CryptoFailure("tls13 certificate verify signature validation failed")
8285                })
8286            }
8287            _ => Err(Error::UnsupportedFeature(
8288                "unsupported tls13 certificate verify signature scheme",
8289            )),
8290        }
8291    }
8292
8293    /// Overrides record sequence counters for external validation harness scenarios.
8294    /// # Arguments
8295    ///
8296    /// * `self` — `&mut self`.
8297    /// * `client_sequence` — `client_sequence: u64`.
8298    /// * `server_sequence` — `server_sequence: u64`.
8299    ///
8300    /// # Panics
8301    ///
8302    /// This function does not panic.
8303    ///
8304    pub fn set_record_sequences_for_test(&mut self, client_sequence: u64, server_sequence: u64) {
8305        self.client_sequence = client_sequence;
8306        self.server_sequence = server_sequence;
8307    }
8308
8309    /// Installs CertificateVerify public-key material for validation harness testing flows.
8310    /// # Arguments
8311    ///
8312    /// * `self` — `&mut self`.
8313    /// * `leaf_spki_der` — `leaf_spki_der: Vec<u8>`.
8314    ///
8315    /// # Panics
8316    ///
8317    /// This function does not panic.
8318    ///
8319    pub fn set_tls13_certificate_verify_material_for_test(&mut self, leaf_spki_der: Vec<u8>) {
8320        self.tls13_server_leaf_public_key_der = Some(leaf_spki_der);
8321        self.tls13_server_certificate_chain_validated = true;
8322    }
8323
8324    /// Builds TLS 1.3 server CertificateVerify transcript message bytes for external signing tests.
8325    /// # Arguments
8326    ///
8327    /// * `&self` — `&self`.
8328    ///
8329    /// # Returns
8330    ///
8331    /// The value described by the return type in the function signature.
8332    ///
8333    /// # Panics
8334    ///
8335    /// This function does not panic.
8336    ///
8337    pub fn tls13_server_certificate_verify_message_for_test(&self) -> Vec<u8> {
8338        build_tls13_server_certificate_verify_message(&self.transcript_hash())
8339    }
8340
8341    /// Installs client/server traffic keys derived from handshake PRK.
8342    ///
8343    /// # Arguments
8344    ///
8345    /// * `self` — `&mut self`.
8346    /// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8347    /// * `secret` — `secret: &[u8]`.
8348    /// * `transcript_hash` — `transcript_hash: &[u8]`.
8349    ///
8350    /// # Returns
8351    ///
8352    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8353    ///
8354    /// # Errors
8355    ///
8356    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8357    ///
8358    /// # Panics
8359    ///
8360    /// This function does not panic.
8361    ///
8362    fn install_traffic_keys(
8363        &mut self,
8364        hash_algorithm: HashAlgorithm,
8365        secret: &[u8],
8366        transcript_hash: &[u8],
8367    ) -> Result<()> {
8368        let (client_key, server_key, client_iv, server_iv) = match self.version {
8369            TlsVersion::Tls13 | TlsVersion::Dtls13 => {
8370                let hash_len = hash_algorithm.output_len();
8371                let client_hs_traffic = tls13_expand_label_for_hash(
8372                    hash_algorithm,
8373                    secret,
8374                    b"c hs traffic",
8375                    transcript_hash,
8376                    hash_len,
8377                )?;
8378                let server_hs_traffic = tls13_expand_label_for_hash(
8379                    hash_algorithm,
8380                    secret,
8381                    b"s hs traffic",
8382                    transcript_hash,
8383                    hash_len,
8384                )?;
8385                self.tls13_client_handshake_traffic_secret = Some(client_hs_traffic.clone());
8386                self.tls13_server_handshake_traffic_secret = Some(server_hs_traffic.clone());
8387                self.install_tls13_record_protection_keys(
8388                    hash_algorithm,
8389                    &client_hs_traffic,
8390                    &server_hs_traffic,
8391                )?;
8392                return Ok(());
8393            }
8394            TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => {
8395                let client_key_16: [u8; 16] =
8396                    hkdf_expand_for_hash(hash_algorithm, secret, b"client_write_key", 16)?
8397                        .try_into()
8398                        .expect("hkdf output length should be 16");
8399                let server_key_16: [u8; 16] =
8400                    hkdf_expand_for_hash(hash_algorithm, secret, b"server_write_key", 16)?
8401                        .try_into()
8402                        .expect("hkdf output length should be 16");
8403                let mut client_key = [0_u8; 32];
8404                let mut server_key = [0_u8; 32];
8405                client_key[..16].copy_from_slice(&client_key_16);
8406                server_key[..16].copy_from_slice(&server_key_16);
8407                let client_iv: [u8; 12] =
8408                    hkdf_expand_for_hash(hash_algorithm, secret, b"client_write_iv", 12)?
8409                        .try_into()
8410                        .expect("hkdf output length should be 12");
8411                let server_iv: [u8; 12] =
8412                    hkdf_expand_for_hash(hash_algorithm, secret, b"server_write_iv", 12)?
8413                        .try_into()
8414                        .expect("hkdf output length should be 12");
8415                (client_key, server_key, client_iv, server_iv)
8416            }
8417        };
8418        self.client_write_key = Some(client_key);
8419        self.server_write_key = Some(server_key);
8420        self.client_write_iv = Some(client_iv);
8421        self.server_write_iv = Some(server_iv);
8422        self.sync_dtls13_traffic_keys_from_record_protection_state();
8423        Ok(())
8424    }
8425
8426    /// Installs TLS 1.3 application traffic secrets and switches record keys to application epoch.
8427    ///
8428    /// # Arguments
8429    ///
8430    /// * `self` — `&mut self`.
8431    ///
8432    /// # Returns
8433    ///
8434    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8435    ///
8436    /// # Errors
8437    ///
8438    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8439    ///
8440    /// # Panics
8441    ///
8442    /// This function does not panic.
8443    ///
8444    fn install_tls13_application_traffic_keys(&mut self) -> Result<()> {
8445        if !self.version.uses_tls13_handshake_semantics() {
8446            return Ok(());
8447        }
8448        let hash_algorithm = self.negotiated_hash_algorithm();
8449        let hash_len = hash_algorithm.output_len();
8450        let transcript_hash = self.transcript_hash();
8451        let handshake_secret = self.handshake_secret.as_ref().ok_or(Error::StateError(
8452            "handshake secret must be available before tls13 application traffic keys",
8453        ))?;
8454        let derived = tls13_expand_label_for_hash(
8455            hash_algorithm,
8456            handshake_secret,
8457            b"derived",
8458            &[],
8459            hash_len,
8460        )?;
8461        let zero_ikm = vec![0_u8; hash_len];
8462        let master_secret = hkdf_extract_with_salt_for_hash(hash_algorithm, &derived, &zero_ikm);
8463        let client_app_secret = tls13_expand_label_for_hash(
8464            hash_algorithm,
8465            &master_secret,
8466            b"c ap traffic",
8467            &transcript_hash,
8468            hash_len,
8469        )?;
8470        let server_app_secret = tls13_expand_label_for_hash(
8471            hash_algorithm,
8472            &master_secret,
8473            b"s ap traffic",
8474            &transcript_hash,
8475            hash_len,
8476        )?;
8477        self.install_tls13_record_protection_keys(
8478            hash_algorithm,
8479            &client_app_secret,
8480            &server_app_secret,
8481        )?;
8482        self.install_tls13_exporter_and_resumption_secrets(
8483            hash_algorithm,
8484            &master_secret,
8485            &transcript_hash,
8486        )?;
8487        self.tls13_master_secret = Some(master_secret);
8488        self.tls13_client_application_traffic_secret = Some(client_app_secret);
8489        self.tls13_server_application_traffic_secret = Some(server_app_secret);
8490        self.client_sequence = 0;
8491        self.server_sequence = 0;
8492        Ok(())
8493    }
8494
8495    /// Derives TLS 1.3 exporter and resumption master secrets from current master secret.
8496    ///
8497    /// # Arguments
8498    ///
8499    /// * `self` — `&mut self`.
8500    /// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8501    /// * `master_secret` — `master_secret: &[u8]`.
8502    /// * `transcript_hash` — `transcript_hash: &[u8]`.
8503    ///
8504    /// # Returns
8505    ///
8506    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8507    ///
8508    /// # Errors
8509    ///
8510    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8511    ///
8512    /// # Panics
8513    ///
8514    /// This function does not panic.
8515    ///
8516    fn install_tls13_exporter_and_resumption_secrets(
8517        &mut self,
8518        hash_algorithm: HashAlgorithm,
8519        master_secret: &[u8],
8520        transcript_hash: &[u8],
8521    ) -> Result<()> {
8522        let hash_len = hash_algorithm.output_len();
8523        self.tls13_exporter_master_secret = Some(tls13_expand_label_for_hash(
8524            hash_algorithm,
8525            master_secret,
8526            b"exp master",
8527            transcript_hash,
8528            hash_len,
8529        )?);
8530        self.tls13_resumption_master_secret = Some(tls13_expand_label_for_hash(
8531            hash_algorithm,
8532            master_secret,
8533            b"res master",
8534            transcript_hash,
8535            hash_len,
8536        )?);
8537        Ok(())
8538    }
8539
8540    /// Derives and installs TLS 1.3 record protection key/iv pairs from traffic secrets.
8541    ///
8542    /// # Arguments
8543    ///
8544    /// * `self` — `&mut self`.
8545    /// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8546    /// * `client_traffic_secret` — `client_traffic_secret: &[u8]`.
8547    /// * `server_traffic_secret` — `server_traffic_secret: &[u8]`.
8548    ///
8549    /// # Returns
8550    ///
8551    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8552    ///
8553    /// # Errors
8554    ///
8555    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8556    ///
8557    /// # Panics
8558    ///
8559    /// This function does not panic.
8560    ///
8561    fn install_tls13_record_protection_keys(
8562        &mut self,
8563        hash_algorithm: HashAlgorithm,
8564        client_traffic_secret: &[u8],
8565        server_traffic_secret: &[u8],
8566    ) -> Result<()> {
8567        let suite = self.selected_cipher_suite.ok_or(Error::StateError(
8568            "cipher suite must be selected before tls13 record protection keys",
8569        ))?;
8570        let key_len = suite.tls13_traffic_key_len().ok_or(Error::StateError(
8571            "tls 1.3 record protection requires a tls 1.3 AEAD cipher suite",
8572        ))?;
8573        let client_key_material = tls13_expand_label_for_hash(
8574            hash_algorithm,
8575            client_traffic_secret,
8576            b"key",
8577            &[],
8578            key_len,
8579        )?;
8580        let server_key_material = tls13_expand_label_for_hash(
8581            hash_algorithm,
8582            server_traffic_secret,
8583            b"key",
8584            &[],
8585            key_len,
8586        )?;
8587        let mut client_key = [0_u8; 32];
8588        let mut server_key = [0_u8; 32];
8589        client_key[..key_len].copy_from_slice(&client_key_material);
8590        server_key[..key_len].copy_from_slice(&server_key_material);
8591        let client_iv: [u8; 12] =
8592            tls13_expand_label_for_hash(hash_algorithm, client_traffic_secret, b"iv", &[], 12)?
8593                .try_into()
8594                .expect("tls13 iv length should be 12");
8595        let server_iv: [u8; 12] =
8596            tls13_expand_label_for_hash(hash_algorithm, server_traffic_secret, b"iv", &[], 12)?
8597                .try_into()
8598                .expect("tls13 iv length should be 12");
8599        self.client_write_key = Some(client_key);
8600        self.server_write_key = Some(server_key);
8601        self.client_write_iv = Some(client_iv);
8602        self.server_write_iv = Some(server_iv);
8603        self.sync_dtls13_traffic_keys_from_record_protection_state();
8604        Ok(())
8605    }
8606
8607    /// Mirrors installed record-protection keys into DTLS1.3 traffic state when using DTLS profile.
8608    ///
8609    /// # Arguments
8610    ///
8611    /// * `self` — `&mut self`.
8612    ///
8613    /// # Panics
8614    ///
8615    /// This function does not panic.
8616    ///
8617    fn sync_dtls13_traffic_keys_from_record_protection_state(&mut self) {
8618        if !self.version.is_dtls() {
8619            return;
8620        }
8621        self.dtls13_client_write_key = self.client_write_key.map(|full| {
8622            full[..16]
8623                .try_into()
8624                .expect("dtls13 shim copies first 16 bytes of traffic key material")
8625        });
8626        self.dtls13_client_write_iv = self.client_write_iv;
8627        self.dtls13_server_write_key = self.server_write_key.map(|full| {
8628            full[..16]
8629                .try_into()
8630                .expect("dtls13 shim copies first 16 bytes of traffic key material")
8631        });
8632        self.dtls13_server_write_iv = self.server_write_iv;
8633        self.dtls13_outbound_epoch = 0;
8634        self.dtls13_outbound_sequence = 0;
8635        self.dtls13_inbound_replay_tracker = DtlsEpochReplayTracker::new();
8636        self.dtls13_client_inbound_replay_tracker = DtlsEpochReplayTracker::new();
8637    }
8638
8639    /// Installs TLS 1.3 Finished key derived from current handshake secret material.
8640    ///
8641    /// # Arguments
8642    ///
8643    /// * `self` — `&mut self`.
8644    /// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8645    /// * `prk` — `prk: &[u8]`.
8646    ///
8647    /// # Returns
8648    ///
8649    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8650    ///
8651    /// # Errors
8652    ///
8653    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8654    ///
8655    /// # Panics
8656    ///
8657    /// This function does not panic.
8658    ///
8659    fn install_tls13_finished_key(
8660        &mut self,
8661        hash_algorithm: HashAlgorithm,
8662        prk: &[u8],
8663    ) -> Result<()> {
8664        self.tls13_finished_key = match self.version {
8665            TlsVersion::Tls13 | TlsVersion::Dtls13 => {
8666                let finished_len = hash_algorithm.output_len();
8667                Some(hkdf_expand_for_hash(
8668                    hash_algorithm,
8669                    prk,
8670                    b"tls13 finished",
8671                    finished_len,
8672                )?)
8673            }
8674            TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => None,
8675        };
8676        Ok(())
8677    }
8678
8679    /// Computes version-appropriate expected Finished verify_data bytes.
8680    ///
8681    /// # Arguments
8682    ///
8683    /// * `&self` — `&self`.
8684    ///
8685    /// # Returns
8686    ///
8687    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8688    ///
8689    /// # Errors
8690    ///
8691    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8692    ///
8693    /// # Panics
8694    ///
8695    /// This function does not panic.
8696    ///
8697    fn compute_expected_finished(&self) -> Result<Vec<u8>> {
8698        let hash = self.transcript_hash();
8699        match self.version {
8700            TlsVersion::Tls12 | TlsVersion::Dtls12 => {
8701                let secret = self.handshake_secret.as_ref().ok_or(Error::StateError(
8702                    "handshake secret must be available before finished",
8703                ))?;
8704                tls12_prf_for_hash(
8705                    self.negotiated_hash_algorithm(),
8706                    secret,
8707                    b"client finished",
8708                    &hash,
8709                    12,
8710                )
8711            }
8712            TlsVersion::Tls13 | TlsVersion::Dtls13 => {
8713                let key = self.tls13_finished_key.as_ref().ok_or(Error::StateError(
8714                    "tls13 finished key must be available before finished",
8715                ))?;
8716                Ok(finished_hmac_for_hash(
8717                    self.negotiated_hash_algorithm(),
8718                    key,
8719                    &hash,
8720                ))
8721            }
8722            TlsVersion::Tls10 | TlsVersion::Tls11 => Ok(finished_hmac_for_hash(
8723                self.negotiated_hash_algorithm(),
8724                b"finished",
8725                &hash,
8726            )),
8727        }
8728    }
8729
8730    /// Appends bytes to transcript log and selected transcript hash context.
8731    ///
8732    /// # Arguments
8733    ///
8734    /// * `self` — `&mut self`.
8735    /// * `message` — `message: &[u8]`.
8736    ///
8737    /// # Panics
8738    ///
8739    /// This function does not panic.
8740    ///
8741    fn append_transcript(&mut self, message: &[u8]) {
8742        self.transcript.extend_from_slice(message);
8743        self.transcript_hash.update(message);
8744    }
8745
8746    /// Resets transcript bytes/hash for a new handshake flight from `Idle`.
8747    ///
8748    /// # Panics
8749    ///
8750    /// This function does not panic.
8751    fn reset_transcript_for_new_handshake(&mut self) {
8752        self.transcript.clear();
8753        self.transcript_hash = TranscriptHashState::for_version(self.version);
8754    }
8755
8756    /// Resets transcript context to a single ClientHello for modeled 0-RTT server decrypt.
8757    ///
8758    /// # Arguments
8759    ///
8760    /// * `client_hello` — Encoded ClientHello message bytes to anchor early-data transcript hash.
8761    ///
8762    /// # Returns
8763    ///
8764    /// `()`.
8765    ///
8766    /// # Panics
8767    ///
8768    /// This function does not panic.
8769    fn reset_tls13_early_data_transcript_to_client_hello(&mut self, client_hello: &[u8]) {
8770        self.transcript.clear();
8771        self.transcript_hash = TranscriptHashState::for_version(self.version);
8772        self.append_transcript(client_hello);
8773    }
8774
8775    /// Derives deterministic X25519 and P-256 key shares for TLS 1.3 ClientHello interop.
8776    ///
8777    /// # Arguments
8778    ///
8779    /// * `self` — `&mut self`.
8780    /// * `random` — `random: &[u8]`.
8781    ///
8782    /// # Returns
8783    ///
8784    /// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8785    ///
8786    /// # Errors
8787    ///
8788    /// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8789    ///
8790    /// # Panics
8791    ///
8792    /// This function does not panic.
8793    ///
8794    fn prepare_client_key_share(&mut self, random: &[u8]) -> Result<Tls13ClientPublicKeyShares> {
8795        if !self.version.uses_tls13_handshake_semantics() {
8796            return Ok(Tls13ClientPublicKeyShares::default());
8797        }
8798        let x25519_private = derive_deterministic_x25519_private(random, b"tls13 client x25519");
8799        let x25519_public = x25519_private.clone().public_key().bytes;
8800        self.tls13_client_x25519_private = Some(x25519_private);
8801
8802        let p256_private = derive_deterministic_p256_private(random, b"tls13 client secp256r1")?;
8803        let p256_public = p256_private.public_key()?.to_uncompressed()?;
8804        self.tls13_client_p256_private = Some(p256_private);
8805
8806        let (mlkem_private, mlkem_public) =
8807            derive_deterministic_mlkem768_keypair(random, b"tls13 client mlkem768")?;
8808        self.tls13_client_mlkem768_private = Some(mlkem_private);
8809        let mlkem_public = mlkem_public.as_bytes().to_vec();
8810
8811        let mut hybrid_public = Vec::with_capacity(32 + mlkem_public.len());
8812        hybrid_public.extend_from_slice(&x25519_public);
8813        hybrid_public.extend_from_slice(&mlkem_public);
8814
8815        Ok(Tls13ClientPublicKeyShares {
8816            x25519: Some(x25519_public),
8817            secp256r1_uncompressed: Some(p256_public),
8818            mlkem768: Some(mlkem_public),
8819            x25519_mlkem768_hybrid: Some(hybrid_public),
8820        })
8821    }
8822
8823    /// Rebuilds transcript hash context from stored transcript bytes and selected suite policy.
8824    ///
8825    /// # Arguments
8826    ///
8827    /// * `self` — `&mut self`.
8828    ///
8829    /// # Panics
8830    ///
8831    /// This function does not panic.
8832    ///
8833    fn rebuild_transcript_hash_from_selected_suite(&mut self) {
8834        let Some(suite) = self.selected_cipher_suite else {
8835            return;
8836        };
8837        self.transcript_hash = suite.transcript_hash_state();
8838        self.transcript_hash.update(&self.transcript);
8839    }
8840
8841    /// Applies TLS 1.3 HRR transcript reset via synthetic message_hash entry.
8842    ///
8843    /// # Arguments
8844    ///
8845    /// * `self` — `&mut self`.
8846    ///
8847    /// # Panics
8848    ///
8849    /// This function does not panic.
8850    ///
8851    fn reset_transcript_for_hrr(&mut self) {
8852        let prior_hash = self.transcript_hash();
8853        self.transcript.clear();
8854        if let Some(suite) = self.selected_cipher_suite {
8855            self.transcript_hash = suite.transcript_hash_state();
8856        } else {
8857            self.transcript_hash = TranscriptHashState::for_version(self.version);
8858        }
8859        let message_hash = encode_handshake_message(0xFE, &prior_hash);
8860        self.append_transcript(&message_hash);
8861    }
8862
8863    /// Resolves hash algorithm from negotiated suite or current transcript state fallback.
8864    ///
8865    /// # Arguments
8866    ///
8867    /// * `&self` — `&self`.
8868    ///
8869    /// # Returns
8870    ///
8871    /// The value described by the return type in the function signature.
8872    ///
8873    /// # Panics
8874    ///
8875    /// This function does not panic.
8876    ///
8877    fn negotiated_hash_algorithm(&self) -> HashAlgorithm {
8878        self.selected_cipher_suite
8879            .map(CipherSuite::hash_algorithm)
8880            .unwrap_or_else(|| self.transcript_hash.algorithm())
8881    }
8882}
8883
8884/// Implements TLS 1.3-style handshake secret derivation from placeholder ECDHE material.
8885///
8886/// # Arguments
8887///
8888/// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8889/// * `shared_secret` — `shared_secret: &[u8]`.
8890/// * `suite` — `suite: Option<CipherSuite>`.
8891///
8892/// # Returns
8893///
8894/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8895///
8896/// # Errors
8897///
8898/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8899///
8900/// # Panics
8901///
8902/// This function does not panic.
8903///
8904fn derive_tls13_handshake_secret(
8905    hash_algorithm: HashAlgorithm,
8906    shared_secret: &[u8],
8907    suite: Option<CipherSuite>,
8908) -> Result<Vec<u8>> {
8909    let hash_len = hash_algorithm.output_len();
8910    let zero_ikm = vec![0_u8; hash_len];
8911    let early_secret = hkdf_extract_for_hash(hash_algorithm, &zero_ikm);
8912    let derived =
8913        tls13_expand_label_for_hash(hash_algorithm, &early_secret, b"derived", &[], hash_len)?;
8914    let mut handshake_secret =
8915        hkdf_extract_with_salt_for_hash(hash_algorithm, &derived, shared_secret);
8916    if let Some(selected) = suite {
8917        if selected.hash_algorithm() != hash_algorithm {
8918            handshake_secret =
8919                hkdf_extract_with_salt_for_hash(selected.hash_algorithm(), &derived, shared_secret);
8920        }
8921    }
8922    Ok(handshake_secret)
8923}
8924
8925/// Combines classical and PQ shared secrets into one hybrid secret for TLS 1.3 key schedule.
8926///
8927/// # Arguments
8928///
8929/// * `classical` — `classical: &[u8; 32]`.
8930/// * `pq` — `pq: &[u8; 32]`.
8931///
8932/// # Returns
8933///
8934/// The value described by the return type in the function signature.
8935///
8936/// # Panics
8937///
8938/// This function does not panic.
8939///
8940fn combine_tls13_hybrid_shared_secret(classical: &[u8; 32], pq: &[u8; 32]) -> [u8; 32] {
8941    sha256(&[classical.as_slice(), pq.as_slice()].concat())
8942}
8943
8944/// Routes TLS 1.2 PRF derivation through suite-selected hash policy.
8945///
8946/// # Arguments
8947///
8948/// * `hash_algorithm` — `hash_algorithm: HashAlgorithm`.
8949/// * `secret` — `secret: &[u8]`.
8950/// * `label` — `label: &[u8]`.
8951/// * `seed` — `seed: &[u8]`.
8952/// * `len` — `len: usize`.
8953///
8954/// # Returns
8955///
8956/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
8957///
8958/// # Errors
8959///
8960/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
8961///
8962/// # Panics
8963///
8964/// This function does not panic.
8965///
8966fn tls12_prf_for_hash(
8967    hash_algorithm: HashAlgorithm,
8968    secret: &[u8],
8969    label: &[u8],
8970    seed: &[u8],
8971    len: usize,
8972) -> Result<Vec<u8>> {
8973    match hash_algorithm {
8974        HashAlgorithm::Sha256 => tls12_prf_sha256(secret, label, seed, len),
8975        HashAlgorithm::Sha384 => tls12_prf_sha384(secret, label, seed, len),
8976    }
8977}
8978
8979/// Compares byte slices in constant-time style and returns equality result.
8980///
8981/// # Arguments
8982///
8983/// * `left` — `left: &[u8]`.
8984/// * `right` — `right: &[u8]`.
8985///
8986/// # Returns
8987///
8988/// `true` or `false` according to the checks in the function body.
8989///
8990/// # Panics
8991///
8992/// This function does not panic.
8993///
8994fn constant_time_eq(left: &[u8], right: &[u8]) -> bool {
8995    let max_len = left.len().max(right.len());
8996    let mut diff = left.len() ^ right.len();
8997    for idx in 0..max_len {
8998        let l = left.get(idx).copied().unwrap_or(0);
8999        let r = right.get(idx).copied().unwrap_or(0);
9000        diff |= usize::from(l ^ r);
9001    }
9002    diff == 0
9003}
9004
9005/// Extracts first PSK binder value from encoded ClientHello pre_shared_key extension.
9006///
9007/// # Arguments
9008///
9009/// * `client_hello` — `client_hello: &[u8]`.
9010///
9011/// # Returns
9012///
9013/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9014///
9015/// # Errors
9016///
9017/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9018///
9019/// # Panics
9020///
9021/// This function does not panic.
9022///
9023fn extract_first_psk_binder_from_client_hello(client_hello: &[u8]) -> Result<Vec<u8>> {
9024    let info = parse_client_hello_info(client_hello)?;
9025    info.extensions
9026        .psk_binders
9027        .first()
9028        .cloned()
9029        .ok_or(Error::ParseFailure(
9030            "client hello missing pre_shared_key binder",
9031        ))
9032}
9033
9034/// Returns ClientHello copy with all pre_shared_key binder bytes replaced with zeros.
9035///
9036/// # Arguments
9037///
9038/// * `client_hello` — `client_hello: &[u8]`.
9039///
9040/// # Returns
9041///
9042/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9043///
9044/// # Errors
9045///
9046/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9047///
9048/// # Panics
9049///
9050/// This function does not panic.
9051///
9052fn zero_client_hello_psk_binders(client_hello: &[u8]) -> Result<Vec<u8>> {
9053    let (handshake_type, body) = parse_handshake_message(client_hello)?;
9054    if handshake_type != HANDSHAKE_CLIENT_HELLO {
9055        return Err(Error::ParseFailure("invalid client hello type"));
9056    }
9057    if body.len() < 39 {
9058        return Err(Error::ParseFailure("client hello body too short"));
9059    }
9060    let mut out = client_hello.to_vec();
9061    let session_id_len = body[34] as usize;
9062    let suites_len_offset = 35 + session_id_len;
9063    if body.len() < suites_len_offset + 2 {
9064        return Err(Error::ParseFailure(
9065            "client hello missing cipher suites length",
9066        ));
9067    }
9068    let suites_len =
9069        u16::from_be_bytes([body[suites_len_offset], body[suites_len_offset + 1]]) as usize;
9070    let suites_end = suites_len_offset + 2 + suites_len;
9071    if body.len() < suites_end + 3 {
9072        return Err(Error::ParseFailure(
9073            "client hello missing compression methods",
9074        ));
9075    }
9076    let compression_methods_len = body[suites_end] as usize;
9077    let compression_methods_end = suites_end + 1 + compression_methods_len;
9078    if body.len() < compression_methods_end + 2 {
9079        return Err(Error::ParseFailure("client hello missing extension length"));
9080    }
9081    let extensions_len = u16::from_be_bytes([
9082        body[compression_methods_end],
9083        body[compression_methods_end + 1],
9084    ]) as usize;
9085    let extensions_start_in_body = compression_methods_end + 2;
9086    let extensions_end_in_body = extensions_start_in_body + extensions_len;
9087    if body.len() < extensions_end_in_body {
9088        return Err(Error::ParseFailure("client hello extensions truncated"));
9089    }
9090
9091    let body_offset = 4; // handshake header bytes in full message
9092    let mut ext_cursor = extensions_start_in_body;
9093    while ext_cursor < extensions_end_in_body {
9094        if extensions_end_in_body - ext_cursor < 4 {
9095            return Err(Error::ParseFailure(
9096                "client hello extension header truncated",
9097            ));
9098        }
9099        let ext_type = u16::from_be_bytes([body[ext_cursor], body[ext_cursor + 1]]);
9100        let ext_len = u16::from_be_bytes([body[ext_cursor + 2], body[ext_cursor + 3]]) as usize;
9101        let ext_data_start = ext_cursor + 4;
9102        let ext_data_end = ext_data_start + ext_len;
9103        if ext_data_end > extensions_end_in_body {
9104            return Err(Error::ParseFailure("client hello extension truncated"));
9105        }
9106        if ext_type == EXT_PRE_SHARED_KEY {
9107            if ext_len < 4 {
9108                return Err(Error::ParseFailure("pre_shared_key extension too short"));
9109            }
9110            let identities_len =
9111                u16::from_be_bytes([body[ext_data_start], body[ext_data_start + 1]]) as usize;
9112            if ext_len < 2 + identities_len + 2 {
9113                return Err(Error::ParseFailure("pre_shared_key identities truncated"));
9114            }
9115            let binders_len_offset = ext_data_start + 2 + identities_len;
9116            let binders_len =
9117                u16::from_be_bytes([body[binders_len_offset], body[binders_len_offset + 1]])
9118                    as usize;
9119            let mut binder_cursor = binders_len_offset + 2;
9120            let binders_end = binder_cursor + binders_len;
9121            if binders_end != ext_data_end {
9122                return Err(Error::ParseFailure(
9123                    "invalid pre_shared_key binder vector length",
9124                ));
9125            }
9126            while binder_cursor < binders_end {
9127                let binder_len = body[binder_cursor] as usize;
9128                binder_cursor += 1;
9129                if binder_cursor + binder_len > binders_end {
9130                    return Err(Error::ParseFailure("pre_shared_key binder bytes truncated"));
9131                }
9132                let start = body_offset + binder_cursor;
9133                let end = start + binder_len;
9134                out[start..end].fill(0);
9135                binder_cursor += binder_len;
9136            }
9137            return Ok(out);
9138        }
9139        ext_cursor = ext_data_end;
9140    }
9141
9142    Err(Error::ParseFailure(
9143        "client hello missing pre_shared_key extension",
9144    ))
9145}
9146
9147/// Returns default client-advertised suites for the current prototype version.
9148///
9149/// # Arguments
9150///
9151/// * `version` — `version: TlsVersion`.
9152///
9153/// # Returns
9154///
9155/// The value described by the return type in the function signature.
9156///
9157/// # Panics
9158///
9159/// This function does not panic.
9160///
9161fn default_client_cipher_suites(version: TlsVersion) -> Vec<CipherSuite> {
9162    match version {
9163        TlsVersion::Tls13 | TlsVersion::Dtls13 => vec![
9164            CipherSuite::TlsAes256GcmSha384,
9165            CipherSuite::TlsAes128GcmSha256,
9166            CipherSuite::TlsChacha20Poly1305Sha256,
9167        ],
9168        TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => {
9169            vec![
9170                CipherSuite::TlsEcdheRsaWithAes256GcmSha384,
9171                CipherSuite::TlsEcdheRsaWithAes128GcmSha256,
9172            ]
9173        }
9174    }
9175}
9176
9177/// Encodes a minimally structured TLS ClientHello body for prototype negotiation.
9178///
9179/// # Arguments
9180///
9181/// * `version` — `version: TlsVersion`.
9182/// * `random` — `random: &[u8]`.
9183/// * `suites` — `suites: &[CipherSuite]`.
9184/// * `key_shares` — `key_shares: &Tls13ClientPublicKeyShares`.
9185/// * `sni_server_name` — `sni_server_name: Option<&str>`.
9186/// * `alpn_protocols` — `alpn_protocols: &[Vec<u8>]`.
9187/// * `offer_early_data` — `offer_early_data: bool`.
9188/// * `psk_offer` — `psk_offer: Option<&PskClientOffer<'_>>`.
9189///
9190/// # Returns
9191///
9192/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9193///
9194/// # Errors
9195///
9196/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9197///
9198/// # Panics
9199///
9200/// This function does not panic.
9201#[allow(clippy::too_many_arguments)]
9202fn encode_client_hello_body(
9203    version: TlsVersion,
9204    random: &[u8],
9205    suites: &[CipherSuite],
9206    key_shares: &Tls13ClientPublicKeyShares,
9207    sni_server_name: Option<&str>,
9208    alpn_protocols: &[Vec<u8>],
9209    request_ocsp_stapling: bool,
9210    offer_early_data: bool,
9211    psk_offer: Option<&PskClientOffer<'_>>,
9212    tls12_session_id: Option<&[u8]>,
9213) -> Result<Vec<u8>> {
9214    if random.len() != 32 {
9215        return Err(Error::InvalidLength("client hello random must be 32 bytes"));
9216    }
9217    if suites.is_empty() {
9218        return Err(Error::InvalidLength(
9219            "client hello suite list must not be empty",
9220        ));
9221    }
9222    let mut body = Vec::new();
9223    body.extend_from_slice(&legacy_wire_version(version));
9224    body.extend_from_slice(random);
9225    if version == TlsVersion::Tls12 {
9226        let session_id = tls12_session_id.unwrap_or(&[]);
9227        if session_id.len() > 32 {
9228            return Err(Error::InvalidLength(
9229                "tls12 session id must not exceed 32 bytes",
9230            ));
9231        }
9232        body.push(session_id.len() as u8);
9233        body.extend_from_slice(session_id);
9234    } else {
9235        body.push(0x00); // session_id length
9236    }
9237    body.extend_from_slice(&((suites.len() * 2) as u16).to_be_bytes());
9238    for suite in suites {
9239        body.extend_from_slice(&suite.to_u16().to_be_bytes());
9240    }
9241    body.extend_from_slice(&[0x01, 0x00]); // compression_methods: null
9242    let extensions = build_client_hello_extensions(
9243        version,
9244        key_shares,
9245        sni_server_name,
9246        alpn_protocols,
9247        request_ocsp_stapling,
9248        offer_early_data,
9249        psk_offer,
9250    )?;
9251    body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
9252    body.extend_from_slice(&extensions);
9253    Ok(body)
9254}
9255
9256/// Encodes a minimally structured TLS ServerHello body for prototype parsing.
9257///
9258/// # Arguments
9259///
9260/// * `version` — `version: TlsVersion`.
9261/// * `suite` — `suite: CipherSuite`.
9262/// * `random` — `random: &[u8]`.
9263///
9264/// # Returns
9265///
9266/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9267///
9268/// # Errors
9269///
9270/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9271///
9272/// # Panics
9273///
9274/// This function does not panic.
9275///
9276fn encode_server_hello_body(
9277    version: TlsVersion,
9278    suite: CipherSuite,
9279    random: &[u8],
9280) -> Result<Vec<u8>> {
9281    encode_server_hello_body_with_key_share(version, suite, random, None)
9282}
9283
9284/// Encodes ServerHello with optional explicit `key_share` bytes (for tests and tooling).
9285///
9286/// # Arguments
9287///
9288/// * `version` — `version: TlsVersion`.
9289/// * `suite` — `suite: CipherSuite`.
9290/// * `random` — `random: &[u8]`.
9291/// * `key_share_override` — `key_share_override: Option<(u16, &[u8])>`.
9292///
9293/// # Returns
9294///
9295/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9296///
9297/// # Errors
9298///
9299/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9300///
9301/// # Panics
9302///
9303/// This function does not panic.
9304///
9305fn encode_server_hello_body_with_key_share(
9306    version: TlsVersion,
9307    suite: CipherSuite,
9308    random: &[u8],
9309    key_share_override: Option<(u16, &[u8])>,
9310) -> Result<Vec<u8>> {
9311    if random.len() != 32 {
9312        return Err(Error::InvalidLength("server hello random must be 32 bytes"));
9313    }
9314    let mut body = Vec::new();
9315    body.extend_from_slice(&legacy_wire_version(version));
9316    body.extend_from_slice(random);
9317    body.push(0x00); // session_id length
9318    body.extend_from_slice(&suite.to_u16().to_be_bytes());
9319    body.push(0x00); // compression method
9320    let mut extensions = Vec::new();
9321    if version.uses_tls13_handshake_semantics() {
9322        push_extension(
9323            &mut extensions,
9324            EXT_SUPPORTED_VERSIONS,
9325            &0x0304_u16.to_be_bytes(),
9326        );
9327        let mut key_share = Vec::new();
9328        if let Some((g, bytes)) = key_share_override {
9329            if g == TLS13_KEY_SHARE_GROUP_X25519 && bytes.len() != 32 {
9330                return Err(Error::ParseFailure(
9331                    "invalid x25519 server key_share key_exchange length",
9332                ));
9333            }
9334            if g == TLS13_KEY_SHARE_GROUP_SECP256R1 && bytes.len() != 65 {
9335                return Err(Error::ParseFailure(
9336                    "invalid secp256r1 server key_share key_exchange length",
9337                ));
9338            }
9339            if g == TLS13_KEY_SHARE_GROUP_MLKEM768 && bytes.len() != MLKEM_CIPHERTEXT_LEN {
9340                return Err(Error::ParseFailure(
9341                    "invalid mlkem768 server key_share key_exchange length",
9342                ));
9343            }
9344            if g == TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID
9345                && bytes.len() != (32 + MLKEM_CIPHERTEXT_LEN)
9346            {
9347                return Err(Error::ParseFailure(
9348                    "invalid x25519_mlkem768 hybrid server key_share key_exchange length",
9349                ));
9350            }
9351            if g != TLS13_KEY_SHARE_GROUP_X25519
9352                && g != TLS13_KEY_SHARE_GROUP_SECP256R1
9353                && g != TLS13_KEY_SHARE_GROUP_MLKEM768
9354                && g != TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID
9355            {
9356                return Err(Error::ParseFailure("unsupported server key_share group"));
9357            }
9358            key_share.extend_from_slice(&g.to_be_bytes());
9359            key_share.extend_from_slice(&(bytes.len() as u16).to_be_bytes());
9360            key_share.extend_from_slice(bytes);
9361        } else {
9362            let private = derive_deterministic_x25519_private(random, b"tls13 server x25519");
9363            let public = private.public_key().bytes;
9364            key_share.extend_from_slice(&TLS13_KEY_SHARE_GROUP_X25519.to_be_bytes());
9365            key_share.extend_from_slice(&32_u16.to_be_bytes());
9366            key_share.extend_from_slice(&public);
9367        }
9368        push_extension(&mut extensions, EXT_KEY_SHARE, &key_share);
9369    }
9370    body.extend_from_slice(&(extensions.len() as u16).to_be_bytes());
9371    body.extend_from_slice(&extensions);
9372    Ok(body)
9373}
9374
9375/// Parses supported server hello encoding and extracts selected cipher suite.
9376///
9377/// # Arguments
9378///
9379/// * `msg` — `msg: &[u8]`.
9380///
9381/// # Returns
9382///
9383/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9384///
9385/// # Errors
9386///
9387/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9388///
9389/// # Panics
9390///
9391/// This function does not panic.
9392///
9393fn parse_server_hello(msg: &[u8]) -> Result<ParsedServerHello> {
9394    if msg.len() == 3 && msg.first().copied() == Some(HANDSHAKE_SERVER_HELLO) {
9395        let suite_id = u16::from_be_bytes([msg[1], msg[2]]);
9396        let suite = CipherSuite::from_u16(suite_id)
9397            .ok_or(Error::ParseFailure("unsupported cipher suite"))?;
9398        return Ok(ParsedServerHello {
9399            suite,
9400            key_share: None,
9401            hello_retry_request: false,
9402            requested_group: None,
9403        });
9404    }
9405
9406    let (handshake_type, body) = parse_handshake_message(msg)?;
9407    if handshake_type != HANDSHAKE_SERVER_HELLO {
9408        return Err(Error::ParseFailure("invalid server hello type"));
9409    }
9410    if body.len() < 40 {
9411        return Err(Error::ParseFailure("server hello body too short"));
9412    }
9413    let session_id_len = body[34] as usize;
9414    let suite_start = 35 + session_id_len;
9415    let suite_end = suite_start + 2;
9416    if body.len() < suite_end + 3 {
9417        return Err(Error::ParseFailure("server hello missing cipher suite"));
9418    }
9419    let suite_id = u16::from_be_bytes([body[suite_start], body[suite_start + 1]]);
9420    let suite =
9421        CipherSuite::from_u16(suite_id).ok_or(Error::ParseFailure("unsupported cipher suite"))?;
9422    let legacy_version = u16::from_be_bytes([body[0], body[1]]);
9423    if is_tls13_suite(suite) && legacy_version != 0x0303 && legacy_version != 0xFEFD {
9424        return Err(Error::ParseFailure(
9425            "invalid tls13 server hello legacy_version",
9426        ));
9427    }
9428    let compression_method = body[suite_end];
9429    if compression_method != 0x00 {
9430        return Err(Error::ParseFailure(
9431            "invalid server hello compression method",
9432        ));
9433    }
9434    let random = &body[2..34];
9435    let hello_retry_request = random == TLS13_HRR_RANDOM;
9436    let mut key_share_parsed = None;
9437    let mut requested_group = None;
9438    let mut seen_key_share_extension = false;
9439    let mut seen_supported_versions_extension = false;
9440    let mut supports_tls13 = false;
9441    let mut seen_extension_types = Vec::new();
9442    let ext_len_offset = suite_end + 1;
9443    let ext_len = u16::from_be_bytes([body[ext_len_offset], body[ext_len_offset + 1]]) as usize;
9444    let ext_start = ext_len_offset + 2;
9445    let ext_end = ext_start + ext_len;
9446    if ext_end > body.len() {
9447        return Err(Error::ParseFailure("server hello extensions truncated"));
9448    }
9449    let mut cursor = &body[ext_start..ext_end];
9450    while !cursor.is_empty() {
9451        if cursor.len() < 4 {
9452            return Err(Error::ParseFailure(
9453                "server hello extension header truncated",
9454            ));
9455        }
9456        let ext_type = u16::from_be_bytes([cursor[0], cursor[1]]);
9457        let ext_data_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
9458        cursor = &cursor[4..];
9459        if cursor.len() < ext_data_len {
9460            return Err(Error::ParseFailure("server hello extension truncated"));
9461        }
9462        if seen_extension_types.contains(&ext_type) {
9463            return Err(Error::ParseFailure("duplicate server hello extension type"));
9464        }
9465        seen_extension_types.push(ext_type);
9466        let ext_data = &cursor[..ext_data_len];
9467        match ext_type {
9468            EXT_SIGNATURE_ALGORITHMS | EXT_PSK_KEY_EXCHANGE_MODES | EXT_SERVER_NAME => {
9469                return Err(Error::ParseFailure(
9470                    "server hello contains forbidden extension type",
9471                ));
9472            }
9473            EXT_SUPPORTED_VERSIONS => {
9474                if ext_data_len != 2 {
9475                    return Err(Error::ParseFailure(
9476                        "invalid server hello supported_versions length",
9477                    ));
9478                }
9479                seen_supported_versions_extension = true;
9480                let selected_version = u16::from_be_bytes([ext_data[0], ext_data[1]]);
9481                if selected_version != 0x0304 {
9482                    return Err(Error::ParseFailure(
9483                        "invalid tls13 server hello supported_versions value",
9484                    ));
9485                }
9486                supports_tls13 = true;
9487            }
9488            EXT_KEY_SHARE => {
9489                seen_key_share_extension = true;
9490                if hello_retry_request {
9491                    if ext_data_len != 2 {
9492                        return Err(Error::ParseFailure("invalid hrr key_share length"));
9493                    }
9494                    requested_group = Some(u16::from_be_bytes([ext_data[0], ext_data[1]]));
9495                } else {
9496                    if ext_data_len < 4 {
9497                        return Err(Error::ParseFailure("invalid server key_share length"));
9498                    }
9499                    let group = u16::from_be_bytes([ext_data[0], ext_data[1]]);
9500                    let key_len = u16::from_be_bytes([ext_data[2], ext_data[3]]) as usize;
9501                    if ext_data_len != 4 + key_len {
9502                        return Err(Error::ParseFailure("invalid server key_share length"));
9503                    }
9504                    key_share_parsed = Some(match group {
9505                        TLS13_KEY_SHARE_GROUP_X25519 => {
9506                            if key_len != 32 {
9507                                return Err(Error::ParseFailure(
9508                                    "invalid x25519 server key_share key_exchange length",
9509                                ));
9510                            }
9511                            let mut key = [0_u8; 32];
9512                            key.copy_from_slice(&ext_data[4..36]);
9513                            Tls13ServerKeyShareParsed::X25519(key)
9514                        }
9515                        TLS13_KEY_SHARE_GROUP_SECP256R1 => {
9516                            if key_len != 65 {
9517                                return Err(Error::ParseFailure(
9518                                    "invalid secp256r1 server key_share key_exchange length",
9519                                ));
9520                            }
9521                            let mut key = [0_u8; 65];
9522                            key.copy_from_slice(&ext_data[4..69]);
9523                            Tls13ServerKeyShareParsed::Secp256r1(key)
9524                        }
9525                        TLS13_KEY_SHARE_GROUP_MLKEM768 => {
9526                            if key_len != MLKEM_CIPHERTEXT_LEN {
9527                                return Err(Error::ParseFailure(
9528                                    "invalid mlkem768 server key_share key_exchange length",
9529                                ));
9530                            }
9531                            Tls13ServerKeyShareParsed::MlKem768(ext_data[4..].to_vec())
9532                        }
9533                        TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID => {
9534                            if key_len != (32 + MLKEM_CIPHERTEXT_LEN) {
9535                                return Err(Error::ParseFailure(
9536                                    "invalid x25519_mlkem768 hybrid server key_share key_exchange length",
9537                                ));
9538                            }
9539                            let mut x25519 = [0_u8; 32];
9540                            x25519.copy_from_slice(&ext_data[4..36]);
9541                            let mlkem768 = ext_data[36..].to_vec();
9542                            Tls13ServerKeyShareParsed::X25519MlKem768Hybrid { x25519, mlkem768 }
9543                        }
9544                        _ => {
9545                            return Err(Error::ParseFailure("unsupported server key_share"));
9546                        }
9547                    });
9548                }
9549            }
9550            _ => {}
9551        }
9552        cursor = &cursor[ext_data_len..];
9553    }
9554    if hello_retry_request && !seen_key_share_extension {
9555        return Err(Error::ParseFailure("hrr missing key_share extension"));
9556    }
9557    if !hello_retry_request
9558        && is_tls13_suite(suite)
9559        && legacy_version == 0x0303
9560        && !seen_supported_versions_extension
9561    {
9562        return Err(Error::ParseFailure(
9563            "tls13 server hello missing supported_versions extension",
9564        ));
9565    }
9566    if !hello_retry_request && is_tls13_suite(suite) && legacy_version == 0x0303 && !supports_tls13
9567    {
9568        return Err(Error::ParseFailure(
9569            "invalid tls13 server hello supported_versions value",
9570        ));
9571    }
9572    if !hello_retry_request
9573        && is_tls13_suite(suite)
9574        && legacy_version == 0x0303
9575        && !seen_key_share_extension
9576    {
9577        return Err(Error::ParseFailure(
9578            "tls13 server hello missing key_share extension",
9579        ));
9580    }
9581    Ok(ParsedServerHello {
9582        suite,
9583        key_share: key_share_parsed,
9584        hello_retry_request,
9585        requested_group,
9586    })
9587}
9588
9589/// Returns true when suite belongs to TLS 1.3 suite registry.
9590///
9591/// # Arguments
9592///
9593/// * `suite` — `suite: CipherSuite`.
9594///
9595/// # Returns
9596///
9597/// `true` or `false` according to the checks in the function body.
9598///
9599/// # Panics
9600///
9601/// This function does not panic.
9602///
9603fn is_tls13_suite(suite: CipherSuite) -> bool {
9604    matches!(
9605        suite,
9606        CipherSuite::TlsAes128GcmSha256
9607            | CipherSuite::TlsAes256GcmSha384
9608            | CipherSuite::TlsChacha20Poly1305Sha256
9609    )
9610}
9611
9612/// Parses minimally-structured ClientHello and extracts suite + extension metadata.
9613///
9614/// # Arguments
9615///
9616/// * `msg` — `msg: &[u8]`.
9617///
9618/// # Returns
9619///
9620/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9621///
9622/// # Errors
9623///
9624/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9625///
9626/// # Panics
9627///
9628/// This function does not panic.
9629///
9630fn parse_client_hello_info(msg: &[u8]) -> Result<ClientHelloInfo> {
9631    let (handshake_type, body) = parse_handshake_message(msg)?;
9632    if handshake_type != HANDSHAKE_CLIENT_HELLO {
9633        return Err(Error::ParseFailure("invalid client hello type"));
9634    }
9635    if body.len() < 39 {
9636        return Err(Error::ParseFailure("client hello body too short"));
9637    }
9638    let session_id_len = body[34] as usize;
9639    let suites_len_offset = 35 + session_id_len;
9640    if body.len() < suites_len_offset + 2 {
9641        return Err(Error::ParseFailure(
9642            "client hello missing cipher suites length",
9643        ));
9644    }
9645    let suites_len =
9646        u16::from_be_bytes([body[suites_len_offset], body[suites_len_offset + 1]]) as usize;
9647    if suites_len == 0 || !suites_len.is_multiple_of(2) {
9648        return Err(Error::ParseFailure(
9649            "invalid client hello cipher suites length",
9650        ));
9651    }
9652    let suites_start = suites_len_offset + 2;
9653    let suites_end = suites_start + suites_len;
9654    if body.len() < suites_end + 3 {
9655        return Err(Error::ParseFailure("client hello cipher suites truncated"));
9656    }
9657
9658    let mut suites = Vec::new();
9659    for chunk in body[suites_start..suites_end].chunks_exact(2) {
9660        let codepoint = u16::from_be_bytes([chunk[0], chunk[1]]);
9661        if let Some(suite) = CipherSuite::from_u16(codepoint) {
9662            suites.push(suite);
9663        }
9664    }
9665    if suites.is_empty() {
9666        return Err(Error::ParseFailure(
9667            "client hello has no supported cipher suite",
9668        ));
9669    }
9670
9671    let compression_methods_len = body[suites_end] as usize;
9672    let compression_methods_start = suites_end + 1;
9673    let compression_methods_end = compression_methods_start + compression_methods_len;
9674    if body.len() < compression_methods_end + 2 {
9675        return Err(Error::ParseFailure(
9676            "client hello missing compression methods",
9677        ));
9678    }
9679    let extensions_len = u16::from_be_bytes([
9680        body[compression_methods_end],
9681        body[compression_methods_end + 1],
9682    ]) as usize;
9683    let extensions_start = compression_methods_end + 2;
9684    let extensions_end = extensions_start + extensions_len;
9685    if body.len() < extensions_end {
9686        return Err(Error::ParseFailure("client hello extensions truncated"));
9687    }
9688    if body.len() != extensions_end {
9689        return Err(Error::ParseFailure("client hello has trailing bytes"));
9690    }
9691    let extensions = parse_client_hello_extensions(&body[extensions_start..extensions_end])?;
9692
9693    Ok(ClientHelloInfo {
9694        offered_cipher_suites: suites,
9695        extensions,
9696    })
9697}
9698
9699/// Chooses the first server-preferred suite also present in client offer.
9700///
9701/// # Arguments
9702///
9703/// * `hello` — `hello: &ClientHelloInfo`.
9704/// * `preferred` — `preferred: &[CipherSuite]`.
9705/// * `version` — `version: TlsVersion`.
9706///
9707/// # Returns
9708///
9709/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9710///
9711/// # Errors
9712///
9713/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9714///
9715/// # Panics
9716///
9717/// This function does not panic.
9718///
9719fn pick_intersection_suite(
9720    hello: &ClientHelloInfo,
9721    preferred: &[CipherSuite],
9722    version: TlsVersion,
9723) -> Result<CipherSuite> {
9724    for suite in preferred {
9725        if !hello.offered_cipher_suites.contains(suite) {
9726            continue;
9727        }
9728        if !suite_supported_by_version(*suite, version) {
9729            continue;
9730        }
9731        if suite_allowed_by_extensions(*suite, version, &hello.extensions) {
9732            return Ok(*suite);
9733        }
9734    }
9735    Err(Error::ParseFailure("no mutually supported cipher suite"))
9736}
9737
9738/// Returns true when one suite is valid for the target protocol version family.
9739///
9740/// # Arguments
9741///
9742/// * `suite` — `suite: CipherSuite`.
9743/// * `version` — `version: TlsVersion`.
9744///
9745/// # Returns
9746///
9747/// `true` or `false` according to the checks in the function body.
9748///
9749/// # Panics
9750///
9751/// This function does not panic.
9752///
9753fn suite_supported_by_version(suite: CipherSuite, version: TlsVersion) -> bool {
9754    match version {
9755        TlsVersion::Tls13 | TlsVersion::Dtls13 => matches!(
9756            suite,
9757            CipherSuite::TlsAes128GcmSha256
9758                | CipherSuite::TlsAes256GcmSha384
9759                | CipherSuite::TlsChacha20Poly1305Sha256
9760        ),
9761        TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => {
9762            matches!(
9763                suite,
9764                CipherSuite::TlsEcdheRsaWithAes128GcmSha256
9765                    | CipherSuite::TlsEcdheRsaWithAes256GcmSha384
9766            )
9767        }
9768    }
9769}
9770
9771/// Applies extension-level checks for negotiated suite acceptance.
9772///
9773/// # Arguments
9774///
9775/// * `suite` — `suite: CipherSuite`.
9776/// * `version` — `version: TlsVersion`.
9777/// * `extensions` — `extensions: &ClientHelloExtensions`.
9778///
9779/// # Returns
9780///
9781/// `true` or `false` according to the checks in the function body.
9782///
9783/// # Panics
9784///
9785/// This function does not panic.
9786///
9787fn suite_allowed_by_extensions(
9788    suite: CipherSuite,
9789    version: TlsVersion,
9790    extensions: &ClientHelloExtensions,
9791) -> bool {
9792    match version {
9793        TlsVersion::Tls13 | TlsVersion::Dtls13 => {
9794            if matches!(
9795                suite,
9796                CipherSuite::TlsAes128GcmSha256
9797                    | CipherSuite::TlsAes256GcmSha384
9798                    | CipherSuite::TlsChacha20Poly1305Sha256
9799            ) {
9800                return tls13_client_hello_offers_supported_key_exchange(
9801                    &extensions.supported_versions,
9802                    &extensions.key_share_groups,
9803                    &extensions.signature_algorithms,
9804                );
9805            }
9806            true
9807        }
9808        TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => true,
9809    }
9810}
9811
9812/// Builds minimally required ClientHello extensions per protocol version.
9813///
9814/// # Arguments
9815///
9816/// * `version` — `version: TlsVersion`.
9817/// * `key_shares` — `key_shares: &Tls13ClientPublicKeyShares`.
9818/// * `sni_server_name` — `sni_server_name: Option<&str>`.
9819/// * `alpn_protocols` — `alpn_protocols: &[Vec<u8>]`.
9820/// * `offer_early_data` — `offer_early_data: bool`.
9821/// * `psk_offer` — `psk_offer: Option<&PskClientOffer<'_>>`.
9822///
9823/// # Returns
9824///
9825/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9826///
9827/// # Errors
9828///
9829/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9830///
9831/// # Panics
9832///
9833/// This function does not panic.
9834///
9835fn build_client_hello_extensions(
9836    version: TlsVersion,
9837    key_shares: &Tls13ClientPublicKeyShares,
9838    sni_server_name: Option<&str>,
9839    alpn_protocols: &[Vec<u8>],
9840    request_ocsp_stapling: bool,
9841    offer_early_data: bool,
9842    psk_offer: Option<&PskClientOffer<'_>>,
9843) -> Result<Vec<u8>> {
9844    let mut extensions = Vec::new();
9845    match version {
9846        TlsVersion::Tls13 | TlsVersion::Dtls13 => {
9847            // supported_versions: TLS 1.3 plus TLS 1.2 fallback marker.
9848            let mut supported_versions = Vec::new();
9849            supported_versions.push(4_u8);
9850            supported_versions.extend_from_slice(&0x0304_u16.to_be_bytes());
9851            supported_versions.extend_from_slice(&0x0303_u16.to_be_bytes());
9852            push_extension(&mut extensions, EXT_SUPPORTED_VERSIONS, &supported_versions);
9853
9854            // signature_algorithms: modeled TLS 1.3 schemes aligned with verify support.
9855            let mut sigalgs = Vec::new();
9856            let supported_sigalgs = [
9857                TLS13_SIGALG_ECDSA_SECP256R1_SHA256,
9858                TLS13_SIGALG_RSA_PSS_RSAE_SHA256,
9859                TLS13_SIGALG_RSA_PSS_RSAE_SHA384,
9860                TLS13_SIGALG_ED25519,
9861                TLS13_SIGALG_MLDSA65,
9862            ];
9863            sigalgs.extend_from_slice(&((supported_sigalgs.len() * 2) as u16).to_be_bytes());
9864            for sigalg in supported_sigalgs {
9865                sigalgs.extend_from_slice(&sigalg.to_be_bytes());
9866            }
9867            push_extension(&mut extensions, EXT_SIGNATURE_ALGORITHMS, &sigalgs);
9868
9869            // key_share: X25519 and optional secp256r1 entries for modeled ECDHE breadth.
9870            let mut key_share_list = Vec::new();
9871            if let Some(public) = key_shares.x25519 {
9872                key_share_list.extend_from_slice(&TLS13_KEY_SHARE_GROUP_X25519.to_be_bytes());
9873                key_share_list.extend_from_slice(&32_u16.to_be_bytes());
9874                key_share_list.extend_from_slice(&public);
9875            }
9876            if let Some(public) = key_shares.secp256r1_uncompressed {
9877                key_share_list.extend_from_slice(&TLS13_KEY_SHARE_GROUP_SECP256R1.to_be_bytes());
9878                key_share_list.extend_from_slice(&65_u16.to_be_bytes());
9879                key_share_list.extend_from_slice(&public);
9880            }
9881            if let Some(public) = key_shares.mlkem768.as_ref() {
9882                key_share_list.extend_from_slice(&TLS13_KEY_SHARE_GROUP_MLKEM768.to_be_bytes());
9883                key_share_list.extend_from_slice(&(public.len() as u16).to_be_bytes());
9884                key_share_list.extend_from_slice(public);
9885            }
9886            if let Some(public) = key_shares.x25519_mlkem768_hybrid.as_ref() {
9887                key_share_list
9888                    .extend_from_slice(&TLS13_KEY_SHARE_GROUP_X25519_MLKEM768_HYBRID.to_be_bytes());
9889                key_share_list.extend_from_slice(&(public.len() as u16).to_be_bytes());
9890                key_share_list.extend_from_slice(public);
9891            }
9892            if key_share_list.is_empty() {
9893                return Err(Error::InvalidLength(
9894                    "tls13 client hello key_share extension must not be empty",
9895                ));
9896            }
9897            let mut key_share_ext = Vec::new();
9898            key_share_ext.extend_from_slice(&(key_share_list.len() as u16).to_be_bytes());
9899            key_share_ext.extend_from_slice(&key_share_list);
9900            push_extension(&mut extensions, EXT_KEY_SHARE, &key_share_ext);
9901            if let Some(server_name) = sni_server_name {
9902                let server_name_extension_data = encode_server_name_extension_data(server_name)?;
9903                push_extension(
9904                    &mut extensions,
9905                    EXT_SERVER_NAME,
9906                    &server_name_extension_data,
9907                );
9908            }
9909            if request_ocsp_stapling {
9910                let status_request_data = encode_status_request_ocsp_extension_data()?;
9911                push_extension(&mut extensions, EXT_STATUS_REQUEST, &status_request_data);
9912            }
9913            if !alpn_protocols.is_empty() {
9914                let alpn_extension_data = encode_alpn_extension_data(alpn_protocols)?;
9915                push_extension(&mut extensions, EXT_ALPN, &alpn_extension_data);
9916            }
9917            if offer_early_data {
9918                if psk_offer.is_none() {
9919                    return Err(Error::StateError(
9920                        "tls13 early_data extension requires pre_shared_key offer",
9921                    ));
9922                }
9923                push_extension(&mut extensions, EXT_EARLY_DATA, &[]);
9924            }
9925            if let Some(psk) = psk_offer {
9926                let psk_key_exchange_modes = [1_u8, TLS13_PSK_KEY_EXCHANGE_MODE_PSK_DHE_KE];
9927                push_extension(
9928                    &mut extensions,
9929                    EXT_PSK_KEY_EXCHANGE_MODES,
9930                    &psk_key_exchange_modes,
9931                );
9932                let psk_extension = encode_pre_shared_key_extension(psk)?;
9933                push_extension(&mut extensions, EXT_PRE_SHARED_KEY, &psk_extension);
9934            }
9935        }
9936        TlsVersion::Tls10 | TlsVersion::Tls11 | TlsVersion::Tls12 | TlsVersion::Dtls12 => {
9937            // signature_algorithms: placeholder vector for non-TLS1.3 paths.
9938            let mut sigalgs = Vec::new();
9939            sigalgs.extend_from_slice(&2_u16.to_be_bytes());
9940            sigalgs.extend_from_slice(&0x0401_u16.to_be_bytes());
9941            push_extension(&mut extensions, EXT_SIGNATURE_ALGORITHMS, &sigalgs);
9942        }
9943    }
9944    Ok(extensions)
9945}
9946
9947/// Appends one `Extension` (type + length + value) to output buffer.
9948///
9949/// # Arguments
9950///
9951/// * `out` — `out: &mut Vec<u8>`.
9952/// * `ext_type` — `ext_type: u16`.
9953/// * `ext_data` — `ext_data: &[u8]`.
9954///
9955/// # Panics
9956///
9957/// This function does not panic.
9958///
9959fn push_extension(out: &mut Vec<u8>, ext_type: u16, ext_data: &[u8]) {
9960    out.extend_from_slice(&ext_type.to_be_bytes());
9961    out.extend_from_slice(&(ext_data.len() as u16).to_be_bytes());
9962    out.extend_from_slice(ext_data);
9963}
9964
9965/// Parses selected ClientHello extensions needed for current prototype checks.
9966///
9967/// # Arguments
9968///
9969/// * `input` — `input: &[u8]`.
9970///
9971/// # Returns
9972///
9973/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
9974///
9975/// # Errors
9976///
9977/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
9978///
9979/// # Panics
9980///
9981/// This function does not panic.
9982///
9983fn parse_client_hello_extensions(input: &[u8]) -> Result<ClientHelloExtensions> {
9984    let mut out = ClientHelloExtensions::default();
9985    let mut cursor = input;
9986    let mut seen_supported_versions = false;
9987    let mut seen_signature_algorithms = false;
9988    let mut seen_key_share = false;
9989    let mut seen_psk_key_exchange_modes = false;
9990    let mut seen_pre_shared_key = false;
9991    let mut seen_early_data = false;
9992    let mut seen_extension_types = Vec::new();
9993    while !cursor.is_empty() {
9994        if cursor.len() < 4 {
9995            return Err(Error::ParseFailure(
9996                "client hello extension header truncated",
9997            ));
9998        }
9999        let ext_type = u16::from_be_bytes([cursor[0], cursor[1]]);
10000        let ext_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
10001        cursor = &cursor[4..];
10002        if cursor.len() < ext_len {
10003            return Err(Error::ParseFailure("client hello extension truncated"));
10004        }
10005        let ext_data = &cursor[..ext_len];
10006        if seen_extension_types.contains(&ext_type) {
10007            return Err(Error::ParseFailure("duplicate client hello extension type"));
10008        }
10009        seen_extension_types.push(ext_type);
10010        if seen_pre_shared_key {
10011            return Err(Error::ParseFailure(
10012                "pre_shared_key extension must be the last extension",
10013            ));
10014        }
10015        match ext_type {
10016            EXT_SUPPORTED_VERSIONS => {
10017                if seen_supported_versions {
10018                    return Err(Error::ParseFailure(
10019                        "duplicate supported_versions extension",
10020                    ));
10021                }
10022                out.supported_versions = parse_supported_versions_extension(ext_data)?;
10023                seen_supported_versions = true;
10024            }
10025            EXT_SIGNATURE_ALGORITHMS => {
10026                if seen_signature_algorithms {
10027                    return Err(Error::ParseFailure(
10028                        "duplicate signature_algorithms extension",
10029                    ));
10030                }
10031                out.signature_algorithms = parse_u16_vector_with_len(ext_data)?;
10032                if out.signature_algorithms.is_empty() {
10033                    return Err(Error::ParseFailure(
10034                        "signature_algorithms extension must not be empty",
10035                    ));
10036                }
10037                seen_signature_algorithms = true;
10038            }
10039            EXT_KEY_SHARE => {
10040                if seen_key_share {
10041                    return Err(Error::ParseFailure("duplicate key_share extension"));
10042                }
10043                out.key_share_groups = parse_key_share_groups_extension(ext_data)?;
10044                seen_key_share = true;
10045            }
10046            EXT_SERVER_NAME => {
10047                out.sni_server_name = Some(parse_server_name_extension(ext_data)?);
10048            }
10049            EXT_ALPN => {
10050                out.alpn_protocols = parse_alpn_protocol_name_list(ext_data)?;
10051            }
10052            EXT_STATUS_REQUEST => {
10053                out.status_request_ocsp = parse_status_request_ocsp_extension(ext_data)?;
10054            }
10055            EXT_PSK_KEY_EXCHANGE_MODES => {
10056                if seen_psk_key_exchange_modes {
10057                    return Err(Error::ParseFailure(
10058                        "duplicate psk_key_exchange_modes extension",
10059                    ));
10060                }
10061                out.psk_key_exchange_modes = parse_u8_vector_with_len(ext_data)?;
10062                if !out
10063                    .psk_key_exchange_modes
10064                    .contains(&TLS13_PSK_KEY_EXCHANGE_MODE_PSK_DHE_KE)
10065                {
10066                    return Err(Error::ParseFailure(
10067                        "psk_key_exchange_modes must include psk_dhe_ke",
10068                    ));
10069                }
10070                seen_psk_key_exchange_modes = true;
10071            }
10072            EXT_PRE_SHARED_KEY => {
10073                if seen_pre_shared_key {
10074                    return Err(Error::ParseFailure("duplicate pre_shared_key extension"));
10075                }
10076                let (identity_count, identities, obfuscated_ages, binders) =
10077                    parse_pre_shared_key_extension(ext_data)?;
10078                out.psk_identity_count = identity_count;
10079                out.psk_identities = identities;
10080                out.psk_obfuscated_ticket_ages = obfuscated_ages;
10081                out.psk_binders = binders;
10082                seen_pre_shared_key = true;
10083            }
10084            EXT_EARLY_DATA => {
10085                if seen_early_data {
10086                    return Err(Error::ParseFailure("duplicate early_data extension"));
10087                }
10088                if !ext_data.is_empty() {
10089                    return Err(Error::ParseFailure(
10090                        "client hello early_data extension must be empty",
10091                    ));
10092                }
10093                out.early_data_offered = true;
10094                seen_early_data = true;
10095            }
10096            _ => {}
10097        }
10098        cursor = &cursor[ext_len..];
10099    }
10100    if seen_pre_shared_key && !seen_psk_key_exchange_modes {
10101        return Err(Error::ParseFailure(
10102            "pre_shared_key extension requires psk_key_exchange_modes extension",
10103        ));
10104    }
10105    if seen_early_data && !seen_pre_shared_key {
10106        return Err(Error::ParseFailure(
10107            "early_data extension requires pre_shared_key extension",
10108        ));
10109    }
10110    if seen_psk_key_exchange_modes && !seen_pre_shared_key {
10111        return Err(Error::ParseFailure(
10112            "psk_key_exchange_modes extension requires pre_shared_key extension",
10113        ));
10114    }
10115    if seen_key_share && out.key_share_groups.is_empty() {
10116        return Err(Error::ParseFailure("key_share extension must not be empty"));
10117    }
10118    let advertises_tls13 = out.supported_versions.contains(&0x0304);
10119    if seen_pre_shared_key && !advertises_tls13 {
10120        return Err(Error::ParseFailure(
10121            "pre_shared_key extension requires tls13 supported_versions entry",
10122        ));
10123    }
10124    if seen_key_share && !advertises_tls13 {
10125        return Err(Error::ParseFailure(
10126            "key_share extension requires tls13 supported_versions entry",
10127        ));
10128    }
10129    if advertises_tls13 && !seen_signature_algorithms {
10130        return Err(Error::ParseFailure(
10131            "tls13 supported_versions requires signature_algorithms extension",
10132        ));
10133    }
10134    if advertises_tls13 && !seen_key_share {
10135        return Err(Error::ParseFailure(
10136            "tls13 supported_versions requires key_share extension",
10137        ));
10138    }
10139    if seen_pre_shared_key && !seen_key_share {
10140        return Err(Error::ParseFailure(
10141            "pre_shared_key with psk_dhe_ke requires key_share extension",
10142        ));
10143    }
10144    Ok(out)
10145}
10146
10147/// Parses `<len:u8><versions:u16...>` form used by client supported_versions extension.
10148///
10149/// # Arguments
10150///
10151/// * `input` — `input: &[u8]`.
10152///
10153/// # Returns
10154///
10155/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10156///
10157/// # Errors
10158///
10159/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10160///
10161/// # Panics
10162///
10163/// This function does not panic.
10164///
10165fn parse_supported_versions_extension(input: &[u8]) -> Result<Vec<u16>> {
10166    if input.is_empty() {
10167        return Err(Error::ParseFailure("supported_versions extension is empty"));
10168    }
10169    let declared = input[0] as usize;
10170    if input.len() != declared + 1 || !declared.is_multiple_of(2) {
10171        return Err(Error::ParseFailure(
10172            "invalid supported_versions extension length",
10173        ));
10174    }
10175    let mut versions = Vec::new();
10176    for chunk in input[1..].chunks_exact(2) {
10177        let version = u16::from_be_bytes([chunk[0], chunk[1]]);
10178        if versions.contains(&version) {
10179            return Err(Error::ParseFailure(
10180                "duplicate supported_versions entry in extension body",
10181            ));
10182        }
10183        versions.push(version);
10184    }
10185    Ok(versions)
10186}
10187
10188/// Validates SNI DNS host syntax used by modeled server_name extension hooks.
10189///
10190/// # Arguments
10191///
10192/// * `name` — `name: &str`.
10193///
10194/// # Returns
10195///
10196/// `true` or `false` according to the checks in the function body.
10197///
10198/// # Panics
10199///
10200/// This function does not panic.
10201///
10202fn is_valid_sni_dns_name(name: &str) -> bool {
10203    if name.is_empty() || !name.is_ascii() {
10204        return false;
10205    }
10206    let trimmed = if let Some(stripped) = name.strip_suffix('.') {
10207        stripped
10208    } else {
10209        name
10210    };
10211    if trimmed.is_empty() || trimmed.len() > u16::MAX as usize {
10212        return false;
10213    }
10214    if trimmed
10215        .as_bytes()
10216        .iter()
10217        .any(|byte| *byte <= 0x20 || *byte >= 0x7f)
10218    {
10219        return false;
10220    }
10221    for label in trimmed.split('.') {
10222        if label.is_empty() || label.len() > 63 {
10223            return false;
10224        }
10225        let bytes = label.as_bytes();
10226        if bytes.first() == Some(&b'-') || bytes.last() == Some(&b'-') {
10227            return false;
10228        }
10229        if !bytes
10230            .iter()
10231            .all(|byte| byte.is_ascii_alphanumeric() || *byte == b'-')
10232        {
10233            return false;
10234        }
10235    }
10236    true
10237}
10238
10239/// Parses one SNI server_name extension payload into a DNS host_name string.
10240///
10241/// # Arguments
10242///
10243/// * `input` — `input: &[u8]`.
10244///
10245/// # Returns
10246///
10247/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10248///
10249/// # Errors
10250///
10251/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10252///
10253/// # Panics
10254///
10255/// This function does not panic.
10256///
10257fn parse_server_name_extension(input: &[u8]) -> Result<String> {
10258    if input.len() < 5 {
10259        return Err(Error::ParseFailure("server_name extension too short"));
10260    }
10261    let list_len = u16::from_be_bytes([input[0], input[1]]) as usize;
10262    if list_len == 0 || input.len() != list_len + 2 {
10263        return Err(Error::ParseFailure("invalid server_name extension length"));
10264    }
10265    if input[2] != 0x00 {
10266        return Err(Error::ParseFailure("unsupported server_name type"));
10267    }
10268    let name_len = u16::from_be_bytes([input[3], input[4]]) as usize;
10269    if name_len == 0 || input.len() != 5 + name_len {
10270        return Err(Error::ParseFailure("invalid server_name host_name length"));
10271    }
10272    let name = core::str::from_utf8(&input[5..])
10273        .map_err(|_| Error::ParseFailure("invalid sni server_name"))?;
10274    if !is_valid_sni_dns_name(name) {
10275        return Err(Error::ParseFailure("invalid sni server_name"));
10276    }
10277    Ok(name.to_owned())
10278}
10279
10280/// Encodes one SNI host_name string into TLS server_name extension payload bytes.
10281///
10282/// # Arguments
10283///
10284/// * `server_name` — `server_name: &str`.
10285///
10286/// # Returns
10287///
10288/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10289///
10290/// # Errors
10291///
10292/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10293///
10294/// # Panics
10295///
10296/// This function does not panic.
10297///
10298fn encode_server_name_extension_data(server_name: &str) -> Result<Vec<u8>> {
10299    if !is_valid_sni_dns_name(server_name) {
10300        return Err(Error::ParseFailure("invalid sni server_name"));
10301    }
10302    let name_bytes = server_name.as_bytes();
10303    let mut entry = Vec::new();
10304    entry.push(0x00); // host_name
10305    entry.extend_from_slice(&(name_bytes.len() as u16).to_be_bytes());
10306    entry.extend_from_slice(name_bytes);
10307    let mut out = Vec::new();
10308    out.extend_from_slice(&(entry.len() as u16).to_be_bytes());
10309    out.extend_from_slice(&entry);
10310    Ok(out)
10311}
10312
10313/// Encodes RFC 6066/8446 `status_request` data for OCSP stapling support.
10314fn encode_status_request_ocsp_extension_data() -> Result<Vec<u8>> {
10315    let mut out = Vec::new();
10316    out.push(0x01); // status_type=ocsp
10317    out.extend_from_slice(&0_u16.to_be_bytes()); // responder_id_list length
10318    out.extend_from_slice(&0_u16.to_be_bytes()); // request_extensions length
10319    Ok(out)
10320}
10321
10322/// Parses `status_request` extension and accepts the OCSP form.
10323fn parse_status_request_ocsp_extension(input: &[u8]) -> Result<bool> {
10324    if input.len() != 5 {
10325        return Err(Error::ParseFailure(
10326            "invalid status_request extension length",
10327        ));
10328    }
10329    if input[0] != 0x01 {
10330        return Err(Error::ParseFailure(
10331            "status_request extension must use ocsp status type",
10332        ));
10333    }
10334    let responder_id_list_len = u16::from_be_bytes([input[1], input[2]]) as usize;
10335    let request_extensions_len = u16::from_be_bytes([input[3], input[4]]) as usize;
10336    if responder_id_list_len != 0 || request_extensions_len != 0 {
10337        return Err(Error::ParseFailure(
10338            "status_request extension non-empty responder/request vectors are unsupported",
10339        ));
10340    }
10341    Ok(true)
10342}
10343
10344/// Parses ALPN extension payload into ordered protocol-name vector.
10345///
10346/// # Arguments
10347///
10348/// * `input` — `input: &[u8]`.
10349///
10350/// # Returns
10351///
10352/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10353///
10354/// # Errors
10355///
10356/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10357///
10358/// # Panics
10359///
10360/// This function does not panic.
10361///
10362fn parse_alpn_protocol_name_list(input: &[u8]) -> Result<Vec<Vec<u8>>> {
10363    if input.len() < 2 {
10364        return Err(Error::ParseFailure(
10365            "alpn extension missing protocol_name_list",
10366        ));
10367    }
10368    let declared_len = u16::from_be_bytes([input[0], input[1]]) as usize;
10369    if declared_len == 0 || input.len() != declared_len + 2 {
10370        return Err(Error::ParseFailure("invalid alpn extension length"));
10371    }
10372    let mut cursor = &input[2..];
10373    let mut protocols = Vec::new();
10374    while !cursor.is_empty() {
10375        let protocol_len = cursor[0] as usize;
10376        cursor = &cursor[1..];
10377        if protocol_len == 0 {
10378            return Err(Error::ParseFailure("alpn protocol must not be empty"));
10379        }
10380        if cursor.len() < protocol_len {
10381            return Err(Error::ParseFailure("alpn protocol truncated"));
10382        }
10383        let protocol = cursor[..protocol_len].to_vec();
10384        if protocols.contains(&protocol) {
10385            return Err(Error::ParseFailure("duplicate alpn protocol"));
10386        }
10387        protocols.push(protocol);
10388        cursor = &cursor[protocol_len..];
10389    }
10390    Ok(protocols)
10391}
10392
10393/// Encodes ordered ALPN protocol names into TLS extension payload bytes.
10394///
10395/// # Arguments
10396///
10397/// * `protocols` — `protocols: &[Vec<u8>]`.
10398///
10399/// # Returns
10400///
10401/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10402///
10403/// # Errors
10404///
10405/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10406///
10407/// # Panics
10408///
10409/// This function does not panic.
10410///
10411fn encode_alpn_extension_data(protocols: &[Vec<u8>]) -> Result<Vec<u8>> {
10412    if protocols.is_empty() {
10413        return Err(Error::InvalidLength(
10414            "alpn extension must include at least one protocol",
10415        ));
10416    }
10417    let mut protocol_name_list = Vec::new();
10418    let mut seen_protocols = Vec::new();
10419    for protocol in protocols {
10420        if protocol.is_empty() {
10421            return Err(Error::InvalidLength("alpn protocol must not be empty"));
10422        }
10423        if protocol.len() > u8::MAX as usize {
10424            return Err(Error::InvalidLength(
10425                "alpn protocol length must not exceed 255 bytes",
10426            ));
10427        }
10428        if seen_protocols.contains(protocol) {
10429            return Err(Error::ParseFailure("duplicate alpn protocol"));
10430        }
10431        seen_protocols.push(protocol.clone());
10432        protocol_name_list.push(protocol.len() as u8);
10433        protocol_name_list.extend_from_slice(protocol);
10434    }
10435    let mut extension_data = Vec::new();
10436    extension_data.extend_from_slice(&(protocol_name_list.len() as u16).to_be_bytes());
10437    extension_data.extend_from_slice(&protocol_name_list);
10438    Ok(extension_data)
10439}
10440
10441/// Parses `<len:u16><items:u16...>` style vector and returns u16 items.
10442///
10443/// # Arguments
10444///
10445/// * `input` — `input: &[u8]`.
10446///
10447/// # Returns
10448///
10449/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10450///
10451/// # Errors
10452///
10453/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10454///
10455/// # Panics
10456///
10457/// This function does not panic.
10458///
10459fn parse_u16_vector_with_len(input: &[u8]) -> Result<Vec<u16>> {
10460    if input.len() < 2 {
10461        return Err(Error::ParseFailure("u16 vector missing length prefix"));
10462    }
10463    let len = u16::from_be_bytes([input[0], input[1]]) as usize;
10464    if input.len() != len + 2 || !len.is_multiple_of(2) {
10465        return Err(Error::ParseFailure("invalid u16 vector length"));
10466    }
10467    let mut out = Vec::new();
10468    for chunk in input[2..].chunks_exact(2) {
10469        let value = u16::from_be_bytes([chunk[0], chunk[1]]);
10470        if out.contains(&value) {
10471            return Err(Error::ParseFailure("duplicate u16 vector entry"));
10472        }
10473        out.push(value);
10474    }
10475    Ok(out)
10476}
10477
10478/// Parses `<len:u8><items:u8...>` style vector and returns u8 items.
10479///
10480/// # Arguments
10481///
10482/// * `input` — `input: &[u8]`.
10483///
10484/// # Returns
10485///
10486/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10487///
10488/// # Errors
10489///
10490/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10491///
10492/// # Panics
10493///
10494/// This function does not panic.
10495///
10496fn parse_u8_vector_with_len(input: &[u8]) -> Result<Vec<u8>> {
10497    if input.is_empty() {
10498        return Err(Error::ParseFailure("u8 vector missing length prefix"));
10499    }
10500    let len = input[0] as usize;
10501    if input.len() != len + 1 {
10502        return Err(Error::ParseFailure("invalid u8 vector length"));
10503    }
10504    if len == 0 {
10505        return Err(Error::ParseFailure("u8 vector must not be empty"));
10506    }
10507    let mut out = Vec::new();
10508    for value in &input[1..] {
10509        if out.contains(value) {
10510            return Err(Error::ParseFailure("duplicate u8 vector entry"));
10511        }
10512        out.push(*value);
10513    }
10514    Ok(out)
10515}
10516
10517/// Parses CertificateRequest body shape used by TLS 1.3.
10518///
10519/// # Arguments
10520///
10521/// * `body` — `body: &[u8]`.
10522///
10523/// # Returns
10524///
10525/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10526///
10527/// # Errors
10528///
10529/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10530///
10531/// # Panics
10532///
10533/// This function does not panic.
10534///
10535fn parse_certificate_request_body(body: &[u8]) -> Result<()> {
10536    if body.len() < 3 {
10537        return Err(Error::ParseFailure("certificate request body too short"));
10538    }
10539    let context_len = body[0] as usize;
10540    let ext_len_offset = 1 + context_len;
10541    if body.len() < ext_len_offset + 2 {
10542        return Err(Error::ParseFailure("certificate request context truncated"));
10543    }
10544    let ext_len = u16::from_be_bytes([body[ext_len_offset], body[ext_len_offset + 1]]) as usize;
10545    let ext_start = ext_len_offset + 2;
10546    if body.len() != ext_start + ext_len {
10547        return Err(Error::ParseFailure(
10548            "certificate request extensions truncated",
10549        ));
10550    }
10551    parse_certificate_request_extensions(&body[ext_start..])?;
10552    Ok(())
10553}
10554
10555/// Parses CertificateRequest extensions vector and validates entry structure.
10556///
10557/// # Arguments
10558///
10559/// * `input` — `input: &[u8]`.
10560///
10561/// # Returns
10562///
10563/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10564///
10565/// # Errors
10566///
10567/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10568///
10569/// # Panics
10570///
10571/// This function does not panic.
10572///
10573fn parse_certificate_request_extensions(input: &[u8]) -> Result<()> {
10574    let mut cursor = input;
10575    let mut seen_extension_types = Vec::new();
10576    let mut seen_signature_algorithms = false;
10577    while !cursor.is_empty() {
10578        if cursor.len() < 4 {
10579            return Err(Error::ParseFailure(
10580                "certificate request extension header truncated",
10581            ));
10582        }
10583        let ext_type = u16::from_be_bytes([cursor[0], cursor[1]]);
10584        let ext_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
10585        if seen_extension_types.contains(&ext_type) {
10586            return Err(Error::ParseFailure(
10587                "duplicate certificate request extension type",
10588            ));
10589        }
10590        if matches!(
10591            ext_type,
10592            EXT_SUPPORTED_VERSIONS
10593                | EXT_KEY_SHARE
10594                | EXT_PRE_SHARED_KEY
10595                | EXT_PSK_KEY_EXCHANGE_MODES
10596                | EXT_SERVER_NAME
10597        ) {
10598            return Err(Error::ParseFailure(
10599                "certificate request contains forbidden extension type",
10600            ));
10601        }
10602        seen_extension_types.push(ext_type);
10603        cursor = &cursor[4..];
10604        if cursor.len() < ext_len {
10605            return Err(Error::ParseFailure(
10606                "certificate request extension truncated",
10607            ));
10608        }
10609        if ext_type == EXT_SIGNATURE_ALGORITHMS {
10610            let signature_algorithms = parse_u16_vector_with_len(&cursor[..ext_len])?;
10611            if signature_algorithms.is_empty() {
10612                return Err(Error::ParseFailure(
10613                    "certificate request signature_algorithms must not be empty",
10614                ));
10615            }
10616            seen_signature_algorithms = true;
10617        }
10618        cursor = &cursor[ext_len..];
10619    }
10620    if !seen_signature_algorithms {
10621        return Err(Error::ParseFailure(
10622            "certificate request missing signature_algorithms extension",
10623        ));
10624    }
10625    Ok(())
10626}
10627
10628/// Parses EncryptedExtensions body and validates extension vector structure.
10629///
10630/// # Arguments
10631///
10632/// * `body` — `body: &[u8]`.
10633///
10634/// # Returns
10635///
10636/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10637///
10638/// # Errors
10639///
10640/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10641///
10642/// # Panics
10643///
10644/// This function does not panic.
10645///
10646fn parse_encrypted_extensions_body(body: &[u8]) -> Result<ParsedEncryptedExtensions> {
10647    if body.len() < 2 {
10648        return Err(Error::ParseFailure("encrypted extensions body too short"));
10649    }
10650    let extensions_len = u16::from_be_bytes([body[0], body[1]]) as usize;
10651    if body.len() != 2 + extensions_len {
10652        return Err(Error::ParseFailure("encrypted extensions malformed length"));
10653    }
10654    let mut cursor = &body[2..];
10655    let mut seen_extension_types = Vec::new();
10656    let mut selected_alpn_protocol = None;
10657    let mut server_name_acknowledged = false;
10658    let mut early_data_accepted = false;
10659    while !cursor.is_empty() {
10660        if cursor.len() < 4 {
10661            return Err(Error::ParseFailure(
10662                "encrypted extensions entry header truncated",
10663            ));
10664        }
10665        let ext_type = u16::from_be_bytes([cursor[0], cursor[1]]);
10666        let ext_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
10667        if ext_len > TLS13_MAX_EXTENSION_VALUE_BYTES {
10668            return Err(Error::ParseFailure(
10669                "encrypted extensions extension value exceeds modeled maximum",
10670            ));
10671        }
10672        if seen_extension_types.contains(&ext_type) {
10673            return Err(Error::ParseFailure("duplicate encrypted extensions type"));
10674        }
10675        seen_extension_types.push(ext_type);
10676        cursor = &cursor[4..];
10677        if cursor.len() < ext_len {
10678            return Err(Error::ParseFailure("encrypted extensions entry truncated"));
10679        }
10680        let ext_data = &cursor[..ext_len];
10681        match ext_type {
10682            EXT_SERVER_NAME => {
10683                if !ext_data.is_empty() {
10684                    return Err(Error::ParseFailure(
10685                        "encrypted extensions server_name must be empty",
10686                    ));
10687                }
10688                server_name_acknowledged = true;
10689            }
10690            EXT_ALPN => {
10691                let protocols = parse_alpn_protocol_name_list(ext_data)?;
10692                if protocols.len() != 1 {
10693                    return Err(Error::ParseFailure(
10694                        "encrypted extensions alpn must select exactly one protocol",
10695                    ));
10696                }
10697                selected_alpn_protocol = protocols.first().cloned();
10698            }
10699            EXT_EARLY_DATA => {
10700                if !ext_data.is_empty() {
10701                    return Err(Error::ParseFailure(
10702                        "encrypted extensions early_data must be empty",
10703                    ));
10704                }
10705                early_data_accepted = true;
10706            }
10707            EXT_SUPPORTED_VERSIONS
10708            | EXT_KEY_SHARE
10709            | EXT_PRE_SHARED_KEY
10710            | EXT_PSK_KEY_EXCHANGE_MODES => {
10711                return Err(Error::ParseFailure(
10712                    "encrypted extensions contains forbidden extension type",
10713                ));
10714            }
10715            _ => {}
10716        }
10717        cursor = &cursor[ext_len..];
10718    }
10719    Ok(ParsedEncryptedExtensions {
10720        selected_alpn_protocol,
10721        server_name_acknowledged,
10722        early_data_accepted,
10723    })
10724}
10725
10726/// Parses Certificate body shape used by TLS 1.3 and extracts certificate entries.
10727///
10728/// # Arguments
10729///
10730/// * `body` — `body: &[u8]`.
10731///
10732/// # Returns
10733///
10734/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
10735///
10736/// # Errors
10737///
10738/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
10739///
10740/// # Panics
10741///
10742/// This function does not panic.
10743///
10744fn parse_certificate_body(body: &[u8]) -> Result<ParsedTls13CertificateBody> {
10745    if body.len() < 4 {
10746        return Err(Error::ParseFailure("certificate body too short"));
10747    }
10748    let context_len = body[0] as usize;
10749    let list_len_offset = 1 + context_len;
10750    if body.len() < list_len_offset + 3 {
10751        return Err(Error::ParseFailure("certificate list length missing"));
10752    }
10753    let cert_list_len = u32::from_be_bytes([
10754        0x00,
10755        body[list_len_offset],
10756        body[list_len_offset + 1],
10757        body[list_len_offset + 2],
10758    ]) as usize;
10759    let cert_list_start = list_len_offset + 3;
10760    let cert_list_end = cert_list_start + cert_list_len;
10761    if cert_list_end > body.len() {
10762        return Err(Error::ParseFailure("certificate list truncated"));
10763    }
10764    let mut certificates = Vec::new();
10765    let mut cursor = &body[cert_list_start..cert_list_end];
10766    let mut leaf_ocsp_staple = None;
10767    while !cursor.is_empty() {
10768        if cursor.len() < 5 {
10769            return Err(Error::ParseFailure("certificate entry truncated"));
10770        }
10771        let cert_len = u32::from_be_bytes([0x00, cursor[0], cursor[1], cursor[2]]) as usize;
10772        let cert_end = 3 + cert_len;
10773        if cursor.len() < cert_end + 2 {
10774            return Err(Error::ParseFailure("certificate bytes truncated"));
10775        }
10776        certificates.push(cursor[3..cert_end].to_vec());
10777        let ext_len = u16::from_be_bytes([cursor[cert_end], cursor[cert_end + 1]]) as usize;
10778        let ext_end = cert_end + 2 + ext_len;
10779        if cursor.len() < ext_end {
10780            return Err(Error::ParseFailure(
10781                "certificate entry extensions truncated",
10782            ));
10783        }
10784        let parsed_staple = parse_certificate_entry_extensions(&cursor[cert_end + 2..ext_end])?;
10785        if certificates.len() == 1 {
10786            leaf_ocsp_staple = parsed_staple;
10787        }
10788        cursor = &cursor[ext_end..];
10789    }
10790    if certificates.is_empty() {
10791        return Err(Error::ParseFailure("certificate list must not be empty"));
10792    }
10793    if cert_list_end != body.len() {
10794        return Err(Error::ParseFailure("certificate body trailing bytes"));
10795    }
10796    Ok(ParsedTls13CertificateBody {
10797        certificates,
10798        leaf_ocsp_staple,
10799    })
10800}
10801
10802/// Parses a TLS 1.2 Certificate body and extracts DER certificate entries.
10803///
10804/// # Arguments
10805///
10806/// * `body` — Handshake body bytes for a TLS 1.2 `Certificate` message.
10807///
10808/// # Returns
10809///
10810/// On success, non-empty DER certificate entries in wire order (leaf first).
10811///
10812/// # Errors
10813///
10814/// Returns [`noxtls_core::Error`] for malformed list framing, truncated entries, or trailing bytes.
10815///
10816/// # Panics
10817///
10818/// This function does not panic.
10819fn parse_tls12_certificate_list(body: &[u8]) -> Result<Vec<Vec<u8>>> {
10820    if body.len() < 3 {
10821        return Err(Error::ParseFailure(
10822            "tls12 certificate message is malformed",
10823        ));
10824    }
10825    let list_len = ((body[0] as usize) << 16) | ((body[1] as usize) << 8) | body[2] as usize;
10826    if list_len == 0 || list_len != body.len() - 3 {
10827        return Err(Error::ParseFailure(
10828            "tls12 certificate list length is malformed",
10829        ));
10830    }
10831    let mut certificates = Vec::new();
10832    let mut cursor = &body[3..];
10833    while !cursor.is_empty() {
10834        if cursor.len() < 3 {
10835            return Err(Error::ParseFailure(
10836                "tls12 certificate entry length is truncated",
10837            ));
10838        }
10839        let cert_len =
10840            ((cursor[0] as usize) << 16) | ((cursor[1] as usize) << 8) | cursor[2] as usize;
10841        if cert_len == 0 {
10842            return Err(Error::ParseFailure(
10843                "tls12 certificate entry must not be empty",
10844            ));
10845        }
10846        if cursor.len() < 3 + cert_len {
10847            return Err(Error::ParseFailure("tls12 certificate entry is truncated"));
10848        }
10849        certificates.push(cursor[3..3 + cert_len].to_vec());
10850        cursor = &cursor[3 + cert_len..];
10851    }
10852    if certificates.is_empty() {
10853        return Err(Error::ParseFailure(
10854            "tls12 certificate list must not be empty",
10855        ));
10856    }
10857    Ok(certificates)
10858}
10859
10860/// Parses TLS 1.2 ServerKeyExchange ECDHE-style body and enforces modern signature-scheme policy.
10861///
10862/// # Arguments
10863///
10864/// * `body` — Handshake body bytes for TLS 1.2 `ServerKeyExchange`.
10865///
10866/// # Returns
10867///
10868/// `Ok(())` when shape and signature-scheme policy checks pass.
10869///
10870/// # Errors
10871///
10872/// Returns [`noxtls_core::Error`] when body shape is malformed or signature scheme is disallowed.
10873///
10874/// # Panics
10875///
10876/// This function does not panic.
10877fn parse_tls12_server_key_exchange_body(body: &[u8]) -> Result<()> {
10878    if body.len() < 8 {
10879        return Err(Error::ParseFailure(
10880            "tls12 server key exchange body must include key share and signature fields",
10881        ));
10882    }
10883    if body[0] != 0x03 {
10884        return Err(Error::ParseFailure(
10885            "tls12 server key exchange requires named_curve parameters",
10886        ));
10887    }
10888    let public_len = body[3] as usize;
10889    if public_len == 0 {
10890        return Err(Error::ParseFailure(
10891            "tls12 server key exchange public key must not be empty",
10892        ));
10893    }
10894    let signature_header_offset = 4 + public_len;
10895    if body.len() < signature_header_offset + 4 {
10896        return Err(Error::ParseFailure(
10897            "tls12 server key exchange signature header is truncated",
10898        ));
10899    }
10900    let signature_scheme = u16::from_be_bytes([
10901        body[signature_header_offset],
10902        body[signature_header_offset + 1],
10903    ]);
10904    if !tls12_signature_scheme_is_modern(signature_scheme) {
10905        return Err(Error::ParseFailure(
10906            "tls12 server key exchange uses unsupported signature scheme",
10907        ));
10908    }
10909    let signature_len = u16::from_be_bytes([
10910        body[signature_header_offset + 2],
10911        body[signature_header_offset + 3],
10912    ]) as usize;
10913    if signature_len == 0 {
10914        return Err(Error::ParseFailure(
10915            "tls12 server key exchange signature must not be empty",
10916        ));
10917    }
10918    if body.len() != signature_header_offset + 4 + signature_len {
10919        return Err(Error::ParseFailure(
10920            "tls12 server key exchange signature length is malformed",
10921        ));
10922    }
10923    Ok(())
10924}
10925
10926/// Parses TLS 1.2 CertificateVerify body and enforces modern signature-scheme policy.
10927///
10928/// # Arguments
10929///
10930/// * `body` — Handshake body bytes for TLS 1.2 `CertificateVerify`.
10931///
10932/// # Returns
10933///
10934/// `Ok(())` when shape and signature-scheme policy checks pass.
10935///
10936/// # Errors
10937///
10938/// Returns [`noxtls_core::Error`] when body shape is malformed or signature scheme is disallowed.
10939///
10940/// # Panics
10941///
10942/// This function does not panic.
10943fn parse_tls12_certificate_verify_body(body: &[u8]) -> Result<()> {
10944    if body.len() < 4 {
10945        return Err(Error::ParseFailure(
10946            "tls12 client certificate verify body must include signature scheme and length",
10947        ));
10948    }
10949    let signature_scheme = u16::from_be_bytes([body[0], body[1]]);
10950    if !tls12_signature_scheme_is_modern(signature_scheme) {
10951        return Err(Error::ParseFailure(
10952            "tls12 client certificate verify uses unsupported signature scheme",
10953        ));
10954    }
10955    let signature_len = u16::from_be_bytes([body[2], body[3]]) as usize;
10956    if signature_len == 0 {
10957        return Err(Error::ParseFailure(
10958            "tls12 client certificate verify signature must not be empty",
10959        ));
10960    }
10961    if body.len() != 4 + signature_len {
10962        return Err(Error::ParseFailure(
10963            "tls12 client certificate verify signature length is malformed",
10964        ));
10965    }
10966    Ok(())
10967}
10968
10969/// Returns whether TLS 1.2 signature algorithm is allowed by default-safe policy.
10970///
10971/// # Arguments
10972///
10973/// * `signature_scheme` — TLS SignatureScheme identifier.
10974///
10975/// # Returns
10976///
10977/// `true` for modern schemes enabled by default, `false` otherwise.
10978///
10979/// # Panics
10980///
10981/// This function does not panic.
10982fn tls12_signature_scheme_is_modern(signature_scheme: u16) -> bool {
10983    matches!(
10984        signature_scheme,
10985        TLS13_SIGALG_ECDSA_SECP256R1_SHA256
10986            | TLS13_SIGALG_RSA_PSS_RSAE_SHA256
10987            | TLS13_SIGALG_RSA_PSS_RSAE_SHA384
10988            | TLS13_SIGALG_ED25519
10989            | TLS13_SIGALG_MLDSA65
10990    )
10991}
10992
10993/// Parses one CertificateEntry extension vector and validates structure.
10994///
10995/// # Arguments
10996///
10997/// * `input` — `input: &[u8]`.
10998///
10999/// # Returns
11000///
11001/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11002///
11003/// # Errors
11004///
11005/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11006///
11007/// # Panics
11008///
11009/// This function does not panic.
11010///
11011fn parse_certificate_entry_extensions(input: &[u8]) -> Result<Option<Vec<u8>>> {
11012    let mut cursor = input;
11013    let mut seen_extension_types = Vec::new();
11014    let mut status_request_ocsp = None;
11015    while !cursor.is_empty() {
11016        if cursor.len() < 4 {
11017            return Err(Error::ParseFailure(
11018                "certificate entry extension header truncated",
11019            ));
11020        }
11021        let ext_type = u16::from_be_bytes([cursor[0], cursor[1]]);
11022        let ext_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
11023        if seen_extension_types.contains(&ext_type) {
11024            return Err(Error::ParseFailure(
11025                "duplicate certificate entry extension type",
11026            ));
11027        }
11028        seen_extension_types.push(ext_type);
11029        cursor = &cursor[4..];
11030        if cursor.len() < ext_len {
11031            return Err(Error::ParseFailure("certificate entry extension truncated"));
11032        }
11033        let ext_data = &cursor[..ext_len];
11034        if ext_type == EXT_STATUS_REQUEST {
11035            if status_request_ocsp.is_some() {
11036                return Err(Error::ParseFailure(
11037                    "duplicate certificate entry status_request extension",
11038                ));
11039            }
11040            status_request_ocsp = Some(parse_certificate_entry_status_request_extension(ext_data)?);
11041        }
11042        cursor = &cursor[ext_len..];
11043    }
11044    Ok(status_request_ocsp)
11045}
11046
11047/// Encodes one CertificateEntry `status_request` extension with OCSP staple payload.
11048fn encode_certificate_entry_status_request_extension(ocsp_staple: &[u8]) -> Result<Vec<u8>> {
11049    if ocsp_staple.is_empty() {
11050        return Err(Error::InvalidLength("ocsp staple must not be empty"));
11051    }
11052    if ocsp_staple.len() > 0x00FF_FFFF {
11053        return Err(Error::InvalidLength("ocsp staple is too large"));
11054    }
11055    let mut status_request_payload = Vec::new();
11056    status_request_payload.push(0x01); // status_type=ocsp
11057    let staple_len = ocsp_staple.len() as u32;
11058    status_request_payload.extend_from_slice(&staple_len.to_be_bytes()[1..4]);
11059    status_request_payload.extend_from_slice(ocsp_staple);
11060
11061    let mut extension = Vec::new();
11062    extension.extend_from_slice(&EXT_STATUS_REQUEST.to_be_bytes());
11063    extension.extend_from_slice(&(status_request_payload.len() as u16).to_be_bytes());
11064    extension.extend_from_slice(&status_request_payload);
11065    Ok(extension)
11066}
11067
11068/// Parses one CertificateEntry `status_request` extension and extracts OCSP staple bytes.
11069fn parse_certificate_entry_status_request_extension(input: &[u8]) -> Result<Vec<u8>> {
11070    if input.len() < 4 {
11071        return Err(Error::ParseFailure(
11072            "certificate entry status_request extension is truncated",
11073        ));
11074    }
11075    if input[0] != 0x01 {
11076        return Err(Error::ParseFailure(
11077            "certificate entry status_request must use ocsp status type",
11078        ));
11079    }
11080    let ocsp_len = ((input[1] as usize) << 16) | ((input[2] as usize) << 8) | input[3] as usize;
11081    if ocsp_len == 0 {
11082        return Err(Error::ParseFailure(
11083            "certificate entry status_request ocsp response must not be empty",
11084        ));
11085    }
11086    if input.len() != 4 + ocsp_len {
11087        return Err(Error::ParseFailure(
11088            "certificate entry status_request ocsp response is truncated",
11089        ));
11090    }
11091    Ok(input[4..].to_vec())
11092}
11093
11094/// Parses CertificateVerify body shape used by TLS 1.3.
11095///
11096/// # Arguments
11097///
11098/// * `body` — `body: &[u8]`.
11099///
11100/// # Returns
11101///
11102/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11103///
11104/// # Errors
11105///
11106/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11107///
11108/// # Panics
11109///
11110/// This function does not panic.
11111///
11112fn parse_certificate_verify_fields(body: &[u8]) -> Result<(u16, &[u8])> {
11113    if body.len() < 4 {
11114        return Err(Error::ParseFailure("certificate verify body too short"));
11115    }
11116    let signature_scheme = u16::from_be_bytes([body[0], body[1]]);
11117    let sig_len = u16::from_be_bytes([body[2], body[3]]) as usize;
11118    if body.len() != 4 + sig_len {
11119        return Err(Error::ParseFailure(
11120            "certificate verify signature truncated",
11121        ));
11122    }
11123    Ok((signature_scheme, &body[4..]))
11124}
11125
11126/// Returns true when CertificateVerify scheme is supported by current TLS13 implementation.
11127///
11128/// # Arguments
11129///
11130/// * `signature_scheme` — `signature_scheme: u16`.
11131///
11132/// # Returns
11133///
11134/// `true` or `false` according to the checks in the function body.
11135///
11136/// # Panics
11137///
11138/// This function does not panic.
11139///
11140fn tls13_supported_certificate_verify_signature_scheme(signature_scheme: u16) -> bool {
11141    matches!(
11142        signature_scheme,
11143        TLS13_SIGALG_ECDSA_SECP256R1_SHA256
11144            | TLS13_SIGALG_RSA_PSS_RSAE_SHA256
11145            | TLS13_SIGALG_RSA_PSS_RSAE_SHA384
11146            | TLS13_SIGALG_ED25519
11147            | TLS13_SIGALG_MLDSA65
11148    )
11149}
11150
11151/// Parses NewSessionTicket body shape used by TLS 1.3.
11152///
11153/// # Arguments
11154///
11155/// * `body` — `body: &[u8]`.
11156///
11157/// # Returns
11158///
11159/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11160///
11161/// # Errors
11162///
11163/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11164///
11165/// # Panics
11166///
11167/// This function does not panic.
11168///
11169fn parse_new_session_ticket_body(body: &[u8]) -> Result<()> {
11170    if body.len() < 11 {
11171        return Err(Error::ParseFailure("new session ticket body too short"));
11172    }
11173    let nonce_len = body[8] as usize;
11174    let ticket_len_offset = 9 + nonce_len;
11175    if body.len() < ticket_len_offset + 2 {
11176        return Err(Error::ParseFailure("new session ticket nonce truncated"));
11177    }
11178    let ticket_len =
11179        u16::from_be_bytes([body[ticket_len_offset], body[ticket_len_offset + 1]]) as usize;
11180    let ext_len_offset = ticket_len_offset + 2 + ticket_len;
11181    if body.len() < ext_len_offset + 2 {
11182        return Err(Error::ParseFailure("new session ticket bytes truncated"));
11183    }
11184    let ext_len = u16::from_be_bytes([body[ext_len_offset], body[ext_len_offset + 1]]) as usize;
11185    if body.len() != ext_len_offset + 2 + ext_len {
11186        return Err(Error::ParseFailure(
11187            "new session ticket extensions truncated",
11188        ));
11189    }
11190    Ok(())
11191}
11192
11193/// Builds TLS 1.3 CertificateVerify signed message for server role.
11194///
11195/// # Arguments
11196///
11197/// * `transcript_hash` — `transcript_hash: &[u8]`.
11198///
11199/// # Returns
11200///
11201/// The value described by the return type in the function signature.
11202///
11203/// # Panics
11204///
11205/// This function does not panic.
11206///
11207fn build_tls13_server_certificate_verify_message(transcript_hash: &[u8]) -> Vec<u8> {
11208    const PREFIX_LEN: usize = 64;
11209    const CONTEXT: &[u8] = b"TLS 1.3, server CertificateVerify";
11210    let mut out = Vec::with_capacity(PREFIX_LEN + CONTEXT.len() + 1 + transcript_hash.len());
11211    out.extend(core::iter::repeat_n(0x20_u8, PREFIX_LEN));
11212    out.extend_from_slice(CONTEXT);
11213    out.push(0x00);
11214    out.extend_from_slice(transcript_hash);
11215    out
11216}
11217
11218/// Parses DER RSAPublicKey bytes and constructs a `RsaPublicKey`.
11219///
11220/// # Arguments
11221///
11222/// * `public_key_der` — `public_key_der: &[u8]`.
11223///
11224/// # Returns
11225///
11226/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11227///
11228/// # Errors
11229///
11230/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11231///
11232/// # Panics
11233///
11234/// This function does not panic.
11235///
11236fn parse_rsa_public_key_der(public_key_der: &[u8]) -> Result<RsaPublicKey> {
11237    let (rsa_seq, rem) = parse_der_node(public_key_der)
11238        .map_err(|_| Error::ParseFailure("failed to parse server RSA public key"))?;
11239    if rsa_seq.tag != 0x30 || !rem.is_empty() {
11240        return Err(Error::ParseFailure(
11241            "invalid server RSA public key sequence",
11242        ));
11243    }
11244    let (modulus_node, rest) = parse_der_node(rsa_seq.body)
11245        .map_err(|_| Error::ParseFailure("failed to parse server RSA modulus"))?;
11246    let (exponent_node, tail) = parse_der_node(rest)
11247        .map_err(|_| Error::ParseFailure("failed to parse server RSA exponent"))?;
11248    if modulus_node.tag != 0x02 || exponent_node.tag != 0x02 || !tail.is_empty() {
11249        return Err(Error::ParseFailure(
11250            "invalid server RSA public key integer fields",
11251        ));
11252    }
11253    RsaPublicKey::from_be_bytes(modulus_node.body, exponent_node.body)
11254        .map_err(|_| Error::CryptoFailure("failed to construct server RSA public key"))
11255}
11256
11257/// Parses key_share extension and returns advertised key exchange group IDs.
11258///
11259/// # Arguments
11260///
11261/// * `input` — `input: &[u8]`.
11262///
11263/// # Returns
11264///
11265/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11266///
11267/// # Errors
11268///
11269/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11270///
11271/// # Panics
11272///
11273/// This function does not panic.
11274///
11275fn parse_key_share_groups_extension(input: &[u8]) -> Result<Vec<u16>> {
11276    if input.len() < 2 {
11277        return Err(Error::ParseFailure(
11278            "key_share extension missing list length",
11279        ));
11280    }
11281    let list_len = u16::from_be_bytes([input[0], input[1]]) as usize;
11282    if input.len() != list_len + 2 {
11283        return Err(Error::ParseFailure("invalid key_share extension length"));
11284    }
11285    let mut cursor = &input[2..];
11286    let mut groups = Vec::new();
11287    while !cursor.is_empty() {
11288        if cursor.len() < 4 {
11289            return Err(Error::ParseFailure("key_share entry truncated"));
11290        }
11291        let group = u16::from_be_bytes([cursor[0], cursor[1]]);
11292        let key_len = u16::from_be_bytes([cursor[2], cursor[3]]) as usize;
11293        if groups.contains(&group) {
11294            return Err(Error::ParseFailure("duplicate key_share group"));
11295        }
11296        if key_len == 0 {
11297            return Err(Error::ParseFailure(
11298                "key_share key_exchange must not be empty",
11299            ));
11300        }
11301        cursor = &cursor[4..];
11302        if cursor.len() < key_len {
11303            return Err(Error::ParseFailure("key_share key_exchange truncated"));
11304        }
11305        groups.push(group);
11306        cursor = &cursor[key_len..];
11307    }
11308    Ok(groups)
11309}
11310
11311/// Encodes TLS 1.3 pre_shared_key extension with one identity and one binder.
11312///
11313/// # Arguments
11314///
11315/// * `offer` — `offer: &PskClientOffer<'_>`.
11316///
11317/// # Returns
11318///
11319/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11320///
11321/// # Errors
11322///
11323/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11324///
11325/// # Panics
11326///
11327/// This function does not panic.
11328///
11329fn encode_pre_shared_key_extension(offer: &PskClientOffer<'_>) -> Result<Vec<u8>> {
11330    if offer.identities.is_empty() || offer.binders.is_empty() {
11331        return Err(Error::InvalidLength(
11332            "psk identity/binder list must not be empty",
11333        ));
11334    }
11335    if offer.identities.len() != offer.binders.len() {
11336        return Err(Error::InvalidLength(
11337            "psk identity and binder list lengths must match",
11338        ));
11339    }
11340    let mut identities = Vec::new();
11341    let mut binders = Vec::new();
11342    for (identity, binder) in offer.identities.iter().zip(offer.binders.iter()) {
11343        if identity.identity.is_empty() || binder.is_empty() {
11344            return Err(Error::InvalidLength(
11345                "psk identity and binder must not be empty",
11346            ));
11347        }
11348        if identity.identity.len() > u16::MAX as usize || binder.len() > u8::MAX as usize {
11349            return Err(Error::InvalidLength("psk identity or binder too long"));
11350        }
11351        identities.extend_from_slice(&(identity.identity.len() as u16).to_be_bytes());
11352        identities.extend_from_slice(identity.identity);
11353        identities.extend_from_slice(&identity.obfuscated_ticket_age.to_be_bytes());
11354        binders.push(binder.len() as u8);
11355        binders.extend_from_slice(binder);
11356    }
11357
11358    let mut out = Vec::new();
11359    out.extend_from_slice(&(identities.len() as u16).to_be_bytes());
11360    out.extend_from_slice(&identities);
11361    out.extend_from_slice(&(binders.len() as u16).to_be_bytes());
11362    out.extend_from_slice(&binders);
11363    Ok(out)
11364}
11365
11366/// Parses TLS 1.3 pre_shared_key extension and returns identity count and binders.
11367///
11368/// # Arguments
11369///
11370/// * `input` — `input: &[u8]`.
11371///
11372/// # Returns
11373///
11374/// On success, the `Ok` payload described by the return type; see the function body for the concrete value.
11375///
11376/// # Errors
11377///
11378/// Returns [`noxtls_core::Error`] when inputs or handshake state invalidate the operation; see the function body for specific error construction sites.
11379///
11380/// # Panics
11381///
11382/// This function does not panic.
11383///
11384fn parse_pre_shared_key_extension(
11385    input: &[u8],
11386) -> Result<(usize, Vec<Vec<u8>>, Vec<u32>, Vec<Vec<u8>>)> {
11387    if input.len() < 4 {
11388        return Err(Error::ParseFailure("pre_shared_key extension too short"));
11389    }
11390    let identities_len = u16::from_be_bytes([input[0], input[1]]) as usize;
11391    if input.len() < 2 + identities_len + 2 {
11392        return Err(Error::ParseFailure("pre_shared_key identities truncated"));
11393    }
11394    let identities_end = 2 + identities_len;
11395    let mut id_cursor = &input[2..identities_end];
11396    let mut identity_count = 0_usize;
11397    let mut identities = Vec::new();
11398    let mut obfuscated_ages = Vec::new();
11399    while !id_cursor.is_empty() {
11400        if id_cursor.len() < 6 {
11401            return Err(Error::ParseFailure(
11402                "pre_shared_key identity entry truncated",
11403            ));
11404        }
11405        let id_len = u16::from_be_bytes([id_cursor[0], id_cursor[1]]) as usize;
11406        if id_len == 0 {
11407            return Err(Error::ParseFailure(
11408                "pre_shared_key identity must not be empty",
11409            ));
11410        }
11411        if id_cursor.len() < 2 + id_len + 4 {
11412            return Err(Error::ParseFailure(
11413                "pre_shared_key identity bytes truncated",
11414            ));
11415        }
11416        let identity = id_cursor[2..2 + id_len].to_vec();
11417        if identities.iter().any(|existing| existing == &identity) {
11418            return Err(Error::ParseFailure("duplicate pre_shared_key identity"));
11419        }
11420        identities.push(identity);
11421        obfuscated_ages.push(u32::from_be_bytes([
11422            id_cursor[2 + id_len],
11423            id_cursor[3 + id_len],
11424            id_cursor[4 + id_len],
11425            id_cursor[5 + id_len],
11426        ]));
11427        identity_count = identity_count.saturating_add(1);
11428        id_cursor = &id_cursor[2 + id_len + 4..];
11429    }
11430
11431    let binders_len =
11432        u16::from_be_bytes([input[identities_end], input[identities_end + 1]]) as usize;
11433    let binders_start = identities_end + 2;
11434    let binders_end = binders_start + binders_len;
11435    if input.len() != binders_end {
11436        return Err(Error::ParseFailure(
11437            "invalid pre_shared_key binder vector length",
11438        ));
11439    }
11440    let mut binders = Vec::new();
11441    let mut binder_cursor = &input[binders_start..binders_end];
11442    while !binder_cursor.is_empty() {
11443        let binder_len = binder_cursor[0] as usize;
11444        if binder_len == 0 {
11445            return Err(Error::ParseFailure(
11446                "pre_shared_key binder must not be empty",
11447            ));
11448        }
11449        binder_cursor = &binder_cursor[1..];
11450        if binder_cursor.len() < binder_len {
11451            return Err(Error::ParseFailure("pre_shared_key binder bytes truncated"));
11452        }
11453        binders.push(binder_cursor[..binder_len].to_vec());
11454        binder_cursor = &binder_cursor[binder_len..];
11455    }
11456    if identity_count != binders.len() {
11457        return Err(Error::ParseFailure(
11458            "pre_shared_key identity and binder counts differ",
11459        ));
11460    }
11461    if identity_count == 0 {
11462        return Err(Error::ParseFailure(
11463            "pre_shared_key extension must include at least one identity",
11464        ));
11465    }
11466    Ok((identity_count, identities, obfuscated_ages, binders))
11467}
11468
11469/// Returns legacy TLS version bytes used in ClientHello/ServerHello structures.
11470///
11471/// # Arguments
11472///
11473/// * `version` — `version: TlsVersion`.
11474///
11475/// # Returns
11476///
11477/// The value described by the return type in the function signature.
11478///
11479/// # Panics
11480///
11481/// This function does not panic.
11482///
11483fn legacy_wire_version(version: TlsVersion) -> [u8; 2] {
11484    match version {
11485        TlsVersion::Tls10 => [0x03, 0x01],
11486        TlsVersion::Tls11 => [0x03, 0x02],
11487        TlsVersion::Tls12 | TlsVersion::Tls13 => [0x03, 0x03],
11488        TlsVersion::Dtls12 | TlsVersion::Dtls13 => [0xFE, 0xFD],
11489    }
11490}