parse: add client hello
This commit is contained in:
parent
ca3f548727
commit
3dcb1f3f39
@ -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)?;
|
||||
|
161
src/parse.rs
161
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!()
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
115
src/tls.rs
115
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<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(());
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user