diff --git a/src/session.rs b/src/session.rs index 99784cc..12569af 100644 --- a/src/session.rs +++ b/src/session.rs @@ -685,8 +685,6 @@ impl<'a> Session<'a> { // 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 @@ -954,6 +952,312 @@ impl<'a> Session<'a> { self.hash.update(certificate_verify_slice); } + pub(crate) fn server_update_for_server_finished( + &mut self, + server_finished_slice: &[u8] + ) { + // Update hash for key computation + self.hash.update(server_finished_slice); + + // Key calculation + if let Ok(sha256) = self.hash.get_sha256_clone() { + // 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() { + // 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!() + }; + } + fn find_handshake_keying_info(&mut self, shared_secret_bytes: &[u8], cipher_suite: CipherSuite) { // Ensure that it is 32-bytes long assert!(shared_secret_bytes.len() == 32); @@ -1596,6 +1900,48 @@ impl<'a> Session<'a> { } } + pub(crate) fn get_server_finished_verify_data(&self) -> Vec { + if let Ok(sha256) = self.hash.get_sha256_clone() { + let hkdf = Hkdf::::from_prk( + self.server_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.server_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()) } diff --git a/src/tls.rs b/src/tls.rs index 9049197..4931821 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -631,6 +631,29 @@ impl<'s> TlsSocket<'s> { &inner_plaintext[..(inner_plaintext_length-1)] ); } + + // Construct and send server finished + let inner_plaintext: HeaplessVec = { + let verify_data = self.session.borrow() + .get_server_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())?; + + let inner_plaintext_length = inner_plaintext.len(); + // { + // self.session.borrow_mut() + // .server_update_for_server_finished(&inner_plaintext[..(inner_plaintext_length-1)]); + // } } // Other states regarding server role