From 9e5a9266fc6c22a618ab62879ecc69a17e0757f6 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 18 Nov 2020 17:39:27 +0800 Subject: [PATCH] state: client cert/verify init --- src/main.rs | 1 + src/session.rs | 352 ++++++++++++++++++++++++++++++++++++++++++++++--- src/tls.rs | 338 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 642 insertions(+), 49 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4de9aa9..c2bed53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,6 +68,7 @@ fn main() { rx_buffer, tx_buffer, &mut RNG, + None ) }; diff --git a/src/session.rs b/src/session.rs index d042568..78c87d9 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,4 +1,4 @@ -use p256::{ EncodedPoint, ecdh::EphemeralSecret }; +use p256::{ EncodedPoint, ecdh::EphemeralSecret, ecdsa::signature::DigestVerifier }; use heapless::{ Vec, consts::* }; use sha2::{ Digest, Sha256, Sha384, Sha512, digest::FixedOutput }; use aes_gcm::{ Aes128Gcm, Aes256Gcm, aes::Aes128 }; @@ -18,9 +18,11 @@ use crate::tls_packet::SignatureScheme; use crate::Error; use crate::fake_rng::FakeRandom; +use core::convert::TryFrom; + type Aes128Ccm = Ccm; -pub(crate) struct Session { +pub(crate) struct Session<'a> { state: TlsState, role: TlsRole, // Session ID for this session @@ -59,14 +61,22 @@ pub(crate) struct Session { // Reset to 0 on rekey AND key exchange // TODO: Force rekey if sequence number need to wrap (very low priority) client_sequence_number: u64, - server_sequence_number: u64, + pub server_sequence_number: u64, // Certificate public key // For Handling CertificateVerify cert_public_key: Option, + // Client certificate and its private key + cert_private_key: Option<(CertificatePrivateKey, alloc::vec::Vec<&'a [u8]>)>, + // Flag for noting the need to send client certificate + // Client must cent Certificate extension iff server requested it + need_send_client_cert: bool, + client_cert_verify_sig_alg: Option, } -impl Session { - pub(crate) fn new(role: TlsRole) -> Self { +impl<'a> Session<'a> { + pub(crate) fn new(role: TlsRole, certificate_with_key: Option<( + CertificatePrivateKey, alloc::vec::Vec<&'a [u8]> + )>) -> Self { let hash = Hash::Undetermined { sha256: Sha256::new(), sha384: Sha384::new(), @@ -93,7 +103,10 @@ impl Session { server_application_nonce: None, client_sequence_number: 0, server_sequence_number: 0, - cert_public_key: None + cert_public_key: None, + cert_private_key: certificate_with_key, + need_send_client_cert: false, + client_cert_verify_sig_alg: None } } @@ -129,15 +142,7 @@ impl Session { if self.state != TlsState::WAIT_SH || self.role != TlsRole::Client { todo!() } - // Generate ECDHE shared secret - // Remove private secret - // let ecdhe_shared_secret = - // self.ecdhe_secret - // .take() - // .unwrap() - // .diffie_hellman(&encoded_point) - // .unwrap(); - + let mut shared_secret_bytes: [u8; 32] = [0; 32]; if encoded_point.is_some() { let p256_shared_secret = @@ -496,6 +501,72 @@ impl Session { self.state = TlsState::WAIT_CERT_CR; } + pub(crate) fn client_update_for_certificate_request( + &mut self, + cert_request_slice: &[u8], + signature_algorithms: &[crate::tls_packet::SignatureScheme] + ) { + self.hash.update(cert_request_slice); + // Note the need of sending client certificate + self.need_send_client_cert = true; + // Determine the supplied client certificate indeed has an + // acceptable signature algorithm + let mut private_key_algorithm_acceptable = false; + if let Some((private_key, cert)) = &self.cert_private_key { + if let CertificatePrivateKey::RSA {..} = private_key { + for sig_alg in signature_algorithms.iter() { + use crate::tls_packet::SignatureScheme::*; + if *sig_alg == rsa_pkcs1_sha256 + || *sig_alg == rsa_pkcs1_sha384 + || *sig_alg == rsa_pkcs1_sha512 + || *sig_alg == rsa_pss_rsae_sha256 + || *sig_alg == rsa_pss_rsae_sha384 + || *sig_alg == rsa_pss_rsae_sha512 + || *sig_alg == rsa_pss_pss_sha256 + || *sig_alg == rsa_pss_pss_sha384 + || *sig_alg == rsa_pss_pss_sha512 + { + private_key_algorithm_acceptable = true; + self.client_cert_verify_sig_alg.replace(*sig_alg); + break; + } + } + } else if let CertificatePrivateKey::ECDSA_SECP256R1_SHA256 {..} + = private_key + { + for sig_alg in signature_algorithms.iter() { + use crate::tls_packet::SignatureScheme::*; + if *sig_alg == ecdsa_secp256r1_sha256 + { + private_key_algorithm_acceptable = true; + self.client_cert_verify_sig_alg.replace(*sig_alg); + break; + } + } + } else if let CertificatePrivateKey::ED25519 {..} = private_key { + for sig_alg in signature_algorithms.iter() { + use crate::tls_packet::SignatureScheme::*; + if *sig_alg == ed25519 + { + private_key_algorithm_acceptable = true; + self.client_cert_verify_sig_alg.replace(*sig_alg); + break; + } + } + } + } + + // Dump the private key and certificate if the other side will not take it + if !private_key_algorithm_acceptable { + self.cert_private_key.take(); + } + + log::info!("client key: {:?}", self.cert_private_key.is_some()); + + // Move to the next state + self.state = TlsState::WAIT_CERT; + } + pub(crate) fn client_update_for_wait_cert_cr( &mut self, cert_slice: &[u8], @@ -525,11 +596,39 @@ impl Session { // Handle Ed25519 and p256 separately // These 2 algorithms have a mandated hash function if signature_algorithm == SignatureScheme::ecdsa_secp256r1_sha256 { - todo!() + let verify_hash = Sha256::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, server CertificateVerify") + .chain(&[0]) + .chain(&transcript_hash); + let ecdsa_signature = p256::ecdsa::Signature::from_asn1(signature).unwrap(); + self.cert_public_key + .take() + .unwrap() + .get_ecdsa_secp256r1_sha256_verify_key() + .unwrap() + .verify_digest( + verify_hash, &ecdsa_signature + ).unwrap(); + return } if signature_algorithm == SignatureScheme::ed25519 { - todo!() + let verify_hash = Sha512::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, server CertificateVerify") + .chain(&[0]) + .chain(&transcript_hash); + let ed25519_signature = ed25519_dalek::Signature::try_from( + signature + ).unwrap(); + self.cert_public_key.take() + .unwrap() + .get_ed25519_public_key() + .unwrap() + .verify_prehashed(verify_hash, None, &ed25519_signature) + .unwrap(); + return } // Get verification hash, and verify the signature @@ -696,6 +795,8 @@ impl Session { self.hash.get_sha256_clone().unwrap() ); + log::info!("Server traffic secret: {:?}", server_application_traffic_secret); + self.client_application_traffic_secret.replace( Vec::from_slice(&client_application_traffic_secret).unwrap() ); @@ -983,6 +1084,26 @@ impl Session { self.state = TlsState::SERVER_CONNECTED; } + pub(crate) fn client_update_for_certificate_in_server_connected( + &mut self, + client_certificate_slice: &[u8] + ) + { + // Sequence number is updated by send methods + // No need to change state as client will send everything needed immediately + self.hash.update(client_certificate_slice); + } + + pub(crate) fn client_update_for_cert_verify_in_server_connected( + &mut self, + client_certificate_verify_slice: &[u8] + ) + { + // Sequence number is updated by send methods + // No need to change state as client will send everything needed immediately + self.hash.update(client_certificate_verify_slice); + } + pub(crate) fn client_update_for_server_connected( &mut self, @@ -1017,6 +1138,190 @@ impl Session { self.changed_cipher_spec = true; } + pub(crate) fn need_to_send_client_certificate(&self) -> bool { + self.need_send_client_cert + } + + pub(crate) fn get_private_certificate_slices(&self) -> Option<&alloc::vec::Vec<&[u8]>> { + if let Some((_, cert_vec)) = &self.cert_private_key { + Some(cert_vec) + } else { + None + } + } + + pub(crate) fn get_client_certificate_verify_signature(&self) + -> (crate::tls_packet::SignatureScheme, alloc::vec::Vec) + { + if let Some((private_key, client_certificate)) = &self.cert_private_key { + let transcript_hash: Vec = + 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!() + }; + + use crate::tls_packet::SignatureScheme::*; + // RSA signature must be with PSS padding scheme + let get_rsa_padding_scheme = |sig_alg: SignatureScheme| + -> (SignatureScheme, PaddingScheme) + { + match sig_alg { + rsa_pkcs1_sha256 => { + ( + rsa_pss_rsae_sha256, + PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_256)) + ) + }, + rsa_pkcs1_sha384 => { + ( + rsa_pss_rsae_sha384, + PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_384)) + ) + }, + rsa_pkcs1_sha512 => { + ( + rsa_pss_rsae_sha512, + PaddingScheme::new_pkcs1v15_sign(Some(RSAHash::SHA2_512)) + ) + }, + rsa_pss_rsae_sha256 | rsa_pss_pss_sha256 => { + ( + sig_alg, + PaddingScheme::new_pss::(FakeRandom{}) + ) + }, + rsa_pss_rsae_sha384 | rsa_pss_pss_sha384 => { + ( + sig_alg, + PaddingScheme::new_pss::(FakeRandom{}) + ) + }, + rsa_pss_rsae_sha512 | rsa_pss_pss_sha512 => { + ( + sig_alg, + PaddingScheme::new_pss::(FakeRandom{}) + ) + }, + _ => unreachable!() + } + }; + + match private_key { + CertificatePrivateKey::RSA { cert_rsa_private_key } => { + let sig_alg = self.client_cert_verify_sig_alg.unwrap(); + let verify_hash: Vec = match sig_alg { + rsa_pkcs1_sha256 | rsa_pss_rsae_sha256 | rsa_pss_pss_sha256 => { + Vec::from_slice( + &sha2::Sha256::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, client CertificateVerify") + .chain(&[0x00]) + .chain(&transcript_hash) + .finalize() + ).unwrap() + }, + rsa_pkcs1_sha384 | rsa_pss_rsae_sha384 | rsa_pss_pss_sha384 => { + Vec::from_slice( + &sha2::Sha384::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, client CertificateVerify") + .chain(&[0x00]) + .chain(&transcript_hash) + .finalize() + ).unwrap() + }, + rsa_pkcs1_sha512 | rsa_pss_rsae_sha512 | rsa_pss_pss_sha512 => { + Vec::from_slice( + &sha2::Sha512::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, client CertificateVerify") + .chain(&[0x00]) + .chain(&transcript_hash) + .finalize() + ).unwrap() + }, + _ => unreachable!() + }; + let (modified_sig_alg, padding) = get_rsa_padding_scheme(sig_alg); + ( + modified_sig_alg, + cert_rsa_private_key.sign( + padding, &verify_hash + ).unwrap() + ) + }, + + CertificatePrivateKey::ECDSA_SECP256R1_SHA256 { cert_signing_key } => { + let verify_hash = sha2::Sha256::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, client CertificateVerify") + .chain(&[0x00]) + .chain(&transcript_hash); + + use p256::ecdsa::signature::DigestSigner; + let sig_vec = alloc::vec::Vec::from( + cert_signing_key.sign_digest(verify_hash).as_ref() + ); + + ( + ecdsa_secp256r1_sha256, + sig_vec + ) + }, + + CertificatePrivateKey::ED25519 { cert_eddsa_key } => { + let verify_hash = sha2::Sha512::new() + .chain(&[0x20; 64]) + .chain("TLS 1.3, client CertificateVerify") + .chain(&[0x00]) + .chain(&transcript_hash); + + // Ed25519 requires a key-pair to sign + // Get public key from certificate + let certificate = crate::parse::parse_asn1_der_certificate( + client_certificate[0] + ).unwrap().1; + + let cert_public_key = certificate + .get_cert_public_key() + .unwrap(); + let ed25519_public_key = cert_public_key + .get_ed25519_public_key() + .unwrap(); + + let mut keypair_bytes: [u8; 64] = [0; 64]; + &keypair_bytes[..32].clone_from_slice(cert_eddsa_key.as_bytes()); + &keypair_bytes[32..].clone_from_slice(ed25519_public_key.as_bytes()); + + let ed25519_keypair = ed25519_dalek::Keypair::from_bytes( + &keypair_bytes + ).unwrap(); + + let sig_vec = alloc::vec::Vec::from( + ed25519_keypair + .sign_prehashed(verify_hash, None) + .unwrap() + .as_ref() + ); + + ( + ed25519, + sig_vec + ) + } + } + } + else { + // Should definitely NOT be invoking this function + // TODO: Throw error + todo!() + } + + } + pub(crate) fn get_client_finished_verify_data(&self) -> Vec { if let Ok(sha256) = self.hash.get_sha256_clone() { let hkdf = Hkdf::::from_prk( @@ -1235,6 +1540,7 @@ impl Session { associated_data: &[u8], buffer: &mut [u8] ) -> Result<(), Error> { + let (seq_num, nonce, cipher): (u64, &Vec, &Cipher) = match self.role { TlsRole::Server => {( self.client_sequence_number, @@ -1519,3 +1825,15 @@ impl CertificatePublicKey { } } } + +pub enum CertificatePrivateKey { + RSA { + cert_rsa_private_key: rsa::RSAPrivateKey + }, + ECDSA_SECP256R1_SHA256 { + cert_signing_key: p256::ecdsa::SigningKey + }, + ED25519 { + cert_eddsa_key: ed25519_dalek::SecretKey + } +} diff --git a/src/tls.rs b/src/tls.rs index 2cc4eb0..bb18634 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -14,6 +14,7 @@ use byteorder::{ByteOrder, NetworkEndian}; use generic_array::GenericArray; use core::convert::TryFrom; +use core::convert::TryInto; use core::cell::RefCell; use rand_core::{RngCore, CryptoRng}; @@ -52,19 +53,23 @@ pub(crate) enum TlsState { } // TODO: Group up all session_specific parameters into a separate structure -pub struct TlsSocket +pub struct TlsSocket<'s, R: RngCore + CryptoRng> { tcp_handle: SocketHandle, rng: R, - session: RefCell, + session: RefCell>, } -impl TlsSocket { +impl<'s, R: RngCore + CryptoRng> TlsSocket<'s, R> { pub fn new<'a, 'b, 'c>( sockets: &mut SocketSet<'a, 'b, 'c>, rx_buffer: TcpSocketBuffer<'b>, tx_buffer: TcpSocketBuffer<'b>, rng: R, + certificate_with_key: Option<( + crate::session::CertificatePrivateKey, + Vec<&'s [u8]> + )> ) -> Self where 'b: 'c, @@ -75,7 +80,7 @@ impl TlsSocket { tcp_handle, rng, session: RefCell::new( - Session::new(TlsRole::Client) + Session::new(TlsRole::Client, certificate_with_key) ), } } @@ -162,10 +167,14 @@ impl TlsSocket { // TLS client should jump from WAIT_SH directly to WAIT_CERT_CR directly. TlsState::WAIT_EE => {}, - // TLS Client wait for server's certificate + // TLS Client wait for server's certificate/ certificate request // No need to send anything TlsState::WAIT_CERT_CR => {}, + // TLS Client wait for server's certificate after receiveing a request + // No need to send anything + TlsState::WAIT_CERT => {}, + // TLS Client wait for server's certificate cerify // No need to send anything TlsState::WAIT_CV => {}, @@ -176,7 +185,148 @@ impl TlsSocket { TlsState::WAIT_FINISHED => {} // Send client Finished to end handshake + // Also send certificate and certificate verify before client Finished if + // server sent a CertificateRequest beforehand TlsState::SERVER_CONNECTED => { + // Certificate & CertificateVerify + let need_to_send_client_cert = { + self.session.borrow().need_to_send_client_certificate() + }; + if need_to_send_client_cert { + let (certificates_total_length, mut buffer_vec) = { + let mut session = self.session.borrow_mut(); + let mut buffer_vec: Vec = Vec::new(); + let certificates = session + .get_private_certificate_slices() + .clone(); + + // Handshake level, client certificate byte followed by length (u24) + let mut handshake_header: [u8; 4] = [11, 0, 0, 0]; + // Certificate struct: + // request_context = X509: 0 (u8), + // certificate_list to be determined (u24) + let mut certificate_header: [u8; 4] = [0, 0, 0, 0]; + let mut certificates_total_length: u32 = 0; + + // Append place holder bytes (8 of them) in the buffer vector + // Simpily copy the the headers back into the vector + // when all certificates are appended into the vector + buffer_vec.extend_from_slice(&[11, 0, 0, 0, 0, 0, 0, 0]); + + // Certificate Entry struct(s) + if let Some(certificate_list) = certificates { + for cert in certificate_list.iter() { + // cert_data length, to be determined (u24) + let mut cert_data_length: [u8; 3] = [0, 0, 0]; + // extensions: no extension needed + let extension: [u8; 2] = [0, 0]; + + let certificate_length: u32 = u32::try_from(cert.len()).unwrap(); + + NetworkEndian::write_u24( + &mut cert_data_length, + certificate_length + ); + + // Update length in Certificate struct + certificates_total_length += ( + // cert_data (len & data) AND extension (len & data) + 3 + certificate_length + 2 + 0 + ); + + buffer_vec.extend_from_slice(&cert_data_length); + buffer_vec.extend_from_slice(cert); + buffer_vec.extend_from_slice(&extension); + } + } + + // Write total certificate length into Certificate struct + NetworkEndian::write_u24( + &mut buffer_vec[5..8], + certificates_total_length + ); + + // Write the length of the entire handshake + NetworkEndian::write_u24( + &mut buffer_vec[1..4], + // 4 bytes for the Certificate struct header + certificates_total_length + 4 + ); + + // Inner plaintext: record type + buffer_vec.push(22); + (certificates_total_length, buffer_vec) + }; + + self.send_application_slice(sockets, &mut buffer_vec.clone())?; + // Update session + let buffer_vec_length = buffer_vec.len(); + + { + self.session.borrow_mut() + .client_update_for_certificate_in_server_connected( + &buffer_vec[..(buffer_vec_length-1)] + ); + } + + // Send a CertificateVerify as well if any certificates + // were just sent by the client + if certificates_total_length != 0 { + // Serialize CertificateVerify + + // Handshake bytes: + // msg_type = 15, CertificateVerify (u8) + // handshake_data_length = to be determined (u24) + // signature algorithm (u16) + // signature_length (u16) + // signature, the rest + + let mut verify_buffer_vec: Vec = Vec::new(); + // Leave bytes from Handshake struct as placeholders + verify_buffer_vec.extend_from_slice(&[ + 15, + 0, 0, 0, + 0, 0, + 0, 0 + ]); + { + let session = self.session.borrow(); + let (sig_alg, signature) = session + .get_client_certificate_verify_signature(); + + let signature_length: u16 = u16::try_from(signature.len()).unwrap(); + NetworkEndian::write_u24( + &mut verify_buffer_vec[1..4], + (signature_length + 4).into() + ); + NetworkEndian::write_u16( + &mut verify_buffer_vec[4..6], + sig_alg.try_into().unwrap() + ); + NetworkEndian::write_u16( + &mut verify_buffer_vec[6..8], + signature_length + ); + verify_buffer_vec.extend_from_slice(&signature); + } + // Push content byte (handshake: 22) + verify_buffer_vec.push(22); + + log::info!("Client CV: {:?}", verify_buffer_vec); + self.send_application_slice(sockets, &mut verify_buffer_vec.clone())?; + // Update session + let cert_verify_len = verify_buffer_vec.len(); + + { + self.session.borrow_mut() + .client_update_for_cert_verify_in_server_connected( + &verify_buffer_vec[..(cert_verify_len-1)] + ); + } + } + } + + // Client Finished let inner_plaintext: HeaplessVec = { let verify_data = self.session.borrow() .get_client_finished_verify_data(); @@ -192,8 +342,10 @@ impl TlsSocket { buffer }; self.send_application_slice(sockets, &mut inner_plaintext.clone())?; + + let inner_plaintext_length = inner_plaintext.len(); self.session.borrow_mut() - .client_update_for_server_connected(&inner_plaintext); + .client_update_for_server_connected(&inner_plaintext[..(inner_plaintext_length-1)]); } _ => todo!() @@ -449,38 +601,131 @@ impl TlsSocket { // In this stage, wait for a certificate from server // Parse the certificate and check its content TlsState::WAIT_CERT_CR => { - // Verify that it is indeed an Certificate + // Verify that it is indeed an Certificate, or CertificateRequest let might_be_cert = repr.handshake.take().unwrap(); - if might_be_cert.get_msg_type() != HandshakeType::Certificate { - // Process the other handshakes in "handshake_vec" + if might_be_cert.get_msg_type() == HandshakeType::Certificate { + // Process certificates + + // let all_certificates = might_be_cert.get_all_asn1_der_certificates().unwrap(); + // log::info!("Number of certificates: {:?}", all_certificates.len()); + // log::info!("All certificates: {:?}", all_certificates); + + // TODO: Process all certificates + let cert = might_be_cert.get_asn1_der_certificate().unwrap(); + + // TODO: Replace this block after implementing a proper + // certificate verification procdeure + cert.validate_self_signed_signature().expect("Signature mismatched"); + + // 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 + )(handshake_slice) + .map_err(|_| Error::Unrecognized)?; + + self.session.borrow_mut() + .client_update_for_wait_cert_cr( + &cert_slice, + cert.get_cert_public_key().unwrap() + ); + log::info!("Received WAIT_CERT_CR"); + } + else if might_be_cert.get_msg_type() == HandshakeType::CertificateRequest { + // Process signature algorithm extension + // Signature algorithm for the private key of client cert must be included + // within the list of signature algorithms + // + // Client is STRONGLY RECOMMENDED to use a signature algorithm within + // the list of `mandatory to implement` signature algorithms, including: + // rsa_pkcs1_sha256, rsa_pss_rsae_sha256, ecdsa_secp256r1_sha256 + // + // Update client state + let cert_req_extensions: &Vec = might_be_cert + .get_cert_request_extensions() + .unwrap(); + let sig_algs_ext: Option<&crate::tls_packet::Extension> + = cert_req_extensions + .iter() + .find( |&extension| { + extension.extension_type + == crate::tls_packet::ExtensionType::SignatureAlgorithms + } + ); + if sig_algs_ext.is_some() { + // Convert extension into SignatureScheme + if let crate::tls_packet::ExtensionData::SignatureAlgorithms( + scheme_list + ) = &sig_algs_ext.unwrap().extension_data { + // Update session TLS state to WAIT_CERT + // Length of handshake header is 4 + let (_handshake_slice, cert_req_slice) = + take::<_, _, (&[u8], ErrorKind)>( + might_be_cert.length + 4 + )(handshake_slice) + .map_err(|_| Error::Unrecognized)?; + + self.session.borrow_mut() + .client_update_for_certificate_request( + &cert_req_slice, + &scheme_list.supported_signature_algorithms + ); + } + + + } else { + // Reject connection, CertificateRequest must have + // SignatureAlgorithm extension + todo!() + } + log::info!("Received WAIT_CERT_CR"); + } + else { + // Throw alert todo!() } + }, - // let all_certificates = might_be_cert.get_all_asn1_der_certificates().unwrap(); - // log::info!("Number of certificates: {:?}", all_certificates.len()); - // log::info!("All certificates: {:?}", all_certificates); + // In this stage, server will send a certificate chain + // Verify the certificate + TlsState::WAIT_CERT => { + // Verify that it is indeed an Certificate + let might_be_cert = repr.handshake.take().unwrap(); - // TODO: Process all certificates - let cert = might_be_cert.get_asn1_der_certificate().unwrap(); + if might_be_cert.get_msg_type() == HandshakeType::Certificate { + // Process certificates - // TODO: Replace this block after implementing a proper - // certificate verification procdeure - cert.validate_self_signed_signature().expect("Signature mismatched"); + // let all_certificates = might_be_cert.get_all_asn1_der_certificates().unwrap(); + // log::info!("Number of certificates: {:?}", all_certificates.len()); + // log::info!("All certificates: {:?}", all_certificates); - // 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 - )(handshake_slice) - .map_err(|_| Error::Unrecognized)?; + // TODO: Process all certificates + let cert = might_be_cert.get_asn1_der_certificate().unwrap(); - self.session.borrow_mut() - .client_update_for_wait_cert_cr( - &cert_slice, - cert.get_cert_public_key().unwrap() - ); - log::info!("Received WAIT_CERT_CR"); + // TODO: Replace this block after implementing a proper + // certificate verification procdeure + cert.validate_self_signed_signature().expect("Signature mismatched"); + + // 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 + )(handshake_slice) + .map_err(|_| Error::Unrecognized)?; + + self.session.borrow_mut() + .client_update_for_wait_cert_cr( + &cert_slice, + cert.get_cert_public_key().unwrap() + ); + log::info!("Received WAIT_CERT"); + } else { + // Unexpected handshakes + // Throw alert + todo!() + } }, // In this stage, server will eventually send a CertificateVerify @@ -619,6 +864,7 @@ impl TlsSocket { }, _ => return Err(Error::Illegal), }; + NetworkEndian::write_u16( &mut associated_data[3..5], auth_tag_length + u16::try_from(slice.len()).unwrap() @@ -671,7 +917,34 @@ impl TlsSocket { return Ok(0); } - let recv_slice_size = tcp_socket.recv_slice(data)?; + // TODO: Use `recv` to receive instead + // Issue with using recv slice: + // Encrypted application data can cramp together into a TCP Segment + // Dequeuing all bytes from the buffer immediately can cause + // 1. Incorrect decryption, hence throwing error, and + // 2. sequence number to go out of sync forever + let (recv_slice_size, acceptable) = tcp_socket.recv( + |buffer| { + // Read the size of the TLS record beforehand + let record_length: usize = NetworkEndian::read_u16(&buffer[3..5]).into(); + let provided_data_capacity: usize = data.len(); + // Copy the entire byte representation of TLS packet into the + // user-provided buffer, if possible + if provided_data_capacity >= (record_length + 5) { + &data[..(record_length + 5)].clone_from_slice(&buffer[..(record_length + 5)]); + } + ( + (record_length + 5), + ( + (record_length + 5), + provided_data_capacity < (record_length + 5) + ) + ) + } + )?; + + // let recv_slice_size = tcp_socket.recv_slice(data)?; + // Encrypted data need a TLS record wrapper (5 bytes) // Authentication tag (16 bytes, for all supported AEADs) // Content type byte (1 byte) @@ -684,11 +957,12 @@ impl TlsSocket { let mut session = self.session.borrow_mut(); let mut associated_data: [u8; 5] = [0; 5]; associated_data.clone_from_slice(&data[..5]); - log::info!("Received encrypted appdata: {:?}", &data[..recv_slice_size]); + // log::info!("Received encrypted appdata: {:?}", &data[..recv_slice_size]); // Dump association data (TLS Record wrapper) // Only decrypt application data // Always increment sequence number after decrpytion + log::info!("Sequence number: {:?}", session.server_sequence_number); session.decrypt_application_data_in_place( &associated_data, &mut data[5..recv_slice_size]