handshake: fin
This commit is contained in:
parent
0042fea902
commit
ee9b31e3de
@ -8,6 +8,7 @@ edition = "2018"
|
|||||||
hkdf = "0.9.0"
|
hkdf = "0.9.0"
|
||||||
sha-1 = { version = "0.9.1", default-features = false }
|
sha-1 = { version = "0.9.1", default-features = false }
|
||||||
sha2 = { 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 }
|
byteorder = { version = "1.3.4", default-features = false }
|
||||||
num_enum = { version = "0.5.1", default-features = false }
|
num_enum = { version = "0.5.1", default-features = false }
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
|
25
src/fake_rng.rs
Normal file
25
src/fake_rng.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ pub mod buffer;
|
|||||||
pub mod key;
|
pub mod key;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod certificate;
|
pub mod certificate;
|
||||||
|
pub mod fake_rng;
|
||||||
|
|
||||||
use nom::error::ParseError;
|
use nom::error::ParseError;
|
||||||
|
|
||||||
|
35
src/parse.rs
35
src/parse.rs
@ -177,6 +177,21 @@ pub(crate) fn parse_handshake(bytes: &[u8]) -> IResult<&[u8], HandshakeRepr> {
|
|||||||
|
|
||||||
Ok((rest, repr))
|
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!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,17 +396,22 @@ fn parse_certificate_verify(bytes: &[u8]) -> IResult<&[u8], CertificateVerify> {
|
|||||||
signature_length
|
signature_length
|
||||||
))(bytes)?;
|
))(bytes)?;
|
||||||
|
|
||||||
|
log::info!("Sig scheme: {:?}, sig:len: {:?}, rest_len: {:?}",
|
||||||
|
signature_scheme,
|
||||||
|
signature_length,
|
||||||
|
rest.len()
|
||||||
|
);
|
||||||
|
|
||||||
let signature_scheme = SignatureScheme::try_from(
|
let signature_scheme = SignatureScheme::try_from(
|
||||||
NetworkEndian::read_u16(signature_scheme)
|
NetworkEndian::read_u16(signature_scheme)
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let signature_length = NetworkEndian::read_u16(signature_length);
|
let signature_length = NetworkEndian::read_u16(signature_length);
|
||||||
|
|
||||||
let (_, signature) = complete(
|
// Take the signature portion out
|
||||||
take(signature_length)
|
let (rest, signature) = take(signature_length)(rest)?;
|
||||||
)(rest)?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
&[],
|
rest,
|
||||||
CertificateVerify {
|
CertificateVerify {
|
||||||
algorithm: signature_scheme,
|
algorithm: signature_scheme,
|
||||||
signature_length,
|
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> {
|
fn parse_extension(bytes: &[u8], handshake_type: HandshakeType) -> IResult<&[u8], Extension> {
|
||||||
let extension_type = take(2_usize);
|
let extension_type = take(2_usize);
|
||||||
let length = take(2_usize);
|
let length = take(2_usize);
|
||||||
|
227
src/session.rs
227
src/session.rs
@ -1,6 +1,6 @@
|
|||||||
use p256::{ EncodedPoint, ecdh::EphemeralSecret };
|
use p256::{ EncodedPoint, ecdh::EphemeralSecret };
|
||||||
use heapless::{ Vec, consts::* };
|
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::{ Aes128Gcm, Aes256Gcm, aes::Aes128 };
|
||||||
use aes_gcm::{ AeadInPlace, NewAead, aead::Buffer };
|
use aes_gcm::{ AeadInPlace, NewAead, aead::Buffer };
|
||||||
use chacha20poly1305::ChaCha20Poly1305;
|
use chacha20poly1305::ChaCha20Poly1305;
|
||||||
@ -8,7 +8,10 @@ use ccm::Ccm;
|
|||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use byteorder::{ByteOrder, NetworkEndian, BigEndian};
|
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::convert::AsRef;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
@ -16,7 +19,9 @@ use core::cell::RefCell;
|
|||||||
use crate::tls::TlsState;
|
use crate::tls::TlsState;
|
||||||
use crate::tls_packet::CipherSuite;
|
use crate::tls_packet::CipherSuite;
|
||||||
use crate::key::*;
|
use crate::key::*;
|
||||||
|
use crate::tls_packet::SignatureScheme;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
use crate::fake_rng::FakeRandom;
|
||||||
|
|
||||||
type Aes128Ccm = Ccm<Aes128, U16, U12>;
|
type Aes128Ccm = Ccm<Aes128, U16, U12>;
|
||||||
|
|
||||||
@ -157,13 +162,23 @@ impl Session {
|
|||||||
let client_handshake_traffic_secret = derive_secret(
|
let client_handshake_traffic_secret = derive_secret(
|
||||||
&handshake_secret_hkdf,
|
&handshake_secret_hkdf,
|
||||||
"c hs traffic",
|
"c hs traffic",
|
||||||
self.hash.get_sha256_clone()
|
self.hash.get_sha256_clone().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let server_handshake_traffic_secret = derive_secret(
|
let server_handshake_traffic_secret = derive_secret(
|
||||||
&handshake_secret_hkdf,
|
&handshake_secret_hkdf,
|
||||||
"s hs traffic",
|
"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();
|
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(
|
let client_handshake_traffic_secret = derive_secret(
|
||||||
&handshake_secret_hkdf,
|
&handshake_secret_hkdf,
|
||||||
"c hs traffic",
|
"c hs traffic",
|
||||||
self.hash.get_sha384_clone()
|
self.hash.get_sha384_clone().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let server_handshake_traffic_secret = derive_secret(
|
let server_handshake_traffic_secret = derive_secret(
|
||||||
&handshake_secret_hkdf,
|
&handshake_secret_hkdf,
|
||||||
"s hs traffic",
|
"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();
|
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;
|
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 {
|
pub(crate) fn verify_session_id_echo(&self, session_id_echo: &[u8]) -> bool {
|
||||||
if let Some(session_id_inner) = self.session_id {
|
if let Some(session_id_inner) = self.session_id {
|
||||||
session_id_inner == session_id_echo
|
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 {
|
if let Self::Sha256 { sha256 } = self {
|
||||||
sha256.clone()
|
Ok(sha256.clone())
|
||||||
} else {
|
} 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 {
|
if let Self::Sha384 { sha384 } = self {
|
||||||
sha384.clone()
|
Ok(sha384.clone())
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
src/tls.rs
101
src/tls.rs
@ -54,6 +54,7 @@ pub(crate) enum TlsState {
|
|||||||
WAIT_CERT,
|
WAIT_CERT,
|
||||||
WAIT_CV,
|
WAIT_CV,
|
||||||
WAIT_FINISHED,
|
WAIT_FINISHED,
|
||||||
|
SERVER_CONNECTED, // Additional state, for client to send Finished after server Finished
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ pub struct TlsSocket<R: 'static + RngCore + CryptoRng>
|
|||||||
session: RefCell<Session>,
|
session: RefCell<Session>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
pub fn new<'a, 'b, 'c>(
|
pub fn new<'a, 'b, 'c>(
|
||||||
sockets: &mut SocketSet<'a, 'b, 'c>,
|
sockets: &mut SocketSet<'a, 'b, 'c>,
|
||||||
rx_buffer: TcpSocketBuffer<'b>,
|
rx_buffer: TcpSocketBuffer<'b>,
|
||||||
@ -174,6 +175,14 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||||||
// No need to send anything
|
// No need to send anything
|
||||||
TlsState::WAIT_CV => {},
|
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!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +389,7 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||||||
// Practically, nothing will be done about cookies/server name
|
// Practically, nothing will be done about cookies/server name
|
||||||
// Extension processing is therefore skipped
|
// Extension processing is therefore skipped
|
||||||
// Update hash of the session, get EE by taking appropriate length of data
|
// Update hash of the session, get EE by taking appropriate length of data
|
||||||
|
// Length of handshake header is 4
|
||||||
let (handshake_slice, ee_slice) =
|
let (handshake_slice, ee_slice) =
|
||||||
take::<_, _, (&[u8], ErrorKind)>(
|
take::<_, _, (&[u8], ErrorKind)>(
|
||||||
might_be_ee.length + 4
|
might_be_ee.length + 4
|
||||||
@ -440,12 +449,12 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||||||
|
|
||||||
// TODO: Process Certificate
|
// TODO: Process Certificate
|
||||||
let cert = might_be_cert.get_asn1_der_certificate().unwrap();
|
let cert = might_be_cert.get_asn1_der_certificate().unwrap();
|
||||||
log::info!("Certificate Acquisition");
|
log::info!("Certificate validation {:?}",
|
||||||
log::info!("Validation {:?}",
|
|
||||||
validate_root_certificate(cert)
|
validate_root_certificate(cert)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update session TLS state to WAIT_CV
|
// Update session TLS state to WAIT_CV
|
||||||
|
// Length of handshake header is 4
|
||||||
let (handshake_slice, cert_slice) =
|
let (handshake_slice, cert_slice) =
|
||||||
take::<_, _, (&[u8], ErrorKind)>(
|
take::<_, _, (&[u8], ErrorKind)>(
|
||||||
might_be_cert.length + 4
|
might_be_cert.length + 4
|
||||||
@ -457,8 +466,6 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||||||
&cert_slice,
|
&cert_slice,
|
||||||
cert.return_rsa_public_key().unwrap()
|
cert.return_rsa_public_key().unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// In this stage, server will eventually send a CertificateVerify
|
// 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
|
// Pull out the `payload` from TlsRepr, decrypt as CV
|
||||||
// Keep 1 copy to update hash
|
|
||||||
let mut payload = repr.payload.take().unwrap();
|
let mut payload = repr.payload.take().unwrap();
|
||||||
let cert_slice = payload.clone();
|
|
||||||
|
|
||||||
// Instantiate associated data and decrypt
|
// Instantiate associated data and decrypt
|
||||||
let mut array: [u8; 5] = [0; 5];
|
let mut array: [u8; 5] = [0; 5];
|
||||||
@ -491,10 +496,86 @@ impl<R: RngCore + CryptoRng> TlsSocket<R> {
|
|||||||
|
|
||||||
// Parse the certificate from TLS payload
|
// Parse the certificate from TLS payload
|
||||||
let parse_result = parse_inner_plaintext_for_handshake(&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)?;
|
.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()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {},
|
_ => {},
|
||||||
|
@ -114,10 +114,6 @@ impl<'a> TlsRepr<'a> {
|
|||||||
self.handshake.is_none() &&
|
self.handshake.is_none() &&
|
||||||
self.payload.is_some()
|
self.payload.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn decrypt_ee(&self, shared_secret: &SharedSecret) -> HandshakeRepr {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
@ -177,6 +173,32 @@ impl<'a, 'b> HandshakeRepr<'a> {
|
|||||||
Err(())
|
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)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
@ -212,6 +234,8 @@ pub(crate) enum HandshakeData<'a> {
|
|||||||
EncryptedExtensions(EncryptedExtensions),
|
EncryptedExtensions(EncryptedExtensions),
|
||||||
Certificate(Certificate<'a>),
|
Certificate(Certificate<'a>),
|
||||||
CertificateVerify(CertificateVerify<'a>),
|
CertificateVerify(CertificateVerify<'a>),
|
||||||
|
FinishedNeedParse,
|
||||||
|
Finished(Finished<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> HandshakeData<'a> {
|
impl<'a> HandshakeData<'a> {
|
||||||
@ -731,3 +755,8 @@ pub(crate) struct CertificateVerify<'a> {
|
|||||||
pub(crate) signature_length: u16,
|
pub(crate) signature_length: u16,
|
||||||
pub(crate) signature: &'a [u8],
|
pub(crate) signature: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct Finished<'a> {
|
||||||
|
pub(crate) verify_data: &'a [u8]
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user