use super::{
ExtensionType, NamedGroup, RawExtension, ReadCursor, SignatureScheme, put_u8, put_u16,
with_len_u8, with_len_u16, with_len_u24,
};
use crate::tls::{Error, ProtocolVersion};
use alloc::vec::Vec;
pub(crate) fn client_supported_versions() -> RawExtension {
let mut body = Vec::new();
with_len_u8(&mut body, |b| put_u16(b, ProtocolVersion::TLSv1_3.as_u16()));
(ExtensionType::SUPPORTED_VERSIONS, body)
}
pub(crate) fn parse_selected_version(body: &[u8]) -> Result<ProtocolVersion, Error> {
let mut c = ReadCursor::new(body);
let v = c.u16()?;
c.expect_empty()?;
Ok(ProtocolVersion::from_u16(v))
}
pub(crate) fn supported_groups_list(groups: &[NamedGroup]) -> RawExtension {
let mut body = Vec::new();
with_len_u16(&mut body, |b| {
for g in groups {
put_u16(b, g.0);
}
});
(ExtensionType::SUPPORTED_GROUPS, body)
}
pub(crate) fn parse_supported_groups(body: &[u8]) -> Result<Vec<NamedGroup>, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u16()?;
outer.expect_empty()?;
let mut c = ReadCursor::new(list);
let mut out = Vec::new();
while !c.is_empty() {
out.push(NamedGroup(c.u16()?));
}
Ok(out)
}
pub(crate) fn signature_algorithms() -> RawExtension {
let schemes = [
SignatureScheme::ED25519,
SignatureScheme::ED448,
SignatureScheme::ECDSA_SECP256R1_SHA256,
SignatureScheme::ECDSA_SECP384R1_SHA384,
SignatureScheme::ECDSA_SECP521R1_SHA512,
SignatureScheme::RSA_PSS_RSAE_SHA256,
SignatureScheme::RSA_PSS_RSAE_SHA384,
SignatureScheme::MLDSA44,
SignatureScheme::MLDSA65,
SignatureScheme::MLDSA87,
];
let mut body = Vec::new();
with_len_u16(&mut body, |b| {
for s in schemes {
put_u16(b, s.0);
}
});
(ExtensionType::SIGNATURE_ALGORITHMS, body)
}
pub(crate) fn alpn_protocols(protocols: &[&[u8]]) -> RawExtension {
let mut body = Vec::new();
with_len_u16(&mut body, |list| {
for proto in protocols {
with_len_u8(list, |b| b.extend_from_slice(proto));
}
});
(ExtensionType::ALPN, body)
}
pub(crate) fn parse_alpn(body: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u16()?;
outer.expect_empty()?;
let mut c = ReadCursor::new(list);
let mut out = Vec::new();
while !c.is_empty() {
let p = c.vec_u8()?;
if p.is_empty() {
return Err(Error::IllegalParameter);
}
out.push(p.to_vec());
}
Ok(out)
}
#[allow(dead_code)]
pub(crate) fn ec_point_formats() -> RawExtension {
let mut body = Vec::new();
with_len_u8(&mut body, |b| b.push(0)); (ExtensionType::EC_POINT_FORMATS, body)
}
#[allow(dead_code)]
pub(crate) fn parse_ec_point_formats(body: &[u8]) -> Result<Vec<u8>, Error> {
let mut c = ReadCursor::new(body);
let list = c.vec_u8()?;
c.expect_empty()?;
Ok(list.to_vec())
}
#[allow(dead_code)]
pub(crate) fn renegotiation_info_empty() -> RawExtension {
let mut body = Vec::new();
with_len_u8(&mut body, |_| {});
(ExtensionType::RENEGOTIATION_INFO, body)
}
#[allow(dead_code)]
pub(crate) fn parse_renegotiation_info(body: &[u8]) -> Result<Vec<u8>, Error> {
let mut c = ReadCursor::new(body);
let inner = c.vec_u8()?;
c.expect_empty()?;
Ok(inner.to_vec())
}
pub(crate) fn extended_master_secret_empty() -> RawExtension {
(ExtensionType::EXTENDED_MASTER_SECRET, Vec::new())
}
pub(crate) fn parse_extended_master_secret(body: &[u8]) -> Result<(), Error> {
if !body.is_empty() {
return Err(Error::Decode);
}
Ok(())
}
#[allow(dead_code)]
pub(crate) fn session_ticket(ticket: &[u8]) -> RawExtension {
(ExtensionType::SESSION_TICKET, ticket.to_vec())
}
pub(crate) fn record_size_limit(limit: u16) -> RawExtension {
let mut body = Vec::new();
put_u16(&mut body, limit);
(ExtensionType::RECORD_SIZE_LIMIT, body)
}
pub(crate) fn parse_record_size_limit(body: &[u8]) -> Result<u16, Error> {
let mut c = ReadCursor::new(body);
let v = c.u16()?;
c.expect_empty()?;
if !(64..=(1u16 << 14) + 1).contains(&v) {
return Err(Error::IllegalParameter);
}
Ok(v)
}
pub(crate) fn status_request_ocsp() -> RawExtension {
let mut body = Vec::new();
put_u8(&mut body, 1); with_len_u16(&mut body, |_| {}); with_len_u16(&mut body, |_| {}); (ExtensionType::STATUS_REQUEST, body)
}
pub(crate) fn parse_status_request(body: &[u8]) -> Result<(), Error> {
let mut c = ReadCursor::new(body);
let status_type = c.u8()?;
let _responder_id_list = c.vec_u16()?;
let _request_extensions = c.vec_u16()?;
c.expect_empty()?;
if status_type != 1 {
return Err(Error::Decode);
}
Ok(())
}
pub(crate) fn status_request_sh_ack() -> RawExtension {
(ExtensionType::STATUS_REQUEST, Vec::new())
}
pub(crate) fn parse_status_request_sh_ack(body: &[u8]) -> Result<(), Error> {
if body.is_empty() {
Ok(())
} else {
Err(Error::Decode)
}
}
pub(crate) fn certificate_status_ocsp(ocsp_der: &[u8]) -> Vec<u8> {
let mut body = Vec::new();
put_u8(&mut body, 1); with_len_u24(&mut body, |b| b.extend_from_slice(ocsp_der));
body
}
pub(crate) fn parse_certificate_status(body: &[u8]) -> Result<Vec<u8>, Error> {
let mut c = ReadCursor::new(body);
let status_type = c.u8()?;
if status_type != 1 {
return Err(Error::Decode);
}
let ocsp = c.vec_u24()?.to_vec();
c.expect_empty()?;
if ocsp.is_empty() {
return Err(Error::Decode);
}
Ok(ocsp)
}
pub(crate) fn cert_type_list(ty: ExtensionType, types: &[u8]) -> RawExtension {
let mut body = Vec::new();
with_len_u8(&mut body, |b| b.extend_from_slice(types));
(ty, body)
}
pub(crate) fn parse_cert_type_list(body: &[u8]) -> Result<Vec<u8>, Error> {
let mut c = ReadCursor::new(body);
let list = c.vec_u8()?;
c.expect_empty()?;
if list.is_empty() {
return Err(Error::IllegalParameter);
}
Ok(list.to_vec())
}
pub(crate) fn cert_type_selection(ty: ExtensionType, selected: u8) -> RawExtension {
let body = alloc::vec![selected];
(ty, body)
}
pub(crate) fn parse_cert_type_selection(body: &[u8]) -> Result<u8, Error> {
let mut c = ReadCursor::new(body);
let v = c.u8()?;
c.expect_empty()?;
Ok(v)
}
pub(crate) fn server_name(host: &str) -> RawExtension {
let mut body = Vec::new();
with_len_u16(&mut body, |list| {
put_u8(list, 0); with_len_u16(list, |b| b.extend_from_slice(host.as_bytes()));
});
(ExtensionType::SERVER_NAME, body)
}
pub(crate) fn parse_server_name(body: &[u8]) -> Result<Option<alloc::string::String>, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u16()?;
outer.expect_empty()?;
if list.is_empty() {
return Err(Error::Decode);
}
let mut c = ReadCursor::new(list);
while !c.is_empty() {
let name_type = c.u8()?;
let name = c.vec_u16()?;
if name_type == 0 {
let s = core::str::from_utf8(name).map_err(|_| Error::Decode)?;
return Ok(Some(s.into()));
}
}
Ok(None)
}
pub(crate) fn client_key_shares(shares: &[(NamedGroup, Vec<u8>)]) -> RawExtension {
let mut body = Vec::new();
with_len_u16(&mut body, |list| {
for (group, key) in shares {
encode_key_share_entry(list, *group, key);
}
});
(ExtensionType::KEY_SHARE, body)
}
pub(crate) fn server_key_share(group: NamedGroup, public_key: &[u8]) -> RawExtension {
let mut body = Vec::new();
encode_key_share_entry(&mut body, group, public_key);
(ExtensionType::KEY_SHARE, body)
}
pub(crate) fn hrr_key_share(group: NamedGroup) -> RawExtension {
let mut body = Vec::new();
put_u16(&mut body, group.0);
(ExtensionType::KEY_SHARE, body)
}
#[cfg(feature = "ech")]
pub(crate) fn hrr_ech_confirmation(payload: [u8; 8]) -> RawExtension {
(ExtensionType::ENCRYPTED_CLIENT_HELLO, payload.to_vec())
}
fn encode_key_share_entry(out: &mut Vec<u8>, group: NamedGroup, public_key: &[u8]) {
put_u16(out, group.0);
with_len_u16(out, |b| b.extend_from_slice(public_key));
}
pub(crate) fn parse_server_key_share(body: &[u8]) -> Result<(NamedGroup, Vec<u8>), Error> {
let mut c = ReadCursor::new(body);
let group = NamedGroup(c.u16()?);
let key = c.vec_u16()?.to_vec();
c.expect_empty()?;
Ok((group, key))
}
pub(crate) fn parse_hrr_key_share(body: &[u8]) -> Result<NamedGroup, Error> {
let mut c = ReadCursor::new(body);
let group = NamedGroup(c.u16()?);
c.expect_empty()?;
Ok(group)
}
pub(crate) fn parse_client_key_shares(body: &[u8]) -> Result<Vec<(NamedGroup, Vec<u8>)>, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u16()?;
outer.expect_empty()?;
let mut c = ReadCursor::new(list);
let mut shares = Vec::new();
while !c.is_empty() {
let group = NamedGroup(c.u16()?);
let key = c.vec_u16()?.to_vec();
shares.push((group, key));
}
Ok(shares)
}
pub(crate) fn server_supported_versions() -> RawExtension {
let mut body = Vec::new();
put_u16(&mut body, ProtocolVersion::TLSv1_3.as_u16());
(ExtensionType::SUPPORTED_VERSIONS, body)
}
pub(crate) fn find(exts: &[RawExtension], ty: ExtensionType) -> Option<&[u8]> {
exts.iter()
.find(|(t, _)| *t == ty)
.map(|(_, v)| v.as_slice())
}
pub(crate) fn parse_signature_algorithms(body: &[u8]) -> Result<Vec<SignatureScheme>, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u16()?;
outer.expect_empty()?;
let mut c = ReadCursor::new(list);
let mut out = Vec::new();
while !c.is_empty() {
out.push(SignatureScheme(c.u16()?));
}
Ok(out)
}
pub(crate) fn client_offers_tls13(body: &[u8]) -> Result<bool, Error> {
let mut outer = ReadCursor::new(body);
let list = outer.vec_u8()?;
let mut c = ReadCursor::new(list);
let mut found = false;
while !c.is_empty() {
if c.u16()? == ProtocolVersion::TLSv1_3.as_u16() {
found = true;
}
}
Ok(found)
}
pub(crate) fn psk_key_exchange_modes(modes: &[u8]) -> RawExtension {
let mut body = Vec::new();
with_len_u8(&mut body, |b| b.extend_from_slice(modes));
(ExtensionType::PSK_KEY_EXCHANGE_MODES, body)
}
pub(crate) fn parse_psk_key_exchange_modes(body: &[u8]) -> Result<Vec<u8>, Error> {
let mut c = ReadCursor::new(body);
let list = c.vec_u8()?;
c.expect_empty()?;
if list.is_empty() {
return Err(Error::IllegalParameter);
}
Ok(list.to_vec())
}
#[allow(dead_code)]
pub(crate) fn early_data_empty() -> RawExtension {
(ExtensionType::EARLY_DATA, Vec::new())
}
#[allow(dead_code)]
pub(crate) fn early_data_with_size(max: u32) -> RawExtension {
(ExtensionType::EARLY_DATA, max.to_be_bytes().to_vec())
}
pub(crate) fn client_pre_shared_key_placeholder(
identities: &[(Vec<u8>, u32)],
hash_len: usize,
) -> (RawExtension, usize) {
let mut body = Vec::new();
with_len_u16(&mut body, |list| {
for (id, age) in identities {
with_len_u16(list, |b| b.extend_from_slice(id));
list.extend_from_slice(&age.to_be_bytes());
}
});
let binders_start = body.len();
with_len_u16(&mut body, |list| {
for _ in identities {
with_len_u8(list, |b| b.extend(core::iter::repeat_n(0u8, hash_len)));
}
});
let binders_len = body.len() - binders_start;
((ExtensionType::PRE_SHARED_KEY, body), binders_len)
}
pub(crate) type ClientPsk = (Vec<(Vec<u8>, u32)>, Vec<Vec<u8>>);
pub(crate) fn parse_client_pre_shared_key(body: &[u8]) -> Result<ClientPsk, Error> {
let mut c = ReadCursor::new(body);
let identities_bytes = c.vec_u16()?;
let binders_bytes = c.vec_u16()?;
c.expect_empty()?;
let mut id_cur = ReadCursor::new(identities_bytes);
let mut identities = Vec::new();
while !id_cur.is_empty() {
let id = id_cur.vec_u16()?.to_vec();
if id.is_empty() {
return Err(Error::IllegalParameter);
}
let age = id_cur.u32()?;
identities.push((id, age));
}
if identities.is_empty() {
return Err(Error::IllegalParameter);
}
let mut bin_cur = ReadCursor::new(binders_bytes);
let mut binders = Vec::new();
while !bin_cur.is_empty() {
let b = bin_cur.vec_u8()?.to_vec();
if b.len() < 32 {
return Err(Error::IllegalParameter);
}
binders.push(b);
}
if binders.len() != identities.len() {
return Err(Error::IllegalParameter);
}
Ok((identities, binders))
}
#[allow(dead_code)]
pub(crate) fn quic_transport_parameters(body: &[u8]) -> RawExtension {
(ExtensionType::QUIC_TRANSPORT_PARAMETERS, body.to_vec())
}
#[allow(dead_code)]
pub(crate) fn parse_quic_transport_parameters(body: &[u8]) -> &[u8] {
body
}
pub(crate) fn server_pre_shared_key(selected_identity: u16) -> RawExtension {
let mut body = Vec::with_capacity(2);
body.extend_from_slice(&selected_identity.to_be_bytes());
(ExtensionType::PRE_SHARED_KEY, body)
}
pub(crate) fn parse_server_pre_shared_key(body: &[u8]) -> Result<u16, Error> {
let mut c = ReadCursor::new(body);
let v = c.u16()?;
c.expect_empty()?;
Ok(v)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn server_name_roundtrip() {
let (_, body) = server_name("example.test");
assert_eq!(
parse_server_name(&body).unwrap().as_deref(),
Some("example.test")
);
}
#[test]
fn parse_server_name_rejects_empty_list() {
let body = [0u8, 0];
assert!(parse_server_name(&body).is_err());
}
#[test]
fn parse_server_name_skips_unknown_name_type() {
let mut body = Vec::new();
body.extend_from_slice(&5u16.to_be_bytes());
body.push(99); body.extend_from_slice(&2u16.to_be_bytes());
body.extend_from_slice(b"hi");
assert_eq!(parse_server_name(&body).unwrap(), None);
}
#[test]
fn parse_server_name_rejects_non_utf8() {
let mut body = Vec::new();
body.extend_from_slice(&4u16.to_be_bytes()); body.push(0); body.extend_from_slice(&1u16.to_be_bytes());
body.push(0xFF);
assert!(parse_server_name(&body).is_err());
}
}