parse: add client hello

master
occheung 2020-11-25 10:33:51 +08:00
parent ca3f548727
commit 3dcb1f3f39
5 changed files with 297 additions and 74 deletions

View File

@ -86,14 +86,16 @@ impl<'a> TlsBuffer<'a> {
}
}
fn enqueue_client_hello(&mut self, client_hello: ClientHello<'a>) -> Result<()> {
fn enqueue_client_hello(&mut self, client_hello: ClientHello) -> Result<()> {
self.write_u16(client_hello.version.into())?;
self.write(&client_hello.random)?;
self.write_u8(client_hello.session_id_length)?;
self.write(&client_hello.session_id)?;
self.write_u16(client_hello.cipher_suites_length)?;
for suite in client_hello.cipher_suites.iter() {
self.write_u16((*suite).into())?;
if let Some(cipher_suite) = suite {
self.write_u16((*cipher_suite).into())?;
}
}
self.write_u8(client_hello.compression_method_length)?;
self.write_u8(client_hello.compression_methods)?;

View File

@ -164,6 +164,11 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
{
use crate::tls_packet::HandshakeType::*;
match repr.msg_type {
ClientHello => {
let (rest, data) = parse_client_hello(rest)?;
repr.handshake_data = data;
Ok((rest, repr))
},
ServerHello => {
let (rest, data) = parse_server_hello(rest)?;
repr.handshake_data = data;
@ -233,6 +238,79 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
}
}
fn parse_client_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
let version = take(2_usize);
let random = take(32_usize);
let session_id_length = take(1_usize);
let (rest, (version, random, session_id_length)) = tuple((
version, random, session_id_length
))(bytes)?;
let session_id_length = session_id_length[0];
let (rest, session_id) = take(session_id_length)(rest)?;
let (mut rest, cipher_suites_length) = take(2_usize)(rest)?;
let cipher_suites_length = NetworkEndian::read_u16(cipher_suites_length);
let mut cipher_suites: [_; 5] = [None; 5];
let mut index = 0;
// Read cipher suites
// Only 5 of them are supported in terms of enum availability
// AES_CCM_8 is not an acceptable cipher suite, but can still be recorded
for _ in 0..(cipher_suites_length/2) {
let (rem, cipher_suite) = take(2_usize)(rest)?;
if let Ok(cipher_suite) = CipherSuite::try_from(
NetworkEndian::read_u16(cipher_suite)
) {
cipher_suites[index] = Some(cipher_suite);
index += 1;
}
rest = rem;
}
let (rest, compression_method_length) = take(1_usize)(rest)?;
let compression_method_length = compression_method_length[0];
// Can only have compression method being NULL (1 byte of 0)
let (rest, compression_methods) = take(compression_method_length)(rest)?;
if compression_methods != &[0] {
return Err(nom::Err::Failure((&bytes, ErrorKind::Verify)));
}
let (mut rest, extension_length) = take(2_usize)(rest)?;
let mut extension_length = NetworkEndian::read_u16(extension_length);
let mut client_hello = ClientHello {
version: TlsVersion::try_from(NetworkEndian::read_u16(version)).unwrap(),
random: [0; 32],
session_id_length,
session_id: [0; 32],
cipher_suites_length,
cipher_suites,
compression_method_length,
compression_methods: 0,
extension_length,
extensions: Vec::new(),
};
client_hello.random.clone_from_slice(&random);
&mut client_hello.session_id[
32-(usize::try_from(session_id_length).unwrap())..
].clone_from_slice(&session_id);
while extension_length > 0 {
let (rem, extension) = parse_extension(rest, HandshakeType::ClientHello)?;
rest = rem;
extension_length -= u16::try_from(extension.get_length()).unwrap();
client_hello.extensions.push(extension);
}
Ok((rest, HandshakeData::ClientHello(client_hello)))
}
fn parse_server_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
let version = take(2_usize);
let random = take(32_usize);
@ -493,7 +571,7 @@ fn parse_finished(bytes: &[u8]) -> IResult<&[u8], Finished> {
))
}
fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> {
fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> {
let extension_type = take(2_usize);
let length = take(2_usize);
@ -508,13 +586,44 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
// Process extension data according to extension_type
// TODO: Deal with HelloRetryRequest
let (rest, extension_data) = {
// TODO: Handle all mandatory extension types
log::info!("extension type: {:?}", extension_type);
// TODO: Handle all mandatory extension type
use ExtensionType::*;
match extension_type {
SupportedVersions => {
match handshake_type {
HandshakeType::ClientHello => {
todo!()
let (rest, versions_length) = take(1_usize)(rest)?;
let versions_length = versions_length[0];
let (rest, mut versions_slice) = take(versions_length)(rest)?;
let mut versions = Vec::new();
while versions_slice.len() != 0 {
let (rem, version) = take(2_usize)(versions_slice)?;
let tls_version = TlsVersion::try_from(
NetworkEndian::read_u16(version)
).unwrap();
if tls_version != TlsVersion::Unknown {
versions.push(tls_version);
}
versions_slice = rem;
}
let client_supported_versions = ExtensionData::SupportedVersions(
crate::tls_packet::SupportedVersions::ClientHello {
length: versions_length,
versions,
}
);
(
rest,
client_supported_versions
)
},
HandshakeType::ServerHello => {
let (rest, selected_version) = take(2_usize)(rest)?;
@ -530,7 +639,7 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
)
)
},
_ => todo!()
_ => unreachable!()
}
},
SupportedGroups => { // NamedGroupList
@ -568,7 +677,44 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
KeyShare => {
match handshake_type {
HandshakeType::ClientHello => {
todo!()
let (rest, length) = take(2_usize)(rest)?;
let length = NetworkEndian::read_u16(length);
let (rest, mut keyshares) = take(length)(rest)?;
let mut client_shares = Vec::new();
// Read all keyshares
while keyshares.len() != 0 {
let group = take(2_usize);
let length = take(2_usize);
let (rem, (group, length)) = tuple((
group, length
))(keyshares)?;
let mut key_share_entry = KeyShareEntry {
group: NamedGroup::try_from(
NetworkEndian::read_u16(group)
).unwrap(),
length: NetworkEndian::read_u16(length),
key_exchange: Vec::new()
};
let (rem, key_exchange_slice) = take(
key_share_entry.length
)(rem)?;
key_share_entry.key_exchange.extend_from_slice(key_exchange_slice);
client_shares.push(key_share_entry);
keyshares = rem;
}
let key_share_ch = crate::tls_packet::KeyShareEntryContent::KeyShareClientHello {
length,
client_shares
};
(rest, ExtensionData::KeyShareEntry(key_share_ch))
},
HandshakeType::ServerHello => {
let group = take(2_usize);
@ -625,8 +771,11 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
};
(rest, ExtensionData::SignatureAlgorithms(signature_scheme_list))
},
_ => {
let (rest, _) = take(length)(rest)?;
(rest, ExtensionData::Unsupported)
}
_ => todo!()
}
};

View File

@ -68,7 +68,7 @@ pub(crate) struct Session<'a> {
// Reset to 0 on rekey AND key exchange
// TODO: Force rekey if sequence number need to wrap (very low priority)
client_sequence_number: u64,
pub server_sequence_number: u64,
pub(crate) server_sequence_number: u64,
// Certificate public key
// For Handling CertificateVerify
cert_public_key: Option<CertificatePublicKey>,
@ -89,7 +89,7 @@ impl<'a> Session<'a> {
sha384: Sha384::new(),
};
Self {
state: TlsState::START,
state: TlsState::DEFAULT,
role,
local_endpoint: IpEndpoint::default(),
remote_endpoint: IpEndpoint::default(),
@ -119,17 +119,24 @@ impl<'a> Session<'a> {
}
}
// Store the local endpoints for retry TCP handshake
// TCP socket will reset endpoints on RST
pub(crate) fn connect(
&mut self,
remote_endpoint: IpEndpoint,
local_endpoint: IpEndpoint
) {
self.role = TlsRole::Client;
self.state = TlsState::START;
self.state = TlsState::CLIENT_START;
self.local_endpoint = local_endpoint;
self.remote_endpoint = remote_endpoint;
}
pub(crate) fn listen(&mut self) {
self.role = TlsRole::Server;
self.state = TlsState::SERVER_START;
}
// State transition from START to WAIT_SH
pub(crate) fn client_update_for_ch(
&mut self,
@ -139,7 +146,7 @@ impl<'a> Session<'a> {
ch_slice: &[u8]
) {
// Handle inappropriate call to move state
if self.state != TlsState::START || self.role != TlsRole::Client {
if self.state != TlsState::CLIENT_START || self.role != TlsRole::Client {
todo!()
}
self.ecdhe_secret = Some((ecdhe_secret, x25519_secret));
@ -582,7 +589,7 @@ impl<'a> Session<'a> {
log::info!("client key: {:?}", self.cert_private_key.is_some());
// Move to the next state
self.state = TlsState::WAIT_CERT;
self.state = TlsState::CLIENT_WAIT_CERT;
}
pub(crate) fn client_update_for_wait_cert_cr(
@ -592,7 +599,7 @@ impl<'a> Session<'a> {
) {
self.hash.update(cert_slice);
self.cert_public_key.replace(cert_public_key);
self.state = TlsState::WAIT_CV;
self.state = TlsState::CLIENT_WAIT_CV;
}
pub(crate) fn client_update_for_wait_cv(
@ -632,7 +639,7 @@ impl<'a> Session<'a> {
// Usual procedures: update hash
self.hash.update(cert_verify_slice);
// At last, update client state
self.state = TlsState::WAIT_FINISHED;
self.state = TlsState::CLIENT_WAIT_FINISHED;
return;
}
@ -661,7 +668,7 @@ impl<'a> Session<'a> {
// Usual procedures: update hash
self.hash.update(cert_verify_slice);
// At last, update client state
self.state = TlsState::WAIT_FINISHED;
self.state = TlsState::CLIENT_WAIT_FINISHED;
return;
}
@ -760,7 +767,7 @@ impl<'a> Session<'a> {
self.hash.update(cert_verify_slice);
// At last, update client state
self.state = TlsState::WAIT_FINISHED;
self.state = TlsState::CLIENT_WAIT_FINISHED;
}
pub(crate) fn client_update_for_wait_finished(
@ -1112,10 +1119,10 @@ impl<'a> Session<'a> {
// Hash was updated for key computation
// At last, update client state
self.state = TlsState::SERVER_CONNECTED;
self.state = TlsState::SERVER_COMPLETED;
}
pub(crate) fn client_update_for_certificate_in_server_connected(
pub(crate) fn client_update_for_certificate_in_server_completed(
&mut self,
client_certificate_slice: &[u8]
)
@ -1125,7 +1132,7 @@ impl<'a> Session<'a> {
self.hash.update(client_certificate_slice);
}
pub(crate) fn client_update_for_cert_verify_in_server_connected(
pub(crate) fn client_update_for_cert_verify_in_server_completed(
&mut self,
client_certificate_verify_slice: &[u8]
)
@ -1136,7 +1143,7 @@ impl<'a> Session<'a> {
}
pub(crate) fn client_update_for_server_connected(
pub(crate) fn client_update_for_server_completed(
&mut self,
client_finished_slice: &[u8]
)
@ -1146,7 +1153,7 @@ impl<'a> Session<'a> {
self.client_sequence_number = 0;
self.server_sequence_number = 0;
self.hash.update(client_finished_slice);
self.state = TlsState::CONNECTED;
self.state = TlsState::CLIENT_CONNECTED;
}
pub(crate) fn verify_session_id_echo(&self, session_id_echo: &[u8]) -> bool {
@ -1170,7 +1177,7 @@ impl<'a> Session<'a> {
}
pub(crate) fn has_completed_handshake(&self) -> bool {
self.state == TlsState::CONNECTED
self.state == TlsState::CLIENT_CONNECTED
}
pub(crate) fn receive_change_cipher_spec(&mut self) {

View File

@ -36,15 +36,25 @@ use crate::session::{Session, TlsRole};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[allow(non_camel_case_types)]
pub(crate) enum TlsState {
START,
DEFAULT, // The default state of the TLS socket
// Client state machine diagram
CLIENT_START,
WAIT_SH,
WAIT_EE,
WAIT_CERT_CR,
WAIT_CERT,
WAIT_CV,
WAIT_FINISHED,
SERVER_CONNECTED, // Additional state, for client to send Finished after server Finished
CONNECTED,
CLIENT_WAIT_CERT,
CLIENT_WAIT_CV,
CLIENT_WAIT_FINISHED,
SERVER_COMPLETED, // Additional state, for client to send Finished after server Finished
CLIENT_CONNECTED,
// Server state machine diagram
SERVER_START,
NEGOTIATED,
WAIT_FLIGHT,
SERVER_WAIT_CERT,
SERVER_WAIT_CV,
SERVER_WAIT_FINISHED,
SERVER_CONNECTED,
}
pub struct TlsSocket<'s>
@ -119,6 +129,25 @@ impl<'s> TlsSocket<'s> {
Ok(())
}
pub fn listen<T>(
&mut self,
sockets: &mut SocketSet,
local_endpoint: T
) -> Result<()>
where
T: Into<IpEndpoint>
{
// Listen from TCP socket
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
tcp_socket.listen(local_endpoint)?;
// Update tls session to server_start
let mut session = self.session.borrow_mut();
session.listen();
Ok(())
}
pub fn update_handshake(&mut self, sockets: &mut SocketSet) -> Result<bool> {
// Handle TLS handshake through TLS states
let tls_state = {
@ -130,17 +159,17 @@ impl<'s> TlsSocket<'s> {
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
let tls_socket = self.session.borrow();
// Check if it should connect to client or not
if tls_socket.get_session_role() != crate::session::TlsRole::Client {
// Return true for no need to do anymore handshake
return Ok(true);
}
// // Check if it should connect to client or not
// if tls_socket.get_session_role() != crate::session::TlsRole::Client {
// // Return true for no need to do anymore handshake
// return Ok(true);
// }
// Skip handshake processing if it is already completed
// However, redo TCP handshake if TLS socket is trying to connect and
// TCP socket is not connected
if tcp_socket.state() != TcpState::Established {
if tls_state == TlsState::START {
if tls_state == TlsState::CLIENT_START {
// Restart TCP handshake is it is closed for some reason
if !tcp_socket.is_open() {
tcp_socket.connect(
@ -154,14 +183,15 @@ impl<'s> TlsSocket<'s> {
// after finishing the handshake
return Ok(false);
}
}
}
// Handle TLS handshake through TLS states
match tls_state {
// Do nothing on the default state
// Socket has not been assigned to be a client or server
TlsState::DEFAULT => {},
// Initiate TLS handshake
TlsState::START => {
TlsState::CLIENT_START => {
// Prepare field that is randomised,
// Supply it to the TLS repr builder.
let ecdh_secret = EphemeralSecret::random(&mut self.rng);
@ -219,21 +249,21 @@ impl<'s> TlsSocket<'s> {
// TLS Client wait for server's certificate after receiveing a request
// No need to send anything
TlsState::WAIT_CERT => {},
TlsState::CLIENT_WAIT_CERT => {},
// TLS Client wait for server's certificate cerify
// No need to send anything
TlsState::WAIT_CV => {},
TlsState::CLIENT_WAIT_CV => {},
// Last step of server authentication
// TLS Client wait for server's Finished handshake
// No need to send anything
TlsState::WAIT_FINISHED => {}
TlsState::CLIENT_WAIT_FINISHED => {}
// Send client Finished to end handshake
// Also send certificate and certificate verify before client Finished if
// server sent a CertificateRequest beforehand
TlsState::SERVER_CONNECTED => {
TlsState::SERVER_COMPLETED => {
// Certificate & CertificateVerify
let need_to_send_client_cert = {
self.session.borrow().need_to_send_client_certificate()
@ -307,7 +337,7 @@ impl<'s> TlsSocket<'s> {
{
self.session.borrow_mut()
.client_update_for_certificate_in_server_connected(
.client_update_for_certificate_in_server_completed(
&buffer_vec[..(buffer_vec_length-1)]
);
}
@ -361,7 +391,7 @@ impl<'s> TlsSocket<'s> {
{
self.session.borrow_mut()
.client_update_for_cert_verify_in_server_connected(
.client_update_for_cert_verify_in_server_completed(
&verify_buffer_vec[..(cert_verify_len-1)]
);
}
@ -387,17 +417,22 @@ impl<'s> TlsSocket<'s> {
let inner_plaintext_length = inner_plaintext.len();
self.session.borrow_mut()
.client_update_for_server_connected(&inner_plaintext[..(inner_plaintext_length-1)]);
.client_update_for_server_completed(&inner_plaintext[..(inner_plaintext_length-1)]);
}
// There is no need to care about handshake if it was completed
TlsState::CONNECTED => {
TlsState::CLIENT_CONNECTED => {
return Ok(true);
}
// This state waits for Client Hello handshake from a client
// There is nothing to send
TlsState::SERVER_START => {}
// Other states regarding server role
_ => {}
}
// Read for TLS packet
// Proposition: Decouple all data from TLS record layer before processing
// Recouple a brand new TLS record wrapper
@ -406,7 +441,15 @@ impl<'s> TlsSocket<'s> {
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
tcp_socket.recv(
|buffer| {
// log::info!("Received Buffer: {:?}", buffer);
let buffer_size = buffer.len();
// Provide a way to end the process early
if buffer_size == 0 {
return (0, ())
}
log::info!("Received something");
let mut tls_repr_vec: Vec<(&[u8], TlsRepr)> = Vec::new();
let mut bytes = &buffer[..buffer_size];
@ -766,7 +809,7 @@ impl<'s> TlsSocket<'s> {
// In this stage, server will send a certificate chain
// Verify the certificate
TlsState::WAIT_CERT => {
TlsState::CLIENT_WAIT_CERT => {
// Verify that it is indeed an Certificate
let might_be_cert = repr.handshake.take().unwrap();
@ -807,7 +850,7 @@ impl<'s> TlsSocket<'s> {
// In this stage, server will eventually send a CertificateVerify
// Verify that the signature is indeed correct
TlsState::WAIT_CV => {
TlsState::CLIENT_WAIT_CV => {
// Ensure that it is CertificateVerify
let might_be_cert_verify = repr.handshake.take().unwrap();
if might_be_cert_verify.get_msg_type() != HandshakeType::CertificateVerify {
@ -837,7 +880,7 @@ impl<'s> TlsSocket<'s> {
},
// Client will receive a Finished handshake from server
TlsState::WAIT_FINISHED => {
TlsState::CLIENT_WAIT_FINISHED => {
// Ensure that it is Finished
let might_be_server_finished = repr.handshake.take().unwrap();
if might_be_server_finished.get_msg_type() != HandshakeType::Finished {
@ -861,6 +904,18 @@ impl<'s> TlsSocket<'s> {
might_be_server_finished.get_verify_data().unwrap()
);
log::info!("Received server FIN");
},
// Server will reveice a Client Hello initiating the TLS handshake
TlsState::SERVER_START => {
// Ensure that is a Client Hello
let might_be_client_hello = repr.handshake.take().unwrap();
if might_be_client_hello.get_msg_type() != HandshakeType::ClientHello {
// Throw alert
todo!()
}
log::info!("Received client hello");
}
_ => {},
@ -925,7 +980,7 @@ impl<'s> TlsSocket<'s> {
// If the handshake is not completed, do not pull bytes out of the buffer
// through TlsSocket.recv_slice()
// Handshake recv should be through TCPSocket directly.
if session.get_tls_state() != TlsState::CONNECTED {
if session.get_tls_state() != TlsState::CLIENT_CONNECTED {
return Ok(0);
}
@ -1008,7 +1063,7 @@ impl<'s> TlsSocket<'s> {
// through TlsSocket.send_slice()
// Handshake send should be through TCPSocket directly.
let mut session = self.session.borrow_mut();
if session.get_tls_state() != TlsState::CONNECTED {
if session.get_tls_state() != TlsState::CLIENT_CONNECTED {
return Ok(());
}

View File

@ -227,15 +227,15 @@ pub(crate) enum CipherSuite {
}
#[derive(Debug, Clone)]
pub(crate) struct ClientHello<'a> {
pub(crate) version: TlsVersion, // Legacy: Must be Tls12 (0x0303)
pub(crate) struct ClientHello {
pub(crate) version: TlsVersion, // Legacy: Must be Tls12 (0x0303)
pub(crate) random: [u8; 32],
pub(crate) session_id_length: u8, // Legacy: Keep it 32
pub(crate) session_id: [u8; 32], // Legacy: Fill this with an unpredictable value
pub(crate) session_id_length: u8, // Legacy: Keep it 32
pub(crate) session_id: [u8; 32], // Legacy: Fill this with an unpredictable value
pub(crate) cipher_suites_length: u16,
pub(crate) cipher_suites: &'a[CipherSuite],
pub(crate) compression_method_length: u8, // Legacy: Must be 1, to contain a byte
pub(crate) compression_methods: u8, // Legacy: Must be 1 byte of 0
pub(crate) cipher_suites: [Option<CipherSuite>; 5], // Will only realistically support 5 cipher suites
pub(crate) compression_method_length: u8, // Legacy: Must be 1, to contain a byte
pub(crate) compression_methods: u8, // Legacy: Must be 1 byte of 0
pub(crate) extension_length: u16,
pub(crate) extensions: Vec<Extension>,
}
@ -243,7 +243,7 @@ pub(crate) struct ClientHello<'a> {
#[derive(Debug, Clone)]
pub(crate) enum HandshakeData<'a> {
Uninitialized,
ClientHello(ClientHello<'a>),
ClientHello(ClientHello),
ServerHello(ServerHello<'a>),
EncryptedExtensions(EncryptedExtensions),
Certificate(Certificate<'a>),
@ -262,7 +262,7 @@ impl<'a> HandshakeData<'a> {
}
}
impl<'a> ClientHello<'a> {
impl ClientHello {
pub(self) fn new(p256_secret: &EphemeralSecret, x25519_secret: &x25519_dalek::EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self {
let mut client_hello = ClientHello {
version: TlsVersion::Tls12,
@ -270,18 +270,24 @@ impl<'a> ClientHello<'a> {
session_id_length: 32,
session_id,
cipher_suites_length: 0,
cipher_suites: &[
CipherSuite::TLS_AES_128_GCM_SHA256,
CipherSuite::TLS_AES_256_GCM_SHA384,
CipherSuite::TLS_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_AES_128_CCM_SHA256,
cipher_suites: [
Some(CipherSuite::TLS_AES_128_GCM_SHA256),
Some(CipherSuite::TLS_AES_256_GCM_SHA384),
Some(CipherSuite::TLS_CHACHA20_POLY1305_SHA256),
Some(CipherSuite::TLS_AES_128_CCM_SHA256),
None
],
compression_method_length: 1,
compression_methods: 0,
extension_length: 0,
extensions: Vec::new(),
};
client_hello.cipher_suites_length = u16::try_from(client_hello.cipher_suites.len() * 2).unwrap();
for suite_option in client_hello.cipher_suites.iter() {
if suite_option.is_some() {
client_hello.cipher_suites_length += 2;
}
}
client_hello.add_ch_supported_versions()
.add_sig_algs()
@ -457,12 +463,12 @@ impl<'a> ClientHello<'a> {
}
pub(crate) fn get_length(&self) -> usize {
let mut length: usize = 2; // TlsVersion size
length += 32; // Random size
length += 1; // Legacy session_id length size
length += 32; // Legacy session_id size
length += 2; // Cipher_suites_length size
length += self.cipher_suites.len() * 2;
let mut length: usize = 2; // TlsVersion size
length += 32; // Random size
length += 1; // Legacy session_id length size
length += 32; // Legacy session_id size
length += 2; // Cipher_suites_length size
length += usize::try_from(self.cipher_suites_length).unwrap();
length += 1;
length += 1;
length += 2;
@ -514,6 +520,9 @@ pub(crate) enum ExtensionType {
PostHandshakeAuth = 49,
SignatureAlgorithmsCert = 50,
KeyShare = 51,
#[num_enum(default)]
Unknown = 0xFFFF,
}
impl ExtensionType {
@ -544,6 +553,7 @@ pub(crate) enum ExtensionData {
NegotiatedGroups(NamedGroupList),
KeyShareEntry(KeyShareEntryContent),
ServerName(ServerName),
Unsupported,
}
impl ExtensionData {