diff --git a/src/session.rs b/src/session.rs index 6fa8ee8..59b7c62 100644 --- a/src/session.rs +++ b/src/session.rs @@ -41,21 +41,30 @@ pub(crate) struct Session { // Ephemeral secret for ECDHE key exchange ecdhe_secret: Option, // Block ciphers for client & server - client_cipher: Option, - server_cipher: Option, - // Traffic secret for client & server + client_handshake_cipher: Option, + server_handshake_cipher: Option, + client_application_cipher: Option, + server_application_cipher: Option, + // Traffic secret for client & server during handshake // Keeping traffic secret for key re-computation - client_traffic_secret: Option>, - server_traffic_secret: Option>, + client_handshake_traffic_secret: Option>, + server_handshake_traffic_secret: Option>, + // Traffic secret for client & server during app data transfer + // Keeping traffic secret for key re-computation + client_application_traffic_secret: Option>, + server_application_traffic_secret: Option>, // Nonce (IV) for client & server // Always 12 bytes long - client_nonce: Option>, - server_nonce: Option>, + client_handshake_nonce: Option>, + server_handshake_nonce: Option>, + client_application_nonce: Option>, + server_application_nonce: Option>, // Sequence number: Start from 0, 64 bits // Increment by one per record processed (read OR write) // Reset to 0 on rekey AND key exchange - // TODO: Force rekey if sequence_number need to wrap - sequence_number: u64, + // TODO: Force rekey if sequence number need to wrap + client_sequence_number: u64, + server_sequence_number: u64, // Certificate public key // For Handling CertificateVerify cert_rsa_public_key: Option, @@ -75,13 +84,20 @@ impl Session { latest_secret: None, hash, ecdhe_secret: None, - client_cipher: None, - server_cipher: None, - client_traffic_secret: None, - server_traffic_secret: None, - client_nonce: None, - server_nonce: None, - sequence_number: 0, + client_handshake_cipher: None, + server_handshake_cipher: None, + client_application_cipher: None, + server_application_cipher: None, + client_handshake_traffic_secret: None, + server_handshake_traffic_secret: None, + client_application_traffic_secret: None, + server_application_traffic_secret: None, + client_handshake_nonce: None, + server_handshake_nonce: None, + client_application_nonce: None, + server_application_nonce: None, + client_sequence_number: 0, + server_sequence_number: 0, cert_rsa_public_key: None } } @@ -174,10 +190,10 @@ impl Session { // Store client_handshake_traffic_secret and // server_handshake_traffic_secret // Initial values of both secrets don't matter - self.client_traffic_secret.replace( + self.client_handshake_traffic_secret.replace( Vec::from_slice(&client_handshake_traffic_secret).unwrap() ); - self.server_traffic_secret.replace( + self.server_handshake_traffic_secret.replace( Vec::from_slice(&server_handshake_traffic_secret).unwrap() ); @@ -254,8 +270,8 @@ impl Session { }; // Store nonce - self.client_nonce = Some(client_handshake_iv); - self.server_nonce = Some(server_handshake_iv); + 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 @@ -267,12 +283,12 @@ impl Session { let server_handshake_cipher = Aes128Gcm::new( GenericArray::from_slice(&server_handshake_key) ); - self.client_cipher = Some( + self.client_handshake_cipher = Some( Cipher::Aes128Gcm { aes128gcm: client_handshake_cipher } ); - self.server_cipher = Some( + self.server_handshake_cipher = Some( Cipher::Aes128Gcm { aes128gcm: server_handshake_cipher } @@ -285,12 +301,12 @@ impl Session { let server_handshake_cipher = ChaCha20Poly1305::new( GenericArray::from_slice(&server_handshake_key) ); - self.client_cipher = Some( + self.client_handshake_cipher = Some( Cipher::Chacha20poly1305 { chacha20poly1305: client_handshake_cipher } ); - self.server_cipher = Some( + self.server_handshake_cipher = Some( Cipher::Chacha20poly1305 { chacha20poly1305: server_handshake_cipher } @@ -303,12 +319,12 @@ impl Session { let server_handshake_cipher = Aes128Ccm::new( GenericArray::from_slice(&server_handshake_key) ); - self.client_cipher = Some( + self.client_handshake_cipher = Some( Cipher::Ccm { ccm: client_handshake_cipher } ); - self.server_cipher = Some( + self.server_handshake_cipher = Some( Cipher::Ccm { ccm: server_handshake_cipher } @@ -362,10 +378,10 @@ impl Session { // Store client_handshake_traffic_secret and // server_handshake_traffic_secret // Initial values of both secrets don't matter - self.client_traffic_secret.replace( + self.client_handshake_traffic_secret.replace( Vec::from_slice(&client_handshake_traffic_secret).unwrap() ); - self.server_traffic_secret.replace( + self.server_handshake_traffic_secret.replace( Vec::from_slice(&server_handshake_traffic_secret).unwrap() ); @@ -424,8 +440,8 @@ impl Session { }; // Store nonce - self.client_nonce = Some(client_handshake_iv); - self.server_nonce = Some(server_handshake_iv); + 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) @@ -433,12 +449,12 @@ impl Session { let server_handshake_cipher = Aes256Gcm::new( GenericArray::from_slice(&server_handshake_key) ); - self.client_cipher = Some( + self.client_handshake_cipher = Some( Cipher::Aes256Gcm { aes256gcm: client_handshake_cipher } ); - self.server_cipher = Some( + self.server_handshake_cipher = Some( Cipher::Aes256Gcm { aes256gcm: server_handshake_cipher } @@ -452,7 +468,8 @@ impl Session { self.state = TlsState::WAIT_EE; // Key exchange occurred, set seq_num to 0. - self.sequence_number = 0; + self.client_sequence_number = 0; + self.server_sequence_number = 0; } pub(crate) fn client_update_for_ee(&mut self, ee_slice: &[u8]) { @@ -588,7 +605,7 @@ impl Session { // Take hash from session if let Ok(sha256) = self.hash.get_sha256_clone() { let hkdf = Hkdf::::from_prk( - self.server_traffic_secret.as_ref().unwrap() + self.server_handshake_traffic_secret.as_ref().unwrap() ).unwrap(); // Compute finished_key @@ -600,19 +617,187 @@ impl Session { let transcript_hash = sha256.finalize(); // Compute verify_data - // let computed_verify_data = Sha256::new() - // .chain(&okm) - // .chain(&transcript_hash) - // .finalize(); let mut hmac = Hmac::::new_varkey(&okm).unwrap(); hmac.update(&transcript_hash); - log::info!("HMAC: {:?}", hmac); - log::info!("Received data: {:?}", server_verify_data); hmac.verify(server_verify_data).unwrap(); + // Update hash for key computation + self.hash.update(server_finished_slice); + + // Derive application traffic secret, key, IV on client's side + // 1. Derive secret from "Handshake Secret" + let hkdf = Hkdf::::from_prk( + // TLS requires the removal of secret if such secret is not of any use + // Replace "latest_secret" with None + self.latest_secret.as_ref().unwrap() + ).unwrap(); + + let empty_hash = Sha256::new().chain(""); + let derived_secret = derive_secret(&hkdf, "derived", empty_hash); + + // 2. HKDF-extract "Master Secret" + let zero_ikm: GenericArray::OutputSize> + = Default::default(); + let (master_secret, master_secret_hkdf) = Hkdf::::extract( + Some(&derived_secret), + &zero_ikm + ); + + // Replace latest secret with "master_secret" + self.latest_secret.replace( + Vec::from_slice(&master_secret).unwrap() + ); + + // 3. Get application traffic secret + let client_application_traffic_secret = derive_secret( + &master_secret_hkdf, + "c ap traffic", + self.hash.get_sha256_clone().unwrap() + ); + + let server_application_traffic_secret = derive_secret( + &master_secret_hkdf, + "s ap traffic", + self.hash.get_sha256_clone().unwrap() + ); + + self.client_application_traffic_secret.replace( + Vec::from_slice(&client_application_traffic_secret).unwrap() + ); + self.server_application_traffic_secret.replace( + Vec::from_slice(&server_application_traffic_secret).unwrap() + ); + + // 4. Replace cipher and IV + let client_application_traffic_hkdf = Hkdf::::from_prk( + &client_application_traffic_secret + ).unwrap(); + let server_application_traffic_hkdf = Hkdf::::from_prk( + &server_application_traffic_secret + ).unwrap(); + + // Init key and IV holders + let cipher_suite = self.client_handshake_cipher.as_ref().unwrap().get_cipher_suite_type(); + + let (mut client_key_holder, mut client_iv_holder, + mut server_key_holder, mut server_iv_holder): + (Vec::, Vec::, Vec::, Vec::) = + match cipher_suite { + CipherSuite::TLS_AES_128_GCM_SHA256 => { + ( + Vec::from_slice(&[0; 16]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap(), + Vec::from_slice(&[0; 16]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap() + ) + }, + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => { + ( + Vec::from_slice(&[0; 32]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap(), + Vec::from_slice(&[0; 32]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap() + ) + }, + CipherSuite::TLS_AES_128_CCM_SHA256 => { + ( + Vec::from_slice(&[0; 16]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap(), + Vec::from_slice(&[0; 16]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap() + ) + }, + // TLS_AES_128_CCM_8_SHA256 is not offered + // TLS_AES_256_GCM_SHA384 should not have SHA256 as hash + _ => unreachable!() + }; + + // Derive Key and IV for both server and client + hkdf_expand_label( + &client_application_traffic_hkdf, + "key", + "", + &mut client_key_holder + ); + hkdf_expand_label( + &client_application_traffic_hkdf, + "iv", + "", + &mut client_iv_holder + ); + hkdf_expand_label( + &server_application_traffic_hkdf, + "key", + "", + &mut server_key_holder + ); + hkdf_expand_label( + &server_application_traffic_hkdf, + "iv", + "", + &mut server_iv_holder + ); + + // Store IV/nonce + self.client_application_nonce.replace(client_iv_holder); + self.server_application_nonce.replace(server_iv_holder); + + // Instantiate new ciphers + match cipher_suite { + CipherSuite::TLS_AES_128_GCM_SHA256 => { + self.client_application_cipher.replace( + Cipher::Aes128Gcm { + aes128gcm: Aes128Gcm::new( + &GenericArray::from_slice(&client_key_holder) + ) + } + ); + self.server_application_cipher.replace( + Cipher::Aes128Gcm { + aes128gcm: Aes128Gcm::new( + &GenericArray::from_slice(&server_key_holder) + ) + } + ); + }, + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 => { + self.client_application_cipher.replace( + Cipher::Chacha20poly1305 { + chacha20poly1305: ChaCha20Poly1305::new( + &GenericArray::from_slice(&client_key_holder) + ) + } + ); + self.server_application_cipher.replace( + Cipher::Chacha20poly1305 { + chacha20poly1305: ChaCha20Poly1305::new( + &GenericArray::from_slice(&server_key_holder) + ) + } + ); + }, + CipherSuite::TLS_AES_128_CCM_SHA256 => { + self.client_application_cipher.replace( + Cipher::Ccm { + ccm: Aes128Ccm::new( + &GenericArray::from_slice(&client_key_holder) + ) + } + ); + self.server_application_cipher.replace( + Cipher::Ccm { + ccm: Aes128Ccm::new( + &GenericArray::from_slice(&server_key_holder) + ) + } + ); + }, + _ => unreachable!() + } + } else if let Ok(sha384) = self.hash.get_sha384_clone() { let hkdf = Hkdf::::from_prk( - self.server_traffic_secret.as_ref().unwrap() + self.server_handshake_traffic_secret.as_ref().unwrap() ).unwrap(); // Compute finished_key @@ -623,31 +808,156 @@ impl Session { // Get transcript hash let transcript_hash = sha384.finalize(); - // Compute verify_data - // let computed_verify_data = Sha384::new() - // .chain(&okm) - // .chain(&transcript_hash) - // .finalize(); - // log::info!("Computed data: {:?}", computed_verify_data); - // log::info!("Received data: {:?}", server_verify_data); - // assert_eq!(computed_verify_data.as_slice(), server_verify_data); + // Compute verify_data using HMAC let mut hmac = Hmac::::new_varkey(&okm).unwrap(); hmac.update(&transcript_hash); log::info!("HMAC: {:?}", hmac); log::info!("Received data: {:?}", server_verify_data); hmac.verify(server_verify_data).unwrap(); + // Update hash for key computation + self.hash.update(server_finished_slice); + + // Derive application traffic secret, key, IV on client's side + // 1. Derive secret from "Handshake Secret" + let hkdf = Hkdf::::from_prk( + self.latest_secret.as_ref().unwrap() + ).unwrap(); + + let empty_hash = Sha384::new().chain(""); + let derived_secret = derive_secret(&hkdf, "derived", empty_hash); + + // 2. HKDF-extract "Master Secret" + let zero_ikm: GenericArray::OutputSize> + = Default::default(); + let (master_secret, master_secret_hkdf) = Hkdf::::extract( + Some(&derived_secret), + &zero_ikm + ); + + // Replace latest secret with "master_secret" + self.latest_secret.replace( + Vec::from_slice(&master_secret).unwrap() + ); + + // 3. Get application traffic secret + let client_application_traffic_secret = derive_secret( + &master_secret_hkdf, + "c ap traffic", + self.hash.get_sha384_clone().unwrap() + ); + + let server_application_traffic_secret = derive_secret( + &master_secret_hkdf, + "s ap traffic", + self.hash.get_sha384_clone().unwrap() + ); + + self.client_application_traffic_secret.replace( + Vec::from_slice(&client_application_traffic_secret).unwrap() + ); + self.server_application_traffic_secret.replace( + Vec::from_slice(&server_application_traffic_secret).unwrap() + ); + + // 4. Replace cipher and IV + let client_application_traffic_hkdf = Hkdf::::from_prk( + &client_application_traffic_secret + ).unwrap(); + let server_application_traffic_hkdf = Hkdf::::from_prk( + &server_application_traffic_secret + ).unwrap(); + + // Init key and IV holders + let cipher_suite = self.client_handshake_cipher.as_ref().unwrap().get_cipher_suite_type(); + + let (mut client_key_holder, mut client_iv_holder, + mut server_key_holder, mut server_iv_holder): + (Vec::, Vec::, Vec::, Vec::) = + match cipher_suite { + CipherSuite::TLS_AES_256_GCM_SHA384 => { + ( + Vec::from_slice(&[0; 32]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap(), + Vec::from_slice(&[0; 32]).unwrap(), + Vec::from_slice(&[0; 12]).unwrap() + ) + }, + // TLS_AES_128_CCM_8_SHA256 is not offered + // Only TLS_AES_256_GCM_SHA384 should have SHA384 as hash + _ => unreachable!() + }; + + // Derive Key and IV for both server and client + hkdf_expand_label( + &client_application_traffic_hkdf, + "key", + "", + &mut client_key_holder + ); + hkdf_expand_label( + &client_application_traffic_hkdf, + "iv", + "", + &mut client_iv_holder + ); + hkdf_expand_label( + &server_application_traffic_hkdf, + "key", + "", + &mut server_key_holder + ); + hkdf_expand_label( + &server_application_traffic_hkdf, + "iv", + "", + &mut server_iv_holder + ); + + // Store IV/nonce + self.client_application_nonce.replace(client_iv_holder); + self.server_application_nonce.replace(server_iv_holder); + + // Instantiate new ciphers + match cipher_suite { + CipherSuite::TLS_AES_256_GCM_SHA384 => { + self.client_application_cipher.replace( + Cipher::Aes256Gcm { + aes256gcm: Aes256Gcm::new( + &GenericArray::from_slice(&client_key_holder) + ) + } + ); + self.server_application_cipher.replace( + Cipher::Aes256Gcm { + aes256gcm: Aes256Gcm::new( + &GenericArray::from_slice(&server_key_holder) + ) + } + ); + }, + _ => unreachable!() + } + } else { unreachable!() }; - - // Usual procedures: update hash - self.hash.update(server_finished_slice); + // Hash was updated for key computation // At last, update client state self.state = TlsState::SERVER_CONNECTED; } + + pub(crate) fn client_update_for_server_connected( + &mut self, + client_finished_slice: &[u8] + ) + { + self.hash.update(client_finished_slice); + self.state = TlsState::CONNECTED; + } + 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 @@ -668,25 +978,73 @@ impl Session { self.changed_cipher_spec = true; } + pub(crate) fn get_client_finished_verify_data(&self) -> Vec { + if let Ok(sha256) = self.hash.get_sha256_clone() { + let hkdf = Hkdf::::from_prk( + self.client_handshake_traffic_secret.as_ref().unwrap() + ).unwrap(); + + // Compute finished_key + let mut okm: GenericArray::::OutputSize> = + Default::default(); + hkdf_expand_label(&hkdf, "finished", "", &mut okm); + + // Get transcript hash + let transcript_hash = sha256.finalize(); + + // Compute verify_data, store in heapless vec + let mut hmac = Hmac::::new_varkey(&okm).unwrap(); + hmac.update(&transcript_hash); + Vec::from_slice(&hmac.finalize().into_bytes()).unwrap() + + } else if let Ok(sha384) = self.hash.get_sha384_clone() { + let hkdf = Hkdf::::from_prk( + self.client_handshake_traffic_secret.as_ref().unwrap() + ).unwrap(); + + // Compute finished_key + let mut okm: GenericArray::::OutputSize> = + Default::default(); + hkdf_expand_label(&hkdf, "finished", "", &mut okm); + + // Get transcript hash + let transcript_hash = sha384.finalize(); + + // Compute verify_data, store in heapless vec + let mut hmac = Hmac::::new_varkey(&okm).unwrap(); + hmac.update(&transcript_hash); + Vec::from_slice(&hmac.finalize().into_bytes()).unwrap() + + } else { + unreachable!() + } + } + + pub(crate) fn get_cipher_suite_type(&self) -> Option { + self.client_handshake_cipher.as_ref().map(|cipher| cipher.get_cipher_suite_type()) + } + pub(crate) fn encrypt_in_place( &self, associated_data: &[u8], buffer: &mut dyn Buffer ) -> Result<(), Error> { - let (nonce, cipher): (&Vec, &Cipher) = match self.role { + let (seq_num, nonce, cipher): (u64, &Vec, &Cipher) = match self.role { TlsRole::Client => {( - self.client_nonce.as_ref().unwrap(), - self.client_cipher.as_ref().unwrap() + self.client_sequence_number, + self.client_handshake_nonce.as_ref().unwrap(), + self.client_handshake_cipher.as_ref().unwrap() )}, TlsRole::Server => {( - self.server_nonce.as_ref().unwrap(), - self.server_cipher.as_ref().unwrap() + self.server_sequence_number, + self.server_handshake_nonce.as_ref().unwrap(), + self.server_handshake_cipher.as_ref().unwrap() )}, }; // Calculate XOR'ed nonce let nonce: u128 = NetworkEndian::read_uint128(nonce, 12); - let clipped_seq_num: u128 = self.sequence_number.into(); + let clipped_seq_num: u128 = seq_num.into(); let mut processed_nonce: [u8; 12] = [0; 12]; NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12); @@ -697,25 +1055,58 @@ impl Session { ) } + pub(crate) fn encrypt_in_place_detached( + &self, + associated_data: &[u8], + buffer: &mut [u8] + ) -> Result, Error> { + let (seq_num, nonce, cipher): (u64, &Vec, &Cipher) = match self.role { + TlsRole::Client => {( + self.client_sequence_number, + self.client_handshake_nonce.as_ref().unwrap(), + self.client_handshake_cipher.as_ref().unwrap() + )}, + TlsRole::Server => {( + self.server_sequence_number, + self.server_handshake_nonce.as_ref().unwrap(), + self.server_handshake_cipher.as_ref().unwrap() + )}, + }; + + // Calculate XOR'ed nonce + let nonce: u128 = NetworkEndian::read_uint128(nonce, 12); + let clipped_seq_num: u128 = seq_num.into(); + let mut processed_nonce: [u8; 12] = [0; 12]; + NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12); + + cipher.encrypt_in_place_detached( + &GenericArray::from_slice(&processed_nonce), + associated_data, + buffer + ) + } + pub(crate) fn decrypt_in_place( &self, associated_data: &[u8], buffer: &mut dyn Buffer ) -> Result<(), Error> { - let (nonce, cipher): (&Vec, &Cipher) = match self.role { + let (seq_num, nonce, cipher): (u64, &Vec, &Cipher) = match self.role { TlsRole::Server => {( - self.client_nonce.as_ref().unwrap(), - self.client_cipher.as_ref().unwrap() + self.client_sequence_number, + self.client_handshake_nonce.as_ref().unwrap(), + self.client_handshake_cipher.as_ref().unwrap() )}, TlsRole::Client => {( - self.server_nonce.as_ref().unwrap(), - self.server_cipher.as_ref().unwrap() + self.server_sequence_number, + self.server_handshake_nonce.as_ref().unwrap(), + self.server_handshake_cipher.as_ref().unwrap() )}, }; // Calculate XOR'ed nonce let nonce: u128 = NetworkEndian::read_uint128(nonce, 12); - let clipped_seq_num: u128 = self.sequence_number.into(); + let clipped_seq_num: u128 = seq_num.into(); let mut processed_nonce: [u8; 12] = [0; 12]; NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12); @@ -726,8 +1117,12 @@ impl Session { ) } - pub(crate) fn increment_sequence_number(&mut self) { - self.sequence_number += 1; + pub(crate) fn increment_client_sequence_number(&mut self) { + self.client_sequence_number += 1; + } + + pub(crate) fn increment_server_sequence_number(&mut self) { + self.server_sequence_number += 1; } } @@ -789,7 +1184,7 @@ impl Hash { } } - pub(crate) fn get_sha256_clone(&mut self) -> Result { + pub(crate) fn get_sha256_clone(&self) -> Result { if let Self::Sha256 { sha256 } = self { Ok(sha256.clone()) } else { @@ -797,7 +1192,7 @@ impl Hash { } } - pub(crate) fn get_sha384_clone(&mut self) -> Result { + pub(crate) fn get_sha384_clone(&self) -> Result { if let Self::Sha384 { sha384 } = self { Ok(sha384.clone()) } else { @@ -844,6 +1239,28 @@ impl Cipher { }.map_err(|_| Error::EncryptionError) } + pub(crate) fn encrypt_in_place_detached( + &self, + nonce: &GenericArray, + associated_data: &[u8], + buffer: &mut [u8] + ) -> Result, Error> { + match self { + Cipher::Aes128Gcm { aes128gcm } => { + aes128gcm.encrypt_in_place_detached(nonce, associated_data, buffer) + }, + Cipher::Aes256Gcm { aes256gcm } => { + aes256gcm.encrypt_in_place_detached(nonce, associated_data, buffer) + }, + Cipher::Chacha20poly1305 { chacha20poly1305 } => { + chacha20poly1305.encrypt_in_place_detached(nonce, associated_data, buffer) + }, + Cipher::Ccm { ccm } => { + ccm.encrypt_in_place_detached(nonce, associated_data, buffer) + } + }.map_err(|_| Error::EncryptionError) + } + pub(crate) fn decrypt_in_place( &self, nonce: &GenericArray, @@ -865,4 +1282,21 @@ impl Cipher { } }.map_err(|_| Error::DecryptionError) } + + pub(crate) fn get_cipher_suite_type(&self) -> CipherSuite { + match self { + Cipher::Aes128Gcm { aes128gcm } => { + CipherSuite::TLS_AES_128_GCM_SHA256 + }, + Cipher::Aes256Gcm { aes256gcm } => { + CipherSuite::TLS_AES_256_GCM_SHA384 + }, + Cipher::Chacha20poly1305 { chacha20poly1305 } => { + CipherSuite::TLS_CHACHA20_POLY1305_SHA256 + }, + Cipher::Ccm { ccm } => { + CipherSuite::TLS_AES_128_CCM_SHA256 + } + } + } } \ No newline at end of file diff --git a/src/tls.rs b/src/tls.rs index 3d49d44..205cd11 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -36,6 +36,7 @@ use nom::error::make_error; use nom::error::ErrorKind; use alloc::vec::{ self, Vec }; +use heapless::Vec as HeaplessVec; use crate::Error as TlsError; use crate::tls_packet::*; @@ -181,7 +182,25 @@ impl TlsSocket { TlsState::WAIT_FINISHED => {} // Send client Finished to end handshake - TlsState::SERVER_CONNECTED => {} + TlsState::SERVER_CONNECTED => { + let mut inner_plaintext: HeaplessVec = { + let verify_data = self.session.borrow() + .get_client_finished_verify_data(); + let mut handshake_header: [u8; 4] = [20, 0, 0, 0]; + NetworkEndian::write_u24( + &mut handshake_header[1..4], + u32::try_from(verify_data.len()).unwrap() + ); + let mut buffer = HeaplessVec::from_slice(&handshake_header).unwrap(); + buffer.extend_from_slice(&verify_data).unwrap(); + // Inner plaintext: record type + buffer.push(22).unwrap(); + buffer + }; + self.send_application_slice(sockets, &mut inner_plaintext.clone())?; + self.session.borrow_mut() + .client_update_for_server_connected(&inner_plaintext); + } _ => todo!() } @@ -571,11 +590,13 @@ impl TlsSocket { .map_err(|_| Error::Unrecognized)?; // Perform verification, update TLS state if successful + // Update traffic secret, reset sequence number self.session.borrow_mut() .client_update_for_wait_finished( server_finished_slice, might_be_server_finished.get_verify_data().unwrap() ); + log::info!("Computed secret"); } _ => {}, @@ -583,7 +604,7 @@ impl TlsSocket { // A TLS Record was received and processed and verified // Increment sequence number - self.session.borrow_mut().increment_sequence_number(); + self.session.borrow_mut().increment_server_sequence_number(); Ok(()) } @@ -609,7 +630,7 @@ impl TlsSocket { Err(Error::Truncated) } )?; - self.session.borrow_mut().increment_sequence_number(); + self.session.borrow_mut().increment_client_sequence_number(); Ok(()) } @@ -631,7 +652,53 @@ impl TlsSocket { Err(Error::Truncated) } )?; - self.session.borrow_mut().increment_sequence_number(); + self.session.borrow_mut().increment_client_sequence_number(); + Ok(()) + } + + // Send method for TLS Handshake that needs to be encrypted. + // Does the following things: + // 1. Encryption + // 2. Add TLS header in front of application data + // Input should be inner plaintext + // Note: Do not put this slice into the transcript hash. It is polluted. + fn send_application_slice(&self, sockets: &mut SocketSet, slice: &mut [u8]) -> Result<()> { + let mut tcp_socket = sockets.get::(self.tcp_handle); + if !tcp_socket.can_send() { + return Err(Error::Illegal); + } + + log::info!("Delivered slice: {:?}", slice); + + // Borrow session in advance + let mut client_session = self.session.borrow_mut(); + + // 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() { + Some(CipherSuite::TLS_AES_128_GCM_SHA256) | + Some(CipherSuite::TLS_AES_256_GCM_SHA384) | + Some(CipherSuite::TLS_AES_128_CCM_SHA256) | + Some(CipherSuite::TLS_CHACHA20_POLY1305_SHA256) => { + 16 + }, + _ => return Err(Error::Illegal), + }; + NetworkEndian::write_u16( + &mut associated_data[3..5], + auth_tag_length + u16::try_from(slice.len()).unwrap() + ); + + let auth_tag = client_session.encrypt_in_place_detached( + &associated_data, + slice + ).map_err(|_| Error::Illegal)?; + + tcp_socket.send_slice(&associated_data)?; + tcp_socket.send_slice(&slice)?; + tcp_socket.send_slice(&auth_tag)?; + + client_session.increment_client_sequence_number(); Ok(()) } diff --git a/src/tls_packet.rs b/src/tls_packet.rs index 8c43910..0b9d7c1 100644 --- a/src/tls_packet.rs +++ b/src/tls_packet.rs @@ -80,6 +80,14 @@ impl<'a> TlsRepr<'a> { self } + pub(crate) fn change_cipher_spec(mut self) -> Self { + self.content_type = TlsContentType::ChangeCipherSpec; + self.version = TlsVersion::Tls12; + self.length = 1; + self.payload = Some((&[1]).to_vec()); + self + } + // TODO: Consider replace all these boolean function // into a single function that returns the HandshakeType. pub(crate) fn is_server_hello(&self) -> bool {