refactor: update TLS record size constants and related validations

- Rename MAX_TLS_RECORD_SIZE to MAX_TLS_PLAINTEXT_SIZE for clarity.
- Rename MAX_TLS_CHUNK_SIZE to MAX_TLS_CIPHERTEXT_SIZE to reflect its purpose.
- Deprecate old constants in favor of new ones.
- Update various parts of the codebase to use the new constants, including validation checks and tests.
- Add new tests to ensure compliance with RFC 8446 regarding TLS record sizes.
This commit is contained in:
David Osipov
2026-03-20 21:00:36 +04:00
parent 801f670827
commit 3abde52de8
11 changed files with 713 additions and 54 deletions

View File

@@ -152,17 +152,29 @@ pub const TLS_RECORD_CHANGE_CIPHER: u8 = 0x14;
pub const TLS_RECORD_APPLICATION: u8 = 0x17;
/// TLS record type: Alert
pub const TLS_RECORD_ALERT: u8 = 0x15;
/// Maximum TLS record size (RFC 8446 §5.1: MUST NOT exceed 2^14 = 16_384 bytes)
pub const MAX_TLS_RECORD_SIZE: usize = 16_384;
/// Maximum TLS plaintext record payload size.
/// RFC 8446 §5.1: "The length MUST NOT exceed 2^14 bytes."
/// Use this for validating incoming unencrypted records
/// (ClientHello, ChangeCipherSpec, unprotected Handshake messages).
pub const MAX_TLS_PLAINTEXT_SIZE: usize = 16_384;
/// Structural minimum for a valid TLS 1.3 ClientHello with SNI.
/// Derived from RFC 8446 §4.1.2 field layout + Appendix D.4 compat mode.
/// Deliberately conservative (below any real client) to avoid false
/// positives on legitimate connections with compact extension sets.
pub const MIN_TLS_CLIENT_HELLO_SIZE: usize = 100;
/// Maximum TLS chunk size (with overhead)
/// RFC 8446 §5.2 allows up to 16384 + 256 bytes of ciphertext
pub const MAX_TLS_CHUNK_SIZE: usize = 16384 + 256;
/// Maximum TLS ciphertext record payload size.
/// RFC 8446 §5.2: "The length MUST NOT exceed 2^14 + 256 bytes."
/// The +256 accounts for maximum AEAD expansion overhead.
/// Use this for validating or sizing buffers for encrypted records.
pub const MAX_TLS_CIPHERTEXT_SIZE: usize = 16_384 + 256;
#[deprecated(note = "use MAX_TLS_PLAINTEXT_SIZE")]
pub const MAX_TLS_RECORD_SIZE: usize = MAX_TLS_PLAINTEXT_SIZE;
#[deprecated(note = "use MAX_TLS_CIPHERTEXT_SIZE")]
pub const MAX_TLS_CHUNK_SIZE: usize = MAX_TLS_CIPHERTEXT_SIZE;
/// Secure Intermediate payload is expected to be 4-byte aligned.
pub fn is_valid_secure_payload_len(data_len: usize) -> bool {
@@ -325,6 +337,10 @@ pub mod rpc_flags {
pub const ME_CONNECT_TIMEOUT_SECS: u64 = 5;
pub const ME_HANDSHAKE_TIMEOUT_SECS: u64 = 10;
#[cfg(test)]
#[path = "tls_size_constants_security_tests.rs"]
mod tls_size_constants_security_tests;
#[cfg(test)]
mod tests {

View File

@@ -450,7 +450,7 @@ pub fn build_server_hello(
new_session_tickets: u8,
) -> Vec<u8> {
const MIN_APP_DATA: usize = 64;
const MAX_APP_DATA: usize = 16640; // RFC 8446 §5.2 upper bound
const MAX_APP_DATA: usize = MAX_TLS_CIPHERTEXT_SIZE;
let fake_cert_len = fake_cert_len.clamp(MIN_APP_DATA, MAX_APP_DATA);
let x25519_key = gen_fake_x25519_key(rng);

View File

@@ -1189,7 +1189,7 @@ fn test_parse_tls_record_header() {
let header = [0x17, 0x03, 0x03, 0x40, 0x00];
let result = parse_tls_record_header(&header).unwrap();
assert_eq!(result.0, TLS_RECORD_APPLICATION);
assert_eq!(result.1, 16384);
assert_eq!(usize::from(result.1), MAX_TLS_PLAINTEXT_SIZE);
}
#[test]
@@ -1887,7 +1887,7 @@ fn server_hello_clamps_fake_cert_len_upper_bound() {
let app_len = u16::from_be_bytes([response[app_pos + 3], response[app_pos + 4]]) as usize;
assert_eq!(response[app_pos], TLS_RECORD_APPLICATION);
assert_eq!(app_len, 16_640, "fake cert payload must be clamped to TLS record max bound");
assert_eq!(app_len, MAX_TLS_CIPHERTEXT_SIZE, "fake cert payload must be clamped to TLS record max bound");
}
#[test]

View File

@@ -0,0 +1,15 @@
use super::{
MAX_TLS_CIPHERTEXT_SIZE,
MAX_TLS_PLAINTEXT_SIZE,
MIN_TLS_CLIENT_HELLO_SIZE,
};
#[test]
fn tls_size_constants_match_rfc_8446() {
assert_eq!(MAX_TLS_PLAINTEXT_SIZE, 16_384);
assert_eq!(MAX_TLS_CIPHERTEXT_SIZE, 16_640);
assert!(MIN_TLS_CLIENT_HELLO_SIZE < 512);
assert!(MIN_TLS_CLIENT_HELLO_SIZE > 64);
assert!(MAX_TLS_CIPHERTEXT_SIZE > MAX_TLS_PLAINTEXT_SIZE);
}