From 3dcb1f3f390b6a7cff9c5f38bff01020b6eb2e26 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 25 Nov 2020 10:33:51 +0800 Subject: [PATCH] parse: add client hello --- src/buffer.rs | 6 +- src/parse.rs | 161 ++++++++++++++++++++++++++++++++++++++++++++-- src/session.rs | 37 ++++++----- src/tls.rs | 115 ++++++++++++++++++++++++--------- src/tls_packet.rs | 52 +++++++++------ 5 files changed, 297 insertions(+), 74 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index 2e9f40d..765331a 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -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)?; diff --git a/src/parse.rs b/src/parse.rs index 0522809..79d6147 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -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!() } }; diff --git a/src/session.rs b/src/session.rs index 02cb704..d5b4f30 100644 --- a/src/session.rs +++ b/src/session.rs @@ -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, @@ -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) { diff --git a/src/tls.rs b/src/tls.rs index 4ce8add..9f642a6 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -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( + &mut self, + sockets: &mut SocketSet, + local_endpoint: T + ) -> Result<()> + where + T: Into + { + // Listen from TCP socket + let mut tcp_socket = sockets.get::(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 { // Handle TLS handshake through TLS states let tls_state = { @@ -130,17 +159,17 @@ impl<'s> TlsSocket<'s> { let mut tcp_socket = sockets.get::(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::(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(()); } diff --git a/src/tls_packet.rs b/src/tls_packet.rs index a688b06..059cae4 100644 --- a/src/tls_packet.rs +++ b/src/tls_packet.rs @@ -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; 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, } @@ -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 {