diff --git a/src/session.rs b/src/session.rs index bf36d17..9e9bade 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1198,6 +1198,14 @@ impl<'a> Session<'a> { self.state = TlsState::NEGOTIATED; } + pub(crate) fn server_update_for_server_hello( + &mut self, + server_ecdhe_secret: DiffieHellmanPrivateKey, + server_hello_slice: &[u8] + ) { + todo!() + } + pub(crate) fn verify_session_id_echo(&self, session_id_echo: &[u8]) -> bool { if let Some(session_id_inner) = self.session_id { session_id_inner == session_id_echo @@ -1206,6 +1214,30 @@ impl<'a> Session<'a> { } } + pub(crate) fn get_session_id(&self) -> &[u8] { + if let Some(session_id) = &self.session_id { + session_id + } else { + unreachable!() + } + } + + pub(crate) fn get_cipher_suite(&self) -> CipherSuite { + if let Some(cipher_suite) = self.server_selected_cipher { + cipher_suite + } else { + unreachable!() + } + } + + pub(crate) fn get_server_ecdhe_public_key(&self) -> DiffieHellmanPublicKey { + if let Some(server_ecdhe_public_key) = self.ecdhe_public { + server_ecdhe_public_key + } else { + unreachable!() + } + } + pub(crate) fn get_tls_state(&self) -> TlsState { self.state } @@ -1963,6 +1995,7 @@ pub enum CertificatePrivateKey { } } +#[derive(Debug, Clone, Copy)] pub enum DiffieHellmanPublicKey { SECP256R1 { encoded_point: p256::EncodedPoint @@ -1971,3 +2004,12 @@ pub enum DiffieHellmanPublicKey { public_key: x25519_dalek::PublicKey } } + +pub enum DiffieHellmanPrivateKey { + SECP256R1 { + ephemeral_secret: p256::ecdh::EphemeralSecret + }, + X25519 { + ephemeral_secret: x25519_dalek::EphemeralSecret + } +} diff --git a/src/tls.rs b/src/tls.rs index 9625f3a..6793153 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -429,6 +429,50 @@ impl<'s> TlsSocket<'s> { // There is nothing to send TlsState::SERVER_START => {} + // Respond to a Client Hello initiation with: + // - Server Hello + // - Encrypted Extensions + // - (Possible) Certificate Request + // - Certificate + // - CertificateVerify + // - Finished + TlsState::NEGOTIATED => { + let mut session = self.session.borrow_mut(); + let mut random: [u8; 32] = [0; 32]; + self.rng.fill_bytes(&mut random); + // Relay session id + let session_id = session.get_session_id(); + let cipher_suite = session.get_cipher_suite(); + let ecdhe_key = session.get_server_ecdhe_public_key(); + + let repr = TlsRepr::new().server_hello( + &random, + session_id, + cipher_suite, + ecdhe_key + ); + + { + let mut tcp_socket = sockets.get::(self.tcp_handle); + tcp_socket.send( + |data| { + // Enqueue the TLS representation + let mut buffer = TlsBuffer::new(data); + if buffer.enqueue_tls_repr(repr).is_err() { + return (0, ()) + } + let slice: &[u8] = buffer.into(); + + // Update session + todo!(); + + // Send the data + (slice.len(), ()) + } + )?; + } + } + // Other states regarding server role _ => {} } diff --git a/src/tls_packet.rs b/src/tls_packet.rs index 059cae4..a5caa97 100644 --- a/src/tls_packet.rs +++ b/src/tls_packet.rs @@ -9,6 +9,7 @@ use core::convert::TryInto; use alloc::vec::Vec; use crate::certificate::Certificate as Asn1DerCertificate; +use crate::session::DiffieHellmanPublicKey; pub(crate) const HRR_RANDOM: [u8; 32] = [ 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, @@ -59,7 +60,13 @@ impl<'a> TlsRepr<'a> { } } - pub(crate) fn client_hello(mut self, p256_secret: &EphemeralSecret, x25519_secret: &x25519_dalek::EphemeralSecret, random: [u8; 32], session_id: [u8; 32]) -> Self { + pub(crate) fn client_hello( + mut self, + p256_secret: &EphemeralSecret, + x25519_secret: &x25519_dalek::EphemeralSecret, + random: [u8; 32], + session_id: [u8; 32] + ) -> Self { self.content_type = TlsContentType::Handshake; self.version = TlsVersion::Tls10; let handshake_repr = { @@ -76,6 +83,35 @@ impl<'a> TlsRepr<'a> { self } + pub(crate) fn server_hello( + mut self, + random: &'a [u8], + session_id: &'a [u8], + cipher_suite: CipherSuite, + server_ecdhe_public_key: DiffieHellmanPublicKey + ) -> Self { + self.content_type = TlsContentType::Handshake; + self.version = TlsVersion::Tls12; + let handshake_repr = { + let mut repr = HandshakeRepr::new(); + repr.msg_type = HandshakeType::ServerHello; + repr.handshake_data = HandshakeData::ServerHello( + { + ServerHello::new( + random, + session_id, + cipher_suite, + server_ecdhe_public_key + ) + } + ); + repr + }; + self.length = handshake_repr.get_length(); + self.handshake = Some(handshake_repr); + self + } + // TODO: Consider replace all these boolean function // into a single function that returns the HandshakeType. pub(crate) fn is_server_hello(&self) -> bool { @@ -256,7 +292,7 @@ impl<'a> HandshakeData<'a> { pub(crate) fn get_length(&self) -> usize { match self { HandshakeData::ClientHello(data) => data.get_length(), - HandshakeData::ServerHello(_data) => todo!(), + HandshakeData::ServerHello(data) => data.get_length(), _ => 0, } } @@ -489,6 +525,121 @@ pub(crate) struct ServerHello<'a> { pub(crate) extensions: Vec, } +impl<'a> ServerHello<'a> { + pub(crate) fn new( + random: &'a[u8], + session_id_echo: &'a[u8], + cipher_suite: CipherSuite, + server_ecdhe_public_key: DiffieHellmanPublicKey, + ) -> Self { + let server_hello = Self { + version: TlsVersion::Tls12, + random, + session_id_echo_length: 32, + session_id_echo, + cipher_suite, + compression_method: 0, + extension_length: 0, + extensions: Vec::new() + }; + + server_hello.add_sh_supported_versions() + .add_key_share(server_ecdhe_public_key) + .finalise() + } + + pub(crate) fn add_sh_supported_versions(mut self) -> Self { + let supported_version_server_hello = SupportedVersions::ServerHello { + selected_version: TlsVersion::Tls13 + }; + let extension_data = ExtensionData::SupportedVersions( + supported_version_server_hello + ); + let extension = Extension { + extension_type: ExtensionType::SupportedVersions, + length: 2, + extension_data + }; + + // Push the extension into the vector + self.extensions.push(extension); + self + } + + pub(crate) fn add_key_share( + mut self, + server_ecdh_public_key: DiffieHellmanPublicKey + ) -> Self { + let mut key_exchange: Vec = Vec::new(); + use DiffieHellmanPublicKey::*; + let group = match server_ecdh_public_key { + SECP256R1 { encoded_point } => { + // Convert EncodedPoint into untagged bytes + // In the format of x || y + // Then put 0x04 before the bytes ( 0x04 || x || y ) + key_exchange.push(0x04); + key_exchange.extend_from_slice( + &encoded_point.to_untagged_bytes().unwrap() + ); + NamedGroup::secp256r1 + }, + X25519 { public_key } => { + key_exchange.extend_from_slice( + public_key.as_bytes() + ); + NamedGroup::x25519 + } + }; + + let length = u16::try_from(key_exchange.len()).unwrap(); + + let server_share = KeyShareEntry { + group, + length, + key_exchange + }; + + let key_share_entry_content = KeyShareEntryContent::KeyShareServerHello { + server_share + }; + + let extension_data = ExtensionData::KeyShareEntry( + key_share_entry_content + ); + + let extension = Extension { + extension_type: ExtensionType::KeyShare, + length: length + 2 + 2, // 4 bytes precedes key_exchange, length(2) and group(2) + extension_data + }; + + self.extensions.push(extension); + self + } + + pub(crate) fn finalise(mut self) -> Self { + let mut sum = 0; + for extension in self.extensions.iter() { + // TODO: Add up the extension length + sum += extension.get_length(); + } + self.extension_length = sum.try_into().unwrap(); + self + } + + 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 size + length += 1; // Compression method: 0 + length += 2; // Extension_length + length += usize::try_from(self.extension_length).unwrap(); + length + } +} + #[derive(Debug, Clone)] pub(crate) struct EncryptedExtensions { pub(crate) length: u16,