handshake: fin

master
occheung 2020-10-29 17:34:03 +08:00
parent 0042fea902
commit ee9b31e3de
7 changed files with 397 additions and 30 deletions

View File

@ -8,6 +8,7 @@ edition = "2018"
hkdf = "0.9.0"
sha-1 = { version = "0.9.1", default-features = false }
sha2 = { version = "0.9.1", default-features = false }
hmac = "0.10.1"
byteorder = { version = "1.3.4", default-features = false }
num_enum = { version = "0.5.1", default-features = false }
log = "0.4.11"

25
src/fake_rng.rs Normal file
View File

@ -0,0 +1,25 @@
// A blank implementor of RngCore that is NOT random
// Justification: RSA padding scheme for verifying PSS signature
// 1. Why is there a static lifetime bound?
// 2. Why need random? It is just signature verification.
// Anyway, the RSAPublicKey::verify() method does NOT care about random at all :)
use rand_core::{RngCore, Error};
pub (crate) struct FakeRandom {}
impl RngCore for FakeRandom {
fn next_u32(&mut self) -> u32 {
0
}
fn next_u64(&mut self) -> u64 {
0
}
fn fill_bytes(&mut self, dest: &mut [u8]) {}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(())
}
}

View File

@ -9,6 +9,7 @@ pub mod buffer;
pub mod key;
pub mod session;
pub mod certificate;
pub mod fake_rng;
use nom::error::ParseError;

View File

@ -177,6 +177,21 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
Ok((rest, repr))
},
Finished => {
// Parse Finished, the size is determined
// Pre-split the slice and then parse for Finished
// i.e. check for completeness
let (rest, possible_verify_data) = take(repr.length)(rest)?;
let (_, handshake_data) = complete(
parse_finished
)(possible_verify_data)?;
repr.handshake_data = HandshakeData::Finished(
handshake_data
);
Ok((rest, repr))
}
_ => todo!()
}
}
@ -381,17 +396,22 @@ fn parse_certificate_verify(bytes: &[u8]) -> IResult<&[u8], CertificateVerify> {
signature_length
))(bytes)?;
log::info!("Sig scheme: {:?}, sig:len: {:?}, rest_len: {:?}",
signature_scheme,
signature_length,
rest.len()
);
let signature_scheme = SignatureScheme::try_from(
NetworkEndian::read_u16(signature_scheme)
).unwrap();
let signature_length = NetworkEndian::read_u16(signature_length);
let (_, signature) = complete(
take(signature_length)
)(rest)?;
// Take the signature portion out
let (rest, signature) = take(signature_length)(rest)?;
Ok((
&[],
rest,
CertificateVerify {
algorithm: signature_scheme,
signature_length,
@ -400,6 +420,13 @@ fn parse_certificate_verify(bytes: &[u8]) -> IResult<&[u8], CertificateVerify> {
))
}
fn parse_finished(bytes: &[u8]) -> IResult<&[u8], Finished> {
Ok((
&[],
Finished { verify_data: bytes }
))
}
fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> {
let extension_type = take(2_usize);
let length = take(2_usize);

View File

@ -1,6 +1,6 @@
use p256::{ EncodedPoint, ecdh::EphemeralSecret };
use heapless::{ Vec, consts::* };
use sha2::{ Digest, Sha256, Sha384, digest::FixedOutput };
use sha2::{ Digest, Sha256, Sha384, Sha512, digest::FixedOutput };
use aes_gcm::{ Aes128Gcm, Aes256Gcm, aes::Aes128 };
use aes_gcm::{ AeadInPlace, NewAead, aead::Buffer };
use chacha20poly1305::ChaCha20Poly1305;
@ -8,7 +8,10 @@ use ccm::Ccm;
use hkdf::Hkdf;
use generic_array::GenericArray;
use byteorder::{ByteOrder, NetworkEndian, BigEndian};
use rsa::RSAPublicKey;
use rsa::{RSAPublicKey, PublicKey, PaddingScheme, Hash as RSAHash};
use hmac::{ Hmac, Mac, NewMac };
use rand_core::RngCore;
use core::convert::AsRef;
use core::cell::RefCell;
@ -16,7 +19,9 @@ use core::cell::RefCell;
use crate::tls::TlsState;
use crate::tls_packet::CipherSuite;
use crate::key::*;
use crate::tls_packet::SignatureScheme;
use crate::Error;
use crate::fake_rng::FakeRandom;
type Aes128Ccm = Ccm<Aes128, U16, U12>;
@ -157,13 +162,23 @@ impl Session {
let client_handshake_traffic_secret = derive_secret(
&handshake_secret_hkdf,
"c hs traffic",
self.hash.get_sha256_clone()
self.hash.get_sha256_clone().unwrap()
);
let server_handshake_traffic_secret = derive_secret(
&handshake_secret_hkdf,
"s hs traffic",
self.hash.get_sha256_clone()
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_traffic_secret.replace(
Vec::from_slice(&client_handshake_traffic_secret).unwrap()
);
self.server_traffic_secret.replace(
Vec::from_slice(&server_handshake_traffic_secret).unwrap()
);
let client_handshake_traffic_secret_hkdf = Hkdf::<Sha256>::from_prk(&client_handshake_traffic_secret).unwrap();
@ -335,13 +350,23 @@ impl Session {
let client_handshake_traffic_secret = derive_secret(
&handshake_secret_hkdf,
"c hs traffic",
self.hash.get_sha384_clone()
self.hash.get_sha384_clone().unwrap()
);
let server_handshake_traffic_secret = derive_secret(
&handshake_secret_hkdf,
"s hs traffic",
self.hash.get_sha384_clone()
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_traffic_secret.replace(
Vec::from_slice(&client_handshake_traffic_secret).unwrap()
);
self.server_traffic_secret.replace(
Vec::from_slice(&server_handshake_traffic_secret).unwrap()
);
let client_handshake_traffic_secret_hkdf = Hkdf::<Sha384>::from_prk(&client_handshake_traffic_secret).unwrap();
@ -445,6 +470,184 @@ impl Session {
self.state = TlsState::WAIT_CV;
}
pub(crate) fn client_update_for_wait_cv(
&mut self,
cert_verify_slice: &[u8],
signature_algorithm: SignatureScheme,
signature: &[u8]
)
{
// Clone the transcript hash from ClientHello all the way to Certificate
let transcript_hash: Vec<u8, U64> = if let Ok(sha256) = self.hash.get_sha256_clone() {
Vec::from_slice(&sha256.finalize()).unwrap()
} else if let Ok(sha384) = self.hash.get_sha384_clone() {
Vec::from_slice(&sha384.finalize()).unwrap()
} else {
unreachable!()
};
// Handle Ed25519 and p256 separately
// These 2 algorithms have a mandated hash function
if signature_algorithm == SignatureScheme::ecdsa_secp256r1_sha256 ||
signature_algorithm == SignatureScheme::ed25519
{
todo!()
}
// Get verification hash, and verify the signature
use crate::tls_packet::SignatureScheme::*;
let get_rsa_padding_scheme = |sig_alg: SignatureScheme| -> PaddingScheme {
match signature_algorithm {
rsa_pkcs1_sha256 => {
PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_256))
},
rsa_pkcs1_sha384 => {
PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_384))
},
rsa_pkcs1_sha512 => {
PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_512))
},
rsa_pss_rsae_sha256 | rsa_pss_pss_sha256 => {
PaddingScheme::new_pss::<Sha256, FakeRandom>(FakeRandom{})
},
rsa_pss_rsae_sha384 | rsa_pss_pss_sha384 => {
PaddingScheme::new_pss::<Sha384, FakeRandom>(FakeRandom{})
},
rsa_pss_rsae_sha512 | rsa_pss_pss_sha512 => {
PaddingScheme::new_pss::<Sha512, FakeRandom>(FakeRandom{})
},
_ => unreachable!()
}
};
match signature_algorithm {
rsa_pkcs1_sha256 | rsa_pss_rsae_sha256 | rsa_pss_pss_sha256 => {
let verify_hash = Sha256::new()
.chain(&[0x20; 64])
.chain("TLS 1.3, server CertificateVerify")
.chain(&[0])
.chain(&transcript_hash)
.finalize();
let padding = get_rsa_padding_scheme(signature_algorithm);
let verify_result = self.cert_rsa_public_key.take().unwrap().verify(
padding, &verify_hash, signature
);
log::info!("Algorithm {:?} Certificate verify: {:?}", signature_algorithm, verify_result);
if verify_result.is_err() {
todo!()
}
},
rsa_pkcs1_sha384 | rsa_pss_rsae_sha384 | rsa_pss_pss_sha384 => {
let verify_hash = Sha384::new()
.chain(&[0x20; 64])
.chain("TLS 1.3, server CertificateVerify")
.chain(&[0])
.chain(&transcript_hash)
.finalize();
let padding = get_rsa_padding_scheme(signature_algorithm);
let verify_result = self.cert_rsa_public_key.take().unwrap().verify(
padding, &verify_hash, signature
);
log::info!("Algorithm {:?} Certificate verify: {:?}", signature_algorithm, verify_result);
if verify_result.is_err() {
todo!()
}
},
rsa_pkcs1_sha512 | rsa_pss_rsae_sha512 | rsa_pss_pss_sha512 => {
let verify_hash = Sha512::new()
.chain(&[0x20; 64])
.chain("TLS 1.3, server CertificateVerify")
.chain(&[0])
.chain(&transcript_hash)
.finalize();
let padding = get_rsa_padding_scheme(signature_algorithm);
let verify_result = self.cert_rsa_public_key.take().unwrap().verify(
padding, &verify_hash, signature
);
if verify_result.is_err() {
todo!()
}
},
_ => unreachable!()
};
// Usual procedures: update hash
self.hash.update(cert_verify_slice);
// At last, update client state
self.state = TlsState::WAIT_FINISHED;
}
pub(crate) fn client_update_for_wait_finished(
&mut self,
server_finished_slice: &[u8],
server_verify_data: &[u8]
)
{
// Take hash from session
if let Ok(sha256) = self.hash.get_sha256_clone() {
let hkdf = Hkdf::<Sha256>::from_prk(
self.server_traffic_secret.as_ref().unwrap()
).unwrap();
// Compute finished_key
let mut okm: GenericArray::<u8, <Sha256 as Digest>::OutputSize> =
Default::default();
hkdf_expand_label(&hkdf, "finished", "", &mut okm);
// Get transcript hash
let transcript_hash = sha256.finalize();
// Compute verify_data
// let computed_verify_data = Sha256::new()
// .chain(&okm)
// .chain(&transcript_hash)
// .finalize();
let mut hmac = Hmac::<Sha256>::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();
} else if let Ok(sha384) = self.hash.get_sha384_clone() {
let hkdf = Hkdf::<Sha384>::from_prk(
self.server_traffic_secret.as_ref().unwrap()
).unwrap();
// Compute finished_key
let mut okm: GenericArray::<u8, <Sha384 as Digest>::OutputSize> =
Default::default();
hkdf_expand_label(&hkdf, "finished", "", &mut okm);
// 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);
let mut hmac = Hmac::<Sha384>::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();
} else {
unreachable!()
};
// Usual procedures: update hash
self.hash.update(server_finished_slice);
// At last, update client state
self.state = TlsState::SERVER_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
@ -586,19 +789,19 @@ impl Hash {
}
}
pub(crate) fn get_sha256_clone(&mut self) -> Sha256 {
pub(crate) fn get_sha256_clone(&mut self) -> Result<Sha256, ()> {
if let Self::Sha256 { sha256 } = self {
sha256.clone()
Ok(sha256.clone())
} else {
unreachable!()
Err(())
}
}
pub(crate) fn get_sha384_clone(&mut self) -> Sha384 {
pub(crate) fn get_sha384_clone(&mut self) -> Result<Sha384, ()> {
if let Self::Sha384 { sha384 } = self {
sha384.clone()
Ok(sha384.clone())
} else {
unreachable!()
Err(())
}
}
}

View File

@ -54,6 +54,7 @@ pub(crate) enum TlsState {
WAIT_CERT,
WAIT_CV,
WAIT_FINISHED,
SERVER_CONNECTED, // Additional state, for client to send Finished after server Finished
CONNECTED,
}
@ -65,7 +66,7 @@ pub struct TlsSocket<R: 'static + RngCore + CryptoRng>
session: RefCell<Session>,
}
impl<R: RngCore + CryptoRng> TlsSocket<R> {
impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
pub fn new<'a, 'b, 'c>(
sockets: &mut SocketSet<'a, 'b, 'c>,
rx_buffer: TcpSocketBuffer<'b>,
@ -174,6 +175,14 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// No need to send anything
TlsState::WAIT_CV => {},
// Last step of server authentication
// TLS Client wait for server's Finished handshake
// No need to send anything
TlsState::WAIT_FINISHED => {}
// Send client Finished to end handshake
TlsState::SERVER_CONNECTED => {}
_ => todo!()
}
@ -380,7 +389,7 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// Practically, nothing will be done about cookies/server name
// Extension processing is therefore skipped
// Update hash of the session, get EE by taking appropriate length of data
// Length of handshake header is 4
let (handshake_slice, ee_slice) =
take::<_, _, (&[u8], ErrorKind)>(
might_be_ee.length + 4
@ -440,12 +449,12 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// TODO: Process Certificate
let cert = might_be_cert.get_asn1_der_certificate().unwrap();
log::info!("Certificate Acquisition");
log::info!("Validation {:?}",
log::info!("Certificate validation {:?}",
validate_root_certificate(cert)
);
// Update session TLS state to WAIT_CV
// Length of handshake header is 4
let (handshake_slice, cert_slice) =
take::<_, _, (&[u8], ErrorKind)>(
might_be_cert.length + 4
@ -457,8 +466,6 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
&cert_slice,
cert.return_rsa_public_key().unwrap()
);
},
// In this stage, server will eventually send a CertificateVerify
@ -471,9 +478,7 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
}
// Pull out the `payload` from TlsRepr, decrypt as CV
// Keep 1 copy to update hash
let mut payload = repr.payload.take().unwrap();
let cert_slice = payload.clone();
// Instantiate associated data and decrypt
let mut array: [u8; 5] = [0; 5];
@ -491,10 +496,86 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
// Parse the certificate from TLS payload
let parse_result = parse_inner_plaintext_for_handshake(&payload);
let (_, mut handshake_vec) = parse_result
let (_, (handshake_slice, mut handshake_vec)) = parse_result
.map_err(|_| Error::Unrecognized)?;
// Get hash from session, validate signature
// Ensure that it is CertificateVerify
let might_be_cert_verify = handshake_vec.remove(0);
if might_be_cert_verify.get_msg_type() != HandshakeType::CertificateVerify {
// Process the other handshakes in "handshake_vec"
todo!()
}
// Take out the portion for CertificateVerify
// Length of handshake header is 4
let (handshake_slice, cert_verify_slice) =
take::<_, _, (&[u8], ErrorKind)>(
might_be_cert_verify.length + 4
)(handshake_slice)
.map_err(|_| Error::Unrecognized)?;
// Perform verification, update TLS state if successful
let (sig_alg, signature) = might_be_cert_verify.get_signature().unwrap();
self.session.borrow_mut()
.client_update_for_wait_cv(
cert_verify_slice,
sig_alg,
signature
);
},
// Client will receive a Finished handshake from server
TlsState::WAIT_FINISHED => {
// Finished 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 Finished
let mut payload = repr.payload.take().unwrap();
// Instantiate associated data and decrypt
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();
{
self.session.borrow_mut().decrypt_in_place(
associated_data,
&mut payload
);
}
log::info!("decrypted wait_fin payload: {:?}", payload);
// Parse the TLS inner ciphertext as a Finished handshake
let parse_result = parse_inner_plaintext_for_handshake(&payload);
let (_, (handshake_slice, mut handshake_vec)) = parse_result
.map_err(|_| Error::Unrecognized)?;
// Ensure that it is Finished
let might_be_server_finished = handshake_vec.remove(0);
if might_be_server_finished.get_msg_type() != HandshakeType::Finished {
// Process the other handshakes in "handshake_vec"
todo!()
}
// Take out the portion for server Finished
// Length of handshake header is 4
let (handshake_slice, server_finished_slice) =
take::<_, _, (&[u8], ErrorKind)>(
might_be_server_finished.length + 4
)(handshake_slice)
.map_err(|_| Error::Unrecognized)?;
// Perform verification, update TLS state if successful
self.session.borrow_mut()
.client_update_for_wait_finished(
server_finished_slice,
might_be_server_finished.get_verify_data().unwrap()
);
}
_ => {},

View File

@ -114,10 +114,6 @@ impl<'a> TlsRepr<'a> {
self.handshake.is_none() &&
self.payload.is_some()
}
pub(crate) fn decrypt_ee(&self, shared_secret: &SharedSecret) -> HandshakeRepr {
todo!()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
@ -177,6 +173,32 @@ impl<'a, 'b> HandshakeRepr<'a> {
Err(())
}
}
pub(crate) fn get_signature(&self) -> Result<(SignatureScheme, &[u8]), ()> {
if self.msg_type != HandshakeType::CertificateVerify {
return Err(())
};
if let HandshakeData::CertificateVerify(
cert_verify
) = &self.handshake_data {
Ok((cert_verify.algorithm, cert_verify.signature))
} else {
Err(())
}
}
pub(crate) fn get_verify_data(self) -> Result<&'a [u8], ()> {
if self.msg_type != HandshakeType::Finished {
return Err(())
};
if let HandshakeData::Finished(
fin
) = &self.handshake_data {
Ok(fin.verify_data)
} else {
Err(())
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
@ -212,6 +234,8 @@ pub(crate) enum HandshakeData<'a> {
EncryptedExtensions(EncryptedExtensions),
Certificate(Certificate<'a>),
CertificateVerify(CertificateVerify<'a>),
FinishedNeedParse,
Finished(Finished<'a>),
}
impl<'a> HandshakeData<'a> {
@ -731,3 +755,8 @@ pub(crate) struct CertificateVerify<'a> {
pub(crate) signature_length: u16,
pub(crate) signature: &'a [u8],
}
#[derive(Debug, Clone)]
pub(crate) struct Finished<'a> {
pub(crate) verify_data: &'a [u8]
}