// Parsing implementations for additional TLS Handshake message types
///|
///|
pub fn parse_client_key_exchange(
data : BytesView,
) -> Result[ClientKeyExchange, ParseError] {
if data.length() < 5 {
return Err(IncompleteRecord(expected=5, available=data.length()))
}
if data[0].to_int() != 0x16 {
return Err(NotTlsHandshake)
}
guard read_u16_int(data, 3) is Some(record_len) else {
return Err(BadLength(field="record.length", offset=3))
}
if record_len < 4 {
return Err(BadLength(field="handshake.header", offset=5))
}
let record_end = 5 + record_len
if record_end < 5 || data.length() < record_end {
return Err(IncompleteRecord(expected=record_end, available=data.length()))
}
if data[5].to_int() != 16 {
return Err(BadHandshakeType(data[5].to_int()))
}
guard read_u24_int(data, 6) is Some(handshake_len) else {
return Err(BadLength(field="handshake.length", offset=6))
}
let body_offset = 9
let body_end = body_offset + handshake_len
if handshake_len < 0 ||
body_end < body_offset ||
body_end > record_end ||
!has_range(data, body_offset, handshake_len) {
return Err(BadLength(field="handshake.body", offset=body_offset))
}
let raw_arr = Array::new(capacity=handshake_len)
for i in 0.. Result[ServerKeyExchange, ParseError] {
if data.length() < 5 {
return Err(IncompleteRecord(expected=5, available=data.length()))
}
if data[0].to_int() != 0x16 {
return Err(NotTlsHandshake)
}
guard read_u16_int(data, 3) is Some(record_len) else {
return Err(BadLength(field="record.length", offset=3))
}
if record_len < 4 {
return Err(BadLength(field="handshake.header", offset=5))
}
let record_end = 5 + record_len
if record_end < 5 || data.length() < record_end {
return Err(IncompleteRecord(expected=record_end, available=data.length()))
}
if data[5].to_int() != 12 {
return Err(BadHandshakeType(data[5].to_int()))
}
guard read_u24_int(data, 6) is Some(handshake_len) else {
return Err(BadLength(field="handshake.length", offset=6))
}
let body_offset = 9
let body_end = body_offset + handshake_len
if handshake_len < 0 ||
body_end < body_offset ||
body_end > record_end ||
!has_range(data, body_offset, handshake_len) {
return Err(BadLength(field="handshake.body", offset=body_offset))
}
let raw_arr = Array::new(capacity=handshake_len)
for i in 0.. Result[NewSessionTicket, ParseError] {
if data.length() < 5 {
return Err(IncompleteRecord(expected=5, available=data.length()))
}
if data[0].to_int() != 0x16 {
return Err(NotTlsHandshake)
}
guard read_u16_int(data, 3) is Some(record_len) else {
return Err(BadLength(field="record.length", offset=3))
}
if record_len < 4 {
return Err(BadLength(field="handshake.header", offset=5))
}
let record_end = 5 + record_len
if record_end < 5 || data.length() < record_end {
return Err(IncompleteRecord(expected=record_end, available=data.length()))
}
if data[5].to_int() != 4 {
return Err(BadHandshakeType(data[5].to_int()))
}
guard read_u24_int(data, 6) is Some(handshake_len) else {
return Err(BadLength(field="handshake.length", offset=6))
}
let body_offset = 9
let body_end = body_offset + handshake_len
if handshake_len < 0 || body_end < body_offset || body_end > record_end {
return Err(BadLength(field="handshake.body", offset=body_offset))
}
// NewSessionTicket layout:
// Ticket Lifetime (4 bytes) + Ticket Age Add (4 bytes) + Ticket Length (2 bytes) + Ticket
if handshake_len < 10 {
return Err(BadLength(field="ticket.header", offset=body_offset))
}
guard read_u32_int(data, body_offset) is Some(lifetime) else {
return Err(BadLength(field="ticket.lifetime", offset=body_offset))
}
guard read_u32_int(data, body_offset + 4) is Some(age_add) else {
return Err(BadLength(field="ticket.age_add", offset=body_offset + 4))
}
guard read_u16_int(data, body_offset + 8) is Some(ticket_len) else {
return Err(BadLength(field="ticket.length", offset=body_offset + 8))
}
if ticket_len < 0 ||
body_offset + 10 + ticket_len > body_end ||
!has_range(data, body_offset + 10, ticket_len) {
return Err(BadLength(field="ticket.body", offset=body_offset + 10))
}
let ticket_arr = Array::new(capacity=ticket_len)
for i in 0.. Result[EncryptedExtensions, ParseError] {
if data.length() < 5 {
return Err(IncompleteRecord(expected=5, available=data.length()))
}
if data[0].to_int() != 0x16 {
return Err(NotTlsHandshake)
}
guard read_u16_int(data, 3) is Some(record_len) else {
return Err(BadLength(field="record.length", offset=3))
}
if record_len < 4 {
return Err(BadLength(field="handshake.header", offset=5))
}
let record_end = 5 + record_len
if record_end < 5 || data.length() < record_end {
return Err(IncompleteRecord(expected=record_end, available=data.length()))
}
if data[5].to_int() != 8 {
return Err(BadHandshakeType(data[5].to_int()))
}
guard read_u24_int(data, 6) is Some(handshake_len) else {
return Err(BadLength(field="handshake.length", offset=6))
}
let body_offset = 9
let body_end = body_offset + handshake_len
if handshake_len < 0 || body_end < body_offset || body_end > record_end {
return Err(BadLength(field="handshake.body", offset=body_offset))
}
if handshake_len < 2 {
return Err(BadLength(field="encrypted_extensions.len", offset=body_offset))
}
guard read_u16_int(data, body_offset) is Some(ext_total_len) else {
return Err(
BadLength(field="encrypted_extensions.length", offset=body_offset),
)
}
if ext_total_len < 0 || body_offset + 2 + ext_total_len > body_end {
return Err(
BadLength(field="encrypted_extensions.body", offset=body_offset + 2),
)
}
let extensions : Array[UInt16] = []
let mut cursor = body_offset + 2
let ext_end = cursor + ext_total_len
while cursor + 4 <= ext_end {
guard read_u16(data, cursor) is Some(ext_type) else {
return Err(BadLength(field="extension.type", offset=cursor))
}
guard read_u16_int(data, cursor + 2) is Some(ext_len) else {
return Err(BadLength(field="extension.length", offset=cursor + 2))
}
cursor = cursor + 4
if ext_len < 0 ||
cursor + ext_len > ext_end ||
!has_range(data, cursor, ext_len) {
return Err(BadLength(field="extension.body", offset=cursor))
}
if !is_grease(ext_type) {
extensions.push(ext_type)
}
cursor = cursor + ext_len
}
if cursor != ext_end {
return Err(BadLength(field="extensions.trailing", offset=cursor))
}
Ok({ extensions, })
}
///|
fn read_u32_int(data : BytesView, offset : Int) -> Int? {
if has_range(data, offset, 4) {
let val = data[offset].to_int() * 16777216 +
data[offset + 1].to_int() * 65536 +
data[offset + 2].to_int() * 256 +
data[offset + 3].to_int()
Some(val)
} else {
None
}
}