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_u16(client_hello.version.into())?;
|
||||||
self.write(&client_hello.random)?;
|
self.write(&client_hello.random)?;
|
||||||
self.write_u8(client_hello.session_id_length)?;
|
self.write_u8(client_hello.session_id_length)?;
|
||||||
self.write(&client_hello.session_id)?;
|
self.write(&client_hello.session_id)?;
|
||||||
self.write_u16(client_hello.cipher_suites_length)?;
|
self.write_u16(client_hello.cipher_suites_length)?;
|
||||||
for suite in client_hello.cipher_suites.iter() {
|
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_method_length)?;
|
||||||
self.write_u8(client_hello.compression_methods)?;
|
self.write_u8(client_hello.compression_methods)?;
|
||||||
|
159
src/parse.rs
159
src/parse.rs
@ -164,6 +164,11 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
|
|||||||
{
|
{
|
||||||
use crate::tls_packet::HandshakeType::*;
|
use crate::tls_packet::HandshakeType::*;
|
||||||
match repr.msg_type {
|
match repr.msg_type {
|
||||||
|
ClientHello => {
|
||||||
|
let (rest, data) = parse_client_hello(rest)?;
|
||||||
|
repr.handshake_data = data;
|
||||||
|
Ok((rest, repr))
|
||||||
|
},
|
||||||
ServerHello => {
|
ServerHello => {
|
||||||
let (rest, data) = parse_server_hello(rest)?;
|
let (rest, data) = parse_server_hello(rest)?;
|
||||||
repr.handshake_data = data;
|
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> {
|
fn parse_server_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
|
||||||
let version = take(2_usize);
|
let version = take(2_usize);
|
||||||
let random = take(32_usize);
|
let random = take(32_usize);
|
||||||
@ -508,13 +586,44 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
|
|||||||
// Process extension data according to extension_type
|
// Process extension data according to extension_type
|
||||||
// TODO: Deal with HelloRetryRequest
|
// TODO: Deal with HelloRetryRequest
|
||||||
let (rest, extension_data) = {
|
let (rest, extension_data) = {
|
||||||
// TODO: Handle all mandatory extension types
|
log::info!("extension type: {:?}", extension_type);
|
||||||
|
// TODO: Handle all mandatory extension type
|
||||||
use ExtensionType::*;
|
use ExtensionType::*;
|
||||||
match extension_type {
|
match extension_type {
|
||||||
SupportedVersions => {
|
SupportedVersions => {
|
||||||
match handshake_type {
|
match handshake_type {
|
||||||
HandshakeType::ClientHello => {
|
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 => {
|
HandshakeType::ServerHello => {
|
||||||
let (rest, selected_version) = take(2_usize)(rest)?;
|
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
|
SupportedGroups => { // NamedGroupList
|
||||||
@ -568,7 +677,44 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
|
|||||||
KeyShare => {
|
KeyShare => {
|
||||||
match handshake_type {
|
match handshake_type {
|
||||||
HandshakeType::ClientHello => {
|
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 => {
|
HandshakeType::ServerHello => {
|
||||||
let group = take(2_usize);
|
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))
|
(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
|
// Reset to 0 on rekey AND key exchange
|
||||||
// TODO: Force rekey if sequence number need to wrap (very low priority)
|
// TODO: Force rekey if sequence number need to wrap (very low priority)
|
||||||
client_sequence_number: u64,
|
client_sequence_number: u64,
|
||||||
pub server_sequence_number: u64,
|
pub(crate) server_sequence_number: u64,
|
||||||
// Certificate public key
|
// Certificate public key
|
||||||
// For Handling CertificateVerify
|
// For Handling CertificateVerify
|
||||||
cert_public_key: Option<CertificatePublicKey>,
|
cert_public_key: Option<CertificatePublicKey>,
|
||||||
@ -89,7 +89,7 @@ impl<'a> Session<'a> {
|
|||||||
sha384: Sha384::new(),
|
sha384: Sha384::new(),
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
state: TlsState::START,
|
state: TlsState::DEFAULT,
|
||||||
role,
|
role,
|
||||||
local_endpoint: IpEndpoint::default(),
|
local_endpoint: IpEndpoint::default(),
|
||||||
remote_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(
|
pub(crate) fn connect(
|
||||||
&mut self,
|
&mut self,
|
||||||
remote_endpoint: IpEndpoint,
|
remote_endpoint: IpEndpoint,
|
||||||
local_endpoint: IpEndpoint
|
local_endpoint: IpEndpoint
|
||||||
) {
|
) {
|
||||||
self.role = TlsRole::Client;
|
self.role = TlsRole::Client;
|
||||||
self.state = TlsState::START;
|
self.state = TlsState::CLIENT_START;
|
||||||
self.local_endpoint = local_endpoint;
|
self.local_endpoint = local_endpoint;
|
||||||
self.remote_endpoint = remote_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
|
// State transition from START to WAIT_SH
|
||||||
pub(crate) fn client_update_for_ch(
|
pub(crate) fn client_update_for_ch(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -139,7 +146,7 @@ impl<'a> Session<'a> {
|
|||||||
ch_slice: &[u8]
|
ch_slice: &[u8]
|
||||||
) {
|
) {
|
||||||
// Handle inappropriate call to move state
|
// 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!()
|
todo!()
|
||||||
}
|
}
|
||||||
self.ecdhe_secret = Some((ecdhe_secret, x25519_secret));
|
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());
|
log::info!("client key: {:?}", self.cert_private_key.is_some());
|
||||||
|
|
||||||
// Move to the next state
|
// 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(
|
pub(crate) fn client_update_for_wait_cert_cr(
|
||||||
@ -592,7 +599,7 @@ impl<'a> Session<'a> {
|
|||||||
) {
|
) {
|
||||||
self.hash.update(cert_slice);
|
self.hash.update(cert_slice);
|
||||||
self.cert_public_key.replace(cert_public_key);
|
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(
|
pub(crate) fn client_update_for_wait_cv(
|
||||||
@ -632,7 +639,7 @@ impl<'a> Session<'a> {
|
|||||||
// Usual procedures: update hash
|
// Usual procedures: update hash
|
||||||
self.hash.update(cert_verify_slice);
|
self.hash.update(cert_verify_slice);
|
||||||
// At last, update client state
|
// At last, update client state
|
||||||
self.state = TlsState::WAIT_FINISHED;
|
self.state = TlsState::CLIENT_WAIT_FINISHED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -661,7 +668,7 @@ impl<'a> Session<'a> {
|
|||||||
// Usual procedures: update hash
|
// Usual procedures: update hash
|
||||||
self.hash.update(cert_verify_slice);
|
self.hash.update(cert_verify_slice);
|
||||||
// At last, update client state
|
// At last, update client state
|
||||||
self.state = TlsState::WAIT_FINISHED;
|
self.state = TlsState::CLIENT_WAIT_FINISHED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -760,7 +767,7 @@ impl<'a> Session<'a> {
|
|||||||
self.hash.update(cert_verify_slice);
|
self.hash.update(cert_verify_slice);
|
||||||
|
|
||||||
// At last, update client state
|
// At last, update client state
|
||||||
self.state = TlsState::WAIT_FINISHED;
|
self.state = TlsState::CLIENT_WAIT_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn client_update_for_wait_finished(
|
pub(crate) fn client_update_for_wait_finished(
|
||||||
@ -1112,10 +1119,10 @@ impl<'a> Session<'a> {
|
|||||||
// Hash was updated for key computation
|
// Hash was updated for key computation
|
||||||
|
|
||||||
// At last, update client state
|
// 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,
|
&mut self,
|
||||||
client_certificate_slice: &[u8]
|
client_certificate_slice: &[u8]
|
||||||
)
|
)
|
||||||
@ -1125,7 +1132,7 @@ impl<'a> Session<'a> {
|
|||||||
self.hash.update(client_certificate_slice);
|
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,
|
&mut self,
|
||||||
client_certificate_verify_slice: &[u8]
|
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,
|
&mut self,
|
||||||
client_finished_slice: &[u8]
|
client_finished_slice: &[u8]
|
||||||
)
|
)
|
||||||
@ -1146,7 +1153,7 @@ impl<'a> Session<'a> {
|
|||||||
self.client_sequence_number = 0;
|
self.client_sequence_number = 0;
|
||||||
self.server_sequence_number = 0;
|
self.server_sequence_number = 0;
|
||||||
self.hash.update(client_finished_slice);
|
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 {
|
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 {
|
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) {
|
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)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub(crate) enum TlsState {
|
pub(crate) enum TlsState {
|
||||||
START,
|
DEFAULT, // The default state of the TLS socket
|
||||||
|
// Client state machine diagram
|
||||||
|
CLIENT_START,
|
||||||
WAIT_SH,
|
WAIT_SH,
|
||||||
WAIT_EE,
|
WAIT_EE,
|
||||||
WAIT_CERT_CR,
|
WAIT_CERT_CR,
|
||||||
WAIT_CERT,
|
CLIENT_WAIT_CERT,
|
||||||
WAIT_CV,
|
CLIENT_WAIT_CV,
|
||||||
WAIT_FINISHED,
|
CLIENT_WAIT_FINISHED,
|
||||||
SERVER_CONNECTED, // Additional state, for client to send Finished after server Finished
|
SERVER_COMPLETED, // Additional state, for client to send Finished after server Finished
|
||||||
CONNECTED,
|
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>
|
pub struct TlsSocket<'s>
|
||||||
@ -119,6 +129,25 @@ impl<'s> TlsSocket<'s> {
|
|||||||
Ok(())
|
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> {
|
pub fn update_handshake(&mut self, sockets: &mut SocketSet) -> Result<bool> {
|
||||||
// Handle TLS handshake through TLS states
|
// Handle TLS handshake through TLS states
|
||||||
let tls_state = {
|
let tls_state = {
|
||||||
@ -130,17 +159,17 @@ impl<'s> TlsSocket<'s> {
|
|||||||
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
||||||
let tls_socket = self.session.borrow();
|
let tls_socket = self.session.borrow();
|
||||||
|
|
||||||
// Check if it should connect to client or not
|
// // Check if it should connect to client or not
|
||||||
if tls_socket.get_session_role() != crate::session::TlsRole::Client {
|
// if tls_socket.get_session_role() != crate::session::TlsRole::Client {
|
||||||
// Return true for no need to do anymore handshake
|
// // Return true for no need to do anymore handshake
|
||||||
return Ok(true);
|
// return Ok(true);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Skip handshake processing if it is already completed
|
// Skip handshake processing if it is already completed
|
||||||
// However, redo TCP handshake if TLS socket is trying to connect and
|
// However, redo TCP handshake if TLS socket is trying to connect and
|
||||||
// TCP socket is not connected
|
// TCP socket is not connected
|
||||||
if tcp_socket.state() != TcpState::Established {
|
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
|
// Restart TCP handshake is it is closed for some reason
|
||||||
if !tcp_socket.is_open() {
|
if !tcp_socket.is_open() {
|
||||||
tcp_socket.connect(
|
tcp_socket.connect(
|
||||||
@ -154,14 +183,15 @@ impl<'s> TlsSocket<'s> {
|
|||||||
// after finishing the handshake
|
// after finishing the handshake
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle TLS handshake through TLS states
|
// Handle TLS handshake through TLS states
|
||||||
match tls_state {
|
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
|
// Initiate TLS handshake
|
||||||
TlsState::START => {
|
TlsState::CLIENT_START => {
|
||||||
// Prepare field that is randomised,
|
// Prepare field that is randomised,
|
||||||
// Supply it to the TLS repr builder.
|
// Supply it to the TLS repr builder.
|
||||||
let ecdh_secret = EphemeralSecret::random(&mut self.rng);
|
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
|
// TLS Client wait for server's certificate after receiveing a request
|
||||||
// No need to send anything
|
// No need to send anything
|
||||||
TlsState::WAIT_CERT => {},
|
TlsState::CLIENT_WAIT_CERT => {},
|
||||||
|
|
||||||
// TLS Client wait for server's certificate cerify
|
// TLS Client wait for server's certificate cerify
|
||||||
// No need to send anything
|
// No need to send anything
|
||||||
TlsState::WAIT_CV => {},
|
TlsState::CLIENT_WAIT_CV => {},
|
||||||
|
|
||||||
// Last step of server authentication
|
// Last step of server authentication
|
||||||
// TLS Client wait for server's Finished handshake
|
// TLS Client wait for server's Finished handshake
|
||||||
// No need to send anything
|
// No need to send anything
|
||||||
TlsState::WAIT_FINISHED => {}
|
TlsState::CLIENT_WAIT_FINISHED => {}
|
||||||
|
|
||||||
// Send client Finished to end handshake
|
// Send client Finished to end handshake
|
||||||
// Also send certificate and certificate verify before client Finished if
|
// Also send certificate and certificate verify before client Finished if
|
||||||
// server sent a CertificateRequest beforehand
|
// server sent a CertificateRequest beforehand
|
||||||
TlsState::SERVER_CONNECTED => {
|
TlsState::SERVER_COMPLETED => {
|
||||||
// Certificate & CertificateVerify
|
// Certificate & CertificateVerify
|
||||||
let need_to_send_client_cert = {
|
let need_to_send_client_cert = {
|
||||||
self.session.borrow().need_to_send_client_certificate()
|
self.session.borrow().need_to_send_client_certificate()
|
||||||
@ -307,7 +337,7 @@ impl<'s> TlsSocket<'s> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
self.session.borrow_mut()
|
self.session.borrow_mut()
|
||||||
.client_update_for_certificate_in_server_connected(
|
.client_update_for_certificate_in_server_completed(
|
||||||
&buffer_vec[..(buffer_vec_length-1)]
|
&buffer_vec[..(buffer_vec_length-1)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -361,7 +391,7 @@ impl<'s> TlsSocket<'s> {
|
|||||||
|
|
||||||
{
|
{
|
||||||
self.session.borrow_mut()
|
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)]
|
&verify_buffer_vec[..(cert_verify_len-1)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -387,17 +417,22 @@ impl<'s> TlsSocket<'s> {
|
|||||||
|
|
||||||
let inner_plaintext_length = inner_plaintext.len();
|
let inner_plaintext_length = inner_plaintext.len();
|
||||||
self.session.borrow_mut()
|
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
|
// There is no need to care about handshake if it was completed
|
||||||
TlsState::CONNECTED => {
|
TlsState::CLIENT_CONNECTED => {
|
||||||
return Ok(true);
|
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
|
// Read for TLS packet
|
||||||
// Proposition: Decouple all data from TLS record layer before processing
|
// Proposition: Decouple all data from TLS record layer before processing
|
||||||
// Recouple a brand new TLS record wrapper
|
// Recouple a brand new TLS record wrapper
|
||||||
@ -406,8 +441,16 @@ impl<'s> TlsSocket<'s> {
|
|||||||
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
||||||
tcp_socket.recv(
|
tcp_socket.recv(
|
||||||
|buffer| {
|
|buffer| {
|
||||||
|
// log::info!("Received Buffer: {:?}", buffer);
|
||||||
let buffer_size = buffer.len();
|
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 tls_repr_vec: Vec<(&[u8], TlsRepr)> = Vec::new();
|
||||||
let mut bytes = &buffer[..buffer_size];
|
let mut bytes = &buffer[..buffer_size];
|
||||||
|
|
||||||
@ -766,7 +809,7 @@ impl<'s> TlsSocket<'s> {
|
|||||||
|
|
||||||
// In this stage, server will send a certificate chain
|
// In this stage, server will send a certificate chain
|
||||||
// Verify the certificate
|
// Verify the certificate
|
||||||
TlsState::WAIT_CERT => {
|
TlsState::CLIENT_WAIT_CERT => {
|
||||||
// Verify that it is indeed an Certificate
|
// Verify that it is indeed an Certificate
|
||||||
let might_be_cert = repr.handshake.take().unwrap();
|
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
|
// In this stage, server will eventually send a CertificateVerify
|
||||||
// Verify that the signature is indeed correct
|
// Verify that the signature is indeed correct
|
||||||
TlsState::WAIT_CV => {
|
TlsState::CLIENT_WAIT_CV => {
|
||||||
// Ensure that it is CertificateVerify
|
// Ensure that it is CertificateVerify
|
||||||
let might_be_cert_verify = repr.handshake.take().unwrap();
|
let might_be_cert_verify = repr.handshake.take().unwrap();
|
||||||
if might_be_cert_verify.get_msg_type() != HandshakeType::CertificateVerify {
|
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
|
// Client will receive a Finished handshake from server
|
||||||
TlsState::WAIT_FINISHED => {
|
TlsState::CLIENT_WAIT_FINISHED => {
|
||||||
// Ensure that it is Finished
|
// Ensure that it is Finished
|
||||||
let might_be_server_finished = repr.handshake.take().unwrap();
|
let might_be_server_finished = repr.handshake.take().unwrap();
|
||||||
if might_be_server_finished.get_msg_type() != HandshakeType::Finished {
|
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()
|
might_be_server_finished.get_verify_data().unwrap()
|
||||||
);
|
);
|
||||||
log::info!("Received server FIN");
|
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
|
// If the handshake is not completed, do not pull bytes out of the buffer
|
||||||
// through TlsSocket.recv_slice()
|
// through TlsSocket.recv_slice()
|
||||||
// Handshake recv should be through TCPSocket directly.
|
// 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);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,7 +1063,7 @@ impl<'s> TlsSocket<'s> {
|
|||||||
// through TlsSocket.send_slice()
|
// through TlsSocket.send_slice()
|
||||||
// Handshake send should be through TCPSocket directly.
|
// Handshake send should be through TCPSocket directly.
|
||||||
let mut session = self.session.borrow_mut();
|
let mut session = self.session.borrow_mut();
|
||||||
if session.get_tls_state() != TlsState::CONNECTED {
|
if session.get_tls_state() != TlsState::CLIENT_CONNECTED {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,13 +227,13 @@ pub(crate) enum CipherSuite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct ClientHello<'a> {
|
pub(crate) struct ClientHello {
|
||||||
pub(crate) version: TlsVersion, // Legacy: Must be Tls12 (0x0303)
|
pub(crate) version: TlsVersion, // Legacy: Must be Tls12 (0x0303)
|
||||||
pub(crate) random: [u8; 32],
|
pub(crate) random: [u8; 32],
|
||||||
pub(crate) session_id_length: u8, // Legacy: Keep it 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: [u8; 32], // Legacy: Fill this with an unpredictable value
|
||||||
pub(crate) cipher_suites_length: u16,
|
pub(crate) cipher_suites_length: u16,
|
||||||
pub(crate) cipher_suites: &'a[CipherSuite],
|
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_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) compression_methods: u8, // Legacy: Must be 1 byte of 0
|
||||||
pub(crate) extension_length: u16,
|
pub(crate) extension_length: u16,
|
||||||
@ -243,7 +243,7 @@ pub(crate) struct ClientHello<'a> {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum HandshakeData<'a> {
|
pub(crate) enum HandshakeData<'a> {
|
||||||
Uninitialized,
|
Uninitialized,
|
||||||
ClientHello(ClientHello<'a>),
|
ClientHello(ClientHello),
|
||||||
ServerHello(ServerHello<'a>),
|
ServerHello(ServerHello<'a>),
|
||||||
EncryptedExtensions(EncryptedExtensions),
|
EncryptedExtensions(EncryptedExtensions),
|
||||||
Certificate(Certificate<'a>),
|
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 {
|
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 {
|
let mut client_hello = ClientHello {
|
||||||
version: TlsVersion::Tls12,
|
version: TlsVersion::Tls12,
|
||||||
@ -270,18 +270,24 @@ impl<'a> ClientHello<'a> {
|
|||||||
session_id_length: 32,
|
session_id_length: 32,
|
||||||
session_id,
|
session_id,
|
||||||
cipher_suites_length: 0,
|
cipher_suites_length: 0,
|
||||||
cipher_suites: &[
|
cipher_suites: [
|
||||||
CipherSuite::TLS_AES_128_GCM_SHA256,
|
Some(CipherSuite::TLS_AES_128_GCM_SHA256),
|
||||||
CipherSuite::TLS_AES_256_GCM_SHA384,
|
Some(CipherSuite::TLS_AES_256_GCM_SHA384),
|
||||||
CipherSuite::TLS_CHACHA20_POLY1305_SHA256,
|
Some(CipherSuite::TLS_CHACHA20_POLY1305_SHA256),
|
||||||
CipherSuite::TLS_AES_128_CCM_SHA256,
|
Some(CipherSuite::TLS_AES_128_CCM_SHA256),
|
||||||
|
None
|
||||||
],
|
],
|
||||||
compression_method_length: 1,
|
compression_method_length: 1,
|
||||||
compression_methods: 0,
|
compression_methods: 0,
|
||||||
extension_length: 0,
|
extension_length: 0,
|
||||||
extensions: Vec::new(),
|
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()
|
client_hello.add_ch_supported_versions()
|
||||||
.add_sig_algs()
|
.add_sig_algs()
|
||||||
@ -462,7 +468,7 @@ impl<'a> ClientHello<'a> {
|
|||||||
length += 1; // Legacy session_id length size
|
length += 1; // Legacy session_id length size
|
||||||
length += 32; // Legacy session_id size
|
length += 32; // Legacy session_id size
|
||||||
length += 2; // Cipher_suites_length size
|
length += 2; // Cipher_suites_length size
|
||||||
length += self.cipher_suites.len() * 2;
|
length += usize::try_from(self.cipher_suites_length).unwrap();
|
||||||
length += 1;
|
length += 1;
|
||||||
length += 1;
|
length += 1;
|
||||||
length += 2;
|
length += 2;
|
||||||
@ -514,6 +520,9 @@ pub(crate) enum ExtensionType {
|
|||||||
PostHandshakeAuth = 49,
|
PostHandshakeAuth = 49,
|
||||||
SignatureAlgorithmsCert = 50,
|
SignatureAlgorithmsCert = 50,
|
||||||
KeyShare = 51,
|
KeyShare = 51,
|
||||||
|
|
||||||
|
#[num_enum(default)]
|
||||||
|
Unknown = 0xFFFF,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionType {
|
impl ExtensionType {
|
||||||
@ -544,6 +553,7 @@ pub(crate) enum ExtensionData {
|
|||||||
NegotiatedGroups(NamedGroupList),
|
NegotiatedGroups(NamedGroupList),
|
||||||
KeyShareEntry(KeyShareEntryContent),
|
KeyShareEntry(KeyShareEntryContent),
|
||||||
ServerName(ServerName),
|
ServerName(ServerName),
|
||||||
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionData {
|
impl ExtensionData {
|
||||||
|
Loading…
Reference in New Issue
Block a user