use crate::internal_alloc::Vec;
use noxtls_core::{Error, Result};
const TLS13_OUTER_CONTENT_TYPE_APPLICATION_DATA: u8 = 0x17;
const TLS13_LEGACY_RECORD_VERSION: [u8; 2] = [0x03, 0x03];
const TLS13_AEAD_TAG_LEN: usize = 16;
const TLS13_MIN_CIPHERTEXT_LEN: usize = 1 + TLS13_AEAD_TAG_LEN;
const TLS12_RECORD_HEADER_LEN: usize = 5;
#[must_use]
pub fn build_record_nonce(base_iv: &[u8; 12], sequence: u64) -> [u8; 12] {
let mut nonce = *base_iv;
let seq_bytes = sequence.to_be_bytes();
for (idx, byte) in seq_bytes.iter().enumerate() {
nonce[4 + idx] ^= *byte;
}
nonce
}
#[must_use]
pub fn encode_tls13_inner_plaintext(
content: &[u8],
content_type: u8,
padding_len: usize,
) -> Vec<u8> {
let mut inner = Vec::with_capacity(content.len() + 1 + padding_len);
inner.extend_from_slice(content);
inner.push(content_type);
inner.resize(inner.len() + padding_len, 0x00);
inner
}
pub fn decode_tls13_inner_plaintext(inner: &[u8]) -> Result<(Vec<u8>, u8)> {
if inner.is_empty() {
return Err(Error::ParseFailure(
"tls13 inner plaintext must not be empty",
));
}
let mut idx = inner.len();
while idx > 0 && inner[idx - 1] == 0x00 {
idx -= 1;
}
if idx == 0 {
return Err(Error::ParseFailure(
"tls13 inner plaintext missing content type",
));
}
let content_type = inner[idx - 1];
let content = inner[..idx - 1].to_vec();
Ok((content, content_type))
}
pub fn encode_tls13_ciphertext_record(payload: &[u8]) -> Result<Vec<u8>> {
if payload.len() < TLS13_MIN_CIPHERTEXT_LEN {
return Err(Error::InvalidLength(
"tls13 ciphertext payload is too short",
));
}
if payload.len() > usize::from(u16::MAX) {
return Err(Error::InvalidLength(
"tls13 ciphertext payload is too large",
));
}
let mut out = Vec::with_capacity(5 + payload.len());
out.push(TLS13_OUTER_CONTENT_TYPE_APPLICATION_DATA);
out.extend_from_slice(&TLS13_LEGACY_RECORD_VERSION);
out.extend_from_slice(&(payload.len() as u16).to_be_bytes());
out.extend_from_slice(payload);
Ok(out)
}
pub fn decode_tls13_ciphertext_record(packet: &[u8]) -> Result<Vec<u8>> {
if packet.len() < 5 {
return Err(Error::ParseFailure("tls13 record header truncated"));
}
if packet[0] != TLS13_OUTER_CONTENT_TYPE_APPLICATION_DATA {
return Err(Error::ParseFailure(
"tls13 record has invalid outer content type",
));
}
if packet[1..3] != TLS13_LEGACY_RECORD_VERSION {
return Err(Error::ParseFailure(
"tls13 record has invalid legacy version",
));
}
let payload_len = u16::from_be_bytes([packet[3], packet[4]]) as usize;
let payload_start = 5;
let payload_end = payload_start + payload_len;
if payload_end > packet.len() {
return Err(Error::ParseFailure("tls13 record payload truncated"));
}
if payload_end != packet.len() {
return Err(Error::ParseFailure("tls13 record has trailing bytes"));
}
if payload_len < TLS13_MIN_CIPHERTEXT_LEN {
return Err(Error::ParseFailure("tls13 record payload too short"));
}
Ok(packet[payload_start..payload_end].to_vec())
}
pub fn encode_tls12_ciphertext_record(
content_type: u8,
version: [u8; 2],
payload: &[u8],
) -> Result<Vec<u8>> {
if payload.len() > usize::from(u16::MAX) {
return Err(Error::InvalidLength(
"tls12 ciphertext payload is too large",
));
}
let mut out = Vec::with_capacity(TLS12_RECORD_HEADER_LEN + payload.len());
out.push(content_type);
out.extend_from_slice(&version);
out.extend_from_slice(&(payload.len() as u16).to_be_bytes());
out.extend_from_slice(payload);
Ok(out)
}
pub fn decode_tls12_ciphertext_record(packet: &[u8]) -> Result<(u8, [u8; 2], Vec<u8>)> {
if packet.len() < TLS12_RECORD_HEADER_LEN {
return Err(Error::ParseFailure("tls12 record header truncated"));
}
let content_type = packet[0];
let version = [packet[1], packet[2]];
let payload_len = u16::from_be_bytes([packet[3], packet[4]]) as usize;
let payload_start = TLS12_RECORD_HEADER_LEN;
let payload_end = payload_start + payload_len;
if payload_end > packet.len() {
return Err(Error::ParseFailure("tls12 record payload truncated"));
}
if payload_end != packet.len() {
return Err(Error::ParseFailure("tls12 record has trailing bytes"));
}
Ok((
content_type,
version,
packet[payload_start..payload_end].to_vec(),
))
}