recv: recognize alert
This commit is contained in:
parent
fe6418df36
commit
5ca7c6b3ff
@ -73,7 +73,7 @@ pub(crate) fn parse_tls_repr(bytes: &[u8]) -> IResult<&[u8], (&[u8], TlsRepr)> {
|
|||||||
)(bytes)?;
|
)(bytes)?;
|
||||||
repr.handshake = Some(handshake);
|
repr.handshake = Some(handshake);
|
||||||
},
|
},
|
||||||
ChangeCipherSpec | ApplicationData => {
|
ChangeCipherSpec | ApplicationData | Alert => {
|
||||||
let mut vec: Vec<u8> = Vec::new();
|
let mut vec: Vec<u8> = Vec::new();
|
||||||
vec.extend_from_slice(bytes);
|
vec.extend_from_slice(bytes);
|
||||||
repr.payload = Some(vec);
|
repr.payload = Some(vec);
|
||||||
|
200
src/tls.rs
200
src/tls.rs
@ -156,7 +156,7 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
|||||||
{
|
{
|
||||||
let tcp_state = self.sockets.get::<TcpSocket>(self.tcp_handle).state();
|
let tcp_state = self.sockets.get::<TcpSocket>(self.tcp_handle).state();
|
||||||
|
|
||||||
//Close TCP socket if necessary
|
// Close TCP socket if necessary
|
||||||
if tcp_state == TcpState::Established && tls_state == TlsState::DEFAULT {
|
if tcp_state == TcpState::Established && tls_state == TlsState::DEFAULT {
|
||||||
self.sockets.get::<TcpSocket>(self.tcp_handle).close();
|
self.sockets.get::<TcpSocket>(self.tcp_handle).close();
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@ -164,19 +164,42 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
|||||||
|
|
||||||
// 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
|
||||||
// TCP socket is not connected
|
// TCP socket is not connected <= seems like a bad piece of idea to me
|
||||||
|
// Reset TLS state to DEFAULT if TCP session is interrupted
|
||||||
|
// This is to close off hanged TLS sockets, when its dependent TCP session
|
||||||
|
// has already ended.
|
||||||
if tcp_state != TcpState::Established {
|
if tcp_state != TcpState::Established {
|
||||||
if tls_state == TlsState::CLIENT_START {
|
use TlsState::*;
|
||||||
// Restart TCP handshake is it is closed for some reason
|
match tls_state {
|
||||||
let mut tcp_socket = self.sockets.get::<TcpSocket>(self.tcp_handle);
|
// Do nothing on the starting states
|
||||||
let session = self.session.borrow();
|
// Namely those immediate precedes TCP handshake,
|
||||||
if !tcp_socket.is_open() {
|
// as handshake can legitimately be incomplete
|
||||||
tcp_socket.connect(
|
DEFAULT |
|
||||||
session.get_remote_endpoint(),
|
SERVER_START => {},
|
||||||
session.get_local_endpoint()
|
|
||||||
)?;
|
// Attempt to reconnect if the socket went down before TLS socket sent anything
|
||||||
|
CLIENT_START => {
|
||||||
|
let mut tcp_socket = self.sockets.get::<TcpSocket>(self.tcp_handle);
|
||||||
|
let session = self.session.borrow();
|
||||||
|
if !tcp_socket.is_open() {
|
||||||
|
log::info!("Socket closed initially");
|
||||||
|
tcp_socket.connect(
|
||||||
|
session.get_remote_endpoint(),
|
||||||
|
session.get_local_endpoint()
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For any other functioning state, the TCP connection being not
|
||||||
|
// established should imply that the TLS connection had been derailed
|
||||||
|
// Reset TLS state to DEFAULT to allow terminate a dead link
|
||||||
|
_ => {
|
||||||
|
let mut session = self.session.borrow_mut();
|
||||||
|
session.reset_state();
|
||||||
|
log::info!("TLS socket resets after TCP socket closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate the procedure, as no processing is necessary
|
// Terminate the procedure, as no processing is necessary
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@ -813,64 +836,115 @@ impl<'a, 'b, 'c> TlsSocket<'a, 'b, 'c> {
|
|||||||
// Process record base on content type
|
// Process record base on content type
|
||||||
log::info!("Record type: {:?}", repr.content_type);
|
log::info!("Record type: {:?}", repr.content_type);
|
||||||
|
|
||||||
if repr.content_type == TlsContentType::ApplicationData {
|
// Handle TLS represenatation according to the content type:
|
||||||
log::info!("Found application data");
|
// Handshake & ChangeCipherSpec: Directly process the handshake
|
||||||
// Take the payload out of TLS Record and decrypt
|
// Alert: Reset session immediately
|
||||||
let mut app_data = repr.payload.take().unwrap();
|
// ApplicationData: Decrypt and then handle, with similar criteria
|
||||||
let mut associated_data = [0; 5];
|
// Reject invalid contents by invalidating the TLS session
|
||||||
associated_data[0] = repr.content_type.into();
|
match repr.content_type {
|
||||||
NetworkEndian::write_u16(
|
TlsContentType::ApplicationData => {
|
||||||
&mut associated_data[1..3],
|
log::info!("Found application data");
|
||||||
repr.version.into()
|
// Take the payload out of TLS Record and decrypt
|
||||||
);
|
let mut app_data = repr.payload.take().unwrap();
|
||||||
NetworkEndian::write_u16(
|
let mut associated_data = [0; 5];
|
||||||
&mut associated_data[3..5],
|
associated_data[0] = repr.content_type.into();
|
||||||
repr.length
|
NetworkEndian::write_u16(
|
||||||
);
|
&mut associated_data[1..3],
|
||||||
{
|
repr.version.into()
|
||||||
let mut session = self.session.borrow_mut();
|
);
|
||||||
session.decrypt_in_place_detached(
|
NetworkEndian::write_u16(
|
||||||
&associated_data,
|
&mut associated_data[3..5],
|
||||||
&mut app_data
|
repr.length
|
||||||
).unwrap();
|
);
|
||||||
session.increment_remote_sequence_number();
|
{
|
||||||
}
|
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)
|
// Discard last 16 bytes (auth tag)
|
||||||
let inner_plaintext = &app_data[..app_data.len()-16];
|
let inner_plaintext = &app_data[..app_data.len()-16];
|
||||||
let (inner_content_type, _) = get_content_type_inner_plaintext(
|
let (inner_content_type, begin_zero) = get_content_type_inner_plaintext(
|
||||||
inner_plaintext
|
inner_plaintext
|
||||||
);
|
);
|
||||||
if inner_content_type != TlsContentType::Handshake {
|
// Find the index of the content type byte
|
||||||
// Silently ignore non-handshakes
|
let content_type_index = match begin_zero {
|
||||||
return Ok(self.session.borrow().has_completed_handshake())
|
Some(index) => index - 1,
|
||||||
}
|
None => app_data.len() - 16 - 1
|
||||||
let (_, mut inner_handshakes) = complete(
|
};
|
||||||
parse_inner_plaintext_for_handshake
|
|
||||||
)(inner_plaintext).unwrap();
|
|
||||||
|
|
||||||
// Sequentially process all handshakes
|
// Process contents that are not handshakes differently
|
||||||
let num_of_handshakes = inner_handshakes.len();
|
// Invalid: Raise an alert to remote side
|
||||||
for _ in 0..num_of_handshakes {
|
// ChangeCipherSpec: It should not be encrypted, raise alert
|
||||||
let (handshake_slice, handshake_repr) = inner_handshakes.remove(0);
|
// Alert: Reset TLS session and terminate TCP session directly
|
||||||
if self.process(
|
// Handshake: Normal procedure as below
|
||||||
handshake_slice,
|
// ApplicationData: Early data is silently ignored and wont be processed
|
||||||
TlsRepr {
|
match inner_content_type {
|
||||||
content_type: TlsContentType::Handshake,
|
TlsContentType::Invalid | TlsContentType::ChangeCipherSpec => {
|
||||||
version: repr.version,
|
self.session.borrow_mut().invalidate_session(
|
||||||
length: u16::try_from(handshake_repr.length).unwrap() + 4,
|
AlertType::UnexpectedMessage,
|
||||||
payload: None,
|
&inner_plaintext[..content_type_index]
|
||||||
handshake: Some(handshake_repr)
|
);
|
||||||
|
return Ok(false);
|
||||||
|
},
|
||||||
|
TlsContentType::Alert => {
|
||||||
|
self.session.borrow_mut().reset_state();
|
||||||
|
return Ok(false);
|
||||||
|
},
|
||||||
|
TlsContentType::ApplicationData => {
|
||||||
|
return Ok(
|
||||||
|
self.session.borrow().has_completed_handshake()
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Ok(self.session.borrow().has_completed_handshake())
|
||||||
}
|
}
|
||||||
).is_err() {
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
TlsContentType::ChangeCipherSpec |
|
||||||
|
TlsContentType::Handshake => {
|
||||||
|
if self.process(repr_slice, repr).is_err() {
|
||||||
return Ok(self.session.borrow().has_completed_handshake())
|
return Ok(self.session.borrow().has_completed_handshake())
|
||||||
}
|
}
|
||||||
|
log::info!("Processed record");
|
||||||
|
},
|
||||||
|
|
||||||
|
TlsContentType::Alert => {
|
||||||
|
self.session.borrow_mut().reset_state();
|
||||||
|
log::info!("Received alert, closing TCP socket..");
|
||||||
|
},
|
||||||
|
|
||||||
|
TlsContentType::Invalid => {
|
||||||
|
self.session.borrow_mut().invalidate_session(
|
||||||
|
AlertType::UnexpectedMessage,
|
||||||
|
&repr.payload.unwrap_or(Vec::new())
|
||||||
|
);
|
||||||
|
log::info!("Received invalid TLS records, terminate immediately..");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if self.process(repr_slice, repr).is_err() {
|
|
||||||
return Ok(self.session.borrow().has_completed_handshake())
|
|
||||||
}
|
|
||||||
log::info!("Processed record");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user