From 81d52e9ec4abb73c9fe174c6bee23159fa009183 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 27 Nov 2020 11:53:45 +0800 Subject: [PATCH] server ee: init --- src/session.rs | 402 ++++++++++++++++++++++++++++++++++++++++++++++++- src/tls.rs | 75 +++++++-- 2 files changed, 459 insertions(+), 18 deletions(-) diff --git a/src/session.rs b/src/session.rs index 9e9bade..6c7598a 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1203,7 +1203,362 @@ impl<'a> Session<'a> { server_ecdhe_secret: DiffieHellmanPrivateKey, server_hello_slice: &[u8] ) { - todo!() + // Hash update + self.hash.update(server_hello_slice); + + let mut shared_secret_bytes: [u8; 32] = [0; 32]; + match (self.ecdhe_public.unwrap(), server_ecdhe_secret) { + ( + DiffieHellmanPublicKey::SECP256R1 { encoded_point }, + DiffieHellmanPrivateKey::SECP256R1 { ephemeral_secret } + ) => { + shared_secret_bytes.clone_from_slice( + ephemeral_secret.diffie_hellman( + &encoded_point + ).unwrap().as_bytes() + ) + }, + ( + DiffieHellmanPublicKey::X25519 { public_key }, + DiffieHellmanPrivateKey::X25519 { ephemeral_secret } + ) => { + shared_secret_bytes.clone_from_slice( + ephemeral_secret.diffie_hellman( + &public_key + ).as_bytes() + ) + }, + _ => unreachable!() + } + + let server_selected_cipher = self.server_selected_cipher.take().unwrap(); + + // Find handshake keys and IV + match server_selected_cipher { + CipherSuite::TLS_AES_128_CCM_SHA256 | + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 | + CipherSuite::TLS_AES_128_GCM_SHA256 => { + // Find early secret wrapped in HKDF + let empty_psk: GenericArray::OutputSize> = Default::default(); + let early_secret_hkdf = Hkdf::::new(None, &empty_psk); + + // Find handshake secret + let empty_hash = Sha256::new().chain(""); + let derived_secret = derive_secret( + &early_secret_hkdf, + "derived", + empty_hash + ); + + let (handshake_secret, handshake_secret_hkdf) = + Hkdf::::extract( + Some(&derived_secret), + &shared_secret_bytes + ); + + // Store the handshake secret + self.latest_secret.replace( + Vec::from_slice(&handshake_secret) + .unwrap() + ); + + let client_handshake_traffic_secret = derive_secret( + &handshake_secret_hkdf, + "c hs traffic", + self.hash.get_sha256_clone().unwrap() + ); + + let server_handshake_traffic_secret = derive_secret( + &handshake_secret_hkdf, + "s hs traffic", + self.hash.get_sha256_clone().unwrap() + ); + + // Store client_handshake_traffic_secret and + // server_handshake_traffic_secret + // Initial values of both secrets don't matter + self.client_handshake_traffic_secret.replace( + Vec::from_slice(&client_handshake_traffic_secret).unwrap() + ); + self.server_handshake_traffic_secret.replace( + Vec::from_slice(&server_handshake_traffic_secret).unwrap() + ); + + let client_handshake_traffic_secret_hkdf = Hkdf::::from_prk(&client_handshake_traffic_secret).unwrap(); + let server_handshake_traffic_secret_hkdf = Hkdf::::from_prk(&server_handshake_traffic_secret).unwrap(); + + // Prepare holder for key and IV + let client_handshake_key: Vec = { + let mut client_handshake_key_holder: Vec = match server_selected_cipher { + // 16 bytes key size + CipherSuite::TLS_AES_128_GCM_SHA256 | + CipherSuite::TLS_AES_128_CCM_SHA256 => { + Vec::from_slice(&[0; 16]).unwrap() + }, + // 32 bytes key size + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => { + Vec::from_slice(&[0; 32]).unwrap() + }, + // Not using Sha256 (AES_GCM_256) / not supported (CCM_8) + _ => unreachable!() + }; + hkdf_expand_label( + &client_handshake_traffic_secret_hkdf, + "key", + "", + &mut client_handshake_key_holder + ); + client_handshake_key_holder + }; + + let client_handshake_iv: Vec = { + let mut client_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap(); + hkdf_expand_label( + &client_handshake_traffic_secret_hkdf, + "iv", + "", + &mut client_handshake_iv_holder + ); + client_handshake_iv_holder + }; + + let server_handshake_key: Vec = { + let mut server_handshake_key_holder: Vec = match server_selected_cipher { + // 16 bytes key size + CipherSuite::TLS_AES_128_GCM_SHA256 | + CipherSuite::TLS_AES_128_CCM_SHA256 => { + Vec::from_slice(&[0; 16]).unwrap() + }, + // 32 bytes key size + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => { + Vec::from_slice(&[0; 32]).unwrap() + }, + // Not using Sha256 (AES_GCM_256) / not supported (CCM_8) + _ => unreachable!() + }; + hkdf_expand_label( + &server_handshake_traffic_secret_hkdf, + "key", + "", + &mut server_handshake_key_holder + ); + server_handshake_key_holder + }; + + let server_handshake_iv: Vec = { + let mut server_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap(); + hkdf_expand_label( + &server_handshake_traffic_secret_hkdf, + "iv", + "", + &mut server_handshake_iv_holder + ); + server_handshake_iv_holder + }; + + // Store nonce + self.client_handshake_nonce = Some(client_handshake_iv); + self.server_handshake_nonce = Some(server_handshake_iv); + + // Construct cipher from key & IV for client & server + // Store the ciphers + match server_selected_cipher { + CipherSuite::TLS_AES_128_GCM_SHA256 => { + let client_handshake_cipher = Aes128Gcm::new( + GenericArray::from_slice(&client_handshake_key) + ); + let server_handshake_cipher = Aes128Gcm::new( + GenericArray::from_slice(&server_handshake_key) + ); + self.client_handshake_cipher = Some( + Cipher::Aes128Gcm { + aes128gcm: client_handshake_cipher + } + ); + self.server_handshake_cipher = Some( + Cipher::Aes128Gcm { + aes128gcm: server_handshake_cipher + } + ); + }, + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => { + let client_handshake_cipher = ChaCha20Poly1305::new( + GenericArray::from_slice(&client_handshake_key) + ); + let server_handshake_cipher = ChaCha20Poly1305::new( + GenericArray::from_slice(&server_handshake_key) + ); + self.client_handshake_cipher = Some( + Cipher::Chacha20poly1305 { + chacha20poly1305: client_handshake_cipher + } + ); + self.server_handshake_cipher = Some( + Cipher::Chacha20poly1305 { + chacha20poly1305: server_handshake_cipher + } + ); + }, + CipherSuite::TLS_AES_128_CCM_SHA256 => { + let client_handshake_cipher = Aes128Ccm::new( + GenericArray::from_slice(&client_handshake_key) + ); + let server_handshake_cipher = Aes128Ccm::new( + GenericArray::from_slice(&server_handshake_key) + ); + self.client_handshake_cipher = Some( + Cipher::Ccm { + ccm: client_handshake_cipher + } + ); + self.server_handshake_cipher = Some( + Cipher::Ccm { + ccm: server_handshake_cipher + } + ); + }, + _ => unreachable!() + } + }, + CipherSuite::TLS_AES_256_GCM_SHA384 => { + // Find early secret in terms wrapped in HKDF + let empty_psk: GenericArray::OutputSize> = Default::default(); + let early_secret_hkdf = + Hkdf::::new(None, &empty_psk); + + // Find handshake secret + let empty_hash = Sha384::new().chain(""); + let derived_secret = derive_secret( + &early_secret_hkdf, + "derived", + empty_hash + ); + + let (handshake_secret, handshake_secret_hkdf) = + Hkdf::::extract( + Some(&derived_secret), + &shared_secret_bytes + ); + + // Store the handshake secret + self.latest_secret.replace( + Vec::from_slice(&handshake_secret) + .unwrap() + ); + + let client_handshake_traffic_secret = derive_secret( + &handshake_secret_hkdf, + "c hs traffic", + self.hash.get_sha384_clone().unwrap() + ); + + let server_handshake_traffic_secret = derive_secret( + &handshake_secret_hkdf, + "s hs traffic", + self.hash.get_sha384_clone().unwrap() + ); + + // Store client_handshake_traffic_secret and + // server_handshake_traffic_secret + // Initial values of both secrets don't matter + self.client_handshake_traffic_secret.replace( + Vec::from_slice(&client_handshake_traffic_secret).unwrap() + ); + self.server_handshake_traffic_secret.replace( + Vec::from_slice(&server_handshake_traffic_secret).unwrap() + ); + + let client_handshake_traffic_secret_hkdf = Hkdf::::from_prk(&client_handshake_traffic_secret).unwrap(); + let server_handshake_traffic_secret_hkdf = Hkdf::::from_prk(&server_handshake_traffic_secret).unwrap(); + + // Prepare holder for key and IV + let client_handshake_key: Vec = { + // 32 bytes key size + let mut client_handshake_key_holder: Vec = + Vec::from_slice(&[0; 32]).unwrap(); + + hkdf_expand_label( + &client_handshake_traffic_secret_hkdf, + "key", + "", + &mut client_handshake_key_holder + ); + client_handshake_key_holder + }; + + let client_handshake_iv: Vec = { + let mut client_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap(); + hkdf_expand_label( + &client_handshake_traffic_secret_hkdf, + "iv", + "", + &mut client_handshake_iv_holder + ); + client_handshake_iv_holder + }; + + let server_handshake_key: Vec = { + // 32 bytes key size + let mut server_handshake_key_holder: Vec = + Vec::from_slice(&[0; 32]).unwrap(); + + hkdf_expand_label( + &server_handshake_traffic_secret_hkdf, + "key", + "", + &mut server_handshake_key_holder + ); + server_handshake_key_holder + }; + + let server_handshake_iv: Vec = { + let mut server_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap(); + hkdf_expand_label( + &server_handshake_traffic_secret_hkdf, + "iv", + "", + &mut server_handshake_iv_holder + ); + server_handshake_iv_holder + }; + + // Store nonce + self.client_handshake_nonce = Some(client_handshake_iv); + self.server_handshake_nonce = Some(server_handshake_iv); + + let client_handshake_cipher = Aes256Gcm::new( + GenericArray::from_slice(&client_handshake_key) + ); + let server_handshake_cipher = Aes256Gcm::new( + GenericArray::from_slice(&server_handshake_key) + ); + self.client_handshake_cipher = Some( + Cipher::Aes256Gcm { + aes256gcm: client_handshake_cipher + } + ); + self.server_handshake_cipher = Some( + Cipher::Aes256Gcm { + aes256gcm: server_handshake_cipher + } + ); + }, + CipherSuite::TLS_AES_128_CCM_8_SHA256 => unreachable!() + } + + // Will send EE, {CR}, Cert, CV FIN in the same state + // No need to mutate FSM + + // Ensure that the sequence numbers start from 0 + self.client_sequence_number = 0; + self.server_sequence_number = 0; + } + + pub(crate) fn server_update_for_encrypted_extension( + &mut self, + encryption_extension_slice: &[u8], + ) { + self.hash.update(encryption_extension_slice); } pub(crate) fn verify_session_id_echo(&self, session_id_echo: &[u8]) -> bool { @@ -1214,9 +1569,9 @@ impl<'a> Session<'a> { } } - pub(crate) fn get_session_id(&self) -> &[u8] { + pub(crate) fn get_session_id(&self) -> [u8; 32] { if let Some(session_id) = &self.session_id { - session_id + *session_id } else { unreachable!() } @@ -1730,6 +2085,30 @@ impl<'a> Session<'a> { self.server_sequence_number += 1; } + pub(crate) fn increment_local_sequence_number(&mut self) { + match self.role { + TlsRole::Client => { + self.client_sequence_number += 1; + }, + TlsRole::Server => { + self.server_sequence_number += 1; + }, + _ => unreachable!() + } + } + + pub(crate) fn increment_remote_sequence_number(&mut self) { + match self.role { + TlsRole::Client => { + self.server_sequence_number += 1; + }, + TlsRole::Server => { + self.client_sequence_number += 1; + }, + _ => unreachable!() + } + } + pub(crate) fn get_session_role(&self) -> TlsRole { self.role } @@ -2013,3 +2392,20 @@ pub enum DiffieHellmanPrivateKey { ephemeral_secret: x25519_dalek::EphemeralSecret } } + +impl DiffieHellmanPrivateKey { + pub fn to_public_key(&self) -> DiffieHellmanPublicKey { + match self { + Self::SECP256R1 { ephemeral_secret } => { + DiffieHellmanPublicKey::SECP256R1 { + encoded_point: p256::EncodedPoint::from(ephemeral_secret) + } + }, + Self::X25519 { ephemeral_secret } => { + DiffieHellmanPublicKey::X25519 { + public_key: x25519_dalek::PublicKey::from(ephemeral_secret) + } + } + } + } +} diff --git a/src/tls.rs b/src/tls.rs index 555a55d..5c20e95 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -31,7 +31,7 @@ use crate::parse::{ get_content_type_inner_plaintext }; use crate::buffer::TlsBuffer; -use crate::session::{Session, TlsRole, DiffieHellmanPublicKey}; +use crate::session::{Session, TlsRole, DiffieHellmanPublicKey, DiffieHellmanPrivateKey}; #[derive(Debug, PartialEq, Eq, Clone, Copy)] #[allow(non_camel_case_types)] @@ -437,23 +437,44 @@ impl<'s> TlsSocket<'s> { // - 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 (session_id, cipher_suite, server_ecdhe_public_key) = { + let mut session = self.session.borrow(); + ( + session.get_session_id(), + session.get_cipher_suite(), + session.get_server_ecdhe_public_key() + ) + }; + let ecdhe_private_key = match server_ecdhe_public_key { + DiffieHellmanPublicKey::SECP256R1 { .. } => { + DiffieHellmanPrivateKey::SECP256R1 { + ephemeral_secret: { + p256::ecdh::EphemeralSecret::random(&mut self.rng) + } + } + }, + DiffieHellmanPublicKey::X25519 { .. } => { + DiffieHellmanPrivateKey::X25519 { + ephemeral_secret: { + x25519_dalek::EphemeralSecret::new(&mut self.rng) + } + } + } + }; + let ecdhe_public_key = ecdhe_private_key.to_public_key(); + // Construct and send SH let repr = TlsRepr::new().server_hello( &random, - session_id, + &session_id, cipher_suite, - ecdhe_key + ecdhe_public_key ); - { let mut tcp_socket = sockets.get::(self.tcp_handle); + let mut session = self.session.borrow_mut(); tcp_socket.send( |data| { // Enqueue the TLS representation @@ -463,14 +484,35 @@ impl<'s> TlsSocket<'s> { } let slice: &[u8] = buffer.into(); - // Update session - // todo!(); + // Update session after sending only SH + session.server_update_for_server_hello( + ecdhe_private_key, + &slice[5..] + ); // Send the data (slice.len(), ()) } )?; } + + // Construct and send minimalistic EE + let inner_plaintext: [u8; 7] = [ + 0x08, // EE type + 0x00, 0x00, 0x02, // Length: 2 + 0x00, 0x00, // Length of extensions: 0 + 22 // Content type of InnerPlainText + ]; + self.send_application_slice(sockets, &mut inner_plaintext.clone())?; + + let inner_plaintext_length = inner_plaintext.len(); + { + let mut session = self.session.borrow_mut(); + session.server_update_for_encrypted_extension( + &inner_plaintext + ); + } + } // Other states regarding server role @@ -1222,16 +1264,19 @@ impl<'s> TlsSocket<'s> { // TODO: Rename this function. It is only good for client finished fn send_application_slice(&self, sockets: &mut SocketSet, slice: &mut [u8]) -> Result<()> { let mut tcp_socket = sockets.get::(self.tcp_handle); + log::info!("Got socket"); if !tcp_socket.can_send() { return Err(Error::Illegal); } + log::info!("Socket usable"); // Borrow session in advance - let mut client_session = self.session.borrow_mut(); + let mut session = self.session.borrow_mut(); + log::info!("Got session"); // Pre-compute TLS record layer as associated_data let mut associated_data: [u8; 5] = [0x17, 0x03, 0x03, 0x00, 0x00]; - let auth_tag_length: u16 = match client_session.get_cipher_suite_type() { + let auth_tag_length: u16 = match session.get_cipher_suite_type() { Some(CipherSuite::TLS_AES_128_GCM_SHA256) | Some(CipherSuite::TLS_AES_256_GCM_SHA384) | Some(CipherSuite::TLS_AES_128_CCM_SHA256) | @@ -1246,7 +1291,7 @@ impl<'s> TlsSocket<'s> { auth_tag_length + u16::try_from(slice.len()).unwrap() ); - let auth_tag = client_session.encrypt_in_place_detached( + let auth_tag = session.encrypt_in_place_detached( &associated_data, slice ).map_err(|_| Error::Illegal)?; @@ -1255,7 +1300,7 @@ impl<'s> TlsSocket<'s> { tcp_socket.send_slice(&slice)?; tcp_socket.send_slice(&auth_tag)?; - client_session.increment_client_sequence_number(); + session.increment_local_sequence_number(); Ok(()) }