Compare commits
2 Commits
25cdd23406
...
fe6418df36
Author | SHA1 | Date |
---|---|---|
occheung | fe6418df36 | |
occheung | 18c307ec1a |
|
@ -14,6 +14,7 @@ use smoltcp::wire::IpEndpoint;
|
||||||
|
|
||||||
use crate::tls::TlsState;
|
use crate::tls::TlsState;
|
||||||
use crate::tls_packet::CipherSuite;
|
use crate::tls_packet::CipherSuite;
|
||||||
|
use crate::tls_packet::AlertType;
|
||||||
use crate::key::*;
|
use crate::key::*;
|
||||||
use crate::tls_packet::SignatureScheme;
|
use crate::tls_packet::SignatureScheme;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
@ -82,6 +83,8 @@ pub(crate) struct Session<'a> {
|
||||||
// Client must cent Certificate extension iff server requested it
|
// Client must cent Certificate extension iff server requested it
|
||||||
need_send_client_cert: bool,
|
need_send_client_cert: bool,
|
||||||
client_cert_verify_sig_alg: Option<crate::tls_packet::SignatureScheme>,
|
client_cert_verify_sig_alg: Option<crate::tls_packet::SignatureScheme>,
|
||||||
|
// Flag for the need of sending alert to terminate TLS session
|
||||||
|
need_send_alert: Option<AlertType>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Session<'a> {
|
impl<'a> Session<'a> {
|
||||||
|
@ -121,7 +124,8 @@ impl<'a> Session<'a> {
|
||||||
cert_public_key: None,
|
cert_public_key: None,
|
||||||
cert_private_key: certificate_with_key,
|
cert_private_key: certificate_with_key,
|
||||||
need_send_client_cert: false,
|
need_send_client_cert: false,
|
||||||
client_cert_verify_sig_alg: None
|
client_cert_verify_sig_alg: None,
|
||||||
|
need_send_alert: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +147,21 @@ impl<'a> Session<'a> {
|
||||||
self.state = TlsState::SERVER_START;
|
self.state = TlsState::SERVER_START;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn invalidate_session(
|
||||||
|
&mut self,
|
||||||
|
alert: AlertType,
|
||||||
|
received_slice: &[u8]
|
||||||
|
) {
|
||||||
|
self.hash.update(received_slice);
|
||||||
|
self.need_send_alert = Some(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn reset_state(&mut self) {
|
||||||
|
// Clear alert
|
||||||
|
self.need_send_alert = None;
|
||||||
|
self.state = TlsState::DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
// State transition from START to WAIT_SH
|
// State transition from START to WAIT_SH
|
||||||
pub(crate) fn client_update_for_ch(
|
pub(crate) fn client_update_for_ch(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1395,6 +1414,10 @@ impl<'a> Session<'a> {
|
||||||
self.remote_endpoint
|
self.remote_endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_need_send_alert(&self) -> Option<AlertType> {
|
||||||
|
self.need_send_alert
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn has_completed_handshake(&self) -> bool {
|
pub(crate) fn has_completed_handshake(&self) -> bool {
|
||||||
self.state == TlsState::CLIENT_CONNECTED
|
self.state == TlsState::CLIENT_CONNECTED
|
||||||
}
|
}
|
||||||
|
|
519
src/tls.rs
519
src/tls.rs
|
@ -57,7 +57,7 @@ pub(crate) enum TlsState {
|
||||||
SERVER_WAIT_CERT,
|
SERVER_WAIT_CERT,
|
||||||
SERVER_WAIT_CV,
|
SERVER_WAIT_CV,
|
||||||
SERVER_WAIT_FINISHED,
|
SERVER_WAIT_FINISHED,
|
||||||
SERVER_CONNECTED,
|
SERVER_CONNECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TlsSocket<'a, 'b, 'c>
|
pub struct TlsSocket<'a, 'b, 'c>
|
||||||
|
@ -148,15 +148,19 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
self.session.borrow().get_tls_state()
|
self.session.borrow().get_tls_state()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let need_send_alert = {
|
||||||
|
self.session.borrow().get_need_send_alert()
|
||||||
|
};
|
||||||
|
|
||||||
// Check TCP socket/ TLS session
|
// Check TCP socket/ TLS session
|
||||||
{
|
{
|
||||||
let tcp_state = self.sockets.get::<TcpSocket>(self.tcp_handle).state();
|
let tcp_state = self.sockets.get::<TcpSocket>(self.tcp_handle).state();
|
||||||
|
|
||||||
// // Check if it should connect to client or not
|
//Close TCP socket if necessary
|
||||||
// if tls_socket.get_session_role() != crate::session::TlsRole::Client {
|
if tcp_state == TcpState::Established && tls_state == TlsState::DEFAULT {
|
||||||
// // Return true for no need to do anymore handshake
|
self.sockets.get::<TcpSocket>(self.tcp_handle).close();
|
||||||
// return Ok(true);
|
return Ok(false);
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Skip handshake processing if it is already completed
|
// Skip handshake processing if it is already completed
|
||||||
// However, redo TCP handshake if TLS socket is trying to connect and
|
// However, redo TCP handshake if TLS socket is trying to connect and
|
||||||
|
@ -177,6 +181,117 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send alert to start terminating TLS session if necessary
|
||||||
|
if let Some(alert) = need_send_alert {
|
||||||
|
match tls_state {
|
||||||
|
// Client side socket:
|
||||||
|
// States that expects plaintext payload
|
||||||
|
TlsState::WAIT_SH | TlsState::SERVER_START => {
|
||||||
|
// Send the cooresponding alert in plaintext
|
||||||
|
let mut tcp_socket = self.sockets.get::<TcpSocket>(self.tcp_handle);
|
||||||
|
tcp_socket.send(
|
||||||
|
|data| {
|
||||||
|
// Set up a TLS buffer on the internal buffer of TCP socket
|
||||||
|
let mut buffer = TlsBuffer::new(data);
|
||||||
|
// Instantiate a TLS bytes-representation with pre-determined alert
|
||||||
|
let tls_repr = TlsRepr::new().alert(alert);
|
||||||
|
if buffer.enqueue_tls_repr(tls_repr).is_err() {
|
||||||
|
return (0, ())
|
||||||
|
}
|
||||||
|
|
||||||
|
let slice: &[u8] = buffer.into();
|
||||||
|
(slice.len(), ())
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
},
|
||||||
|
// States that expects enrypted payload using handshake secret
|
||||||
|
TlsState::WAIT_EE |
|
||||||
|
TlsState::WAIT_CERT_CR |
|
||||||
|
TlsState::CLIENT_WAIT_CERT |
|
||||||
|
TlsState::CLIENT_WAIT_CV |
|
||||||
|
TlsState::CLIENT_WAIT_FINISHED |
|
||||||
|
TlsState::SERVER_COMPLETED |
|
||||||
|
TlsState::NEGOTIATED |
|
||||||
|
TlsState::WAIT_FLIGHT |
|
||||||
|
TlsState::SERVER_WAIT_CERT |
|
||||||
|
TlsState::SERVER_WAIT_CV => {
|
||||||
|
// Send the corresponding alert in ciphertext using handshake secret
|
||||||
|
let severity: u8 = match alert {
|
||||||
|
AlertType::CloseNotify | AlertType::UserCanceled => {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
_ => 2
|
||||||
|
};
|
||||||
|
let mut alert_array: [u8; 3] = [
|
||||||
|
severity,
|
||||||
|
u8::try_from(alert).unwrap(),
|
||||||
|
21 // Alert content type
|
||||||
|
];
|
||||||
|
self.send_application_slice(&mut alert_array)?;
|
||||||
|
},
|
||||||
|
// States that expects enrypted payload using application data secret
|
||||||
|
TlsState::CLIENT_CONNECTED |
|
||||||
|
TlsState::SERVER_WAIT_FINISHED |
|
||||||
|
TlsState::SERVER_CONNECTED => {
|
||||||
|
// Send the corresponding alert in ciphertext using application data secret
|
||||||
|
// Sending order:
|
||||||
|
// 1. Associated data/ TLS Record layer
|
||||||
|
// 2. Encrypted { Alert }
|
||||||
|
// 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 conveniently
|
||||||
|
];
|
||||||
|
|
||||||
|
NetworkEndian::write_u16(&mut associated_data[3..5],
|
||||||
|
2 // Payload length
|
||||||
|
+ 1 // Content type length
|
||||||
|
+ 16 // Auth tag length
|
||||||
|
);
|
||||||
|
|
||||||
|
// Alert: Warning (1) , Close notify (0)
|
||||||
|
let severity: u8 = match alert {
|
||||||
|
AlertType::CloseNotify | AlertType::UserCanceled => {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
_ => 2
|
||||||
|
};
|
||||||
|
let mut alert_array: [u8; 3] = [
|
||||||
|
severity,
|
||||||
|
u8::try_from(alert).unwrap(),
|
||||||
|
21 // Alert content type
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut session = self.session.borrow_mut();
|
||||||
|
let tag = session.encrypt_application_data_in_place_detached(
|
||||||
|
&associated_data,
|
||||||
|
&mut alert_array
|
||||||
|
).unwrap();
|
||||||
|
session.increment_local_sequence_number();
|
||||||
|
|
||||||
|
let mut tcp_socket = self.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(&alert_array)?;
|
||||||
|
tcp_socket.send_slice(&tag)?;
|
||||||
|
},
|
||||||
|
// Other states, such as client_start and default should never send alert
|
||||||
|
// These stages are too early to raise exceptions
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, revert the FSM to DEFAULT to signal an invokation of
|
||||||
|
// `close()` to the TCP socket
|
||||||
|
self.session.borrow_mut().reset_state();
|
||||||
|
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle TLS handshake through TLS states
|
// Handle TLS handshake through TLS states
|
||||||
match tls_state {
|
match tls_state {
|
||||||
// Do nothing on the default state
|
// Do nothing on the default state
|
||||||
|
@ -676,8 +791,6 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
return Ok(self.session.borrow().has_completed_handshake())
|
return Ok(self.session.borrow().has_completed_handshake())
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Tls can recv");
|
|
||||||
|
|
||||||
// Peak into the first 5 bytes (TLS record layer)
|
// Peak into the first 5 bytes (TLS record layer)
|
||||||
// This tells the length of the entire record
|
// This tells the length of the entire record
|
||||||
let length = match tcp_socket.peek(5) {
|
let length = match tcp_socket.peek(5) {
|
||||||
|
@ -685,8 +798,6 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
_ => return Ok(self.session.borrow().has_completed_handshake())
|
_ => return Ok(self.session.borrow().has_completed_handshake())
|
||||||
};
|
};
|
||||||
|
|
||||||
log::info!("tls record length: {:?}", length);
|
|
||||||
|
|
||||||
// Recv the entire TLS record
|
// Recv the entire TLS record
|
||||||
tcp_socket.recv(
|
tcp_socket.recv(
|
||||||
|buffer| ((length + 5).into(), Vec::from(&buffer[..(length + 5).into()]))
|
|buffer| ((length + 5).into(), Vec::from(&buffer[..(length + 5).into()]))
|
||||||
|
@ -761,119 +872,6 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
log::info!("Processed record");
|
log::info!("Processed record");
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Finally dequeue the record from buffer
|
|
||||||
// if tcp_socket.recv(|_| (length.into(), ())).is_err() {
|
|
||||||
// return Ok(self.session.borrow().has_completed_handshake())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// tcp_socket.recv(
|
|
||||||
// |buffer| {
|
|
||||||
// // log::info!("Received Buffer: {:?}", buffer);
|
|
||||||
// let buffer_size = buffer.len();
|
|
||||||
|
|
||||||
// // Provide a way to end the process early
|
|
||||||
// if buffer_size == 0 {
|
|
||||||
// return (0, ())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// log::info!("Received something");
|
|
||||||
|
|
||||||
// let mut tls_repr_vec: Vec<(&[u8], TlsRepr)> = Vec::new();
|
|
||||||
// let mut bytes = &buffer[..buffer_size];
|
|
||||||
|
|
||||||
// // Sequentially push reprs into vec
|
|
||||||
// loop {
|
|
||||||
// match parse_tls_repr(bytes) {
|
|
||||||
// Ok((rest, (repr_slice, repr))) => {
|
|
||||||
// tls_repr_vec.push(
|
|
||||||
// (repr_slice, repr)
|
|
||||||
// );
|
|
||||||
// if rest.len() == 0 {
|
|
||||||
// break;
|
|
||||||
// } else {
|
|
||||||
// bytes = rest;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// // Dequeue everything and abort processing if it is malformed
|
|
||||||
// _ => return (buffer_size, ())
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Sequencially process the representations in vector
|
|
||||||
// // Decrypt and split the handshake if necessary
|
|
||||||
// let tls_repr_vec_size = tls_repr_vec.len();
|
|
||||||
// for _index in 0..tls_repr_vec_size {
|
|
||||||
// let (repr_slice, mut repr) = tls_repr_vec.remove(0);
|
|
||||||
|
|
||||||
// // Process record base on content type
|
|
||||||
// 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();
|
|
||||||
// session.increment_remote_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);
|
|
||||||
// if 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)
|
|
||||||
// }
|
|
||||||
// ).is_err() {
|
|
||||||
// return (buffer_size, ())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// else {
|
|
||||||
// if self.process(repr_slice, repr).is_err() {
|
|
||||||
// return (buffer_size, ())
|
|
||||||
// }
|
|
||||||
// log::info!("Processed record");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// (buffer_size, ())
|
|
||||||
// }
|
|
||||||
// )?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self.session.borrow().has_completed_handshake())
|
Ok(self.session.borrow().has_completed_handshake())
|
||||||
|
@ -926,15 +924,23 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
|
|
||||||
// Check random: Cannot be SHA-256 of "HelloRetryRequest"
|
// Check random: Cannot be SHA-256 of "HelloRetryRequest"
|
||||||
if server_hello.random == HRR_RANDOM {
|
if server_hello.random == HRR_RANDOM {
|
||||||
// Abort communication
|
// Abort communication with illegal parameter alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check session_id_echo
|
// Check session_id_echo
|
||||||
// The socket should have a session_id after moving from START state
|
// The socket should have a session_id after moving from START state
|
||||||
if !self.session.borrow().verify_session_id_echo(server_hello.session_id_echo) {
|
if !self.session.borrow().verify_session_id_echo(server_hello.session_id_echo) {
|
||||||
// Abort communication
|
// Abort communication with illegal parameter alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note the selected cipher suite
|
// Note the selected cipher suite
|
||||||
|
@ -942,8 +948,12 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
|
|
||||||
// TLSv13 forbidden key compression
|
// TLSv13 forbidden key compression
|
||||||
if server_hello.compression_method != 0 {
|
if server_hello.compression_method != 0 {
|
||||||
// Abort communciation
|
// Abort communication with illegal parameter alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
for extension in server_hello.extensions.iter() {
|
for extension in server_hello.extensions.iter() {
|
||||||
|
@ -954,12 +964,21 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
) = extension.extension_data {
|
) = extension.extension_data {
|
||||||
if selected_version != TlsVersion::Tls13 {
|
if selected_version != TlsVersion::Tls13 {
|
||||||
// Abort for choosing not offered TLS version
|
// Abort for choosing not offered TLS version,
|
||||||
todo!()
|
// with illegal parameter alert
|
||||||
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Abort for illegal extension
|
// Abort for malformatted extension, with decode error alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -985,8 +1004,17 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
x25519_server_key
|
x25519_server_key
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
// The client side implementation of this TLS socket only offers
|
||||||
|
// P-256 and x25519 as ECDHE key exchange algorithms
|
||||||
|
// Respond with illegal parameter alert and then terminate
|
||||||
|
_ => {
|
||||||
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -994,13 +1022,24 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Handle invalid TLS packet
|
// Handle invalid TLS packet
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that both selected_cipher and (p256_public XNOR x25519_public) were received
|
// Check that both selected_cipher and (p256_public OR x25519_public) were received
|
||||||
|
// The case where key_share extension exists but no appropriate keys are returned
|
||||||
|
// is considered in above. The only remaining case is that the `key share` entry extension
|
||||||
|
// is not sent at all.
|
||||||
if selected_cipher.is_none() || (p256_public.is_none() && x25519_public.is_none()) {
|
if selected_cipher.is_none() || (p256_public.is_none() && x25519_public.is_none()) {
|
||||||
// Abort communication
|
// Abort communication
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get slice without reserialization
|
// Get slice without reserialization
|
||||||
|
@ -1022,14 +1061,19 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
// Verify that it is indeed an EE
|
// Verify that it is indeed an EE
|
||||||
let might_be_ee = repr.handshake.take().unwrap();
|
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"
|
// Unexpected message types
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Process payload
|
// Possiblity: Process payload
|
||||||
|
|
||||||
// Practically, nothing will be done about cookies/server name
|
// Practically, nothing will be done about cookies/server name
|
||||||
|
// These fields are typically not session related
|
||||||
// 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
|
// Length of handshake header is 4
|
||||||
let (_handshake_slice, ee_slice) =
|
let (_handshake_slice, ee_slice) =
|
||||||
|
@ -1079,8 +1123,7 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
cert.get_cert_public_key().unwrap()
|
cert.get_cert_public_key().unwrap()
|
||||||
);
|
);
|
||||||
log::info!("Received WAIT_CERT_CR");
|
log::info!("Received WAIT_CERT_CR");
|
||||||
}
|
} else if might_be_cert.get_msg_type() == HandshakeType::CertificateRequest {
|
||||||
else if might_be_cert.get_msg_type() == HandshakeType::CertificateRequest {
|
|
||||||
// Process signature algorithm extension
|
// Process signature algorithm extension
|
||||||
// Signature algorithm for the private key of client cert must be included
|
// Signature algorithm for the private key of client cert must be included
|
||||||
// within the list of signature algorithms
|
// within the list of signature algorithms
|
||||||
|
@ -1121,17 +1164,23 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Reject connection, CertificateRequest must have
|
// Reject connection, CertificateRequest must have
|
||||||
// SignatureAlgorithm extension
|
// SignatureAlgorithm extension
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
log::info!("Received WAIT_CERT_CR");
|
log::info!("Received WAIT_CERT_CR");
|
||||||
}
|
} else {
|
||||||
else {
|
// Throw alert for not recving certificate/certificate request from server side
|
||||||
// Throw alert
|
self.session.borrow_mut().invalidate_session(
|
||||||
todo!()
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1172,7 +1221,11 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
} else {
|
} else {
|
||||||
// Unexpected handshakes
|
// Unexpected handshakes
|
||||||
// Throw alert
|
// Throw alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1183,7 +1236,11 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
let might_be_cert_verify = repr.handshake.take().unwrap();
|
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!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take out the portion for CertificateVerify
|
// Take out the portion for CertificateVerify
|
||||||
|
@ -1212,8 +1269,12 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
// Ensure that it is Finished
|
// Ensure that it is Finished
|
||||||
let might_be_server_finished = repr.handshake.take().unwrap();
|
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"
|
// Server Finished is expected.
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take out the portion for server Finished
|
// Take out the portion for server Finished
|
||||||
|
@ -1239,8 +1300,12 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
// Ensure that is a Client Hello
|
// Ensure that is a Client Hello
|
||||||
let might_be_client_hello = repr.handshake.take().unwrap();
|
let might_be_client_hello = repr.handshake.take().unwrap();
|
||||||
if might_be_client_hello.get_msg_type() != HandshakeType::ClientHello {
|
if might_be_client_hello.get_msg_type() != HandshakeType::ClientHello {
|
||||||
// Throw alert
|
// Throw alert. Client Hello is expected.
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process as Client Hello
|
// Process as Client Hello
|
||||||
|
@ -1265,9 +1330,14 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
if let Some(Some(nominated_cipher_suite)) = recognized_cipher_suite {
|
if let Some(Some(nominated_cipher_suite)) = recognized_cipher_suite {
|
||||||
nominated_cipher_suite
|
nominated_cipher_suite
|
||||||
} else {
|
} else {
|
||||||
// Not appropriate cipher found
|
// No appropriate cipher found,
|
||||||
// Send alert
|
// the full set of security measures cannot be set up.
|
||||||
todo!()
|
// Send alert for this
|
||||||
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::HandshakeFailure,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1300,20 +1370,36 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
{
|
{
|
||||||
// TLS 1.3 was not offered by client
|
// TLS 1.3 was not offered by client
|
||||||
// Reject connection immediately
|
// Reject connection immediately
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::IllegalParameter,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Wrong variant appeared, probably malformed
|
// Wrong variant appeared, probably malformed
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Malformed TLS packet
|
// Malformed TLS packet
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No supported_version extension was found,
|
// No supported_version extension was found,
|
||||||
// Terminate by sending alert
|
// Terminate by sending alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check offered ECDHE algorithm
|
// Check offered ECDHE algorithm
|
||||||
|
@ -1341,11 +1427,23 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Malformed TLS packet
|
// Malformed TLS packet
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Client did not offer ECDHE algorithm
|
// Client did not offer ECDHE algorithm within `supported version` extension
|
||||||
todo!()
|
// While it is allowed, HRR is not handled as acceptable parameters
|
||||||
|
// should have been offered already initially.
|
||||||
|
// Possibility: Tolerate minor mismatch of client hello, and send HRR instead
|
||||||
|
|
||||||
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select usable key
|
// Select usable key
|
||||||
|
@ -1395,20 +1493,32 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no applicable offered client key,
|
// There are no applicable offered client key,
|
||||||
// consider sending a ClientHelloRetry
|
// Proper way of handling: Send a HelloRetryRequest with key generated
|
||||||
if ecdhe_public_key.is_none() {
|
if ecdhe_public_key.is_none() {
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::HandshakeFailure,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Malformed packet
|
// Malformed packet
|
||||||
// Send alert to client
|
// Send alert to client
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The key_share extension was not sent
|
// The key_share extension was not sent
|
||||||
// Consider sending a ClientHelloRequest
|
// Proper way of handling: Send a HelloRetryRequest with key generated
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select signature algorithm
|
// Select signature algorithm
|
||||||
|
@ -1456,8 +1566,12 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
signature_algorithm = Some(*server_signature_algorithm);
|
signature_algorithm = Some(*server_signature_algorithm);
|
||||||
} else {
|
} else {
|
||||||
// Cannot find a suitable signature algorithm for the server side
|
// Cannot find a suitable signature algorithm for the server side
|
||||||
// Terminate the negotiation with alert
|
// Terminate the negotiation with an alert
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::HandshakeFailure,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -1467,12 +1581,20 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Malformed packet, type does not match content
|
// Malformed packet, type does not match content
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::DecodeError,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Will only accept authentication through certificate
|
// Will only accept authentication through certificate
|
||||||
// Send alert if there are no signature algorithms extension
|
// Send alert if there are no signature algorithms extension
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::MissingExtension,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1494,8 +1616,12 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
// Ensure that it is Finished
|
// Ensure that it is Finished
|
||||||
let might_be_client_finished = repr.handshake.take().unwrap();
|
let might_be_client_finished = repr.handshake.take().unwrap();
|
||||||
if might_be_client_finished.get_msg_type() != HandshakeType::Finished {
|
if might_be_client_finished.get_msg_type() != HandshakeType::Finished {
|
||||||
// Process the other handshakes in "handshake_vec"
|
// Expected to recv client finished
|
||||||
todo!()
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
handshake_slice
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take out the portion for server Finished
|
// Take out the portion for server Finished
|
||||||
|
@ -1703,8 +1829,43 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tcp_handle(&self) -> SocketHandle {
|
// Send `Close notify` alert to remote side
|
||||||
self.tcp_handle
|
// Set state to `CLOSED`
|
||||||
|
// Leave TCP termination to polling method
|
||||||
|
pub fn close(&mut self) -> Result<()> {
|
||||||
|
let mut session = self.session.borrow_mut();
|
||||||
|
match session.get_tls_state() {
|
||||||
|
// Send a `close notify` if handshake is established
|
||||||
|
TlsState::CLIENT_CONNECTED | TlsState::SERVER_CONNECTED => {
|
||||||
|
session.invalidate_session(
|
||||||
|
AlertType::CloseNotify,
|
||||||
|
&[]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
// Do nothing if handshake hasn't even started
|
||||||
|
TlsState::DEFAULT => {},
|
||||||
|
// Send `user cancaled` to cancel the handshake negotiation
|
||||||
|
// if it is currently in the middle of one
|
||||||
|
_ => {
|
||||||
|
session.invalidate_session(
|
||||||
|
AlertType::UserCanceled,
|
||||||
|
&[]
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::fmt;
|
||||||
|
impl<'a, 'b, 'c> fmt::Write for TlsSocket<'a, 'b, 'c> {
|
||||||
|
fn write_str(&mut self, slice: &str) -> fmt::Result {
|
||||||
|
let slice = slice.as_bytes();
|
||||||
|
if self.send_slice(slice) == Ok(()) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(fmt::Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,40 @@ pub(crate) enum TlsContentType {
|
||||||
ApplicationData = 23
|
ApplicationData = 23
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
|
#[repr(u8)]
|
||||||
|
pub(crate) enum AlertType {
|
||||||
|
CloseNotify = 0,
|
||||||
|
UnexpectedMessage = 10,
|
||||||
|
BadRecordMac = 20,
|
||||||
|
RecordOverflow = 22,
|
||||||
|
HandshakeFailure = 40,
|
||||||
|
BadCertificate = 42,
|
||||||
|
UnsupportedCertificate = 43,
|
||||||
|
CertificateRevoked = 44,
|
||||||
|
CertificateExpired = 45,
|
||||||
|
CertificateUnknown = 46,
|
||||||
|
IllegalParameter = 47,
|
||||||
|
UnknownCA = 48,
|
||||||
|
AccessDenied = 49,
|
||||||
|
DecodeError = 50,
|
||||||
|
DecryptError = 51,
|
||||||
|
ProtocolVersion = 70,
|
||||||
|
InsufficientSecurity = 71,
|
||||||
|
InternalError = 80,
|
||||||
|
InappropriateFallback = 86,
|
||||||
|
UserCanceled = 90,
|
||||||
|
MissingExtension = 109,
|
||||||
|
UnsupportedExtension = 110,
|
||||||
|
UnrecognizedName = 112,
|
||||||
|
BadCertificateStatusResponse = 113,
|
||||||
|
UnknownPSKIdentity = 115,
|
||||||
|
CertificateRequired = 116,
|
||||||
|
NoApplicationProtcol = 120,
|
||||||
|
#[num_enum(default)]
|
||||||
|
UnknownAlert = 255
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub(crate) enum TlsVersion {
|
pub(crate) enum TlsVersion {
|
||||||
|
@ -113,6 +147,24 @@ impl<'a> TlsRepr<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn alert(mut self, alert: AlertType) -> Self {
|
||||||
|
self.content_type = TlsContentType::Alert;
|
||||||
|
self.version = TlsVersion::Tls12;
|
||||||
|
let mut application_data: Vec<u8> = Vec::new();
|
||||||
|
match alert {
|
||||||
|
AlertType::CloseNotify | AlertType::UserCanceled => {
|
||||||
|
application_data.push(1)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
application_data.push(2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
application_data.push(alert.try_into().unwrap());
|
||||||
|
self.length = 2;
|
||||||
|
self.payload = Some(application_data);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Consider replace all these boolean function
|
// TODO: Consider replace all these boolean function
|
||||||
// into a single function that returns the HandshakeType.
|
// into a single function that returns the HandshakeType.
|
||||||
pub(crate) fn is_server_hello(&self) -> bool {
|
pub(crate) fn is_server_hello(&self) -> bool {
|
||||||
|
|
Loading…
Reference in New Issue