socket interface: init
This commit is contained in:
parent
eedee2602d
commit
0a8ce3fd4c
|
@ -163,7 +163,6 @@ pub fn validate_root_certificate(cert: &Certificate) -> Result<bool, TlsError> {
|
|||
&hasher.finalize(),
|
||||
cert.signature_value
|
||||
);
|
||||
log::info!("Verification result: {:?}", verify_result);
|
||||
Ok(verify_result.is_ok())
|
||||
}
|
||||
_ => {
|
||||
|
|
32
src/parse.rs
32
src/parse.rs
|
@ -119,6 +119,32 @@ pub(crate) fn parse_inner_plaintext_for_handshake(bytes: &[u8]) -> IResult<&[u8]
|
|||
unreachable!()
|
||||
}
|
||||
|
||||
// Input: The entire inner plaintext including TLS record
|
||||
// (record | content | content_type | zeros)
|
||||
// Get the content_type of inner_plaintext
|
||||
// Also get the (optional) starting index of zero paddings
|
||||
pub(crate) fn get_content_type_inner_plaintext(inner_plaintext: &[u8]) -> (TlsContentType, Option<usize>) {
|
||||
// Approach from the rear, discard zeros until a nonzero byte is found
|
||||
let mut zero_padding_start_index = inner_plaintext.len();
|
||||
while (&inner_plaintext[..zero_padding_start_index]).ends_with(&[0x00]) {
|
||||
// Record wrapper takes the first 5 byte
|
||||
// Worst case scenario there must be a content type
|
||||
if zero_padding_start_index > 6 {
|
||||
zero_padding_start_index -= 1;
|
||||
} else {
|
||||
return (TlsContentType::Invalid, None);
|
||||
}
|
||||
}
|
||||
(
|
||||
TlsContentType::try_from(inner_plaintext[zero_padding_start_index-1]).unwrap(),
|
||||
if zero_padding_start_index < inner_plaintext.len() {
|
||||
Some(zero_padding_start_index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Redo EE
|
||||
// Not very appropriate to classify EE as proper handshake
|
||||
// It may include multiple handshakes
|
||||
|
@ -396,12 +422,6 @@ 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();
|
||||
|
|
105
src/session.rs
105
src/session.rs
|
@ -550,7 +550,6 @@ impl Session {
|
|||
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!()
|
||||
}
|
||||
|
@ -954,6 +953,10 @@ impl Session {
|
|||
client_finished_slice: &[u8]
|
||||
)
|
||||
{
|
||||
// Will change server & client key to application key,
|
||||
// Reset sequence number
|
||||
self.client_sequence_number = 0;
|
||||
self.server_sequence_number = 0;
|
||||
self.hash.update(client_finished_slice);
|
||||
self.state = TlsState::CONNECTED;
|
||||
}
|
||||
|
@ -1024,6 +1027,38 @@ impl Session {
|
|||
self.client_handshake_cipher.as_ref().map(|cipher| cipher.get_cipher_suite_type())
|
||||
}
|
||||
|
||||
// TODO: Merge decryption methods
|
||||
pub(crate) fn encrypt_application_data_in_place_detached(
|
||||
&self,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8]
|
||||
) -> Result<GenericArray<u8, U16>, Error> {
|
||||
let (seq_num, nonce, cipher): (u64, &Vec<u8, U12>, &Cipher) = match self.role {
|
||||
TlsRole::Client => {(
|
||||
self.client_sequence_number,
|
||||
self.client_application_nonce.as_ref().unwrap(),
|
||||
self.client_application_cipher.as_ref().unwrap()
|
||||
)},
|
||||
TlsRole::Server => {(
|
||||
self.server_sequence_number,
|
||||
self.server_application_nonce.as_ref().unwrap(),
|
||||
self.server_application_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);
|
||||
|
||||
cipher.encrypt_in_place_detached(
|
||||
&GenericArray::from_slice(&processed_nonce),
|
||||
associated_data,
|
||||
buffer
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn encrypt_in_place(
|
||||
&self,
|
||||
associated_data: &[u8],
|
||||
|
@ -1086,6 +1121,43 @@ impl Session {
|
|||
)
|
||||
}
|
||||
|
||||
// TODO: Merge decryption methods
|
||||
// Take control of the entire decryption, manually invoke detached decryption
|
||||
pub(crate) fn decrypt_application_data_in_place(
|
||||
&self,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
let (seq_num, nonce, cipher): (u64, &Vec<u8, U12>, &Cipher) = match self.role {
|
||||
TlsRole::Client => {(
|
||||
self.server_sequence_number,
|
||||
self.server_application_nonce.as_ref().unwrap(),
|
||||
self.server_application_cipher.as_ref().unwrap()
|
||||
)},
|
||||
TlsRole::Server => {(
|
||||
self.client_sequence_number,
|
||||
self.client_application_nonce.as_ref().unwrap(),
|
||||
self.client_application_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);
|
||||
|
||||
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 decrypt_in_place(
|
||||
&self,
|
||||
associated_data: &[u8],
|
||||
|
@ -1283,6 +1355,37 @@ impl Cipher {
|
|||
}.map_err(|_| Error::DecryptionError)
|
||||
}
|
||||
|
||||
pub(crate) fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &GenericArray<u8, U12>,
|
||||
associated_data: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &GenericArray<u8, U16>
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Cipher::Aes128Gcm { aes128gcm } => {
|
||||
aes128gcm.decrypt_in_place_detached(
|
||||
nonce, associated_data, buffer, tag
|
||||
)
|
||||
},
|
||||
Cipher::Aes256Gcm { aes256gcm } => {
|
||||
aes256gcm.decrypt_in_place_detached(
|
||||
nonce, associated_data, buffer, tag
|
||||
)
|
||||
},
|
||||
Cipher::Chacha20poly1305 { chacha20poly1305 } => {
|
||||
chacha20poly1305.decrypt_in_place_detached(
|
||||
nonce, associated_data, buffer, tag
|
||||
)
|
||||
},
|
||||
Cipher::Ccm { ccm } => {
|
||||
ccm.decrypt_in_place_detached(
|
||||
nonce, associated_data, buffer, tag
|
||||
)
|
||||
}
|
||||
}.map_err(|_| Error::DecryptionError)
|
||||
}
|
||||
|
||||
pub(crate) fn get_cipher_suite_type(&self) -> CipherSuite {
|
||||
match self {
|
||||
Cipher::Aes128Gcm { aes128gcm } => {
|
||||
|
|
121
src/tls.rs
121
src/tls.rs
|
@ -40,7 +40,12 @@ use heapless::Vec as HeaplessVec;
|
|||
|
||||
use crate::Error as TlsError;
|
||||
use crate::tls_packet::*;
|
||||
use crate::parse::{ parse_tls_repr, parse_handshake, parse_inner_plaintext_for_handshake };
|
||||
use crate::parse::{
|
||||
parse_tls_repr,
|
||||
parse_handshake,
|
||||
parse_inner_plaintext_for_handshake,
|
||||
get_content_type_inner_plaintext
|
||||
};
|
||||
use crate::buffer::TlsBuffer;
|
||||
use crate::session::{Session, TlsRole};
|
||||
use crate::certificate::validate_root_certificate;
|
||||
|
@ -468,9 +473,13 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
|||
|
||||
// TODO: Process Certificate
|
||||
let cert = might_be_cert.get_asn1_der_certificate().unwrap();
|
||||
log::info!("Certificate validation {:?}",
|
||||
validate_root_certificate(cert)
|
||||
);
|
||||
|
||||
// TODO: Replace this block after implementing a proper
|
||||
// certificate verification procdeure
|
||||
match validate_root_certificate(cert) {
|
||||
Ok(true) => {},
|
||||
_ => panic!("Certificate does not match")
|
||||
}
|
||||
|
||||
// Update session TLS state to WAIT_CV
|
||||
// Length of handshake header is 4
|
||||
|
@ -567,7 +576,6 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
|||
&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);
|
||||
|
@ -596,7 +604,6 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
|||
server_finished_slice,
|
||||
might_be_server_finished.get_verify_data().unwrap()
|
||||
);
|
||||
log::info!("Computed secret");
|
||||
}
|
||||
|
||||
_ => {},
|
||||
|
@ -662,14 +669,13 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
|||
// 2. Add TLS header in front of application data
|
||||
// Input should be inner plaintext
|
||||
// Note: Do not put this slice into the transcript hash. It is polluted.
|
||||
// TODO: Rename this function. It is only good for client finished
|
||||
fn send_application_slice(&self, sockets: &mut SocketSet, slice: &mut [u8]) -> Result<()> {
|
||||
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
||||
if !tcp_socket.can_send() {
|
||||
return Err(Error::Illegal);
|
||||
}
|
||||
|
||||
log::info!("Delivered slice: {:?}", slice);
|
||||
|
||||
// Borrow session in advance
|
||||
let mut client_session = self.session.borrow_mut();
|
||||
|
||||
|
@ -727,4 +733,103 @@ impl<R: 'static + RngCore + CryptoRng> TlsSocket<R> {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recv_slice(&self, sockets: &mut SocketSet, data: &mut [u8]) -> Result<usize> {
|
||||
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
||||
if !tcp_socket.can_recv() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
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)
|
||||
// Zero paddings (>=0 bytes)
|
||||
if recv_slice_size < 22 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// Get Associated Data
|
||||
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]);
|
||||
|
||||
// Dump association data (TLS Record wrapper)
|
||||
// Only decrypt application data
|
||||
// Always increment sequence number after decrpytion
|
||||
session.decrypt_application_data_in_place(
|
||||
&associated_data,
|
||||
&mut data[5..recv_slice_size]
|
||||
).unwrap();
|
||||
session.increment_server_sequence_number();
|
||||
|
||||
// Make sure it is application data
|
||||
let (content_type, padding_start_index) =
|
||||
get_content_type_inner_plaintext(&data[..(recv_slice_size-16)]);
|
||||
|
||||
// If it is not application data, handle it internally
|
||||
if content_type != TlsContentType::ApplicationData {
|
||||
// TODO:: Implement key update
|
||||
log::info!("Other decrypted: {:?}", &data[..(recv_slice_size-16)]);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// Otherwise, it is surely application data.
|
||||
// Prune TLS record wrapper (5 bytes) from data.
|
||||
data.rotate_left(5);
|
||||
|
||||
// Remove extra length:
|
||||
// 5 bytes of TLS record header
|
||||
// 16 bytes of authentication tag (included in zero padding search fn)
|
||||
// 1 byte of content type
|
||||
// zero paddings, variated length
|
||||
let actual_application_data_length = recv_slice_size - 5 - 1
|
||||
- padding_start_index.map_or(16,
|
||||
|start| recv_slice_size - start
|
||||
);
|
||||
|
||||
Ok(actual_application_data_length)
|
||||
}
|
||||
|
||||
pub fn send_slice(&self, sockets: &mut SocketSet, data: &[u8]) -> Result<()> {
|
||||
// Sending order:
|
||||
// 1. Associated data/ TLS Record layer
|
||||
// 2. Encrypted { Payload (data) | Content type: Application Data }
|
||||
// 3. Authentication tag (16 bytes for all supported AEADs)
|
||||
let mut associated_data: [u8; 5] = [
|
||||
0x17, // Application data
|
||||
0x03, 0x03, // TLS 1.3 record disguised as TLS 1.2
|
||||
0x00, 0x00 // Length of encrypted data, yet to be determined
|
||||
];
|
||||
|
||||
NetworkEndian::write_u16(&mut associated_data[3..5],
|
||||
u16::try_from(data.len()).unwrap() // Payload length
|
||||
+ 1 // Content type length
|
||||
+ 16 // Auth tag length
|
||||
);
|
||||
|
||||
// TODO: Dynamically size typed Heapless Vec on socket instantiation,
|
||||
// just like MiniMQ
|
||||
let mut vec: HeaplessVec<u8, U1024> = HeaplessVec::from_slice(data).unwrap();
|
||||
vec.push(0x17); // Content type
|
||||
|
||||
let mut session = self.session.borrow_mut();
|
||||
let tag = session.encrypt_application_data_in_place_detached(
|
||||
&associated_data,
|
||||
&mut vec
|
||||
).unwrap();
|
||||
session.increment_client_sequence_number();
|
||||
|
||||
let mut tcp_socket = sockets.get::<TcpSocket>(self.tcp_handle);
|
||||
if !tcp_socket.can_send() {
|
||||
return Err(Error::Illegal);
|
||||
}
|
||||
|
||||
tcp_socket.send_slice(&associated_data)?;
|
||||
tcp_socket.send_slice(&vec)?;
|
||||
tcp_socket.send_slice(&tag)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue