fix: IV, sha128 hkdf

This commit is contained in:
occheung 2020-10-20 15:55:44 +08:00
parent f6ff5cc431
commit 2e8ccdf910
5 changed files with 165 additions and 182 deletions

View File

@ -22,6 +22,11 @@ use hkdf::Hkdf;
use smoltcp_tls::key::*; use smoltcp_tls::key::*;
use smoltcp_tls::buffer::TlsBuffer; use smoltcp_tls::buffer::TlsBuffer;
use asn1_der::{
DerObject,
typed::{ DerEncodable, DerDecodable }
};
struct CountingRng(u64); struct CountingRng(u64);
@ -73,160 +78,16 @@ fn main() {
).unwrap(); ).unwrap();
// tls_socket.tls_connect(&mut sockets).unwrap(); // tls_socket.tls_connect(&mut sockets).unwrap();
let object = DerObject::decode(&CERT).expect("Failed to decode object");
let hello_hash = { println!("raw: {:2X?},\nheader: {:2X?},\ntag: {:2X?},\nvalue: {:2X?}\n",
Sha384::new() object.raw(),
.chain(&CLIENT_HELLO) object.header(),
.chain(&SERVER_HELLO) object.tag(),
.finalize() object.value()
};
println!("Hash: {:?}", hello_hash);
let psk: [u8; 48] = [0; 48];
let early_secret = Hkdf::<Sha384>::new(None, &psk);
let derived_secret = derive_secret(
&early_secret,
"derived",
Sha384::new().chain("")
); );
let (handshake_secret, handshake_secret_hkdf) = Hkdf::<Sha384>::extract(
Some(&derived_secret),
&SHARED_SECRET
);
let client_handshake_traffic_secret = {
let hkdf_label = HkdfLabel {
length: 48,
label_length: 18,
label: b"tls13 c hs traffic",
context_length: 48,
context: &hello_hash,
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_hkdf_label(hkdf_label);
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U48> = GenericArray::default();
handshake_secret_hkdf.expand(info, &mut okm).unwrap();
okm
};
let server_handshake_traffic_secret = {
let hkdf_label = HkdfLabel {
length: 48,
label_length: 18,
label: b"tls13 s hs traffic",
context_length: 48,
context: &hello_hash,
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_hkdf_label(hkdf_label);
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U48> = GenericArray::default();
handshake_secret_hkdf.expand(info, &mut okm).unwrap();
okm
};
let server_handshake_write_key = {
let hkdf_label = HkdfLabel {
length: 32,
label_length: 9,
label: b"tls13 key",
context_length: 0,
context: b"",
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_hkdf_label(hkdf_label);
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by cipher key
let mut okm: GenericArray<u8, U32> = GenericArray::default();
Hkdf::<Sha384>::from_prk(&server_handshake_traffic_secret)
.unwrap()
.expand(info, &mut okm);
okm
};
let server_handshake_write_iv = {
let hkdf_label = HkdfLabel {
length: 12,
label_length: 8,
label: b"tls13 iv",
context_length: 0,
context: b"",
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_hkdf_label(hkdf_label);
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U12> = GenericArray::default();
Hkdf::<Sha384>::from_prk(&server_handshake_traffic_secret)
.unwrap()
.expand(info, &mut okm);
okm
};
let cipher: Aes256Gcm = Aes256Gcm::new(&server_handshake_write_key);
let decrypted_data = {
let mut vec: Vec<u8, U2048> = Vec::from_slice(&CIPHERTEXT).unwrap();
cipher.decrypt_in_place(
&server_handshake_write_iv,
&[
0x17, 0x03, 0x03, 0x00, 0x27
],
&mut vec
).unwrap();
vec
};
println!("{:x?}", client_handshake_traffic_secret);
println!("{:x?}", server_handshake_traffic_secret);
println!("Server handshake key: {:?}", server_handshake_write_key);
println!("Server handshake iv: {:?}", server_handshake_write_iv);
println!("{:x?}", decrypted_data);
println!("Decrypted data length: {:?}", decrypted_data.len());
} }
const SHARED_SECRET: [u8; 32] = [ const CERT: [u8; 805] = [
43, 165, 163, 26, 69, 90, 77, 219, 49, 63, 128, 28, 75, 77, 23, 115, 28, 228, 145, 134, 124, 198, 18, 28, 27, 165, 10, 201, 94, 156, 148, 150 0x30, 0x82, 0x03, 0x21, 0x30, 0x82, 0x02, 0x09, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x15, 0x5a, 0x92, 0xad, 0xc2, 0x04, 0x8f, 0x90, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x22, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x30, 0x35, 0x30, 0x31, 0x33, 0x38, 0x31, 0x37, 0x5a, 0x30, 0x2b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x13, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x75, 0x6c, 0x66, 0x68, 0x65, 0x69, 0x6d, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc4, 0x80, 0x36, 0x06, 0xba, 0xe7, 0x47, 0x6b, 0x08, 0x94, 0x04, 0xec, 0xa7, 0xb6, 0x91, 0x04, 0x3f, 0xf7, 0x92, 0xbc, 0x19, 0xee, 0xfb, 0x7d, 0x74, 0xd7, 0xa8, 0x0d, 0x00, 0x1e, 0x7b, 0x4b, 0x3a, 0x4a, 0xe6, 0x0f, 0xe8, 0xc0, 0x71, 0xfc, 0x73, 0xe7, 0x02, 0x4c, 0x0d, 0xbc, 0xf4, 0xbd, 0xd1, 0x1d, 0x39, 0x6b, 0xba, 0x70, 0x46, 0x4a, 0x13, 0xe9, 0x4a, 0xf8, 0x3d, 0xf3, 0xe1, 0x09, 0x59, 0x54, 0x7b, 0xc9, 0x55, 0xfb, 0x41, 0x2d, 0xa3, 0x76, 0x52, 0x11, 0xe1, 0xf3, 0xdc, 0x77, 0x6c, 0xaa, 0x53, 0x37, 0x6e, 0xca, 0x3a, 0xec, 0xbe, 0xc3, 0xaa, 0xb7, 0x3b, 0x31, 0xd5, 0x6c, 0xb6, 0x52, 0x9c, 0x80, 0x98, 0xbc, 0xc9, 0xe0, 0x28, 0x18, 0xe2, 0x0b, 0xf7, 0xf8, 0xa0, 0x3a, 0xfd, 0x17, 0x04, 0x50, 0x9e, 0xce, 0x79, 0xbd, 0x9f, 0x39, 0xf1, 0xea, 0x69, 0xec, 0x47, 0x97, 0x2e, 0x83, 0x0f, 0xb5, 0xca, 0x95, 0xde, 0x95, 0xa1, 0xe6, 0x04, 0x22, 0xd5, 0xee, 0xbe, 0x52, 0x79, 0x54, 0xa1, 0xe7, 0xbf, 0x8a, 0x86, 0xf6, 0x46, 0x6d, 0x0d, 0x9f, 0x16, 0x95, 0x1a, 0x4c, 0xf7, 0xa0, 0x46, 0x92, 0x59, 0x5c, 0x13, 0x52, 0xf2, 0x54, 0x9e, 0x5a, 0xfb, 0x4e, 0xbf, 0xd7, 0x7a, 0x37, 0x95, 0x01, 0x44, 0xe4, 0xc0, 0x26, 0x87, 0x4c, 0x65, 0x3e, 0x40, 0x7d, 0x7d, 0x23, 0x07, 0x44, 0x01, 0xf4, 0x84, 0xff, 0xd0, 0x8f, 0x7a, 0x1f, 0xa0, 0x52, 0x10, 0xd1, 0xf4, 0xf0, 0xd5, 0xce, 0x79, 0x70, 0x29, 0x32, 0xe2, 0xca, 0xbe, 0x70, 0x1f, 0xdf, 0xad, 0x6b, 0x4b, 0xb7, 0x11, 0x01, 0xf4, 0x4b, 0xad, 0x66, 0x6a, 0x11, 0x13, 0x0f, 0xe2, 0xee, 0x82, 0x9e, 0x4d, 0x02, 0x9d, 0xc9, 0x1c, 0xdd, 0x67, 0x16, 0xdb, 0xb9, 0x06, 0x18, 0x86, 0xed, 0xc1, 0xba, 0x94, 0x21, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x52, 0x30, 0x50, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x89, 0x4f, 0xde, 0x5b, 0xcc, 0x69, 0xe2, 0x52, 0xcf, 0x3e, 0xa3, 0x00, 0xdf, 0xb1, 0x97, 0xb8, 0x1d, 0xe1, 0xc1, 0x46, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x59, 0x16, 0x45, 0xa6, 0x9a, 0x2e, 0x37, 0x79, 0xe4, 0xf6, 0xdd, 0x27, 0x1a, 0xba, 0x1c, 0x0b, 0xfd, 0x6c, 0xd7, 0x55, 0x99, 0xb5, 0xe7, 0xc3, 0x6e, 0x53, 0x3e, 0xff, 0x36, 0x59, 0x08, 0x43, 0x24, 0xc9, 0xe7, 0xa5, 0x04, 0x07, 0x9d, 0x39, 0xe0, 0xd4, 0x29, 0x87, 0xff, 0xe3, 0xeb, 0xdd, 0x09, 0xc1, 0xcf, 0x1d, 0x91, 0x44, 0x55, 0x87, 0x0b, 0x57, 0x1d, 0xd1, 0x9b, 0xdf, 0x1d, 0x24, 0xf8, 0xbb, 0x9a, 0x11, 0xfe, 0x80, 0xfd, 0x59, 0x2b, 0xa0, 0x39, 0x8c, 0xde, 0x11, 0xe2, 0x65, 0x1e, 0x61, 0x8c, 0xe5, 0x98, 0xfa, 0x96, 0xe5, 0x37, 0x2e, 0xef, 0x3d, 0x24, 0x8a, 0xfd, 0xe1, 0x74, 0x63, 0xeb, 0xbf, 0xab, 0xb8, 0xe4, 0xd1, 0xab, 0x50, 0x2a, 0x54, 0xec, 0x00, 0x64, 0xe9, 0x2f, 0x78, 0x19, 0x66, 0x0d, 0x3f, 0x27, 0xcf, 0x20, 0x9e, 0x66, 0x7f, 0xce, 0x5a, 0xe2, 0xe4, 0xac, 0x99, 0xc7, 0xc9, 0x38, 0x18, 0xf8, 0xb2, 0x51, 0x07, 0x22, 0xdf, 0xed, 0x97, 0xf3, 0x2e, 0x3e, 0x93, 0x49, 0xd4, 0xc6, 0x6c, 0x9e, 0xa6, 0x39, 0x6d, 0x74, 0x44, 0x62, 0xa0, 0x6b, 0x42, 0xc6, 0xd5, 0xba, 0x68, 0x8e, 0xac, 0x3a, 0x01, 0x7b, 0xdd, 0xfc, 0x8e, 0x2c, 0xfc, 0xad, 0x27, 0xcb, 0x69, 0xd3, 0xcc, 0xdc, 0xa2, 0x80, 0x41, 0x44, 0x65, 0xd3, 0xae, 0x34, 0x8c, 0xe0, 0xf3, 0x4a, 0xb2, 0xfb, 0x9c, 0x61, 0x83, 0x71, 0x31, 0x2b, 0x19, 0x10, 0x41, 0x64, 0x1c, 0x23, 0x7f, 0x11, 0xa5, 0xd6, 0x5c, 0x84, 0x4f, 0x04, 0x04, 0x84, 0x99, 0x38, 0x71, 0x2b, 0x95, 0x9e, 0xd6, 0x85, 0xbc, 0x5c, 0x5d, 0xd6, 0x45, 0xed, 0x19, 0x90, 0x94, 0x73, 0x40, 0x29, 0x26, 0xdc, 0xb4, 0x0e, 0x34, 0x69, 0xa1, 0x59, 0x41, 0xe8, 0xe2, 0xcc, 0xa8, 0x4b, 0xb6, 0x08, 0x46, 0x36, 0xa0
]; ];
const CLIENT_HELLO: [u8; 0xCB] = [
0x01, 0x00, 0x00, 0xc7, 0x03, 0x03, 0x95, 0x2a, 0xfc, 0xc8, 0xee, 0x76, 0xab, 0xaf, 0x6e, 0x99,
0xd0, 0x63, 0x03, 0x0b, 0x7d, 0x5e, 0x44, 0xa2, 0x2d, 0x00, 0x99, 0xb4, 0x10, 0x0b, 0x22, 0x55,
0xf6, 0xe9, 0x7e, 0xbf, 0xdc, 0xd5, 0x20, 0x81, 0x52, 0xe7, 0x4f, 0x58, 0x54, 0x5a, 0x9f, 0x89,
0xc1, 0x2b, 0xd5, 0x40, 0x61, 0x53, 0xeb, 0x50, 0x8e, 0x77, 0x3a, 0xa9, 0x44, 0x07, 0x0c, 0x2c,
0xab, 0xeb, 0xf5, 0x6b, 0x3d, 0x91, 0x6e, 0x00, 0x08, 0x13, 0x01, 0x13, 0x02, 0x13, 0x03, 0x13,
0x04, 0x01, 0x00, 0x00, 0x76, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x18,
0x00, 0x16, 0x04, 0x03, 0x08, 0x07, 0x08, 0x09, 0x04, 0x01, 0x08, 0x04, 0x08, 0x0a, 0x05, 0x01,
0x08, 0x05, 0x08, 0x0b, 0x06, 0x01, 0x08, 0x06, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x02, 0x00, 0x17,
0x00, 0x33, 0x00, 0x47, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0x0e, 0x9f, 0xff, 0x47, 0x1c,
0x7c, 0xa3, 0xf8, 0x24, 0xfe, 0x25, 0x57, 0x37, 0xbb, 0x0b, 0xe2, 0x11, 0xb2, 0xec, 0x5f, 0xa9,
0x33, 0x2f, 0x66, 0xe8, 0x18, 0xb4, 0x1d, 0x44, 0x61, 0xca, 0x91, 0x89, 0x5f, 0xa2, 0x0f, 0x01,
0x88, 0x97, 0xed, 0xe8, 0xc8, 0x39, 0x71, 0x89, 0x93, 0x7d, 0x35, 0xc2, 0xce, 0xcb, 0x6b, 0xbb,
0xe0, 0x3f, 0xe5, 0xde, 0x6e, 0x3b, 0x17, 0x68, 0x91, 0xbb, 0xe9
];
const SERVER_HELLO: [u8; 0x9B] = [
0x02, 0x00, 0x00, 0x97, 0x03, 0x03, 0x5a, 0x7a, 0x25, 0x58, 0x0a, 0x34, 0x9c, 0x66, 0x08, 0x1f,
0xbf, 0x98, 0x03, 0xd3, 0x55, 0x37, 0x14, 0xe9, 0xdb, 0xfb, 0x12, 0xf3, 0x8c, 0x69, 0x1e, 0xc1,
0xd4, 0xfc, 0x67, 0x4b, 0x06, 0x47, 0x20, 0x81, 0x52, 0xe7, 0x4f, 0x58, 0x54, 0x5a, 0x9f, 0x89,
0xc1, 0x2b, 0xd5, 0x40, 0x61, 0x53, 0xeb, 0x50, 0x8e, 0x77, 0x3a, 0xa9, 0x44, 0x07, 0x0c, 0x2c,
0xab, 0xeb, 0xf5, 0x6b, 0x3d, 0x91, 0x6e, 0x13, 0x02, 0x00, 0x00, 0x4f, 0x00, 0x2b, 0x00, 0x02,
0x03, 0x04, 0x00, 0x33, 0x00, 0x45, 0x00, 0x17, 0x00, 0x41, 0x04, 0xb9, 0x93, 0x81, 0xfd, 0xa5,
0xdc, 0x6d, 0xe2, 0x64, 0x44, 0xbe, 0xa6, 0xd4, 0x7f, 0x8c, 0x0e, 0xb3, 0x6f, 0x4a, 0xcf, 0xa1,
0x73, 0x1b, 0x3c, 0x93, 0x41, 0xef, 0x97, 0x2c, 0x3a, 0x2a, 0xd4, 0xb1, 0xe8, 0xc3, 0x06, 0x3a,
0xf8, 0x2e, 0x8a, 0xf3, 0x35, 0x0a, 0x47, 0x98, 0x47, 0x67, 0x28, 0xab, 0x9d, 0xd2, 0xb4, 0x98,
0x33, 0xc6, 0xa5, 0x3d, 0x99, 0x7e, 0x28, 0x89, 0x2d, 0x9d, 0xd9
];
const CIPHERTEXT: [u8; 39] = [
0xf6, 0xa9, 0x89, 0x64, 0x69, 0xf7, 0x87, 0x96, 0x61, 0xf6, 0xc9, 0xf8, 0x02, 0xfb, 0xfa, 0xa0,
0xae, 0xca, 0x4f, 0x59, 0x9b, 0xb4, 0x26, 0x2b, 0x06, 0x54, 0x4b, 0xce, 0xbc, 0xa4, 0x27, 0x55,
0xc0, 0xe4, 0x69, 0x33, 0x25, 0x46, 0x7f
];

View File

@ -1,7 +1,9 @@
use nom::IResult; use nom::IResult;
use nom::bytes::complete::take; use nom::bytes::complete::take;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::take_till;
use nom::combinator::complete; use nom::combinator::complete;
use nom::sequence::preceded;
use nom::sequence::tuple; use nom::sequence::tuple;
use nom::error::ErrorKind; use nom::error::ErrorKind;
use smoltcp::Error; use smoltcp::Error;
@ -54,6 +56,11 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
Ok((rest, repr)) Ok((rest, repr))
} }
// TODO: Redo EE
// Not very appropriate to classify EE as proper handshake
// It may include multiple handshakes
// Solution 1: Parse handshake again -> Recursion & return type
// Solution 2: Force caller to parse in a loop -> Extra parser to handle EE
pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> { pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
let handshake_type = take(1_usize); let handshake_type = take(1_usize);
let length = take(3_usize); let length = take(3_usize);
@ -151,6 +158,15 @@ fn parse_server_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
Ok((rest, HandshakeData::ServerHello(server_hello))) Ok((rest, HandshakeData::ServerHello(server_hello)))
} }
// For reference: This is the structure of encrypted text
// Source: RFC 8446 Section 5.2
//
// struct {
// opaque content[TLSPlaintext.length];
// ContentType type;
// uint8 zeros[length_of_padding];
// } TLSInnerPlaintext;
fn parse_encrypted_extensions(bytes: &[u8]) -> IResult<&[u8], EncryptedExtensions> { fn parse_encrypted_extensions(bytes: &[u8]) -> IResult<&[u8], EncryptedExtensions> {
let (mut rest, extension_length) = take(2_usize)(bytes)?; let (mut rest, extension_length) = take(2_usize)(bytes)?;
let extension_length: u16 = NetworkEndian::read_u16(extension_length); let extension_length: u16 = NetworkEndian::read_u16(extension_length);
@ -184,7 +200,12 @@ fn parse_encrypted_extensions(bytes: &[u8]) -> IResult<&[u8], EncryptedExtension
// Force completeness. The entire slice is meant to be processed. // Force completeness. The entire slice is meant to be processed.
complete( complete(
take(0_usize) preceded(
take(0_usize),
// There may be zeroes beyond the content_type
// Take "0" out until no more chaining zeros are found
take_till(|byte| byte == 0)
)
)(rest)?; )(rest)?;
Ok((rest, encrypted_extensions)) Ok((rest, encrypted_extensions))

View File

@ -7,6 +7,7 @@ use chacha20poly1305::ChaCha20Poly1305;
use ccm::Ccm; use ccm::Ccm;
use hkdf::Hkdf; use hkdf::Hkdf;
use generic_array::GenericArray; use generic_array::GenericArray;
use byteorder::{ByteOrder, NetworkEndian, BigEndian};
use core::convert::AsRef; use core::convert::AsRef;
use core::cell::RefCell; use core::cell::RefCell;
@ -44,6 +45,11 @@ pub(crate) struct Session {
// Always 12 bytes long // Always 12 bytes long
client_nonce: Option<Vec<u8, U12>>, client_nonce: Option<Vec<u8, U12>>,
server_nonce: Option<Vec<u8, U12>>, server_nonce: Option<Vec<u8, U12>>,
// 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,
} }
impl Session { impl Session {
@ -66,6 +72,7 @@ impl Session {
server_traffic_secret: None, server_traffic_secret: None,
client_nonce: None, client_nonce: None,
server_nonce: None, server_nonce: None,
sequence_number: 0,
} }
} }
@ -87,6 +94,8 @@ impl Session {
} }
// State transition from WAIT_SH to WAIT_EE // State transition from WAIT_SH to WAIT_EE
// TODO: Memory allocation
// It current dumps too much memory onto the stack on invocation
pub(crate) fn client_update_for_sh( pub(crate) fn client_update_for_sh(
&mut self, &mut self,
cipher_suite: CipherSuite, cipher_suite: CipherSuite,
@ -106,8 +115,6 @@ impl Session {
.diffie_hellman(&encoded_point) .diffie_hellman(&encoded_point)
.unwrap(); .unwrap();
log::info!("Shared secret: {:?}", ecdhe_shared_secret.as_bytes());
// Generate Handshake secret // Generate Handshake secret
match cipher_suite { match cipher_suite {
CipherSuite::TLS_AES_128_GCM_SHA256 | CipherSuite::TLS_AES_128_GCM_SHA256 |
@ -218,7 +225,7 @@ impl Session {
let server_handshake_iv: Vec<u8, U12> = { let server_handshake_iv: Vec<u8, U12> = {
let mut server_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap(); let mut server_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap();
hkdf_expand_label( hkdf_expand_label(
&client_handshake_traffic_secret_hkdf, &server_handshake_traffic_secret_hkdf,
"iv", "iv",
"", "",
&mut server_handshake_iv_holder &mut server_handshake_iv_holder
@ -413,6 +420,9 @@ impl Session {
} }
}; };
self.state = TlsState::WAIT_EE; self.state = TlsState::WAIT_EE;
// Key exchange occurred, set seq_num to 0.
self.sequence_number = 0;
} }
pub(crate) fn client_update_for_ee(&mut self) { pub(crate) fn client_update_for_ee(&mut self) {
@ -454,8 +464,15 @@ impl Session {
self.server_cipher.as_ref().unwrap() self.server_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 mut processed_nonce: [u8; 12] = [0; 12];
NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12);
cipher.encrypt_in_place( cipher.encrypt_in_place(
&GenericArray::from_slice(nonce), &GenericArray::from_slice(&processed_nonce),
associated_data, associated_data,
buffer buffer
) )
@ -476,12 +493,23 @@ impl Session {
self.server_cipher.as_ref().unwrap() self.server_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 mut processed_nonce: [u8; 12] = [0; 12];
NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12);
cipher.decrypt_in_place( cipher.decrypt_in_place(
&GenericArray::from_slice(nonce), &GenericArray::from_slice(&processed_nonce),
associated_data, associated_data,
buffer buffer
) )
} }
pub(crate) fn increment_sequence_number(&mut self) {
self.sequence_number += 1;
}
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]

View File

@ -193,8 +193,10 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// //
// CCS message only exist for compatibility reason, // CCS message only exist for compatibility reason,
// Drop the message and update `received_change_cipher_spec` // Drop the message and update `received_change_cipher_spec`
// Note: CSS doesn't count as a proper record, no need to increment sequence number
if repr.is_change_cipher_spec() { if repr.is_change_cipher_spec() {
self.session.borrow_mut().receive_change_cipher_spec(); let mut session = self.session.borrow_mut();
session.receive_change_cipher_spec();
return Ok(()) return Ok(())
} }
@ -322,6 +324,9 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
server_public.unwrap(), server_public.unwrap(),
&slice[5..] &slice[5..]
); );
// Key exchange occurred, seq_num is set to 0
// Do NOT update seq_num again. Early return.
return Ok(());
} }
}, },
@ -336,6 +341,48 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// ExcepytedExtensions are disguised as ApplicationData // ExcepytedExtensions are disguised as ApplicationData
// Pull out the `payload` from TlsRepr, decrypt as EE // Pull out the `payload` from TlsRepr, decrypt as EE
let mut payload = repr.payload.take().unwrap(); let mut payload = repr.payload.take().unwrap();
log::info!("Encrypted payload: {:?}", payload);
let mut array: [u8; 5] = [0; 5];
let mut buffer = TlsBuffer::new(&mut array);
buffer.write_u8(repr.content_type.into())?;
buffer.write_u16(repr.version.into())?;
buffer.write_u16(repr.length)?;
let associated_data: &[u8] = buffer.into();
log::info!("Associated Data: {:?}", associated_data);
{
self.session.borrow_mut().decrypt_in_place(
associated_data,
&mut payload
);
}
log::info!("decrypted EE");
log::info!("{:?}", payload);
// TODO: Parse payload of EE
let parse_result = parse_handshake(&payload);
let (_, encrypted_extensions_handshake) = parse_result
.map_err(|_| Error::Unrecognized)?;
// TODO: Process payload
// Practically, nothing will be done about cookies/server name
// Extension processing is therefore skipped
log::info!("Parsed EE");
self.session.borrow_mut().client_update_for_ee();
},
// In this stage, wait for a certificate from server
// Parse the certificate and check its content
TlsState::WAIT_CERT_CR => {
// Check that the packet is classified as application data
// Certificates transfer is disguised as application data
if !repr.is_application_data() {
// Abort communication, this affect IV calculation
todo!()
}
// Pull out the `payload` from TlsRepr, decrypt as EE
let mut payload = repr.payload.take().unwrap();
// Instantiate associated data and decrypt
let mut array: [u8; 5] = [0; 5]; let mut array: [u8; 5] = [0; 5];
let mut buffer = TlsBuffer::new(&mut array); let mut buffer = TlsBuffer::new(&mut array);
buffer.write_u8(repr.content_type.into())?; buffer.write_u8(repr.content_type.into())?;
@ -343,36 +390,21 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
buffer.write_u16(repr.length)?; buffer.write_u16(repr.length)?;
let associated_data: &[u8] = buffer.into(); let associated_data: &[u8] = buffer.into();
{ {
self.session.borrow().decrypt_in_place( self.session.borrow_mut().decrypt_in_place(
associated_data, associated_data,
&mut payload &mut payload
); );
} }
log::info!("Decrypted payload {:?}", payload); log::info!("Decrypted payload {:?}", payload);
// TODO: Parse payload of EE
let parse_result = parse_handshake(&payload);
let (_, encrypted_extensions_handshake) = parse_result
.map_err(|_| Error::Unrecognized)?;
// TODO: Process payload
// Practically, nothing will be done about cookies/server name
// Extension processing is therefore skipped
log::info!("EE handshake: {:?}", encrypted_extensions_handshake);
self.session.borrow_mut().client_update_for_ee();
log::info!("Transition to WAIT_CERT_CR");
},
// In this stage, wait for a certificate from server
// Parse the certificate and check its content
TlsState::WAIT_CERT_CR => {
}, },
_ => {}, _ => {},
} }
// A TLS Record was received and processed and verified
// Increment sequence number
self.session.borrow_mut().increment_sequence_number();
Ok(()) Ok(())
} }
@ -386,6 +418,9 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
let mut buffer = TlsBuffer::new(&mut array); let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_tls_repr(tls_repr)?; buffer.enqueue_tls_repr(tls_repr)?;
let buffer_size = buffer.get_size(); let buffer_size = buffer.get_size();
// Force send to return if send is unsuccessful
// Only update sequence number if the send is successful
tcp_socket.send_slice(buffer.into()) tcp_socket.send_slice(buffer.into())
.and_then( .and_then(
|size| if size == buffer_size { |size| if size == buffer_size {
@ -393,10 +428,15 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
} else { } else {
Err(Error::Truncated) Err(Error::Truncated)
} }
) )?;
self.session.borrow_mut().increment_sequence_number();
Ok(())
} }
// Generic inner send method for buffer IO, through TCP socket // Generic inner send method for buffer IO, through TCP socket
// Usage: Push a slice representation of ONE TLS packet
// This function will only increment sequence number by 1
// Repeatedly call this function if sending multiple TLS packets is needed
fn send_tls_slice(&self, sockets: &mut SocketSet, slice: &[u8]) -> Result<()> { fn send_tls_slice(&self, sockets: &mut SocketSet, slice: &[u8]) -> Result<()> {
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle); let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
if !tcp_socket.can_send() { if !tcp_socket.can_send() {
@ -410,11 +450,14 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
} else { } else {
Err(Error::Truncated) Err(Error::Truncated)
} }
) )?;
self.session.borrow_mut().increment_sequence_number();
Ok(())
} }
// Generic inner recv method, through TCP socket // Generic inner recv method, through TCP socket
// A TCP packet can contain multiple TLS segments // A TCP packet can contain multiple TLS records (including 0)
// Therefore, sequence nubmer incrementation is not completed here
fn recv_tls_repr<'a>(&'a self, sockets: &mut SocketSet, byte_array: &'a mut [u8]) -> Result<Vec::<TlsRepr>> { fn recv_tls_repr<'a>(&'a self, sockets: &mut SocketSet, byte_array: &'a mut [u8]) -> Result<Vec::<TlsRepr>> {
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle); let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
if !tcp_socket.can_recv() { if !tcp_socket.can_recv() {

View File

@ -189,6 +189,7 @@ pub(crate) enum HandshakeData<'a> {
ClientHello(ClientHello<'a>), ClientHello(ClientHello<'a>),
ServerHello(ServerHello<'a>), ServerHello(ServerHello<'a>),
EncryptedExtensions(EncryptedExtensions), EncryptedExtensions(EncryptedExtensions),
Certificate(Certificate<'a>),
} }
impl<'a> HandshakeData<'a> { impl<'a> HandshakeData<'a> {
@ -644,3 +645,32 @@ pub(crate) struct ServerName {
name_type: NameType, name_type: NameType,
name: ServerNameContent, name: ServerNameContent,
} }
// Note: X.509 format is always selected unless negotiated
// This TLS implementation still yet to support certificate negotiation
#[derive(Debug, Clone)]
pub(crate) enum CertificateEntryInfo<'a> {
RawPublicKey {
ASN1_subjectPublicKeyInfo_length: u32, // Only 24 bits
ASN1_subjectPublicKeyInfo: &'a [u8],
},
X509 {
cert_data_length: u32, // Only 24 bits
cert_data: &'a [u8],
}
}
#[derive(Debug, Clone)]
pub(crate) struct CertificateEntry<'a> {
certificate_entry_into: CertificateEntryInfo<'a>,
extensions_length: u16,
extensions: Vec<Extension>,
}
#[derive(Debug, Clone)]
pub(crate) struct Certificate<'a> {
certificate_request_context_length: u8, // 0 length unless responding to CERT_REQUEST
certificate_request_context: &'a [u8],
certificate_list_length: u32, // Only 24 bits
certificate_list: &'a [CertificateEntry<'a>],
}