fix: mismatch cipher, ee parse

This commit is contained in:
occheung 2020-10-19 17:05:26 +08:00
parent 38bf1d3c3b
commit f6ff5cc431
7 changed files with 208 additions and 70 deletions

View File

@ -107,6 +107,9 @@ impl<'a> TlsBuffer<'a> {
HandshakeData::ClientHello(client_hello) => {
self.enqueue_client_hello(client_hello)
}
HandshakeData::ServerHello(server_hello) => {
self.euqueue_server_hello(server_hello)
}
_ => {
Err(Error::Unrecognized)
}
@ -128,6 +131,17 @@ impl<'a> TlsBuffer<'a> {
self.enqueue_extensions(client_hello.extensions)
}
fn euqueue_server_hello(&mut self, server_hello: ServerHello<'a>) -> Result<()> {
self.write_u16(server_hello.version.into())?;
self.write(&server_hello.random)?;
self.write_u8(server_hello.session_id_echo_length)?;
self.write(&server_hello.session_id_echo)?;
self.write_u16(server_hello.cipher_suite.into())?;
self.write_u8(server_hello.compression_method)?;
self.write_u16(server_hello.extension_length)?;
self.enqueue_extensions(server_hello.extensions)
}
fn enqueue_extensions(&mut self, extensions: Vec<Extension>) -> Result<()> {
for extension in extensions {
self.write_u16(extension.extension_type.into())?;

File diff suppressed because one or more lines are too long

View File

@ -22,8 +22,6 @@ use hkdf::Hkdf;
use smoltcp_tls::key::*;
use smoltcp_tls::buffer::TlsBuffer;
mod encrypted;
use encrypted::ENCRYPTED_DATA;
struct CountingRng(u64);
@ -76,24 +74,32 @@ fn main() {
// tls_socket.tls_connect(&mut sockets).unwrap();
let psk: [u8; 32] = [0; 32];
let early_secret = Hkdf::<Sha256>::new(None, &psk);
let hello_hash = {
Sha384::new()
.chain(&CLIENT_HELLO)
.chain(&SERVER_HELLO)
.finalize()
};
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",
Sha256::new().chain("")
Sha384::new().chain("")
);
let (handshake_secret, handshake_secret_hkdf) = Hkdf::<Sha256>::extract(
let (handshake_secret, handshake_secret_hkdf) = Hkdf::<Sha384>::extract(
Some(&derived_secret),
&SHARED_SECRET
);
let client_handshake_traffic_secret = {
let hkdf_label = HkdfLabel {
length: 32,
length: 48,
label_length: 18,
label: b"tls13 c hs traffic",
context_length: 32,
context: &HELLO_HASH,
context_length: 48,
context: &hello_hash,
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
@ -101,17 +107,18 @@ fn main() {
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U32> = GenericArray::default();
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: 32,
length: 48,
label_length: 18,
label: b"tls13 s hs traffic",
context_length: 32,
context: &HELLO_HASH,
context_length: 48,
context: &hello_hash,
};
let mut array = [0; 100];
let mut buffer = TlsBuffer::new(&mut array);
@ -119,13 +126,14 @@ fn main() {
let info: &[u8] = buffer.into();
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U32> = GenericArray::default();
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: 16,
length: 32,
label_length: 9,
label: b"tls13 key",
context_length: 0,
@ -136,9 +144,9 @@ fn main() {
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, U16> = GenericArray::default();
Hkdf::<Sha256>::from_prk(&server_handshake_traffic_secret)
// 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
@ -158,18 +166,18 @@ fn main() {
// Define output key material (OKM), dynamically sized by hash
let mut okm: GenericArray<u8, U12> = GenericArray::default();
Hkdf::<Sha256>::from_prk(&server_handshake_traffic_secret)
Hkdf::<Sha384>::from_prk(&server_handshake_traffic_secret)
.unwrap()
.expand(info, &mut okm);
okm
};
let cipher: Aes128Gcm = Aes128Gcm::new(&server_handshake_write_key);
let cipher: Aes256Gcm = Aes256Gcm::new(&server_handshake_write_key);
let decrypted_data = {
let mut vec: Vec<u8, U2048> = Vec::from_slice(&ENCRYPTED_DATA).unwrap();
let mut vec: Vec<u8, U2048> = Vec::from_slice(&CIPHERTEXT).unwrap();
cipher.decrypt_in_place(
&server_handshake_write_iv,
&[
0x17, 0x03, 0x03, 0x04, 0x75
0x17, 0x03, 0x03, 0x00, 0x27
],
&mut vec
).unwrap();
@ -178,22 +186,47 @@ fn main() {
println!("{:x?}", client_handshake_traffic_secret);
println!("{:x?}", server_handshake_traffic_secret);
println!("{:x?}", server_handshake_write_key);
println!("{:x?}", server_handshake_write_iv);
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] = [
0xdf, 0x4a, 0x29, 0x1b, 0xaa, 0x1e, 0xb7, 0xcf,
0xa6, 0x93, 0x4b, 0x29, 0xb4, 0x74, 0xba, 0xad,
0x26, 0x97, 0xe2, 0x9f, 0x1f, 0x92, 0x0d, 0xcc,
0x77, 0xc8, 0xa0, 0xa0, 0x88, 0x44, 0x76, 0x24
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
];
const HELLO_HASH: [u8; 32] = [
0xda, 0x75, 0xce, 0x11, 0x39, 0xac, 0x80, 0xda,
0xe4, 0x04, 0x4d, 0xa9, 0x32, 0x35, 0x0c, 0xf6,
0x5c, 0x97, 0xcc, 0xc9, 0xe3, 0x3f, 0x1e, 0x6f,
0x7d, 0x2d, 0x4b, 0x18, 0xb7, 0x36, 0xff, 0xd5
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,5 +1,6 @@
use nom::IResult;
use nom::bytes::complete::take;
use nom::bytes::complete::tag;
use nom::combinator::complete;
use nom::sequence::tuple;
use nom::error::ErrorKind;
@ -53,7 +54,7 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
Ok((rest, repr))
}
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 length = take(3_usize);
@ -73,6 +74,30 @@ fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
repr.handshake_data = data;
Ok((rest, repr))
},
EncryptedExtensions => {
// Split data into EE and the last TLS content byte
let (tls_content_byte, ee_data) = take(repr.length)(rest)?;
// Process TLS content byte.
complete(
tag(&[0x16])
)(tls_content_byte)?;
// Process EE
let (rest, handshake_data) = parse_encrypted_extensions(
ee_data
)?;
repr.handshake_data = HandshakeData::EncryptedExtensions(
handshake_data
);
// Verify that all bytes are comsumed
complete(
take(0_usize)
)(rest)?;
Ok((&[], repr))
}
_ => todo!()
}
}
@ -126,17 +151,26 @@ fn parse_server_hello(bytes: &[u8]) -> IResult<&[u8], HandshakeData> {
Ok((rest, HandshakeData::ServerHello(server_hello)))
}
pub(crate) 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 extension_length: i32 = NetworkEndian::read_u16(extension_length).into();
let extension_length: u16 = NetworkEndian::read_u16(extension_length);
let mut extension_length_counter: i32 = extension_length.into();
let mut extension_vec: Vec<Extension> = Vec::new();
while extension_length > 0 {
let (rem, extension) = parse_extension(rest, HandshakeType::EncryptedExtensions)?;
rest = rem;
extension_length -= i32::try_from(extension.get_length()).unwrap();
// Split the data into "extensions" and the rest
let (rest, mut encypted_extension_data) =
take(usize::try_from(extension_length).unwrap())(rest)?;
while extension_length_counter > 0 {
let (rem, extension) = parse_extension(
encypted_extension_data,
HandshakeType::EncryptedExtensions
)?;
encypted_extension_data = rem;
extension_length_counter -= i32::try_from(extension.get_length()).unwrap();
// Todo:: Proper error
if extension_length < 0 {
if extension_length_counter < 0 {
todo!()
}
@ -144,9 +178,15 @@ pub(crate) fn parse_encrypted_extensions(bytes: &[u8]) -> IResult<&[u8], Encrypt
}
let encrypted_extensions = EncryptedExtensions {
length: u16::try_from(extension_length).unwrap(),
length: extension_length,
extensions: extension_vec
};
// Force completeness. The entire slice is meant to be processed.
complete(
take(0_usize)
)(rest)?;
Ok((rest, encrypted_extensions))
}
@ -190,6 +230,38 @@ fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8]
_ => todo!()
}
},
SupportedGroups => { // NamedGroupList
let (rest, length) = take(2_usize)(rest)?;
let length = NetworkEndian::read_u16(length);
// Isolate contents, for easier error handling
let (rest, mut rem_data) = take(length)(rest)?;
let mut named_group_extension = NamedGroupList {
length,
named_group_list: Vec::new(),
};
for index in 0..(length/2) {
let (rem, named_group) = take(2_usize)(rem_data)?;
rem_data = rem;
let named_group = NamedGroup::try_from(
NetworkEndian::read_u16(named_group)
).unwrap();
named_group_extension.named_group_list.push(named_group);
// Assure completeness
if index == (length/2) {
complete(take(0_usize))(rem_data)?;
}
}
(
rest,
ExtensionData::NegotiatedGroups(
named_group_extension
)
)
}
KeyShare => {
match handshake_type {
HandshakeType::ClientHello => {

View File

@ -106,6 +106,8 @@ impl Session {
.diffie_hellman(&encoded_point)
.unwrap();
log::info!("Shared secret: {:?}", ecdhe_shared_secret.as_bytes());
// Generate Handshake secret
match cipher_suite {
CipherSuite::TLS_AES_128_GCM_SHA256 |
@ -287,7 +289,7 @@ impl Session {
},
_ => unreachable!()
}
}
},
CipherSuite::TLS_AES_256_GCM_SHA384 => {
// Select 1 hash function, then update the hash
self.hash = Hash::select_sha384(self.hash.clone());
@ -376,7 +378,7 @@ impl Session {
let server_handshake_iv: Vec<u8, U12> = {
let mut server_handshake_iv_holder = Vec::from_slice(&[0; 12]).unwrap();
hkdf_expand_label(
&client_handshake_traffic_secret_hkdf,
&server_handshake_traffic_secret_hkdf,
"iv",
"",
&mut server_handshake_iv_holder
@ -405,11 +407,11 @@ impl Session {
}
);
}
},
CipherSuite::TLS_AES_128_CCM_8_SHA256 => {
unreachable!()
}
}
};
self.state = TlsState::WAIT_EE;
}
@ -465,11 +467,11 @@ impl Session {
buffer: &mut dyn Buffer
) -> Result<(), Error> {
let (nonce, cipher): (&Vec<u8, U12>, &Cipher) = match self.role {
TlsRole::Client => {(
TlsRole::Server => {(
self.client_nonce.as_ref().unwrap(),
self.client_cipher.as_ref().unwrap()
)},
TlsRole::Server => {(
TlsRole::Client => {(
self.server_nonce.as_ref().unwrap(),
self.server_cipher.as_ref().unwrap()
)},

View File

@ -34,7 +34,7 @@ use alloc::vec::{ self, Vec };
use crate::Error as TlsError;
use crate::tls_packet::*;
use crate::parse::{ parse_tls_repr, parse_encrypted_extensions };
use crate::parse::{ parse_tls_repr, parse_handshake };
use crate::buffer::TlsBuffer;
use crate::session::{Session, TlsRole};
@ -117,7 +117,10 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
}
// Handle TLS handshake through TLS states
match self.session.borrow().get_tls_state() {
let tls_state = {
self.session.borrow().get_tls_state()
};
match tls_state {
// Initiate TLS handshake
TlsState::START => {
// Prepare field that is randomised,
@ -131,7 +134,7 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
.client_hello(&ecdh_secret, random, session_id.clone());
// Update hash function with client hello handshake
let mut array = [0; 2048];
let mut array = [0; 512];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_tls_repr(repr)?;
let slice: &[u8] = buffer.into();
@ -157,6 +160,10 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// TLS client should jump from WAIT_SH directly to WAIT_CERT_CR directly.
TlsState::WAIT_EE => {},
// TLS Client wait for server's certificate
// No need to send anything
TlsState::WAIT_CERT_CR => {},
_ => todo!()
}
@ -191,7 +198,10 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
return Ok(())
}
match self.session.borrow().get_tls_state() {
let tls_state = {
self.session.borrow().get_tls_state()
};
match tls_state {
// During WAIT_SH for a TLS client, client should wait for ServerHello
TlsState::WAIT_SH => {
// Legacy_protocol must be TLS 1.2
@ -302,11 +312,12 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// This is indeed a desirable ServerHello TLS repr
// Reprocess ServerHello into a slice
// Update session with required parameter
let mut array = [0; 2048];
let mut array = [0; 512];
let mut buffer = TlsBuffer::new(&mut array);
buffer.enqueue_tls_repr(repr);
buffer.enqueue_tls_repr(repr)?;
let slice: &[u8] = buffer.into();
self.session.borrow_mut().client_update_for_sh(
let mut session = self.session.borrow_mut();
session.client_update_for_sh(
selected_cipher.unwrap(),
server_public.unwrap(),
&slice[5..]
@ -331,21 +342,26 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
buffer.write_u16(repr.version.into())?;
buffer.write_u16(repr.length)?;
let associated_data: &[u8] = buffer.into();
self.session.borrow().encrypt_in_place(
{
self.session.borrow().decrypt_in_place(
associated_data,
&mut payload
);
}
log::info!("Decrypted payload {:?}", payload);
// TODO: Parse payload of EE
let (_, encrypted_extensions) =
parse_encrypted_extensions(&payload)
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

View File

@ -188,7 +188,7 @@ pub(crate) enum HandshakeData<'a> {
Uninitialized,
ClientHello(ClientHello<'a>),
ServerHello(ServerHello<'a>),
ExcryptedExtensions(EncryptedExtensions),
EncryptedExtensions(EncryptedExtensions),
}
impl<'a> HandshakeData<'a> {
@ -558,6 +558,9 @@ impl SignatureSchemeList {
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
#[repr(u16)]
pub(crate) enum NamedGroup {
#[num_enum(default)]
UNKNOWN = 0x0000,
/* Elliptic Curve Groups (ECDHE) */
secp256r1 = 0x0017,
secp384r1 = 0x0018,