rustls/rustls/src/conn.rs

1128 lines
37 KiB
Rust

use crate::cipher;
use crate::error::Error;
use crate::key;
#[cfg(feature = "logging")]
use crate::log::{debug, error, trace, warn};
use crate::msgs::alert::AlertMessagePayload;
use crate::msgs::base::Payload;
use crate::msgs::codec::Codec;
use crate::msgs::deframer::MessageDeframer;
use crate::msgs::enums::HandshakeType;
use crate::msgs::enums::{AlertDescription, AlertLevel, ContentType, ProtocolVersion};
use crate::msgs::fragmenter::{MessageFragmenter, MAX_FRAGMENT_LEN};
use crate::msgs::hsjoiner::HandshakeJoiner;
use crate::msgs::message::{BorrowedOpaqueMessage, Message, MessagePayload, OpaqueMessage};
use crate::prf;
use crate::quic;
use crate::rand;
use crate::record_layer;
use crate::suites::{SupportedCipherSuite, Tls12CipherSuite};
use crate::vecbuf::ChunkVecBuffer;
use ring::digest::Digest;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::io;
/// Values of this structure are returned from `Session::process_new_packets`
/// and tell the caller the current I/O state of the TLS connection.
#[derive(Debug, PartialEq)]
pub struct IoState {
tls_bytes_to_write: usize,
plaintext_bytes_to_read: usize,
peer_has_closed: bool,
}
impl IoState {
/// How many bytes could be written by `write_tls` if called
/// right now. A non-zero value implies `wants_write`.
pub fn tls_bytes_to_write(&self) -> usize {
self.tls_bytes_to_write
}
/// How many plaintext bytes could be obtained via `std::io::Read`
/// without further I/O.
pub fn plaintext_bytes_to_read(&self) -> usize {
self.plaintext_bytes_to_read
}
/// True if the peer has sent us a close_notify alert. This is
/// the TLS mechanism to security half-close a TLS connection,
/// and signifies that the peer will not send any further data
/// on this connection.
///
/// This is also signalled via returning `Ok(0)` from
/// `std::io::Read`, after all the received bytes have been
/// retrieved.
pub fn peer_has_closed(&self) -> bool {
self.peer_has_closed
}
}
/// A structure that implements `std::io::Read` for reading plaintext.
pub struct Reader<'a> {
common: &'a mut ConnectionCommon,
}
impl<'a> io::Read for Reader<'a> {
/// Obtain plaintext data received from the peer over this TLS connection.
///
/// If the peer closes the TLS session cleanly, this returns `Ok(0)` once all
/// the pending data has been read. No further data can be received on that
/// connection, so the underlying TCP connection should half-closed too.
///
/// Note that support `close_notify` varies in peer TLS libraries: many do not
/// support it and uncleanly close the TCP connection (this might be
/// vulnerable to truncation attacks depending on the application protocol).
/// This means applications using rustls must both handle EOF
/// from this function, *and* unexpected EOF of the underlying TCP connection.
///
/// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`.
///
/// You may learn the number of bytes available at any time by inspecting
/// the return of `process_new_packets()`.
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.common.read(buf)
}
}
/// Internal trait implemented by the `ServerConnection`/`ClientConnection` allowing
/// them to be the subject of a `Writer`.
pub trait PlaintextSink {
fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>;
fn flush(&mut self) -> io::Result<()>;
}
/// A structure that implements `std::io::Write` for writing plaintext.
pub struct Writer<'a> {
sink: &'a mut dyn PlaintextSink,
}
impl<'a> Writer<'a> {
/// Create a new Writer.
///
/// This is not an external interface. Get one of these objects
/// from `Connection::writer()`.
#[doc(hidden)]
pub fn new(sink: &'a mut dyn PlaintextSink) -> Writer<'a> {
Writer { sink }
}
}
impl<'a> io::Write for Writer<'a> {
/// Send the plaintext `buf` to the peer, encrypting
/// and authenticating it. Once this function succeeds
/// you should call `write_tls` which will output the
/// corresponding TLS records.
///
/// This function buffers plaintext sent before the
/// TLS handshake completes, and sends it as soon
/// as it can. This buffer is of *unlimited size* so
/// writing much data before it can be sent will
/// cause excess memory usage.
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.sink.write(buf)
}
fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
self.sink.write_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
self.sink.flush()
}
}
/// Generalises `ClientConnection` and `ServerConnection`
pub trait Connection: quic::QuicExt + Send + Sync {
/// Read TLS content from `rd`. This method does internal
/// buffering, so `rd` can supply TLS messages in arbitrary-
/// sized chunks (like a socket or pipe might).
///
/// You should call `process_new_packets` each time a call to
/// this function succeeds.
///
/// The returned error only relates to IO on `rd`. TLS-level
/// errors are emitted from `process_new_packets`.
///
/// This function returns `Ok(0)` when the underlying `rd` does
/// so. This typically happens when a socket is cleanly closed,
/// or a file is at EOF.
fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error>;
/// Writes TLS messages to `wr`.
///
/// On success the function returns `Ok(n)` where `n` is a number
/// of bytes written to `wr`, number of bytes after encoding and
/// encryption.
///
/// Note that after function return the connection buffer maybe not
/// yet fully flushed. [`wants_write`] function can be used
/// to check if output buffer is not empty.
///
/// [`wants_write`]: #tymethod.wants_write
fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error>;
/// Returns an object that allows reading plaintext.
fn reader(&mut self) -> Reader;
/// Returns an object that allows writing plaintext.
fn writer(&mut self) -> Writer;
/// Processes any new packets read by a previous call to `read_tls`.
///
/// Errors from this function relate to TLS protocol errors, and
/// are fatal to the connection. Future calls after an error will do
/// no new work and will return the same error. After an error is
/// received from process_new_packets, you should not call read_tls
/// any more (it will fill up buffers to no purpose). However, you
/// may call the other methods on the connection, including write,
/// send_close_notify, and write_tls. Most likely you will want to
/// call write_tls to send any alerts queued by the error and then
/// close the underlying connection.
///
/// Success from this function comes with some sundry state data
/// about the connection.
fn process_new_packets(&mut self) -> Result<IoState, Error>;
/// Returns true if the caller should call `read_tls` as soon
/// as possible.
fn wants_read(&self) -> bool;
/// Returns true if the caller should call `write_tls` as soon
/// as possible.
fn wants_write(&self) -> bool;
/// Returns true if the connection is currently performing the TLS
/// handshake. During this time plaintext written to the
/// connection is buffered in memory.
fn is_handshaking(&self) -> bool;
/// Sets a limit on the internal buffers used to buffer
/// unsent plaintext (prior to completing the TLS handshake)
/// and unsent TLS records.
///
/// By default, there is no limit. The limit can be set
/// at any time, even if the current buffer use is higher.
fn set_buffer_limit(&mut self, limit: usize);
/// Queues a close_notify fatal alert to be sent in the next
/// `write_tls` call. This informs the peer that the
/// connection is being closed.
fn send_close_notify(&mut self);
/// Retrieves the certificate chain used by the peer to authenticate.
///
/// The order of the certificate chain is as it appears in the TLS
/// protocol: the first certificate relates to the peer, the
/// second certifies the first, the third certifies the second, and
/// so on.
///
/// For clients, this is the certificate chain of the server.
///
/// For servers, this is the certificate chain of the client,
/// if client authentication was completed.
///
/// The return value is None until this value is available.
fn peer_certificates(&self) -> Option<Vec<key::Certificate>>;
/// Retrieves the protocol agreed with the peer via ALPN.
///
/// A return value of None after handshake completion
/// means no protocol was agreed (because no protocols
/// were offered or accepted by the peer).
fn alpn_protocol(&self) -> Option<&[u8]>;
/// Retrieves the protocol version agreed with the peer.
///
/// This returns None until the version is agreed.
fn protocol_version(&self) -> Option<ProtocolVersion>;
/// Derives key material from the agreed connection secrets.
///
/// This function fills in `output` with `output.len()` bytes of key
/// material derived from the master session secret using `label`
/// and `context` for diversification.
///
/// See RFC5705 for more details on what this does and is for.
///
/// For TLS1.3 connections, this function does not use the
/// "early" exporter at any point.
///
/// This function fails if called prior to the handshake completing;
/// check with `is_handshaking()` first.
fn export_keying_material(
&self,
output: &mut [u8],
label: &[u8],
context: Option<&[u8]>,
) -> Result<(), Error>;
/// Retrieves the ciphersuite agreed with the peer.
///
/// This returns None until the ciphersuite is agreed.
fn negotiated_cipher_suite(&self) -> Option<&'static SupportedCipherSuite>;
/// This function uses `io` to complete any outstanding IO for
/// this connection.
///
/// This is a convenience function which solely uses other parts
/// of the public API.
///
/// What this means depends on the connection state:
///
/// - If the connection `is_handshaking()`, then IO is performed until
/// the handshake is complete.
/// - Otherwise, if `wants_write` is true, `write_tls` is invoked
/// until it is all written.
/// - Otherwise, if `wants_read` is true, `read_tls` is invoked
/// once.
///
/// The return value is the number of bytes read from and written
/// to `io`, respectively.
///
/// This function will block if `io` blocks.
///
/// Errors from TLS record handling (i.e., from `process_new_packets()`)
/// are wrapped in an `io::ErrorKind::InvalidData`-kind error.
fn complete_io<T>(&mut self, io: &mut T) -> Result<(usize, usize), io::Error>
where
Self: Sized,
T: io::Read + io::Write,
{
let until_handshaked = self.is_handshaking();
let mut eof = false;
let mut wrlen = 0;
let mut rdlen = 0;
loop {
while self.wants_write() {
wrlen += self.write_tls(io)?;
}
if !until_handshaked && wrlen > 0 {
return Ok((rdlen, wrlen));
}
if !eof && self.wants_read() {
match self.read_tls(io)? {
0 => eof = true,
n => rdlen += n,
}
}
match self.process_new_packets() {
Ok(_) => {}
Err(e) => {
// In case we have an alert to send describing this error,
// try a last-gasp write -- but don't predate the primary
// error.
let _ignored = self.write_tls(io);
return Err(io::Error::new(io::ErrorKind::InvalidData, e));
}
};
match (eof, until_handshaked, self.is_handshaking()) {
(_, true, false) => return Ok((rdlen, wrlen)),
(_, false, _) => return Ok((rdlen, wrlen)),
(true, true, true) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
(..) => {}
}
}
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Protocol {
Tcp,
#[cfg(feature = "quic")]
Quic,
}
#[derive(Clone, Debug)]
pub struct ConnectionRandoms {
pub we_are_client: bool,
pub client: [u8; 32],
pub server: [u8; 32],
}
static TLS12_DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01];
impl ConnectionRandoms {
pub fn for_server() -> Result<ConnectionRandoms, rand::GetRandomFailed> {
let mut ret = ConnectionRandoms {
we_are_client: false,
client: [0u8; 32],
server: [0u8; 32],
};
rand::fill_random(&mut ret.server)?;
Ok(ret)
}
pub fn for_client() -> Result<ConnectionRandoms, rand::GetRandomFailed> {
let mut ret = ConnectionRandoms {
we_are_client: true,
client: [0u8; 32],
server: [0u8; 32],
};
rand::fill_random(&mut ret.client)?;
Ok(ret)
}
pub fn set_tls12_downgrade_marker(&mut self) {
assert!(!self.we_are_client);
self.server[24..].copy_from_slice(&TLS12_DOWNGRADE_SENTINEL);
}
pub fn has_tls12_downgrade_marker(&mut self) -> bool {
assert!(self.we_are_client);
// both the server random and TLS12_DOWNGRADE_SENTINEL are
// public values and don't require constant time comparison
self.server[24..] == TLS12_DOWNGRADE_SENTINEL
}
}
fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] {
let mut randoms = [0u8; 64];
randoms[..32].copy_from_slice(first);
randoms[32..].copy_from_slice(second);
randoms
}
/// TLS1.2 per-connection keying material
pub struct ConnectionSecrets {
pub randoms: ConnectionRandoms,
suite: Tls12CipherSuite,
pub master_secret: [u8; 48],
}
impl ConnectionSecrets {
pub(crate) fn new(
randoms: &ConnectionRandoms,
suite: Tls12CipherSuite,
pms: &[u8],
) -> ConnectionSecrets {
let mut ret = ConnectionSecrets {
randoms: randoms.clone(),
suite,
master_secret: [0u8; 48],
};
let randoms = join_randoms(&ret.randoms.client, &ret.randoms.server);
prf::prf(
&mut ret.master_secret,
suite.supported_suite().hmac_algorithm(),
pms,
b"master secret",
&randoms,
);
ret
}
pub(crate) fn new_ems(
randoms: &ConnectionRandoms,
hs_hash: &Digest,
suite: Tls12CipherSuite,
pms: &[u8],
) -> ConnectionSecrets {
let mut ret = ConnectionSecrets {
randoms: randoms.clone(),
master_secret: [0u8; 48],
suite,
};
prf::prf(
&mut ret.master_secret,
suite.supported_suite().hmac_algorithm(),
pms,
b"extended master secret",
hs_hash.as_ref(),
);
ret
}
pub(crate) fn new_resume(
randoms: &ConnectionRandoms,
suite: Tls12CipherSuite,
master_secret: &[u8],
) -> ConnectionSecrets {
let mut ret = ConnectionSecrets {
randoms: randoms.clone(),
suite,
master_secret: [0u8; 48],
};
ret.master_secret
.copy_from_slice(master_secret);
ret
}
pub fn make_key_block(&self) -> Vec<u8> {
let scs = self.suite.supported_suite();
let len = (scs.aead_algorithm.key_len() + self.suite.tls12().fixed_iv_len) * 2
+ self.suite.tls12().explicit_nonce_len;
let mut out = Vec::new();
out.resize(len, 0u8);
// NOTE: opposite order to above for no good reason.
// Don't design security protocols on drugs, kids.
let randoms = join_randoms(&self.randoms.server, &self.randoms.client);
prf::prf(
&mut out,
self.suite
.supported_suite()
.hmac_algorithm(),
&self.master_secret,
b"key expansion",
&randoms,
);
out
}
pub(crate) fn suite(&self) -> Tls12CipherSuite {
self.suite
}
pub fn get_master_secret(&self) -> Vec<u8> {
let mut ret = Vec::new();
ret.extend_from_slice(&self.master_secret);
ret
}
pub fn make_verify_data(&self, handshake_hash: &Digest, label: &[u8]) -> Vec<u8> {
let mut out = Vec::new();
out.resize(12, 0u8);
prf::prf(
&mut out,
self.suite
.supported_suite()
.hmac_algorithm(),
&self.master_secret,
label,
handshake_hash.as_ref(),
);
out
}
pub fn client_verify_data(&self, handshake_hash: &Digest) -> Vec<u8> {
self.make_verify_data(handshake_hash, b"client finished")
}
pub fn server_verify_data(&self, handshake_hash: &Digest) -> Vec<u8> {
self.make_verify_data(handshake_hash, b"server finished")
}
pub fn export_keying_material(&self, output: &mut [u8], label: &[u8], context: Option<&[u8]>) {
let mut randoms = Vec::new();
randoms.extend_from_slice(&self.randoms.client);
randoms.extend_from_slice(&self.randoms.server);
if let Some(context) = context {
assert!(context.len() <= 0xffff);
(context.len() as u16).encode(&mut randoms);
randoms.extend_from_slice(context);
}
prf::prf(
output,
self.suite
.supported_suite()
.hmac_algorithm(),
&self.master_secret,
label,
&randoms,
)
}
}
// --- Common (to client and server) connection functions ---
enum Limit {
Yes,
No,
}
pub struct ConnectionCommon {
pub negotiated_version: Option<ProtocolVersion>,
pub is_client: bool,
pub record_layer: record_layer::RecordLayer,
pub suite: Option<&'static SupportedCipherSuite>,
pub alpn_protocol: Option<Vec<u8>>,
peer_eof: bool,
pub traffic: bool,
pub early_traffic: bool,
sent_fatal_alert: bool,
received_middlebox_ccs: bool,
error: Option<Error>,
message_deframer: MessageDeframer,
pub handshake_joiner: HandshakeJoiner,
pub message_fragmenter: MessageFragmenter,
received_plaintext: ChunkVecBuffer,
sendable_plaintext: ChunkVecBuffer,
pub sendable_tls: ChunkVecBuffer,
/// Protocol whose key schedule should be used. Unused for TLS < 1.3.
pub protocol: Protocol,
#[cfg(feature = "quic")]
pub(crate) quic: Quic,
}
impl ConnectionCommon {
pub fn new(mtu: Option<usize>, client: bool) -> ConnectionCommon {
ConnectionCommon {
negotiated_version: None,
is_client: client,
record_layer: record_layer::RecordLayer::new(),
suite: None,
alpn_protocol: None,
peer_eof: false,
traffic: false,
early_traffic: false,
sent_fatal_alert: false,
received_middlebox_ccs: false,
error: None,
message_deframer: MessageDeframer::new(),
handshake_joiner: HandshakeJoiner::new(),
message_fragmenter: MessageFragmenter::new(mtu.unwrap_or(MAX_FRAGMENT_LEN)),
received_plaintext: ChunkVecBuffer::new(),
sendable_plaintext: ChunkVecBuffer::new(),
sendable_tls: ChunkVecBuffer::new(),
protocol: Protocol::Tcp,
#[cfg(feature = "quic")]
quic: Quic::new(),
}
}
pub fn reader(&mut self) -> Reader {
Reader { common: self }
}
fn current_io_state(&self) -> IoState {
IoState {
tls_bytes_to_write: self.sendable_tls.len(),
plaintext_bytes_to_read: self.received_plaintext.len(),
peer_has_closed: self.peer_eof,
}
}
pub fn is_tls13(&self) -> bool {
matches!(self.negotiated_version, Some(ProtocolVersion::TLSv1_3))
}
fn process_msg(&mut self, mut msg: OpaqueMessage) -> Result<Option<MessageType>, Error> {
// pass message to handshake state machine if any of these are true:
// - TLS1.2 (where it's part of the state machine),
// - prior to determining the version (it's illegal as a first message)
// - if it's not a CCS at all
// - if we've finished the handshake
if msg.typ == ContentType::ChangeCipherSpec && !self.traffic && self.is_tls13() {
if self.received_middlebox_ccs {
return Err(Error::PeerMisbehavedError(
"illegal middlebox CCS received".into(),
));
} else {
self.received_middlebox_ccs = true;
trace!("Dropping CCS");
return Ok(None);
}
}
// Decrypt if demanded by current state.
if self.record_layer.is_decrypting() {
let dm = self.decrypt_incoming(msg)?;
msg = dm;
}
// For handshake messages, we need to join them before parsing
// and processing.
if self.handshake_joiner.want_message(&msg) {
self.handshake_joiner
.take_message(msg)
.ok_or_else(|| {
self.send_fatal_alert(AlertDescription::DecodeError);
Error::CorruptMessagePayload(ContentType::Handshake)
})?;
return Ok(Some(MessageType::Handshake));
}
// Now we can fully parse the message payload.
let msg = Message::try_from(msg)?;
// For alerts, we have separate logic.
if let MessagePayload::Alert(alert) = &msg.payload {
return self.process_alert(alert).map(|()| None);
}
Ok(Some(MessageType::Data(msg)))
}
pub(crate) fn process_new_packets<S: HandleState>(
&mut self,
state: &mut Option<S>,
data: &mut S::Data,
config: &S::Config,
) -> Result<IoState, Error> {
if let Some(ref err) = self.error {
return Err(err.clone());
}
if self.message_deframer.desynced {
return Err(Error::CorruptMessage);
}
while let Some(msg) = self.message_deframer.frames.pop_front() {
let result = self
.process_msg(msg)
.and_then(|val| match val {
Some(MessageType::Handshake) => {
self.process_new_handshake_messages(state, data, config)
}
Some(MessageType::Data(msg)) => {
self.process_main_protocol(msg, state, data, config)
}
None => Ok(()),
});
if let Err(err) = result {
self.error = Some(err.clone());
return Err(err);
}
}
Ok(self.current_io_state())
}
pub(crate) fn process_new_handshake_messages<S: HandleState>(
&mut self,
state: &mut Option<S>,
data: &mut S::Data,
config: &S::Config,
) -> Result<(), Error> {
while let Some(msg) = self.handshake_joiner.frames.pop_front() {
self.process_main_protocol(msg, state, data, &config)?;
}
Ok(())
}
/// Process `msg`. First, we get the current state. Then we ask what messages
/// that state expects, enforced via `check_message`. Finally, we ask the handler
/// to handle the message.
fn process_main_protocol<S: HandleState>(
&mut self,
msg: Message,
state: &mut Option<S>,
data: &mut S::Data,
config: &S::Config,
) -> Result<(), Error> {
// For TLS1.2, outside of the handshake, send rejection alerts for
// renegotiation requests. These can occur any time.
if self.traffic && !self.is_tls13() {
let reject_ty = match self.is_client {
true => HandshakeType::HelloRequest,
false => HandshakeType::ClientHello,
};
if msg.is_handshake_type(reject_ty) {
self.send_warning_alert(AlertDescription::NoRenegotiation);
return Ok(());
}
}
let current = state.take().unwrap();
match current.handle(msg, data, self, config) {
Ok(next) => {
*state = Some(next);
Ok(())
}
Err(e @ Error::InappropriateMessage { .. })
| Err(e @ Error::InappropriateHandshakeMessage { .. }) => {
self.send_fatal_alert(AlertDescription::UnexpectedMessage);
Err(e)
}
Err(e) => Err(e),
}
}
// Changing the keys must not span any fragmented handshake
// messages. Otherwise the defragmented messages will have
// been protected with two different record layer protections,
// which is illegal. Not mentioned in RFC.
pub(crate) fn check_aligned_handshake(&mut self) -> Result<(), Error> {
if !self.handshake_joiner.is_empty() {
self.send_fatal_alert(AlertDescription::UnexpectedMessage);
Err(Error::PeerMisbehavedError(
"key epoch or handshake flight with pending fragment".to_string(),
))
} else {
Ok(())
}
}
pub fn illegal_param(&mut self, why: &str) -> Error {
self.send_fatal_alert(AlertDescription::IllegalParameter);
Error::PeerMisbehavedError(why.to_string())
}
pub fn get_suite(&self) -> Option<&'static SupportedCipherSuite> {
self.suite
}
pub fn get_alpn_protocol(&self) -> Option<&[u8]> {
self.alpn_protocol
.as_ref()
.map(AsRef::as_ref)
}
pub fn decrypt_incoming(&mut self, encr: OpaqueMessage) -> Result<OpaqueMessage, Error> {
if self
.record_layer
.wants_close_before_decrypt()
{
self.send_close_notify();
}
let rc = self.record_layer.decrypt_incoming(encr);
if let Err(Error::PeerSentOversizedRecord) = rc {
self.send_fatal_alert(AlertDescription::RecordOverflow);
}
rc
}
pub fn has_readable_plaintext(&self) -> bool {
!self.received_plaintext.is_empty()
}
pub fn set_buffer_limit(&mut self, limit: usize) {
self.sendable_plaintext.set_limit(limit);
self.sendable_tls.set_limit(limit);
}
pub fn process_alert(&mut self, alert: &AlertMessagePayload) -> Result<(), Error> {
// Reject unknown AlertLevels.
if let AlertLevel::Unknown(_) = alert.level {
self.send_fatal_alert(AlertDescription::IllegalParameter);
}
// If we get a CloseNotify, make a note to declare EOF to our
// caller.
if alert.description == AlertDescription::CloseNotify {
self.peer_eof = true;
return Ok(());
}
// Warnings are nonfatal for TLS1.2, but outlawed in TLS1.3
// (except, for no good reason, user_cancelled).
if alert.level == AlertLevel::Warning {
if self.is_tls13() && alert.description != AlertDescription::UserCanceled {
self.send_fatal_alert(AlertDescription::DecodeError);
} else {
warn!("TLS alert warning received: {:#?}", alert);
return Ok(());
}
}
error!("TLS alert received: {:#?}", alert);
Err(Error::AlertReceived(alert.description))
}
/// Fragment `m`, encrypt the fragments, and then queue
/// the encrypted fragments for sending.
pub fn send_msg_encrypt(&mut self, m: OpaqueMessage) {
let mut plain_messages = VecDeque::new();
self.message_fragmenter
.fragment(m, &mut plain_messages);
for m in plain_messages {
self.send_single_fragment(m.borrow());
}
}
/// Like send_msg_encrypt, but operate on an appdata directly.
fn send_appdata_encrypt(&mut self, payload: &[u8], limit: Limit) -> usize {
// Here, the limit on sendable_tls applies to encrypted data,
// but we're respecting it for plaintext data -- so we'll
// be out by whatever the cipher+record overhead is. That's a
// constant and predictable amount, so it's not a terrible issue.
let len = match limit {
Limit::Yes => self
.sendable_tls
.apply_limit(payload.len()),
Limit::No => payload.len(),
};
let mut plain_messages = VecDeque::new();
self.message_fragmenter.fragment_borrow(
ContentType::ApplicationData,
ProtocolVersion::TLSv1_2,
&payload[..len],
&mut plain_messages,
);
for m in plain_messages {
self.send_single_fragment(m);
}
len
}
fn send_single_fragment(&mut self, m: BorrowedOpaqueMessage) {
// Close connection once we start to run out of
// sequence space.
if self
.record_layer
.wants_close_before_encrypt()
{
self.send_close_notify();
}
// Refuse to wrap counter at all costs. This
// is basically untestable unfortunately.
if self.record_layer.encrypt_exhausted() {
return;
}
let em = self.record_layer.encrypt_outgoing(m);
self.queue_tls_message(em);
}
/// Are we done? i.e., have we processed all received messages,
/// and received a close_notify to indicate that no new messages
/// will arrive?
pub fn connection_at_eof(&self) -> bool {
self.peer_eof && !self.message_deframer.has_pending()
}
/// Read TLS content from `rd`. This method does internal
/// buffering, so `rd` can supply TLS messages in arbitrary-
/// sized chunks (like a socket or pipe might).
pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> io::Result<usize> {
self.message_deframer.read(rd)
}
pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> {
self.sendable_tls.write_to(wr)
}
/// Send plaintext application data, fragmenting and
/// encrypting it as it goes out.
///
/// If internal buffers are too small, this function will not accept
/// all the data.
pub fn send_some_plaintext(&mut self, data: &[u8]) -> usize {
self.send_plain(data, Limit::Yes)
}
pub fn send_early_plaintext(&mut self, data: &[u8]) -> usize {
debug_assert!(self.early_traffic);
debug_assert!(self.record_layer.is_encrypting());
if data.is_empty() {
// Don't send empty fragments.
return 0;
}
self.send_appdata_encrypt(data, Limit::Yes)
}
/// Encrypt and send some plaintext `data`. `limit` controls
/// whether the per-connection buffer limits apply.
///
/// Returns the number of bytes written from `data`: this might
/// be less than `data.len()` if buffer limits were exceeded.
fn send_plain(&mut self, data: &[u8], limit: Limit) -> usize {
if !self.traffic {
// If we haven't completed handshaking, buffer
// plaintext to send once we do.
let len = match limit {
Limit::Yes => self
.sendable_plaintext
.append_limited_copy(data),
Limit::No => self
.sendable_plaintext
.append(data.to_vec()),
};
return len;
}
debug_assert!(self.record_layer.is_encrypting());
if data.is_empty() {
// Don't send empty fragments.
return 0;
}
self.send_appdata_encrypt(data, limit)
}
pub fn start_traffic(&mut self) {
self.traffic = true;
self.flush_plaintext();
}
/// Send any buffered plaintext. Plaintext is buffered if
/// written during handshake.
fn flush_plaintext(&mut self) {
if !self.traffic {
return;
}
while let Some(buf) = self.sendable_plaintext.pop() {
self.send_plain(&buf, Limit::No);
}
}
// Put m into sendable_tls for writing.
fn queue_tls_message(&mut self, m: OpaqueMessage) {
self.sendable_tls.append(m.encode());
}
/// Send a raw TLS message, fragmenting it if needed.
pub fn send_msg(&mut self, m: Message, must_encrypt: bool) {
#[cfg(feature = "quic")]
{
if let Protocol::Quic = self.protocol {
if let MessagePayload::Alert(alert) = m.payload {
self.quic.alert = Some(alert.description);
} else {
debug_assert!(
matches!(m.payload, MessagePayload::Handshake(_)),
"QUIC uses TLS for the cryptographic handshake only"
);
let mut bytes = Vec::new();
m.payload.encode(&mut bytes);
self.quic
.hs_queue
.push_back((must_encrypt, bytes));
}
return;
}
}
if !must_encrypt {
let mut to_send = VecDeque::new();
self.message_fragmenter
.fragment(m.into(), &mut to_send);
for mm in to_send {
self.queue_tls_message(mm);
}
} else {
self.send_msg_encrypt(m.into());
}
}
pub fn take_received_plaintext(&mut self, bytes: Payload) {
self.received_plaintext.append(bytes.0);
}
pub fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let len = self.received_plaintext.read(buf)?;
if len == 0 && !buf.is_empty() {
// no bytes available:
// - if we received a close_notify, this is a genuine permanent EOF
// - otherwise say EWOULDBLOCK
if !self.connection_at_eof() {
return Err(io::ErrorKind::WouldBlock.into());
}
}
Ok(len)
}
pub fn start_encryption_tls12(&mut self, secrets: &ConnectionSecrets) {
let (dec, enc) = cipher::new_tls12(secrets);
self.record_layer
.prepare_message_encrypter(enc);
self.record_layer
.prepare_message_decrypter(dec);
}
#[cfg(feature = "quic")]
pub fn missing_extension(&mut self, why: &str) -> Error {
self.send_fatal_alert(AlertDescription::MissingExtension);
Error::PeerMisbehavedError(why.to_string())
}
pub fn send_warning_alert(&mut self, desc: AlertDescription) {
warn!("Sending warning alert {:?}", desc);
self.send_warning_alert_no_log(desc);
}
pub fn send_fatal_alert(&mut self, desc: AlertDescription) {
warn!("Sending fatal alert {:?}", desc);
debug_assert!(!self.sent_fatal_alert);
let m = Message::build_alert(AlertLevel::Fatal, desc);
self.send_msg(m, self.record_layer.is_encrypting());
self.sent_fatal_alert = true;
}
pub fn send_close_notify(&mut self) {
debug!("Sending warning alert {:?}", AlertDescription::CloseNotify);
self.send_warning_alert_no_log(AlertDescription::CloseNotify);
}
fn send_warning_alert_no_log(&mut self, desc: AlertDescription) {
let m = Message::build_alert(AlertLevel::Warning, desc);
self.send_msg(m, self.record_layer.is_encrypting());
}
pub fn is_quic(&self) -> bool {
#[cfg(feature = "quic")]
{
self.protocol == Protocol::Quic
}
#[cfg(not(feature = "quic"))]
false
}
}
pub(crate) trait HandleState: Sized {
type Data;
type Config;
fn handle(
self,
message: Message,
data: &mut Self::Data,
common: &mut ConnectionCommon,
config: &Self::Config,
) -> Result<Self, Error>;
}
pub enum MessageType {
Handshake,
Data(Message),
}
#[cfg(feature = "quic")]
pub(crate) struct Quic {
/// QUIC transport parameters received from the peer during the handshake
pub params: Option<Vec<u8>>,
pub alert: Option<AlertDescription>,
pub hs_queue: VecDeque<(bool, Vec<u8>)>,
pub early_secret: Option<ring::hkdf::Prk>,
pub hs_secrets: Option<quic::Secrets>,
pub traffic_secrets: Option<quic::Secrets>,
/// Whether keys derived from traffic_secrets have been passed to the QUIC implementation
pub returned_traffic_keys: bool,
}
#[cfg(feature = "quic")]
impl Quic {
pub fn new() -> Self {
Self {
params: None,
alert: None,
hs_queue: VecDeque::new(),
early_secret: None,
hs_secrets: None,
traffic_secrets: None,
returned_traffic_keys: false,
}
}
}