Compare commits
3 Commits
3d566b22e7
...
bfc13dcebc
Author | SHA1 | Date |
---|---|---|
occheung | bfc13dcebc | |
occheung | c57fc79f6b | |
occheung | 59dc5873c5 |
|
@ -26,7 +26,7 @@ default-features = true
|
||||||
features = [ "heapless" ]
|
features = [ "heapless" ]
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.6.0"
|
git = "https://github.com/smoltcp-rs/smoltcp.git"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp", "alloc"]
|
features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp", "alloc"]
|
||||||
|
|
||||||
|
@ -61,11 +61,6 @@ version = "5.1.2"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = []
|
features = []
|
||||||
|
|
||||||
[dependencies.arraydeque]
|
|
||||||
version = "0.4.5"
|
|
||||||
default-features = false
|
|
||||||
features = [ "use_generic_array" ]
|
|
||||||
|
|
||||||
[dependencies.simple_logger]
|
[dependencies.simple_logger]
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
optional = true
|
optional = true
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use num_enum::IntoPrimitive;
|
use num_enum::IntoPrimitive;
|
||||||
use num_enum::TryFromPrimitive;
|
use num_enum::TryFromPrimitive;
|
||||||
|
|
||||||
|
use generic_array::GenericArray;
|
||||||
|
|
||||||
use crate::parse::parse_asn1_der_rsa_public_key;
|
use crate::parse::parse_asn1_der_rsa_public_key;
|
||||||
use crate::Error as TlsError;
|
use crate::Error as TlsError;
|
||||||
|
use crate::session::CertificatePublicKey;
|
||||||
|
|
||||||
use sha1::{Sha1, Digest};
|
use sha1::{Sha1, Digest};
|
||||||
use rsa::{PublicKey, RSAPublicKey, PaddingScheme, BigUint, Hash};
|
use rsa::{PublicKey, RSAPublicKey, PaddingScheme, BigUint, Hash};
|
||||||
|
@ -182,10 +185,112 @@ impl<'a> Certificate<'a> {
|
||||||
BigUint::from_bytes_be(exponent)
|
BigUint::from_bytes_be(exponent)
|
||||||
).map_err(|_| ())
|
).map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// General return public key method
|
||||||
|
// TODO: Replace return_rsa_public_key() with this method
|
||||||
|
// Things to change: session.rs: client_update_for_wait_cert_cr
|
||||||
|
pub(crate) fn get_cert_public_key(&self) -> Result<CertificatePublicKey, ()> {
|
||||||
|
let public_key_info = &self.tbs_certificate.subject_public_key_info;
|
||||||
|
let algorithm_identifier = &public_key_info.algorithm;
|
||||||
|
|
||||||
|
// 3 possibilities: RSA_ENCRYPTION, ID_EC_PUBLIC_KEY, and EdDSA25519
|
||||||
|
match algorithm_identifier.algorithm {
|
||||||
|
oid::RSA_ENCRYPTION => {
|
||||||
|
let (_, (modulus, exponent)) = parse_asn1_der_rsa_public_key(
|
||||||
|
self.tbs_certificate.subject_public_key_info.subject_public_key
|
||||||
|
).map_err(|_| ())?;
|
||||||
|
|
||||||
|
let public_key = RSAPublicKey::new(
|
||||||
|
BigUint::from_bytes_be(modulus),
|
||||||
|
BigUint::from_bytes_be(exponent)
|
||||||
|
).map_err(|_| ())?;
|
||||||
|
Ok(
|
||||||
|
CertificatePublicKey::RSA {
|
||||||
|
cert_rsa_public_key: public_key
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
oid::ID_EC_PUBLIC_KEY => {
|
||||||
|
// Check the type of EC, only support secp256r1
|
||||||
|
// Will definitely NOT support custom curve
|
||||||
|
if algorithm_identifier.parameters != oid::PRIME256V1 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let p256_verify_key = p256::ecdsa::VerifyKey::from_encoded_point(
|
||||||
|
&p256::EncodedPoint::from_untagged_bytes(
|
||||||
|
GenericArray::from_slice(
|
||||||
|
&public_key_info.subject_public_key[1..]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).map_err(|_| ())?;
|
||||||
|
Ok(
|
||||||
|
CertificatePublicKey::ECDSA_SECP256R1_SHA256 {
|
||||||
|
cert_verify_key: p256_verify_key
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
oid::ID_EDDSA_25519 => {
|
||||||
|
let ed25519_public_key = ed25519_dalek::PublicKey::from_bytes(
|
||||||
|
public_key_info.subject_public_key
|
||||||
|
).map_err(|_| ())?;
|
||||||
|
Ok(
|
||||||
|
CertificatePublicKey::ED25519 {
|
||||||
|
cert_eddsa_key: ed25519_public_key
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Centralize OID, another OID module can be found in `parse.rs`
|
||||||
mod oid {
|
mod oid {
|
||||||
// ECDSA signature algorithms
|
// RSA public key
|
||||||
pub const SHA1_WITH_RSA_ENCRYPTION: &'static [u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05];
|
pub const RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01];
|
||||||
|
|
||||||
|
// EC public key for secp256r1
|
||||||
|
pub const ID_EC_PUBLIC_KEY: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01];
|
||||||
|
pub const PRIME256V1: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
|
||||||
|
|
||||||
|
// EDDSA25519 public key, signature algorithm
|
||||||
|
pub const ID_EDDSA_25519: &'static [u8] =
|
||||||
|
&[0x2B, 0x65, 0x70];
|
||||||
|
|
||||||
|
// Supported Signature Algorithm (RFC 4055, RFC 3279)
|
||||||
|
// PKCS #1 v1.5
|
||||||
|
pub const SHA1_WITH_RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05];
|
||||||
|
pub const SHA224_WITH_RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E];
|
||||||
|
pub const SHA256_WITH_RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B];
|
||||||
|
pub const SHA384_WITH_RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C];
|
||||||
|
pub const SHA512_WITH_RSA_ENCRYPTION: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D];
|
||||||
|
|
||||||
|
// RSASSA_PSS
|
||||||
|
pub const ID_RSASSA_PSS: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0A];
|
||||||
|
|
||||||
|
// RSAES_OAEP
|
||||||
|
pub const ID_RSAES_OAEP: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x07];
|
||||||
|
|
||||||
|
// ECDSA signature algorithms, from OID repo
|
||||||
|
pub const ECDSA_WITH_SHA1: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01];
|
||||||
|
pub const ECDSA_WITH_SHA224: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01];
|
||||||
|
pub const ECDSA_WITH_SHA256: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02];
|
||||||
|
pub const ECDSA_WITH_SHA384: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03];
|
||||||
|
pub const ECDSA_WITH_SHA512: &'static [u8] =
|
||||||
|
&[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
src/parse.rs
29
src/parse.rs
|
@ -31,7 +31,8 @@ use core::convert::TryInto;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
|
// Return handshake/payload slice and TLS Record
|
||||||
|
pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], (&[u8], TlsRepr)> {
|
||||||
let content_type = take(1_usize);
|
let content_type = take(1_usize);
|
||||||
let version = take(2_usize);
|
let version = take(2_usize);
|
||||||
let length = take(2_usize);
|
let length = take(2_usize);
|
||||||
|
@ -51,6 +52,9 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
|
||||||
handshake: None,
|
handshake: None,
|
||||||
};
|
};
|
||||||
let (rest, bytes) = take(repr.length)(rest)?;
|
let (rest, bytes) = take(repr.length)(rest)?;
|
||||||
|
|
||||||
|
// Store a copy of the TLS Handshake slice to return
|
||||||
|
let repr_slice_clone = bytes;
|
||||||
{
|
{
|
||||||
use crate::tls_packet::TlsContentType::*;
|
use crate::tls_packet::TlsContentType::*;
|
||||||
match repr.content_type {
|
match repr.content_type {
|
||||||
|
@ -68,7 +72,7 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((rest, repr))
|
Ok((rest, (repr_slice_clone, repr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert TlsInnerPlainText in RFC 8446 into Handshake
|
// Convert TlsInnerPlainText in RFC 8446 into Handshake
|
||||||
|
@ -76,9 +80,9 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], TlsRepr> {
|
||||||
// 1. Handshake can coalesced into a larger TLS record
|
// 1. Handshake can coalesced into a larger TLS record
|
||||||
// 2. Content type and zero paddings at the end
|
// 2. Content type and zero paddings at the end
|
||||||
// Return handshake slice for hashing
|
// Return handshake slice for hashing
|
||||||
pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], (&[u8], Vec<HandshakeRepr>)> {
|
pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8], Vec<(&[u8], HandshakeRepr)>> {
|
||||||
let mut remaining_bytes = bytes;
|
let mut remaining_bytes = bytes;
|
||||||
let mut handshake_vec: Vec<HandshakeRepr> = Vec::new();
|
let mut handshake_vec: Vec<(&[u8], HandshakeRepr)> = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// Perform check on the number of remaining bytes
|
// Perform check on the number of remaining bytes
|
||||||
|
@ -97,20 +101,19 @@ pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8]
|
||||||
)(remaining_bytes)?;
|
)(remaining_bytes)?;
|
||||||
return Ok((
|
return Ok((
|
||||||
&[],
|
&[],
|
||||||
(
|
// // A concatenation of all handshakes received
|
||||||
// A concatenation of all handshakes received
|
// // The remaining content_type byte and zero paddings are stripped
|
||||||
// The remaining content_type byte and zero paddings are stripped
|
// &bytes[
|
||||||
&bytes[
|
// ..(bytes.len()-remaining_bytes.len())
|
||||||
..(bytes.len()-remaining_bytes.len())
|
// ],
|
||||||
],
|
handshake_vec
|
||||||
handshake_vec
|
|
||||||
)
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (rem, handshake_repr) = parse_handshake(remaining_bytes)?;
|
let (rem, handshake_repr) = parse_handshake(remaining_bytes)?;
|
||||||
|
let handshake_slice = &remaining_bytes[..(remaining_bytes.len()-rem.len())];
|
||||||
remaining_bytes = rem;
|
remaining_bytes = rem;
|
||||||
handshake_vec.push(handshake_repr);
|
handshake_vec.push((handshake_slice, handshake_repr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,12 +57,13 @@ pub(crate) struct Session {
|
||||||
// Sequence number: Start from 0, 64 bits
|
// Sequence number: Start from 0, 64 bits
|
||||||
// Increment by one per record processed (read OR write)
|
// Increment by one per record processed (read OR write)
|
||||||
// Reset to 0 on rekey AND key exchange
|
// Reset to 0 on rekey AND key exchange
|
||||||
// TODO: Force rekey if sequence number need to wrap
|
// TODO: Force rekey if sequence number need to wrap (very low priority)
|
||||||
client_sequence_number: u64,
|
client_sequence_number: u64,
|
||||||
server_sequence_number: u64,
|
server_sequence_number: u64,
|
||||||
// Certificate public key
|
// Certificate public key
|
||||||
// For Handling CertificateVerify
|
// For Handling CertificateVerify
|
||||||
cert_rsa_public_key: Option<RSAPublicKey>,
|
cert_rsa_public_key: Option<RSAPublicKey>, // TODO: Replace and remove
|
||||||
|
cert_public_key: Option<CertificatePublicKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
|
@ -93,7 +94,8 @@ impl Session {
|
||||||
server_application_nonce: None,
|
server_application_nonce: None,
|
||||||
client_sequence_number: 0,
|
client_sequence_number: 0,
|
||||||
server_sequence_number: 0,
|
server_sequence_number: 0,
|
||||||
cert_rsa_public_key: None
|
cert_rsa_public_key: None, // TODO: Remove over-specific public key
|
||||||
|
cert_public_key: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,8 +502,7 @@ impl Session {
|
||||||
|
|
||||||
// Handle Ed25519 and p256 separately
|
// Handle Ed25519 and p256 separately
|
||||||
// These 2 algorithms have a mandated hash function
|
// These 2 algorithms have a mandated hash function
|
||||||
if signature_algorithm == SignatureScheme::ecdsa_secp256r1_sha256
|
if signature_algorithm == SignatureScheme::ecdsa_secp256r1_sha256 {
|
||||||
{
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,6 +1122,7 @@ impl Session {
|
||||||
|
|
||||||
// TODO: Merge decryption methods
|
// TODO: Merge decryption methods
|
||||||
// Take control of the entire decryption, manually invoke detached decryption
|
// Take control of the entire decryption, manually invoke detached decryption
|
||||||
|
// TODO: Bad naming, it should say the KEY of application data
|
||||||
pub(crate) fn decrypt_application_data_in_place(
|
pub(crate) fn decrypt_application_data_in_place(
|
||||||
&self,
|
&self,
|
||||||
associated_data: &[u8],
|
associated_data: &[u8],
|
||||||
|
@ -1145,6 +1147,7 @@ impl Session {
|
||||||
let mut processed_nonce: [u8; 12] = [0; 12];
|
let mut processed_nonce: [u8; 12] = [0; 12];
|
||||||
NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12);
|
NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12);
|
||||||
|
|
||||||
|
// Duplicate authentication tag
|
||||||
let buffer_size = buffer.len();
|
let buffer_size = buffer.len();
|
||||||
let tag = GenericArray::clone_from_slice(&buffer[(buffer_size-16)..]);
|
let tag = GenericArray::clone_from_slice(&buffer[(buffer_size-16)..]);
|
||||||
|
|
||||||
|
@ -1156,6 +1159,7 @@ impl Session {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decryption using handshake keys
|
||||||
pub(crate) fn decrypt_in_place(
|
pub(crate) fn decrypt_in_place(
|
||||||
&self,
|
&self,
|
||||||
associated_data: &[u8],
|
associated_data: &[u8],
|
||||||
|
@ -1187,6 +1191,44 @@ impl Session {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A veriant for handshake decryption in-place and detached
|
||||||
|
// Caller need to manually discard the authentication bytes
|
||||||
|
pub(crate) fn decrypt_in_place_detached(
|
||||||
|
&self,
|
||||||
|
associated_data: &[u8],
|
||||||
|
buffer: &mut [u8]
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let (seq_num, nonce, cipher): (u64, &Vec<u8, U12>, &Cipher) = match self.role {
|
||||||
|
TlsRole::Server => {(
|
||||||
|
self.client_sequence_number,
|
||||||
|
self.client_handshake_nonce.as_ref().unwrap(),
|
||||||
|
self.client_handshake_cipher.as_ref().unwrap()
|
||||||
|
)},
|
||||||
|
TlsRole::Client => {(
|
||||||
|
self.server_sequence_number,
|
||||||
|
self.server_handshake_nonce.as_ref().unwrap(),
|
||||||
|
self.server_handshake_cipher.as_ref().unwrap()
|
||||||
|
)},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate XOR'ed nonce
|
||||||
|
let nonce: u128 = NetworkEndian::read_uint128(nonce, 12);
|
||||||
|
let clipped_seq_num: u128 = seq_num.into();
|
||||||
|
let mut processed_nonce: [u8; 12] = [0; 12];
|
||||||
|
NetworkEndian::write_uint128(&mut processed_nonce, nonce ^ clipped_seq_num, 12);
|
||||||
|
|
||||||
|
// Duplicate authentication tag
|
||||||
|
let buffer_size = buffer.len();
|
||||||
|
let tag = GenericArray::clone_from_slice(&buffer[(buffer_size-16)..]);
|
||||||
|
|
||||||
|
cipher.decrypt_in_place_detached(
|
||||||
|
&GenericArray::from_slice(&processed_nonce),
|
||||||
|
associated_data,
|
||||||
|
&mut buffer[..(buffer_size-16)],
|
||||||
|
&tag
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn increment_client_sequence_number(&mut self) {
|
pub(crate) fn increment_client_sequence_number(&mut self) {
|
||||||
self.client_sequence_number += 1;
|
self.client_sequence_number += 1;
|
||||||
}
|
}
|
||||||
|
@ -1400,4 +1442,16 @@ impl Cipher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum CertificatePublicKey {
|
||||||
|
RSA {
|
||||||
|
cert_rsa_public_key: RSAPublicKey
|
||||||
|
},
|
||||||
|
ECDSA_SECP256R1_SHA256 {
|
||||||
|
cert_verify_key: p256::ecdsa::VerifyKey
|
||||||
|
},
|
||||||
|
ED25519 {
|
||||||
|
cert_eddsa_key: ed25519_dalek::PublicKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
248
src/tls.rs
248
src/tls.rs
|
@ -23,6 +23,7 @@ use aes_gcm::AeadInPlace;
|
||||||
|
|
||||||
use nom::bytes::complete::take;
|
use nom::bytes::complete::take;
|
||||||
use nom::error::ErrorKind;
|
use nom::error::ErrorKind;
|
||||||
|
use nom::combinator::complete;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use heapless::Vec as HeaplessVec;
|
use heapless::Vec as HeaplessVec;
|
||||||
|
@ -202,6 +203,7 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
|
|
||||||
// Read for TLS packet
|
// Read for TLS packet
|
||||||
// Proposition: Decouple all data from TLS record layer before processing
|
// Proposition: Decouple all data from TLS record layer before processing
|
||||||
|
// Recouple a brand new TLS record wrapper
|
||||||
let mut array: [u8; 2048] = [0; 2048];
|
let mut array: [u8; 2048] = [0; 2048];
|
||||||
let mut tls_repr_vec = self.recv_tls_repr(sockets, &mut array)?;
|
let mut tls_repr_vec = self.recv_tls_repr(sockets, &mut array)?;
|
||||||
|
|
||||||
|
@ -209,15 +211,84 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
// Process as a queue
|
// Process as a queue
|
||||||
let tls_repr_vec_size = tls_repr_vec.len();
|
let tls_repr_vec_size = tls_repr_vec.len();
|
||||||
for _index in 0..tls_repr_vec_size {
|
for _index in 0..tls_repr_vec_size {
|
||||||
let repr = tls_repr_vec.remove(0);
|
let (repr_slice, mut repr) = tls_repr_vec.remove(0);
|
||||||
self.process(repr)?;
|
// TODO:
|
||||||
|
// Check TLS content type
|
||||||
|
// If application data, decrypt before process.
|
||||||
|
// If there are multiple handshakes within a record,
|
||||||
|
// give each of them a unique TLS record wrapper and process
|
||||||
|
// If a pure application data is found, sliently ignore
|
||||||
|
// Otherwise process directly
|
||||||
|
log::info!("Record type: {:?}", repr.content_type);
|
||||||
|
if repr.content_type == TlsContentType::ApplicationData {
|
||||||
|
log::info!("Found application data");
|
||||||
|
// Take the payload out of TLS Record and decrypt
|
||||||
|
let mut app_data = repr.payload.take().unwrap();
|
||||||
|
let mut associated_data = [0; 5];
|
||||||
|
associated_data[0] = repr.content_type.into();
|
||||||
|
NetworkEndian::write_u16(
|
||||||
|
&mut associated_data[1..3],
|
||||||
|
repr.version.into()
|
||||||
|
);
|
||||||
|
NetworkEndian::write_u16(
|
||||||
|
&mut associated_data[3..5],
|
||||||
|
repr.length
|
||||||
|
);
|
||||||
|
{
|
||||||
|
let mut session = self.session.borrow_mut();
|
||||||
|
session.decrypt_in_place_detached(
|
||||||
|
&associated_data,
|
||||||
|
&mut app_data
|
||||||
|
).unwrap();
|
||||||
|
// log::info!("Decypted data: {:?}", app_data);
|
||||||
|
session.increment_server_sequence_number();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Discard last 16 bytes (auth tag)
|
||||||
|
let inner_plaintext = &app_data[..app_data.len()-16];
|
||||||
|
let (inner_content_type, _) = get_content_type_inner_plaintext(
|
||||||
|
inner_plaintext
|
||||||
|
);
|
||||||
|
if inner_content_type != TlsContentType::Handshake {
|
||||||
|
// Silently ignore non-handshakes
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let (_, mut inner_handshakes) = complete(
|
||||||
|
parse_inner_plaintext_for_handshake
|
||||||
|
)(inner_plaintext).unwrap();
|
||||||
|
|
||||||
|
// Sequentially process all handshakes
|
||||||
|
let num_of_handshakes = inner_handshakes.len();
|
||||||
|
for _ in 0..num_of_handshakes {
|
||||||
|
let (handshake_slice, handshake_repr) = inner_handshakes.remove(0);
|
||||||
|
self.process(
|
||||||
|
handshake_slice,
|
||||||
|
TlsRepr {
|
||||||
|
content_type: TlsContentType::Handshake,
|
||||||
|
version: repr.version,
|
||||||
|
length: u16::try_from(handshake_repr.length).unwrap() + 4,
|
||||||
|
payload: None,
|
||||||
|
handshake: Some(handshake_repr)
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
else {
|
||||||
|
self.process(repr_slice, repr)?;
|
||||||
|
log::info!("Processed record");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.session.borrow().has_completed_handshake())
|
Ok(self.session.borrow().has_completed_handshake())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process TLS ingress during handshake
|
// Process TLS ingress during handshake
|
||||||
fn process(&self, mut repr: TlsRepr) -> Result<()> {
|
// The slice should ONLY include handshake overhead
|
||||||
|
// i.e. Exclude 5 bytes of TLS Record
|
||||||
|
// Include 4 bytes of HandshakeRepr, everything within the same handshake
|
||||||
|
fn process(&self, handshake_slice: &[u8], mut repr: TlsRepr) -> Result<()> {
|
||||||
// Change_cipher_spec check:
|
// Change_cipher_spec check:
|
||||||
// Must receive CCS before recv peer's FINISH message
|
// Must receive CCS before recv peer's FINISH message
|
||||||
// i.e. Must happen after START and before CONNECTED
|
// i.e. Must happen after START and before CONNECTED
|
||||||
|
@ -226,8 +297,10 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
// 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
|
// 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() {
|
||||||
let mut session = self.session.borrow_mut();
|
log::info!("Change Cipher Spec");
|
||||||
|
let mut session = self.session.try_borrow_mut().expect("Cannot borrow mut");
|
||||||
session.receive_change_cipher_spec();
|
session.receive_change_cipher_spec();
|
||||||
|
log::info!("Changed Cipher Spec");
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,12 +310,6 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
match tls_state {
|
match tls_state {
|
||||||
// During WAIT_SH for a TLS client, client should wait for ServerHello
|
// During WAIT_SH for a TLS client, client should wait for ServerHello
|
||||||
TlsState::WAIT_SH => {
|
TlsState::WAIT_SH => {
|
||||||
// Legacy_protocol must be TLS 1.2
|
|
||||||
if repr.version != TlsVersion::Tls12 {
|
|
||||||
// Abort communication
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Validate SH
|
// TODO: Validate SH
|
||||||
if repr.is_server_hello() {
|
if repr.is_server_hello() {
|
||||||
// Check SH content:
|
// Check SH content:
|
||||||
|
@ -342,18 +409,12 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is indeed a desirable ServerHello TLS repr
|
// Get slice without reserialization
|
||||||
// Reprocess ServerHello into a slice
|
|
||||||
// Update session with required parameter
|
|
||||||
let mut array = [0; 512];
|
|
||||||
let mut buffer = TlsBuffer::new(&mut array);
|
|
||||||
buffer.enqueue_tls_repr(repr)?;
|
|
||||||
let slice: &[u8] = buffer.into();
|
|
||||||
let mut session = self.session.borrow_mut();
|
let mut session = self.session.borrow_mut();
|
||||||
session.client_update_for_sh(
|
session.client_update_for_sh(
|
||||||
selected_cipher.unwrap(),
|
selected_cipher.unwrap(),
|
||||||
server_public.unwrap(),
|
server_public.unwrap(),
|
||||||
&slice[5..]
|
handshake_slice
|
||||||
);
|
);
|
||||||
// Key exchange occurred, seq_num is set to 0
|
// Key exchange occurred, seq_num is set to 0
|
||||||
// Do NOT update seq_num again. Early return.
|
// Do NOT update seq_num again. Early return.
|
||||||
|
@ -363,34 +424,9 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
|
|
||||||
// Expect encrypted extensions after receiving SH
|
// Expect encrypted extensions after receiving SH
|
||||||
TlsState::WAIT_EE => {
|
TlsState::WAIT_EE => {
|
||||||
// Check that the packet is classified as application data
|
|
||||||
if !repr.is_application_data() {
|
|
||||||
// Abort communication, this affect IV calculation
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExcepytedExtensions are disguised as ApplicationData
|
|
||||||
// Pull out the `payload` from TlsRepr, decrypt as EE
|
|
||||||
let mut payload = repr.payload.take().unwrap();
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let parse_result = parse_inner_plaintext_for_handshake(&payload);
|
|
||||||
let (_, (handshake_slice, mut handshake_vec)) =
|
|
||||||
parse_result.map_err(|_| Error::Unrecognized)?;
|
|
||||||
|
|
||||||
// Verify that it is indeed an EE
|
// Verify that it is indeed an EE
|
||||||
let might_be_ee = handshake_vec.remove(0);
|
// let might_be_ee = handshake_vec.remove(0);
|
||||||
|
let might_be_ee = repr.handshake.take().unwrap();
|
||||||
if might_be_ee.get_msg_type() != HandshakeType::EncryptedExtensions {
|
if might_be_ee.get_msg_type() != HandshakeType::EncryptedExtensions {
|
||||||
// Process the other handshakes in "handshake_vec"
|
// Process the other handshakes in "handshake_vec"
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -412,48 +448,16 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
.client_update_for_ee(
|
.client_update_for_ee(
|
||||||
&ee_slice
|
&ee_slice
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Handle in WAIT_CERT_CR if there are still unprocessed handshakes
|
log::info!("Received EE");
|
||||||
// Ideas: 1. Split off WAIT_CERT_CR handling into a separate function
|
},
|
||||||
// so WAIT_EE branch can jsut call WAIT_CERT_CR branch
|
|
||||||
// if there are extra handshake unprocessed
|
|
||||||
// 2. Merge state dependent listeners into 1 branch, execute conditionally
|
|
||||||
},
|
|
||||||
|
|
||||||
// In this stage, wait for a certificate from server
|
// In this stage, wait for a certificate from server
|
||||||
// Parse the certificate and check its content
|
// Parse the certificate and check its content
|
||||||
TlsState::WAIT_CERT_CR => {
|
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 CERT
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the certificate from TLS payload
|
|
||||||
let parse_result = parse_inner_plaintext_for_handshake(&payload);
|
|
||||||
let (_, (handshake_slice, mut handshake_vec)) = parse_result
|
|
||||||
.map_err(|_| Error::Unrecognized)?;
|
|
||||||
|
|
||||||
// Verify that it is indeed an Certificate
|
// Verify that it is indeed an Certificate
|
||||||
let might_be_cert = handshake_vec.remove(0);
|
// let might_be_cert = handshake_vec.remove(0);
|
||||||
|
let might_be_cert = repr.handshake.take().unwrap();
|
||||||
if might_be_cert.get_msg_type() != HandshakeType::Certificate {
|
if might_be_cert.get_msg_type() != HandshakeType::Certificate {
|
||||||
// Process the other handshakes in "handshake_vec"
|
// Process the other handshakes in "handshake_vec"
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -482,41 +486,15 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
&cert_slice,
|
&cert_slice,
|
||||||
cert.return_rsa_public_key().unwrap()
|
cert.return_rsa_public_key().unwrap()
|
||||||
);
|
);
|
||||||
|
log::info!("Received WAIT_CERT_CR");
|
||||||
},
|
},
|
||||||
|
|
||||||
// In this stage, server will eventually send a CertificateVerify
|
// In this stage, server will eventually send a CertificateVerify
|
||||||
// Verify that the signature is indeed correct
|
// Verify that the signature is indeed correct
|
||||||
TlsState::WAIT_CV => {
|
TlsState::WAIT_CV => {
|
||||||
// CertificateVerify 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 CV
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the certificate from TLS payload
|
|
||||||
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 CertificateVerify
|
// Ensure that it is CertificateVerify
|
||||||
let might_be_cert_verify = handshake_vec.remove(0);
|
// let might_be_cert_verify = handshake_vec.remove(0);
|
||||||
|
let might_be_cert_verify = repr.handshake.take().unwrap();
|
||||||
if might_be_cert_verify.get_msg_type() != HandshakeType::CertificateVerify {
|
if might_be_cert_verify.get_msg_type() != HandshakeType::CertificateVerify {
|
||||||
// Process the other handshakes in "handshake_vec"
|
// Process the other handshakes in "handshake_vec"
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -538,40 +516,14 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
sig_alg,
|
sig_alg,
|
||||||
signature
|
signature
|
||||||
);
|
);
|
||||||
|
log::info!("Received CV");
|
||||||
},
|
},
|
||||||
|
|
||||||
// Client will receive a Finished handshake from server
|
// Client will receive a Finished handshake from server
|
||||||
TlsState::WAIT_FINISHED => {
|
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
// Ensure that it is Finished
|
||||||
let might_be_server_finished = handshake_vec.remove(0);
|
// let might_be_server_finished = handshake_vec.remove(0);
|
||||||
|
let might_be_server_finished = repr.handshake.take().unwrap();
|
||||||
if might_be_server_finished.get_msg_type() != HandshakeType::Finished {
|
if might_be_server_finished.get_msg_type() != HandshakeType::Finished {
|
||||||
// Process the other handshakes in "handshake_vec"
|
// Process the other handshakes in "handshake_vec"
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -592,15 +544,11 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
server_finished_slice,
|
server_finished_slice,
|
||||||
might_be_server_finished.get_verify_data().unwrap()
|
might_be_server_finished.get_verify_data().unwrap()
|
||||||
);
|
);
|
||||||
|
log::info!("Received server FIN");
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// A TLS Record was received and processed and verified
|
|
||||||
// Increment sequence number
|
|
||||||
self.session.borrow_mut().increment_server_sequence_number();
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,18 +647,20 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
||||||
// Generic inner recv method, through TCP socket
|
// Generic inner recv method, through TCP socket
|
||||||
// A TCP packet can contain multiple TLS records (including 0)
|
// A TCP packet can contain multiple TLS records (including 0)
|
||||||
// Therefore, sequence nubmer incrementation is not completed here
|
// 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<(&[u8], 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() {
|
||||||
return Ok(Vec::new());
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
let array_size = tcp_socket.recv_slice(byte_array)?;
|
let array_size = tcp_socket.recv_slice(byte_array)?;
|
||||||
let mut vec: Vec<TlsRepr> = Vec::new();
|
let mut vec: Vec<(&[u8], TlsRepr)> = Vec::new();
|
||||||
let mut bytes: &[u8] = &byte_array[..array_size];
|
let mut bytes: &[u8] = &byte_array[..array_size];
|
||||||
loop {
|
loop {
|
||||||
match parse_tls_repr(bytes) {
|
match parse_tls_repr(bytes) {
|
||||||
Ok((rest, repr)) => {
|
Ok((rest, (repr_slice, repr))) => {
|
||||||
vec.push(repr);
|
vec.push(
|
||||||
|
(repr_slice, repr)
|
||||||
|
);
|
||||||
if rest.len() == 0 {
|
if rest.len() == 0 {
|
||||||
return Ok(vec);
|
return Ok(vec);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue