rip out quic support

This commit is contained in:
sinuio
2022-05-10 11:47:14 -07:00
parent 6ad83d778c
commit 1f3938489d
14 changed files with 213 additions and 2500 deletions

View File

@@ -25,7 +25,6 @@ webpki = { version = "0.22.0", features = ["alloc", "std"] }
default = ["logging", "tls12"]
logging = ["log"]
dangerous_configuration = []
quic = []
tls12 = []
read_buf = ["rustversion"]
@@ -38,11 +37,6 @@ rustls-pemfile = "0.3.0"
base64 = "0.13.0"
rustls = "0.20.4"
[[example]]
name = "bogo_shim"
path = "examples/internal/bogo_shim.rs"
required-features = ["dangerous_configuration", "quic"]
[[example]]
name = "trytls_shim"
path = "examples/internal/trytls_shim.rs"

View File

@@ -4,7 +4,6 @@ use crate::suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES};
use crate::versions;
use std::fmt;
use std::marker::PhantomData;
/// Building a [`ServerConfig`] or [`ClientConfig`] in a linker-friendly and
/// complete way.

View File

@@ -4,8 +4,6 @@ use crate::error::Error;
use crate::kx::SupportedKxGroup;
#[cfg(feature = "logging")]
use crate::log::trace;
#[cfg(feature = "quic")]
use crate::msgs::enums::AlertDescription;
use crate::msgs::enums::CipherSuite;
use crate::msgs::enums::ProtocolVersion;
use crate::msgs::enums::SignatureScheme;
@@ -17,8 +15,6 @@ use crate::versions;
use crate::KeyLog;
use super::hs;
#[cfg(feature = "quic")]
use crate::quic;
use std::convert::TryFrom;
use std::error::Error as StdError;
@@ -532,67 +528,3 @@ impl ClientConnectionData {
}
impl crate::conn::SideData for ClientConnectionData {}
#[cfg(feature = "quic")]
impl quic::QuicExt for ClientConnection {
fn quic_transport_parameters(&self) -> Option<&[u8]> {
self.inner
.common_state
.quic
.params
.as_ref()
.map(|v| v.as_ref())
}
fn zero_rtt_keys(&self) -> Option<quic::DirectionalKeys> {
Some(quic::DirectionalKeys::new(
self.inner
.data
.resumption_ciphersuite
.and_then(|suite| suite.tls13())?,
self.inner.common_state.quic.early_secret.as_ref()?,
))
}
fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
self.inner.read_quic_hs(plaintext)
}
fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<quic::KeyChange> {
quic::write_hs(&mut self.inner.common_state, buf)
}
fn alert(&self) -> Option<AlertDescription> {
self.inner.common_state.quic.alert
}
}
/// Methods specific to QUIC client sessions
#[cfg(feature = "quic")]
pub trait ClientQuicExt {
/// Make a new QUIC ClientConnection. This differs from `ClientConnection::new()`
/// in that it takes an extra argument, `params`, which contains the
/// TLS-encoded transport parameters to send.
fn new_quic(
config: Arc<ClientConfig>,
quic_version: quic::Version,
name: ServerName,
params: Vec<u8>,
) -> Result<ClientConnection, Error> {
if !config.supports_version(ProtocolVersion::TLSv1_3) {
return Err(Error::General(
"TLS 1.3 support is required for QUIC".into(),
));
}
let ext = match quic_version {
quic::Version::V1Draft => ClientExtension::TransportParametersDraft(params),
quic::Version::V1 => ClientExtension::TransportParameters(params),
};
ClientConnection::new_inner(config, name, vec![ext], Protocol::Quic)
}
}
#[cfg(feature = "quic")]
impl ClientQuicExt for ClientConnection {}

View File

@@ -8,8 +8,6 @@ use crate::kx;
#[cfg(feature = "logging")]
use crate::log::{debug, trace};
use crate::msgs::base::Payload;
#[cfg(feature = "quic")]
use crate::msgs::base::PayloadU16;
use crate::msgs::codec::{Codec, Reader};
use crate::msgs::enums::{
AlertDescription, CipherSuite, Compression, ContentType, ProtocolVersion,
@@ -44,18 +42,14 @@ pub(super) type ClientContext<'a> = crate::conn::Context<'a, ClientConnectionDat
fn find_session(
server_name: &ServerName,
config: &ClientConfig,
#[cfg(feature = "quic")] cx: &mut ClientContext<'_>,
) -> Option<persist::Retrieved<persist::ClientSessionValue>> {
let key = persist::ClientSessionKey::session_for_server_name(server_name);
let key_buf = key.get_encoding();
let value = config
.session_storage
.get(&key_buf)
.or_else(|| {
debug!("No cached session for {:?}", server_name);
None
})?;
let value = config.session_storage.get(&key_buf).or_else(|| {
debug!("No cached session for {:?}", server_name);
None
})?;
#[allow(unused_mut)]
let mut reader = Reader::init(&value[2..]);
@@ -71,14 +65,7 @@ fn find_session(
true => None,
}
})
.and_then(|resuming| {
#[cfg(feature = "quic")]
if cx.common.is_quic() {
let params = PayloadU16::read(&mut reader)?;
cx.common.quic.params = Some(params.0);
}
Some(resuming)
})
.and_then(|resuming| Some(resuming))
}
pub(super) fn start_handshake(
@@ -88,22 +75,14 @@ pub(super) fn start_handshake(
cx: &mut ClientContext<'_>,
) -> NextStateOrError {
let mut transcript_buffer = HandshakeHashBuffer::new();
if config
.client_auth_cert_resolver
.has_certs()
{
if config.client_auth_cert_resolver.has_certs() {
transcript_buffer.set_client_auth_enabled();
}
let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3);
let mut session_id: Option<SessionID> = None;
let mut resuming_session = find_session(
&server_name,
&config,
#[cfg(feature = "quic")]
cx,
);
let mut resuming_session = find_session(&server_name, &config);
let key_share = if support_tls13 {
Some(tls13::initial_key_share(&config, &server_name)?)
@@ -129,8 +108,7 @@ pub(super) fn start_handshake(
}
// https://tools.ietf.org/html/rfc8446#appendix-D.4
// https://tools.ietf.org/html/draft-ietf-quic-tls-34#section-8.4
if session_id.is_none() && !cx.common.is_quic() {
if session_id.is_none() {
session_id = Some(SessionID::random()?);
}
@@ -209,7 +187,7 @@ fn emit_client_hello_for_retry(
(Vec::new(), ProtocolVersion::Unknown(0))
};
let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2) && !cx.common.is_quic();
let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2);
let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3);
let mut supported_versions = Vec::new();
@@ -227,18 +205,8 @@ fn emit_client_hello_for_retry(
let mut exts = vec![
ClientExtension::SupportedVersions(supported_versions),
ClientExtension::ECPointFormats(ECPointFormatList::supported()),
ClientExtension::NamedGroups(
config
.kx_groups
.iter()
.map(|skxg| skxg.name)
.collect(),
),
ClientExtension::SignatureAlgorithms(
config
.verifier
.supported_verify_schemes(),
),
ClientExtension::NamedGroups(config.kx_groups.iter().map(|skxg| skxg.name).collect()),
ClientExtension::SignatureAlgorithms(config.verifier.supported_verify_schemes()),
ClientExtension::ExtendedMasterSecretRequest,
ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
];
@@ -290,9 +258,7 @@ fn emit_client_hello_for_retry(
.as_ref()
.and_then(|resuming| match (suite, resuming.tls13()) {
(Some(suite), Some(resuming)) => {
suite
.tls13()?
.can_resume_from(resuming.suite())?;
suite.tls13()?.can_resume_from(resuming.suite())?;
Some(resuming)
}
(None, Some(resuming)) => Some(resuming),
@@ -324,17 +290,10 @@ fn emit_client_hello_for_retry(
};
// Note what extensions we sent.
hello.sent_extensions = exts
.iter()
.map(ClientExtension::get_type)
.collect();
hello.sent_extensions = exts.iter().map(ClientExtension::get_type).collect();
let session_id = session_id.unwrap_or_else(SessionID::empty);
let mut cipher_suites: Vec<_> = config
.cipher_suites
.iter()
.map(|cs| cs.suite())
.collect();
let mut cipher_suites: Vec<_> = config.cipher_suites.iter().map(|cs| cs.suite()).collect();
// We don't do renegotiation at all, in fact.
cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
@@ -428,34 +387,14 @@ pub(super) fn process_alpn_protocol(
common.alpn_protocol = proto.map(ToOwned::to_owned);
if let Some(alpn_protocol) = &common.alpn_protocol {
if !config
.alpn_protocols
.contains(alpn_protocol)
{
if !config.alpn_protocols.contains(alpn_protocol) {
return Err(common.illegal_param("server sent non-offered ALPN protocol"));
}
}
#[cfg(feature = "quic")]
{
// RFC 9001 says: "While ALPN only specifies that servers use this alert, QUIC clients MUST
// use error 0x0178 to terminate a connection when ALPN negotiation fails." We judge that
// the user intended to use ALPN (rather than some out-of-band protocol negotiation
// mechanism) iff any ALPN protocols were configured. This defends against badly-behaved
// servers which accept a connection that requires an application-layer protocol they do not
// understand.
if common.is_quic() && common.alpn_protocol.is_none() && !config.alpn_protocols.is_empty() {
common.send_fatal_alert(AlertDescription::NoApplicationProtocol);
return Err(Error::NoApplicationProtocol);
}
}
debug!(
"ALPN protocol is {:?}",
common
.alpn_protocol
.as_ref()
.map(|v| bs_debug::BsDebug(v))
common.alpn_protocol.as_ref().map(|v| bs_debug::BsDebug(v))
);
Ok(())
}
@@ -492,10 +431,7 @@ impl State<ClientConnectionData> for ExpectServerHello {
));
}
if server_hello
.get_supported_versions()
.is_some()
{
if server_hello.get_supported_versions().is_some() {
return Err(cx
.common
.illegal_param("server chose v1.2 using v1.3 extension"));
@@ -515,14 +451,11 @@ impl State<ClientConnectionData> for ExpectServerHello {
};
if server_hello.compression_method != Compression::Null {
return Err(cx
.common
.illegal_param("server chose non-Null compression"));
return Err(cx.common.illegal_param("server chose non-Null compression"));
}
if server_hello.has_duplicate_extension() {
cx.common
.send_fatal_alert(AlertDescription::DecodeError);
cx.common.send_fatal_alert(AlertDescription::DecodeError);
return Err(Error::PeerMisbehavedError(
"server sent duplicate extensions".to_string(),
));
@@ -588,9 +521,7 @@ impl State<ClientConnectionData> for ExpectServerHello {
}
// Start our handshake hash, and input the server-hello.
let mut transcript = self
.transcript_buffer
.start_hash(suite.hash_algorithm());
let mut transcript = self.transcript_buffer.start_hash(suite.hash_algorithm());
transcript.add_message(&m);
let randoms = ConnectionRandoms::new(self.random, server_hello.random);
@@ -598,13 +529,13 @@ impl State<ClientConnectionData> for ExpectServerHello {
// handshake_traffic_secret.
match suite {
SupportedCipherSuite::Tls13(suite) => {
let resuming_session = self
.resuming_session
.and_then(|resuming| match resuming.value {
persist::ClientSessionValue::Tls13(inner) => Some(inner),
#[cfg(feature = "tls12")]
persist::ClientSessionValue::Tls12(_) => None,
});
let resuming_session =
self.resuming_session
.and_then(|resuming| match resuming.value {
persist::ClientSessionValue::Tls13(inner) => Some(inner),
#[cfg(feature = "tls12")]
persist::ClientSessionValue::Tls12(_) => None,
});
tls13::handle_server_hello(
self.config,
@@ -624,12 +555,12 @@ impl State<ClientConnectionData> for ExpectServerHello {
}
#[cfg(feature = "tls12")]
SupportedCipherSuite::Tls12(suite) => {
let resuming_session = self
.resuming_session
.and_then(|resuming| match resuming.value {
persist::ClientSessionValue::Tls12(inner) => Some(inner),
persist::ClientSessionValue::Tls13(_) => None,
});
let resuming_session =
self.resuming_session
.and_then(|resuming| match resuming.value {
persist::ClientSessionValue::Tls12(inner) => Some(inner),
persist::ClientSessionValue::Tls13(_) => None,
});
tls12::CompleteServerHelloHandling {
config: self.config,
@@ -723,10 +654,7 @@ impl ExpectServerHelloOrHelloRetryRequest {
}
// Or asks us to use a ciphersuite we didn't offer.
let maybe_cs = self
.next
.config
.find_cipher_suite(hrr.cipher_suite);
let maybe_cs = self.next.config.find_cipher_suite(hrr.cipher_suite);
let cs = match maybe_cs {
Some(cs) => cs,
None => {
@@ -740,10 +668,7 @@ impl ExpectServerHelloOrHelloRetryRequest {
cx.common.suite = Some(cs);
// This is the draft19 change where the transcript became a tree
let transcript = self
.next
.transcript_buffer
.start_hash(cs.hash_algorithm());
let transcript = self.next.transcript_buffer.start_hash(cs.hash_algorithm());
let mut transcript_buffer = transcript.into_hrr_buffer();
transcript_buffer.add_message(&m);
@@ -752,10 +677,7 @@ impl ExpectServerHelloOrHelloRetryRequest {
cx.data.early_data.rejected();
}
let may_send_sct_list = self
.next
.hello
.server_may_send_sct_list();
let may_send_sct_list = self.next.hello.server_may_send_sct_list();
let key_share = match req_group {
Some(group) if group != offered_key_share.group() => {
@@ -795,9 +717,7 @@ impl State<ClientConnectionData> for ExpectServerHelloOrHelloRetryRequest {
MessagePayload::Handshake(HandshakeMessagePayload {
payload: HandshakePayload::ServerHello(..),
..
}) => self
.into_expect_server_hello()
.handle(cx, m),
}) => self.into_expect_server_hello().handle(cx, m),
MessagePayload::Handshake(HandshakeMessagePayload {
payload: HandshakePayload::HelloRetryRequest(..),
..

View File

@@ -26,8 +26,6 @@ use crate::tls13::key_schedule::{
};
use crate::tls13::Tls13CipherSuite;
use crate::verify;
#[cfg(feature = "quic")]
use crate::{conn::Protocol, msgs::base::PayloadU16, quic};
use crate::{sign, KeyLog};
use super::client_conn::ClientConnectionData;
@@ -74,18 +72,14 @@ pub(super) fn handle_server_hello(
) -> hs::NextStateOrError {
validate_server_hello(cx.common, server_hello)?;
let their_key_share = server_hello
.get_key_share()
.ok_or_else(|| {
cx.common
.send_fatal_alert(AlertDescription::MissingExtension);
Error::PeerMisbehavedError("missing key share".to_string())
})?;
let their_key_share = server_hello.get_key_share().ok_or_else(|| {
cx.common
.send_fatal_alert(AlertDescription::MissingExtension);
Error::PeerMisbehavedError("missing key share".to_string())
})?;
if our_key_share.group() != their_key_share.group {
return Err(cx
.common
.illegal_param("wrong group for key share"));
return Err(cx.common.illegal_param("wrong group for key share"));
}
let key_schedule_pre_handshake = if let (Some(selected_psk), Some(early_key_schedule)) =
@@ -110,9 +104,7 @@ pub(super) fn handle_server_hello(
}
if selected_psk != 0 {
return Err(cx
.common
.illegal_param("server selected invalid psk"));
return Err(cx.common.illegal_param("server selected invalid psk"));
}
debug!("Resuming using PSK");
@@ -163,11 +155,6 @@ pub(super) fn handle_server_hello(
.set_message_encrypter(suite.derive_encrypter(&client_key));
}
#[cfg(feature = "quic")]
if cx.common.is_quic() {
cx.common.quic.hs_secrets = Some(quic::Secrets::new(client_key, server_key, suite, true));
}
emit_fake_ccs(&mut sent_tls13_fake_ccs, cx.common);
Ok(Box::new(ExpectEncryptedExtensions {
@@ -210,12 +197,7 @@ pub(super) fn initial_key_share(
let group = maybe_value
.and_then(|enc| NamedGroup::read_bytes(&enc))
.and_then(|group| kx::KeyExchange::choose(group, &config.kx_groups))
.unwrap_or_else(|| {
config
.kx_groups
.first()
.expect("No kx groups configured")
});
.unwrap_or_else(|| config.kx_groups.first().expect("No kx groups configured"));
kx::KeyExchange::start(group).ok_or(Error::FailedToGetRandomBytes)
}
@@ -271,9 +253,7 @@ pub(super) fn prepare_resumption(
// PreSharedKey extension.
let max_early_data_size = resuming_session.max_early_data_size();
if config.enable_early_data && max_early_data_size > 0 && !doing_retry {
cx.data
.early_data
.enable(max_early_data_size as usize);
cx.data.early_data.enable(max_early_data_size as usize);
exts.push(ClientExtension::EarlyData);
}
@@ -284,9 +264,7 @@ pub(super) fn prepare_resumption(
// the message it's contained in (!!!).
let obfuscated_ticket_age = resuming_session.obfuscated_ticket_age();
let binder_len = resuming_suite
.hash_algorithm()
.output_len;
let binder_len = resuming_suite.hash_algorithm().output_len;
let binder = vec![0u8; binder_len];
let psk_identity = PresharedKeyIdentity::new(ticket, obfuscated_ticket_age);
@@ -314,21 +292,12 @@ pub(super) fn derive_early_traffic_secret(
.record_layer
.set_message_encrypter(resuming_suite.derive_encrypter(&client_early_traffic_secret));
#[cfg(feature = "quic")]
if cx.common.is_quic() {
cx.common.quic.early_secret = Some(client_early_traffic_secret);
}
// Now the client can send encrypted early data
cx.common.early_traffic = true;
trace!("Starting early data traffic");
}
pub(super) fn emit_fake_ccs(sent_tls13_fake_ccs: &mut bool, common: &mut CommonState) {
if common.is_quic() {
return;
}
if std::mem::replace(sent_tls13_fake_ccs, true) {
return;
}
@@ -395,21 +364,6 @@ impl State<ClientConnectionData> for ExpectEncryptedExtensions {
validate_encrypted_extensions(cx.common, &self.hello, exts)?;
hs::process_alpn_protocol(cx.common, &self.config, exts.get_alpn_protocol())?;
#[cfg(feature = "quic")]
{
// QUIC transport parameters
if cx.common.is_quic() {
match exts.get_quic_params_extension() {
Some(params) => cx.common.quic.params = Some(params),
None => {
return Err(cx
.common
.missing_extension("QUIC transport parameters not found"));
}
}
}
}
if let Some(resuming_session) = self.resuming_session {
let was_early_traffic = cx.common.early_traffic;
if was_early_traffic {
@@ -423,19 +377,12 @@ impl State<ClientConnectionData> for ExpectEncryptedExtensions {
if was_early_traffic && !cx.common.early_traffic {
// If no early traffic, set the encryption key for handshakes
cx.common
.record_layer
.set_message_encrypter(
self.suite
.derive_encrypter(self.key_schedule.client_key()),
);
cx.common.record_layer.set_message_encrypter(
self.suite.derive_encrypter(self.key_schedule.client_key()),
);
}
cx.common.peer_certificates = Some(
resuming_session
.server_cert_chain()
.to_vec(),
);
cx.common.peer_certificates = Some(resuming_session.server_cert_chain().to_vec());
// We *don't* reverify the certificate chain here: resumption is a
// continuation of the previous session in terms of security policy.
@@ -551,8 +498,7 @@ impl State<ClientConnectionData> for ExpectCertificateRequest {
// Must be empty during handshake.
if !certreq.context.0.is_empty() {
warn!("Server sent non-empty certreq context");
cx.common
.send_fatal_alert(AlertDescription::DecodeError);
cx.common.send_fatal_alert(AlertDescription::DecodeError);
return Err(Error::CorruptMessagePayload(ContentType::Handshake));
}
@@ -575,9 +521,7 @@ impl State<ClientConnectionData> for ExpectCertificateRequest {
}
let client_auth = ClientAuthDetails::resolve(
self.config
.client_auth_cert_resolver
.as_ref(),
self.config.client_auth_cert_resolver.as_ref(),
certreq.get_authorities_extension(),
&compat_sigschemes,
Some(certreq.context.0.clone()),
@@ -619,8 +563,7 @@ impl State<ClientConnectionData> for ExpectCertificate {
// This is only non-empty for client auth.
if !cert_chain.context.0.is_empty() {
warn!("certificate with non-empty context during handshake");
cx.common
.send_fatal_alert(AlertDescription::DecodeError);
cx.common.send_fatal_alert(AlertDescription::DecodeError);
return Err(Error::CorruptMessagePayload(ContentType::Handshake));
}
@@ -813,10 +756,6 @@ fn emit_finished_tls13(
}
fn emit_end_of_early_data_tls13(transcript: &mut HandshakeHash, common: &mut CommonState) {
if common.is_quic() {
return;
}
let m = Message {
version: ProtocolVersion::TLSv1_3,
payload: MessagePayload::Handshake(HandshakeMessagePayload {
@@ -848,14 +787,11 @@ impl State<ClientConnectionData> for ExpectFinished {
require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?;
let handshake_hash = st.transcript.get_current_hash();
let expect_verify_data = st
.key_schedule
.sign_server_finish(&handshake_hash);
let expect_verify_data = st.key_schedule.sign_server_finish(&handshake_hash);
let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0)
.map_err(|_| {
cx.common
.send_fatal_alert(AlertDescription::DecryptError);
cx.common.send_fatal_alert(AlertDescription::DecryptError);
Error::DecryptError
})
.map(|_| verify::FinishedMessageVerified::assertion())?;
@@ -871,10 +807,7 @@ impl State<ClientConnectionData> for ExpectFinished {
cx.data.early_data.finished();
cx.common
.record_layer
.set_message_encrypter(
st.suite
.derive_encrypter(st.key_schedule.client_key()),
);
.set_message_encrypter(st.suite.derive_encrypter(st.key_schedule.client_key()));
}
/* Send our authentication/finished messages. These are still encrypted
@@ -902,9 +835,8 @@ impl State<ClientConnectionData> for ExpectFinished {
}
}
let (key_schedule_finished, client_key, server_key) = st
.key_schedule
.into_traffic_with_client_finished_pending(
let (key_schedule_finished, client_key, server_key) =
st.key_schedule.into_traffic_with_client_finished_pending(
hash_after_handshake,
&*st.config.key_log,
&st.randoms.client,
@@ -939,15 +871,6 @@ impl State<ClientConnectionData> for ExpectFinished {
_fin_verified: fin,
};
#[cfg(feature = "quic")]
{
if cx.common.protocol == Protocol::Quic {
cx.common.quic.traffic_secrets =
Some(quic::Secrets::new(client_key, server_key, st.suite, true));
return Ok(Box::new(ExpectQuicTraffic(st)));
}
}
Ok(Box::new(st))
}
}
@@ -968,7 +891,7 @@ struct ExpectTraffic {
}
impl ExpectTraffic {
#[allow(clippy::unnecessary_wraps)] // returns Err for #[cfg(feature = "quic")]
#[allow(clippy::unnecessary_wraps)]
fn handle_new_ticket_tls13(
&mut self,
cx: &mut ClientContext<'_>,
@@ -1000,40 +923,18 @@ impl ExpectTraffic {
self.suite,
nst.ticket.0.clone(),
secret,
cx.common
.peer_certificates
.clone()
.unwrap_or_default(),
cx.common.peer_certificates.clone().unwrap_or_default(),
time_now,
nst.lifetime,
nst.age_add,
nst.get_max_early_data_size()
.unwrap_or_default(),
nst.get_max_early_data_size().unwrap_or_default(),
);
#[cfg(feature = "quic")]
if let Some(sz) = nst.get_max_early_data_size() {
if cx.common.protocol == Protocol::Quic && sz != 0 && sz != 0xffff_ffff {
return Err(Error::PeerMisbehavedError(
"invalid max_early_data_size".into(),
));
}
}
let key = persist::ClientSessionKey::session_for_server_name(&self.server_name);
#[allow(unused_mut)]
let mut ticket = value.get_encoding();
#[cfg(feature = "quic")]
if let (Protocol::Quic, Some(ref quic_params)) =
(cx.common.protocol, &cx.common.quic.params)
{
PayloadU16::encode_slice(quic_params, &mut ticket);
}
let worked = self
.session_storage
.put(key.get_encoding(), ticket);
let worked = self.session_storage.put(key.get_encoding(), ticket);
if worked {
debug!("Ticket saved");
@@ -1048,16 +949,6 @@ impl ExpectTraffic {
common: &mut CommonState,
kur: &KeyUpdateRequest,
) -> Result<(), Error> {
#[cfg(feature = "quic")]
{
if let Protocol::Quic = common.protocol {
common.send_fatal_alert(AlertDescription::UnexpectedMessage);
let msg = "KeyUpdate received in QUIC connection".to_string();
warn!("{}", msg);
return Err(Error::PeerMisbehavedError(msg));
}
}
// Mustn't be interleaved with other handshake messages.
common.check_aligned_handshake()?;
@@ -1073,15 +964,10 @@ impl ExpectTraffic {
}
// Update our read-side keys.
let new_read_key = self
.key_schedule
.next_server_application_traffic_secret();
let new_read_key = self.key_schedule.next_server_application_traffic_secret();
common
.record_layer
.set_message_decrypter(
self.suite
.derive_decrypter(&new_read_key),
);
.set_message_decrypter(self.suite.derive_decrypter(&new_read_key));
Ok(())
}
@@ -1090,9 +976,7 @@ impl ExpectTraffic {
impl State<ClientConnectionData> for ExpectTraffic {
fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError {
match m.payload {
MessagePayload::ApplicationData(payload) => cx
.common
.take_received_plaintext(payload),
MessagePayload::ApplicationData(payload) => cx.common.take_received_plaintext(payload),
MessagePayload::Handshake(HandshakeMessagePayload {
payload: HandshakePayload::NewSessionTicketTLS13(ref new_ticket),
..
@@ -1128,39 +1012,10 @@ impl State<ClientConnectionData> for ExpectTraffic {
self.want_write_key_update = false;
common.send_msg_encrypt(Message::build_key_update_notify().into());
let write_key = self
.key_schedule
.next_client_application_traffic_secret();
let write_key = self.key_schedule.next_client_application_traffic_secret();
common
.record_layer
.set_message_encrypter(self.suite.derive_encrypter(&write_key));
}
}
}
#[cfg(feature = "quic")]
struct ExpectQuicTraffic(ExpectTraffic);
#[cfg(feature = "quic")]
impl State<ClientConnectionData> for ExpectQuicTraffic {
fn handle(mut self: Box<Self>, cx: &mut ClientContext<'_>, m: Message) -> hs::NextStateOrError {
let nst = require_handshake_msg!(
m,
HandshakeType::NewSessionTicket,
HandshakePayload::NewSessionTicketTLS13
)?;
self.0
.handle_new_ticket_tls13(cx, nst)?;
Ok(self)
}
fn export_keying_material(
&self,
output: &mut [u8],
label: &[u8],
context: Option<&[u8]>,
) -> Result<(), Error> {
self.0
.export_keying_material(output, label, context)
}
}

View File

@@ -13,8 +13,6 @@ use crate::msgs::hsjoiner::HandshakeJoiner;
use crate::msgs::message::{
BorrowedPlainMessage, Message, MessagePayload, OpaqueMessage, PlainMessage,
};
#[cfg(feature = "quic")]
use crate::quic;
use crate::record_layer;
use crate::suites::SupportedCipherSuite;
#[cfg(feature = "tls12")]
@@ -94,44 +92,6 @@ impl Connection {
}
}
#[cfg(feature = "quic")]
impl crate::quic::QuicExt for Connection {
fn quic_transport_parameters(&self) -> Option<&[u8]> {
match self {
Connection::Client(conn) => conn.quic_transport_parameters(),
Connection::Server(conn) => conn.quic_transport_parameters(),
}
}
fn zero_rtt_keys(&self) -> Option<quic::DirectionalKeys> {
match self {
Connection::Client(conn) => conn.zero_rtt_keys(),
Connection::Server(conn) => conn.zero_rtt_keys(),
}
}
fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
match self {
Connection::Client(conn) => conn.read_quic_hs(plaintext),
Connection::Server(conn) => conn.read_quic_hs(plaintext),
}
}
fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<quic::KeyChange> {
match self {
Connection::Client(conn) => quic::write_hs(conn, buf),
Connection::Server(conn) => quic::write_hs(conn, buf),
}
}
fn alert(&self) -> Option<AlertDescription> {
match self {
Connection::Client(conn) => conn.alert(),
Connection::Server(conn) => conn.alert(),
}
}
}
impl Deref for Connection {
type Target = CommonState;
@@ -344,8 +304,6 @@ impl<'a> io::Write for Writer<'a> {
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) enum Protocol {
Tcp,
#[cfg(feature = "quic")]
Quic,
}
#[derive(Debug)]
@@ -712,33 +670,6 @@ impl<Data> ConnectionCommon<Data> {
}
}
#[cfg(feature = "quic")]
impl<Data> ConnectionCommon<Data> {
pub(crate) fn read_quic_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
let state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) {
Ok(state) => state,
Err(e) => {
self.state = Err(e.clone());
return Err(e);
}
};
let msg = PlainMessage {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_3,
payload: Payload::new(plaintext.to_vec()),
};
if self.handshake_joiner.take_message(msg).is_none() {
self.common_state.quic.alert = Some(AlertDescription::DecodeError);
return Err(Error::CorruptMessage);
}
self.process_new_handshake_messages(state)
.map(|state| self.state = Ok(state))
}
}
impl<T> Deref for ConnectionCommon<T> {
type Target = CommonState;
@@ -774,11 +705,9 @@ pub struct CommonState {
received_plaintext: ChunkVecBuffer,
sendable_plaintext: ChunkVecBuffer,
pub(crate) sendable_tls: ChunkVecBuffer,
#[allow(dead_code)] // only read for QUIC
#[allow(dead_code)]
/// Protocol whose key schedule should be used. Unused for TLS < 1.3.
pub(crate) protocol: Protocol,
#[cfg(feature = "quic")]
pub(crate) quic: Quic,
}
impl CommonState {
@@ -805,8 +734,6 @@ impl CommonState {
sendable_tls: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)),
protocol: Protocol::Tcp,
#[cfg(feature = "quic")]
quic: Quic::new(),
})
}
@@ -1139,23 +1066,6 @@ impl CommonState {
/// Send a raw TLS message, fragmenting it if needed.
pub(crate) 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);
@@ -1178,12 +1088,6 @@ impl CommonState {
self.record_layer.prepare_message_decrypter(dec);
}
#[cfg(feature = "quic")]
pub(crate) fn missing_extension(&mut self, why: &str) -> Error {
self.send_fatal_alert(AlertDescription::MissingExtension);
Error::PeerMisbehavedError(why.to_string())
}
fn send_warning_alert(&mut self, desc: AlertDescription) {
warn!("Sending warning alert {:?}", desc);
self.send_warning_alert_no_log(desc);
@@ -1271,15 +1175,6 @@ impl CommonState {
peer_has_closed: self.has_received_close_notify,
}
}
pub(crate) fn is_quic(&self) -> bool {
#[cfg(feature = "quic")]
{
self.protocol == Protocol::Quic
}
#[cfg(not(feature = "quic"))]
false
}
}
pub(crate) trait State<Data>: Send + Sync {
@@ -1306,34 +1201,6 @@ pub(crate) struct Context<'a, Data> {
pub(crate) data: &'a mut Data,
}
#[cfg(feature = "quic")]
pub(crate) struct Quic {
/// QUIC transport parameters received from the peer during the handshake
pub(crate) params: Option<Vec<u8>>,
pub(crate) alert: Option<AlertDescription>,
pub(crate) hs_queue: VecDeque<(bool, Vec<u8>)>,
pub(crate) early_secret: Option<ring::hkdf::Prk>,
pub(crate) hs_secrets: Option<quic::Secrets>,
pub(crate) traffic_secrets: Option<quic::Secrets>,
/// Whether keys derived from traffic_secrets have been passed to the QUIC implementation
pub(crate) returned_traffic_keys: bool,
}
#[cfg(feature = "quic")]
impl Quic {
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,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum Side {
Client,

View File

@@ -241,11 +241,6 @@
//! such as replacing the certificate verification process. Applications
//! requesting this feature should be reviewed carefully.
//!
//! - `quic`: this feature exposes additional constructors and functions
//! for using rustls as a TLS library for QUIC. See the `quic` module for
//! details of these. You will only need this if you're writing a QUIC
//! implementation.
//!
//! - `tls12`: enables support for TLS version 1.2. This feature is in the default
//! set. Note that, due to the additive nature of Cargo features and because it
//! is enabled by default, other crates in your dependency graph could re-enable
@@ -396,9 +391,6 @@ pub mod client {
mod tls13;
pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert};
#[cfg(feature = "quic")]
#[cfg_attr(docsrs, doc(cfg(feature = "quic")))]
pub use client_conn::ClientQuicExt;
pub use client_conn::InvalidDnsNameError;
pub use client_conn::ResolvesClientCert;
pub use client_conn::ServerName;
@@ -462,11 +454,6 @@ pub mod kx_group {
/// Message signing interfaces and implementations.
pub mod sign;
#[cfg(feature = "quic")]
#[cfg_attr(docsrs, doc(cfg(feature = "quic")))]
/// APIs for implementing QUIC TLS
pub mod quic;
/// This is the rustls manual.
pub mod manual;

View File

@@ -334,9 +334,7 @@ impl ConvertServerNameList for ServerNameRequest {
}
}
self.iter()
.filter_map(only_dns_hostnames)
.next()
self.iter().filter_map(only_dns_hostnames).next()
}
}
@@ -908,9 +906,7 @@ impl ClientHelloPayload {
}
pub fn find_extension(&self, ext: ExtensionType) -> Option<&ClientExtension> {
self.extensions
.iter()
.find(|x| x.get_type() == ext)
self.extensions.iter().find(|x| x.get_type() == ext)
}
pub fn get_sni_extension(&self) -> Option<&ServerNameRequest> {
@@ -953,17 +949,6 @@ impl ClientHelloPayload {
}
}
pub fn get_quic_params_extension(&self) -> Option<Vec<u8>> {
let ext = self
.find_extension(ExtensionType::TransportParameters)
.or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?;
match *ext {
ClientExtension::TransportParameters(ref bytes)
| ClientExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()),
_ => None,
}
}
pub fn get_ticket_extension(&self) -> Option<&ClientExtension> {
self.find_extension(ExtensionType::SessionTicket)
}
@@ -1041,8 +1026,7 @@ impl ClientHelloPayload {
}
pub fn early_data_extension_offered(&self) -> bool {
self.find_extension(ExtensionType::EarlyData)
.is_some()
self.find_extension(ExtensionType::EarlyData).is_some()
}
}
@@ -1166,9 +1150,7 @@ impl HelloRetryRequest {
}
fn find_extension(&self, ext: ExtensionType) -> Option<&HelloRetryExtension> {
self.extensions
.iter()
.find(|x| x.get_type() == ext)
self.extensions.iter().find(|x| x.get_type() == ext)
}
pub fn get_requested_key_share_group(&self) -> Option<NamedGroup> {
@@ -1740,9 +1722,7 @@ pub trait HasServerExtensions {
}
fn find_extension(&self, ext: ExtensionType) -> Option<&ServerExtension> {
self.get_extensions()
.iter()
.find(|x| x.get_type() == ext)
self.get_extensions().iter().find(|x| x.get_type() == ext)
}
fn get_alpn_protocol(&self) -> Option<&[u8]> {
@@ -1753,20 +1733,8 @@ pub trait HasServerExtensions {
}
}
fn get_quic_params_extension(&self) -> Option<Vec<u8>> {
let ext = self
.find_extension(ExtensionType::TransportParameters)
.or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?;
match *ext {
ServerExtension::TransportParameters(ref bytes)
| ServerExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()),
_ => None,
}
}
fn early_data_extension_offered(&self) -> bool {
self.find_extension(ExtensionType::EarlyData)
.is_some()
self.find_extension(ExtensionType::EarlyData).is_some()
}
}
@@ -1900,9 +1868,7 @@ impl Codec for CertificateRequestPayloadTLS13 {
impl CertificateRequestPayloadTLS13 {
pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> {
self.extensions
.iter()
.find(|x| x.get_type() == ext)
self.extensions.iter().find(|x| x.get_type() == ext)
}
pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> {
@@ -2041,9 +2007,7 @@ impl NewSessionTicketPayloadTLS13 {
}
pub fn find_extension(&self, ext: ExtensionType) -> Option<&NewSessionTicketExtension> {
self.exts
.iter()
.find(|x| x.get_type() == ext)
self.exts.iter().find(|x| x.get_type() == ext)
}
pub fn get_max_early_data_size(&self) -> Option<u32> {
@@ -2313,9 +2277,7 @@ impl HandshakeMessagePayload {
HandshakePayload::ClientHello(ref ch) => match ch.extensions.last() {
Some(ClientExtension::PresharedKey(ref offer)) => {
let mut binders_encoding = Vec::new();
offer
.binders
.encode(&mut binders_encoding);
offer.binders.encode(&mut binders_encoding);
binders_encoding.len()
}
_ => 0,

View File

@@ -184,10 +184,7 @@ fn can_roundtrip_multiname_sni() {
assert!(req.has_duplicate_names_for_type());
let dns_name_str: &str = req
.get_single_hostname()
.unwrap()
.into();
let dns_name_str: &str = req.get_single_hostname().unwrap().into();
assert_eq!(dns_name_str, "hi");
assert_eq!(req[0].typ, ServerNameType::HostName);
@@ -516,8 +513,7 @@ fn client_get_sigalgs_extension() {
#[test]
fn client_get_namedgroups_extension() {
test_client_extension_getter(ExtensionType::EllipticCurves, |chp| {
chp.get_namedgroups_extension()
.is_some()
chp.get_namedgroups_extension().is_some()
});
}
@@ -535,14 +531,6 @@ fn client_get_alpn_extension() {
});
}
#[test]
fn client_get_quic_params_extension() {
test_client_extension_getter(ExtensionType::TransportParameters, |chp| {
chp.get_quic_params_extension()
.is_some()
});
}
#[test]
fn client_get_versions_extension() {
test_client_extension_getter(ExtensionType::SupportedVersions, |chp| {
@@ -618,8 +606,7 @@ fn test_helloretry_extension_getter(typ: ExtensionType, getter: fn(&HelloRetryRe
#[test]
fn helloretry_get_requested_key_share_group() {
test_helloretry_extension_getter(ExtensionType::KeyShare, |hrr| {
hrr.get_requested_key_share_group()
.is_some()
hrr.get_requested_key_share_group().is_some()
});
}
@@ -716,9 +703,7 @@ fn server_get_supported_versions() {
}
fn test_cert_extension_getter(typ: ExtensionType, getter: fn(&CertificateEntry) -> bool) {
let mut ce = get_sample_certificatepayloadtls13()
.entries
.remove(0);
let mut ce = get_sample_certificatepayloadtls13().entries.remove(0);
let mut exts = std::mem::take(&mut ce.exts);
exts.retain(|ext| ext.get_type() == typ);

View File

@@ -1,619 +0,0 @@
/// This module contains optional APIs for implementing QUIC TLS.
use crate::cipher::{Iv, IvLen};
pub use crate::client::ClientQuicExt;
use crate::conn::CommonState;
use crate::error::Error;
use crate::msgs::enums::AlertDescription;
pub use crate::server::ServerQuicExt;
use crate::suites::BulkAlgorithm;
use crate::tls13::key_schedule::hkdf_expand;
use crate::tls13::{Tls13CipherSuite, TLS13_AES_128_GCM_SHA256_INTERNAL};
use ring::{aead, hkdf};
/// Secrets used to encrypt/decrypt traffic
#[derive(Clone, Debug)]
pub struct Secrets {
/// Secret used to encrypt packets transmitted by the client
client: hkdf::Prk,
/// Secret used to encrypt packets transmitted by the server
server: hkdf::Prk,
/// Cipher suite used with these secrets
suite: &'static Tls13CipherSuite,
is_client: bool,
}
impl Secrets {
pub(crate) fn new(
client: hkdf::Prk,
server: hkdf::Prk,
suite: &'static Tls13CipherSuite,
is_client: bool,
) -> Self {
Self {
client,
server,
suite,
is_client,
}
}
/// Derive the next set of packet keys
pub fn next_packet_keys(&mut self) -> PacketKeySet {
let keys = PacketKeySet::new(self);
self.update();
keys
}
fn update(&mut self) {
let hkdf_alg = self.suite.hkdf_algorithm;
self.client = hkdf_expand(&self.client, hkdf_alg, b"quic ku", &[]);
self.server = hkdf_expand(&self.server, hkdf_alg, b"quic ku", &[]);
}
fn local_remote(&self) -> (&hkdf::Prk, &hkdf::Prk) {
if self.is_client {
(&self.client, &self.server)
} else {
(&self.server, &self.client)
}
}
}
/// Generic methods for QUIC sessions
pub trait QuicExt {
/// Return the TLS-encoded transport parameters for the session's peer.
///
/// While the transport parameters are technically available prior to the
/// completion of the handshake, they cannot be fully trusted until the
/// handshake completes, and reliance on them should be minimized.
/// However, any tampering with the parameters will cause the handshake
/// to fail.
fn quic_transport_parameters(&self) -> Option<&[u8]>;
/// Compute the keys for encrypting/decrypting 0-RTT packets, if available
fn zero_rtt_keys(&self) -> Option<DirectionalKeys>;
/// Consume unencrypted TLS handshake data.
///
/// Handshake data obtained from separate encryption levels should be supplied in separate calls.
fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error>;
/// Emit unencrypted TLS handshake data.
///
/// When this returns `Some(_)`, the new keys must be used for future handshake data.
fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange>;
/// Emit the TLS description code of a fatal alert, if one has arisen.
///
/// Check after `read_hs` returns `Err(_)`.
fn alert(&self) -> Option<AlertDescription>;
}
/// Keys used to communicate in a single direction
pub struct DirectionalKeys {
/// Encrypts or decrypts a packet's headers
pub header: HeaderProtectionKey,
/// Encrypts or decrypts the payload of a packet
pub packet: PacketKey,
}
impl DirectionalKeys {
pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self {
Self {
header: HeaderProtectionKey::new(suite, secret),
packet: PacketKey::new(suite, secret),
}
}
}
/// A QUIC header protection key
pub struct HeaderProtectionKey(aead::quic::HeaderProtectionKey);
impl HeaderProtectionKey {
fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self {
let alg = match suite.common.bulk {
BulkAlgorithm::Aes128Gcm => &aead::quic::AES_128,
BulkAlgorithm::Aes256Gcm => &aead::quic::AES_256,
BulkAlgorithm::Chacha20Poly1305 => &aead::quic::CHACHA20,
};
Self(hkdf_expand(secret, alg, b"quic hp", &[]))
}
/// Adds QUIC Header Protection.
///
/// `sample` must contain the sample of encrypted payload; see
/// [Header Protection Sample].
///
/// `first` must reference the first byte of the header, referred to as
/// `packet[0]` in [Header Protection Application].
///
/// `packet_number` must reference the Packet Number field; this is
/// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
///
/// Returns an error without modifying anything if `sample` is not
/// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
/// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]).
///
/// Otherwise, `first` and `packet_number` will have the header protection added.
///
/// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
/// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
/// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
#[inline]
pub fn encrypt_in_place(
&self,
sample: &[u8],
first: &mut u8,
packet_number: &mut [u8],
) -> Result<(), Error> {
self.xor_in_place(sample, first, packet_number, false)
}
/// Removes QUIC Header Protection.
///
/// `sample` must contain the sample of encrypted payload; see
/// [Header Protection Sample].
///
/// `first` must reference the first byte of the header, referred to as
/// `packet[0]` in [Header Protection Application].
///
/// `packet_number` must reference the Packet Number field; this is
/// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application].
///
/// Returns an error without modifying anything if `sample` is not
/// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]),
/// or `packet_number` is longer than allowed (see
/// [Packet Number Encoding and Decoding]).
///
/// Otherwise, `first` and `packet_number` will have the header protection removed.
///
/// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1
/// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2
/// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1
#[inline]
pub fn decrypt_in_place(
&self,
sample: &[u8],
first: &mut u8,
packet_number: &mut [u8],
) -> Result<(), Error> {
self.xor_in_place(sample, first, packet_number, true)
}
fn xor_in_place(
&self,
sample: &[u8],
first: &mut u8,
packet_number: &mut [u8],
masked: bool,
) -> Result<(), Error> {
// This implements [Header Protection Application] almost verbatim.
let mask = self
.0
.new_mask(sample)
.map_err(|_| Error::General("sample of invalid length".into()))?;
// The `unwrap()` will not panic because `new_mask` returns a
// non-empty result.
let (first_mask, pn_mask) = mask.split_first().unwrap();
// It is OK for the `mask` to be longer than `packet_number`,
// but a valid `packet_number` will never be longer than `mask`.
if packet_number.len() > pn_mask.len() {
return Err(Error::General("packet number too long".into()));
}
// Infallible from this point on. Before this point, `first` and
// `packet_number` are unchanged.
const LONG_HEADER_FORM: u8 = 0x80;
let bits = match *first & LONG_HEADER_FORM == LONG_HEADER_FORM {
true => 0x0f, // Long header: 4 bits masked
false => 0x1f, // Short header: 5 bits masked
};
let first_plain = match masked {
// When unmasking, use the packet length bits after unmasking
true => (*first ^ (first_mask & bits)),
// When masking, use the packet length bits before masking
false => *first,
};
let pn_len = (first_plain & 0x03) as usize + 1;
*first ^= first_mask & bits;
for (dst, m) in packet_number
.iter_mut()
.zip(pn_mask)
.take(pn_len)
{
*dst ^= m;
}
Ok(())
}
/// Expected sample length for the key's algorithm
#[inline]
pub fn sample_len(&self) -> usize {
self.0.algorithm().sample_len()
}
}
/// Keys to encrypt or decrypt the payload of a packet
pub struct PacketKey {
/// Encrypts or decrypts a packet's payload
key: aead::LessSafeKey,
/// Computes unique nonces for each packet
iv: Iv,
/// The cipher suite used for this packet key
suite: &'static Tls13CipherSuite,
}
impl PacketKey {
fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk) -> Self {
Self {
key: aead::LessSafeKey::new(hkdf_expand(
secret,
suite.common.aead_algorithm,
b"quic key",
&[],
)),
iv: hkdf_expand(secret, IvLen, b"quic iv", &[]),
suite,
}
}
/// Encrypt a QUIC packet
///
/// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as
/// the additional authenticated data; and the `payload`. The authentication tag is returned if
/// encryption succeeds.
///
/// Fails iff the payload is longer than allowed by the cipher suite's AEAD algorithm.
pub fn encrypt_in_place(
&self,
packet_number: u64,
header: &[u8],
payload: &mut [u8],
) -> Result<Tag, Error> {
let aad = aead::Aad::from(header);
let nonce = nonce_for(packet_number, &self.iv);
let tag = self
.key
.seal_in_place_separate_tag(nonce, aad, payload)
.map_err(|_| Error::EncryptError)?;
Ok(Tag(tag))
}
/// Decrypt a QUIC packet
///
/// Takes the packet `header`, which is used as the additional authenticated data, and the
/// `payload`, which includes the authentication tag.
///
/// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the
/// length found in the return value.
pub fn decrypt_in_place<'a>(
&self,
packet_number: u64,
header: &[u8],
payload: &'a mut [u8],
) -> Result<&'a [u8], Error> {
let payload_len = payload.len();
let aad = aead::Aad::from(header);
let nonce = nonce_for(packet_number, &self.iv);
self.key
.open_in_place(nonce, aad, payload)
.map_err(|_| Error::DecryptError)?;
let plain_len = payload_len - self.key.algorithm().tag_len();
Ok(&payload[..plain_len])
}
/// Number of times the packet key can be used without sacrificing confidentiality
///
/// See <https://www.rfc-editor.org/rfc/rfc9001.html#name-confidentiality-limit>.
#[inline]
pub fn confidentiality_limit(&self) -> u64 {
self.suite.confidentiality_limit
}
/// Number of times the packet key can be used without sacrificing integrity
///
/// See <https://www.rfc-editor.org/rfc/rfc9001.html#name-integrity-limit>.
#[inline]
pub fn integrity_limit(&self) -> u64 {
self.suite.integrity_limit
}
/// Tag length for the underlying AEAD algorithm
#[inline]
pub fn tag_len(&self) -> usize {
self.key.algorithm().tag_len()
}
}
/// AEAD tag, must be appended to encrypted cipher text
pub struct Tag(aead::Tag);
impl AsRef<[u8]> for Tag {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
/// Packet protection keys for bidirectional 1-RTT communication
pub struct PacketKeySet {
/// Encrypts outgoing packets
pub local: PacketKey,
/// Decrypts incoming packets
pub remote: PacketKey,
}
impl PacketKeySet {
fn new(secrets: &Secrets) -> Self {
let (local, remote) = secrets.local_remote();
Self {
local: PacketKey::new(secrets.suite, local),
remote: PacketKey::new(secrets.suite, remote),
}
}
}
/// Complete set of keys used to communicate with the peer
pub struct Keys {
/// Encrypts outgoing packets
pub local: DirectionalKeys,
/// Decrypts incoming packets
pub remote: DirectionalKeys,
}
impl Keys {
/// Construct keys for use with initial packets
pub fn initial(version: Version, client_dst_connection_id: &[u8], is_client: bool) -> Self {
const CLIENT_LABEL: &[u8] = b"client in";
const SERVER_LABEL: &[u8] = b"server in";
let salt = version.initial_salt();
let hs_secret = hkdf::Salt::new(hkdf::HKDF_SHA256, salt).extract(client_dst_connection_id);
let secrets = Secrets {
client: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, CLIENT_LABEL, &[]),
server: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, SERVER_LABEL, &[]),
suite: TLS13_AES_128_GCM_SHA256_INTERNAL,
is_client,
};
Self::new(&secrets)
}
fn new(secrets: &Secrets) -> Self {
let (local, remote) = secrets.local_remote();
Self {
local: DirectionalKeys::new(secrets.suite, local),
remote: DirectionalKeys::new(secrets.suite, remote),
}
}
}
pub(crate) fn write_hs(this: &mut CommonState, buf: &mut Vec<u8>) -> Option<KeyChange> {
while let Some((_, msg)) = this.quic.hs_queue.pop_front() {
buf.extend_from_slice(&msg);
if let Some(&(true, _)) = this.quic.hs_queue.front() {
if this.quic.hs_secrets.is_some() {
// Allow the caller to switch keys before proceeding.
break;
}
}
}
if let Some(secrets) = this.quic.hs_secrets.take() {
return Some(KeyChange::Handshake {
keys: Keys::new(&secrets),
});
}
if let Some(mut secrets) = this.quic.traffic_secrets.take() {
if !this.quic.returned_traffic_keys {
this.quic.returned_traffic_keys = true;
let keys = Keys::new(&secrets);
secrets.update();
return Some(KeyChange::OneRtt {
keys,
next: secrets,
});
}
}
None
}
/// Key material for use in QUIC packet spaces
///
/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections):
///
/// * Initial: these can be created from [`Keys::initial()`]
/// * 0-RTT keys: can be retrieved from [`QuicExt::zero_rtt_keys()`]
/// * Handshake: these are returned from [`QuicExt::write_hs()`] after `ClientHello` and
/// `ServerHello` messages have been exchanged
/// * 1-RTT keys: these are returned from [`QuicExt::write_hs()`] after the handshake is done
///
/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive
/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that
/// only packet keys are updated by key updates; header protection keys remain the same.
#[allow(clippy::large_enum_variant)]
pub enum KeyChange {
/// Keys for the handshake space
Handshake {
/// Header and packet keys for the handshake space
keys: Keys,
},
/// Keys for 1-RTT data
OneRtt {
/// Header and packet keys for 1-RTT data
keys: Keys,
/// Secrets to derive updated keys from
next: Secrets,
},
}
/// Compute the nonce to use for encrypting or decrypting `packet_number`
fn nonce_for(packet_number: u64, iv: &Iv) -> ring::aead::Nonce {
let mut out = [0; aead::NONCE_LEN];
out[4..].copy_from_slice(&packet_number.to_be_bytes());
for (out, inp) in out.iter_mut().zip(iv.0.iter()) {
*out ^= inp;
}
aead::Nonce::assume_unique_for_key(out)
}
/// QUIC protocol version
///
/// Governs version-specific behavior in the TLS layer
#[non_exhaustive]
#[derive(Clone, Copy)]
pub enum Version {
/// Draft versions 29, 30, 31 and 32
V1Draft,
/// First stable RFC
V1,
}
impl Version {
fn initial_salt(self) -> &'static [u8; 20] {
match self {
Version::V1Draft => &[
// https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61,
0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99,
],
Version::V1 => &[
// https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
],
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn short_packet_header_protection() {
// https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea
const PN: u64 = 654360564;
const SECRET: &[u8] = &[
0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad,
0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3,
0x0f, 0x21, 0x63, 0x2b,
];
let secret = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, SECRET);
use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL;
let hpk = HeaderProtectionKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret);
let packet = PacketKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret);
const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, 0x01];
let mut buf = PLAIN.to_vec();
let (header, payload) = buf.split_at_mut(4);
let tag = packet
.encrypt_in_place(PN, &*header, payload)
.unwrap();
buf.extend(tag.as_ref());
let pn_offset = 1;
let (header, sample) = buf.split_at_mut(pn_offset + 4);
let (first, rest) = header.split_at_mut(1);
let sample = &sample[..hpk.sample_len()];
hpk.encrypt_in_place(sample, &mut first[0], dbg!(rest))
.unwrap();
const PROTECTED: &[u8] = &[
0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57,
0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb,
];
assert_eq!(&buf, PROTECTED);
let (header, sample) = buf.split_at_mut(pn_offset + 4);
let (first, rest) = header.split_at_mut(1);
let sample = &sample[..hpk.sample_len()];
hpk.decrypt_in_place(sample, &mut first[0], rest)
.unwrap();
let (header, payload_tag) = buf.split_at_mut(4);
let plain = packet
.decrypt_in_place(PN, &*header, payload_tag)
.unwrap();
assert_eq!(plain, &PLAIN[4..]);
}
#[test]
fn key_update_test_vector() {
fn equal_prk(x: &hkdf::Prk, y: &hkdf::Prk) -> bool {
let mut x_data = [0; 16];
let mut y_data = [0; 16];
let x_okm = x
.expand(&[b"info"], &aead::quic::AES_128)
.unwrap();
x_okm.fill(&mut x_data[..]).unwrap();
let y_okm = y
.expand(&[b"info"], &aead::quic::AES_128)
.unwrap();
y_okm.fill(&mut y_data[..]).unwrap();
x_data == y_data
}
let mut secrets = Secrets {
// Constant dummy values for reproducibility
client: hkdf::Prk::new_less_safe(
hkdf::HKDF_SHA256,
&[
0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
],
),
server: hkdf::Prk::new_less_safe(
hkdf::HKDF_SHA256,
&[
0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
],
),
suite: TLS13_AES_128_GCM_SHA256_INTERNAL,
is_client: true,
};
secrets.update();
assert!(equal_prk(
&secrets.client,
&hkdf::Prk::new_less_safe(
hkdf::HKDF_SHA256,
&[
0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
]
)
));
assert!(equal_prk(
&secrets.server,
&hkdf::Prk::new_less_safe(
hkdf::HKDF_SHA256,
&[
0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
]
)
));
}
}

View File

@@ -91,10 +91,7 @@ impl ExtensionProcessing {
if let Some(their_protocols) = maybe_their_protocols {
let their_protocols = their_protocols.to_slices();
if their_protocols
.iter()
.any(|protocol| protocol.is_empty())
{
if their_protocols.iter().any(|protocol| protocol.is_empty()) {
return Err(Error::PeerMisbehavedError(
"client offered empty ALPN protocol".to_string(),
));
@@ -115,71 +112,31 @@ impl ExtensionProcessing {
}
}
#[cfg(feature = "quic")]
{
if cx.common.is_quic() {
// QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001
// says: "The server MUST treat the inability to select a compatible application
// protocol as a connection error of type 0x0178". We judge that ALPN was desired
// (rather than some out-of-band protocol negotiation mechanism) iff any ALPN
// protocols were configured locally or offered by the client. This helps prevent
// successful establishment of connections between peers that can't understand
// each other.
if cx.common.alpn_protocol.is_none()
&& (!our_protocols.is_empty() || maybe_their_protocols.is_some())
{
cx.common
.send_fatal_alert(AlertDescription::NoApplicationProtocol);
return Err(Error::NoApplicationProtocol);
}
match hello.get_quic_params_extension() {
Some(params) => cx.common.quic.params = Some(params),
None => {
return Err(cx
.common
.missing_extension("QUIC transport parameters not found"));
}
}
}
}
let for_resume = resumedata.is_some();
// SNI
if !for_resume && hello.get_sni_extension().is_some() {
self.exts
.push(ServerExtension::ServerNameAck);
self.exts.push(ServerExtension::ServerNameAck);
}
// Send status_request response if we have one. This is not allowed
// if we're resuming, and is only triggered if we have an OCSP response
// to send.
if !for_resume
&& hello
.find_extension(ExtensionType::StatusRequest)
.is_some()
{
if !for_resume && hello.find_extension(ExtensionType::StatusRequest).is_some() {
if ocsp_response.is_some() && !cx.common.is_tls13() {
// Only TLS1.2 sends confirmation in ServerHello
self.exts
.push(ServerExtension::CertificateStatusAck);
self.exts.push(ServerExtension::CertificateStatusAck);
}
} else {
// Throw away any OCSP response so we don't try to send it later.
ocsp_response.take();
}
if !for_resume
&& hello
.find_extension(ExtensionType::SCT)
.is_some()
{
if !for_resume && hello.find_extension(ExtensionType::SCT).is_some() {
if !cx.common.is_tls13() {
// Take the SCT list, if any, so we don't send it later,
// and put it in the legacy extension.
if let Some(sct_list) = sct_list.take() {
self.exts
.push(ServerExtension::make_sct(sct_list.to_vec()));
self.exts.push(ServerExtension::make_sct(sct_list.to_vec()));
}
}
} else {
@@ -216,20 +173,15 @@ impl ExtensionProcessing {
// Tickets:
// If we get any SessionTicket extension and have tickets enabled,
// we send an ack.
if hello
.find_extension(ExtensionType::SessionTicket)
.is_some()
&& config.ticketer.enabled()
if hello.find_extension(ExtensionType::SessionTicket).is_some() && config.ticketer.enabled()
{
self.send_ticket = true;
self.exts
.push(ServerExtension::SessionTicketAck);
self.exts.push(ServerExtension::SessionTicketAck);
}
// Confirm use of EMS if offered.
if using_ems {
self.exts
.push(ServerExtension::ExtendedMasterSecretAck);
self.exts.push(ServerExtension::ExtendedMasterSecretAck);
}
}
}
@@ -275,12 +227,8 @@ impl ExpectClientHello {
m: &Message,
cx: &mut ServerContext<'_>,
) -> NextStateOrError {
let tls13_enabled = self
.config
.supports_version(ProtocolVersion::TLSv1_3);
let tls12_enabled = self
.config
.supports_version(ProtocolVersion::TLSv1_2);
let tls13_enabled = self.config.supports_version(ProtocolVersion::TLSv1_3);
let tls12_enabled = self.config.supports_version(ProtocolVersion::TLSv1_2);
// Are we doing TLS1.3?
let maybe_versions_ext = client_hello.get_versions_extension();
@@ -289,11 +237,6 @@ impl ExpectClientHello {
ProtocolVersion::TLSv1_3
} else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled {
return Err(bad_version(cx.common, "TLS1.2 not offered/enabled"));
} else if cx.common.is_quic() {
return Err(bad_version(
cx.common,
"Expecting QUIC connection, but client does not support TLSv1_3",
));
} else {
ProtocolVersion::TLSv1_2
}
@@ -304,11 +247,6 @@ impl ExpectClientHello {
cx.common,
"Server requires TLS1.3, but client omitted versions ext",
));
} else if cx.common.is_quic() {
return Err(bad_version(
cx.common,
"Expecting QUIC connection, but client does not support TLSv1_3",
));
} else {
ProtocolVersion::TLSv1_2
};
@@ -323,14 +261,10 @@ impl ExpectClientHello {
client_hello.get_alpn_extension(),
);
let certkey = self
.config
.cert_resolver
.resolve(client_hello);
let certkey = self.config.cert_resolver.resolve(client_hello);
certkey.ok_or_else(|| {
cx.common
.send_fatal_alert(AlertDescription::AccessDenied);
cx.common.send_fatal_alert(AlertDescription::AccessDenied);
Error::General("no server certificate chain resolved".to_string())
})?
};
@@ -366,9 +300,7 @@ impl ExpectClientHello {
HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash),
HandshakeHashOrBuffer::Hash(inner) if inner.algorithm() == starting_hash => inner,
_ => {
return Err(cx
.common
.illegal_param("hash differed on retry"));
return Err(cx.common.illegal_param("hash differed on retry"));
}
};
@@ -499,11 +431,7 @@ pub(super) fn process_client_hello<'a>(
let client_suites = supported_cipher_suites
.iter()
.copied()
.filter(|scs| {
client_hello
.cipher_suites
.contains(&scs.suite())
})
.filter(|scs| client_hello.cipher_suites.contains(&scs.suite()))
.collect::<Vec<_>>();
let mut sig_schemes = client_hello

View File

@@ -19,8 +19,6 @@ use crate::ticketer;
use crate::tls13::key_schedule::{KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending};
use crate::tls13::Tls13CipherSuite;
use crate::verify;
#[cfg(feature = "quic")]
use crate::{check::inappropriate_message, conn::Protocol};
use super::hs::{self, HandshakeHashOrBuffer, ServerContext};
use super::server_conn::ServerConnectionData;
@@ -52,8 +50,6 @@ mod client_hello {
use crate::msgs::handshake::ServerExtension;
use crate::msgs::handshake::ServerHelloPayload;
use crate::msgs::handshake::SessionID;
#[cfg(feature = "quic")]
use crate::quic;
use crate::server::common::ActiveCertifiedKey;
use crate::sign;
use crate::tls13::key_schedule::{
@@ -107,9 +103,7 @@ mod client_hello {
_ => unreachable!(),
};
let handshake_hash = self
.transcript
.get_hash_given(&binder_plaintext);
let handshake_hash = self.transcript.get_hash_given(&binder_plaintext);
let key_schedule = KeyScheduleEarly::new(suite.hkdf_algorithm, psk);
let real_binder =
@@ -144,9 +138,7 @@ mod client_hello {
mut sigschemes_ext: Vec<SignatureScheme>,
) -> hs::NextStateOrError {
if client_hello.compression_methods.len() != 1 {
return Err(cx
.common
.illegal_param("client offered wrong compressions"));
return Err(cx.common.illegal_param("client offered wrong compressions"));
}
let groups_ext = client_hello
@@ -161,9 +153,7 @@ mod client_hello {
.ok_or_else(|| hs::incompatible(cx.common, "client didn't send keyshares"))?;
if client_hello.has_keyshare_extension_with_duplicates() {
return Err(cx
.common
.illegal_param("client sent duplicate keyshares"));
return Err(cx.common.illegal_param("client sent duplicate keyshares"));
}
let early_data_requested = client_hello.early_data_extension_offered();
@@ -180,11 +170,7 @@ mod client_hello {
.config
.kx_groups
.iter()
.find_map(|group| {
shares_ext
.iter()
.find(|share| share.group == group.name)
});
.find_map(|group| shares_ext.iter().find(|share| share.group == group.name));
let chosen_share = match chosen_share {
Some(s) => s,
@@ -202,9 +188,7 @@ mod client_hello {
if let Some(group) = retry_group_maybe {
if self.done_retry {
return Err(cx
.common
.illegal_param("did not follow retry request"));
return Err(cx.common.illegal_param("did not follow retry request"));
}
emit_hello_retry_request(
@@ -252,9 +236,7 @@ mod client_hello {
if let Some(psk_offer) = client_hello.get_psk() {
if !client_hello.check_psk_ext_is_last() {
return Err(cx
.common
.illegal_param("psk extension in wrong position"));
return Err(cx.common.illegal_param("psk extension in wrong position"));
}
if psk_offer.binders.is_empty() {
@@ -286,8 +268,7 @@ mod client_hello {
&resume.master_secret.0,
&psk_offer.binders[i].0,
) {
cx.common
.send_fatal_alert(AlertDescription::DecryptError);
cx.common.send_fatal_alert(AlertDescription::DecryptError);
return Err(Error::PeerMisbehavedError(
"client sent wrong binder".to_string(),
));
@@ -323,9 +304,7 @@ mod client_hello {
&client_hello.session_id,
chosen_share,
chosen_psk_index,
resumedata
.as_ref()
.map(|x| &x.master_secret.0[..]),
resumedata.as_ref().map(|x| &x.master_secret.0[..]),
&self.config,
)?;
if !self.done_retry {
@@ -371,12 +350,9 @@ mod client_hello {
// are encrypted with the handshake keys.
match doing_early_data {
EarlyDataDecision::Disabled => {
cx.common
.record_layer
.set_message_decrypter(
self.suite
.derive_decrypter(key_schedule.client_key()),
);
cx.common.record_layer.set_message_decrypter(
self.suite.derive_decrypter(key_schedule.client_key()),
);
cx.data.early_data.reject();
}
EarlyDataDecision::RequestedButRejected => {
@@ -384,8 +360,7 @@ mod client_hello {
cx.common
.record_layer
.set_message_decrypter_with_trial_decryption(
self.suite
.derive_decrypter(key_schedule.client_key()),
self.suite.derive_decrypter(key_schedule.client_key()),
max_early_data_size(self.config.max_early_data_size),
);
cx.data.early_data.reject();
@@ -422,7 +397,7 @@ mod client_hello {
key_schedule: key_schedule_traffic,
send_ticket: self.send_ticket,
}))
} else if doing_early_data == EarlyDataDecision::Accepted && !cx.common.is_quic() {
} else if doing_early_data == EarlyDataDecision::Accepted {
// Not used for QUIC: RFC 9001 §8.3: Clients MUST NOT send the EndOfEarlyData
// message. A server MUST treat receipt of a CRYPTO frame in a 0-RTT packet as a
// connection error of type PROTOCOL_VIOLATION.
@@ -536,22 +511,10 @@ mod client_hello {
.set_message_decrypter(suite.derive_decrypter(key));
}
#[cfg(feature = "quic")]
if cx.common.is_quic() {
// If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing
// before the application can see.
cx.common.quic.early_secret = early_data_client_key;
cx.common.quic.hs_secrets =
Some(quic::Secrets::new(_client_key, server_key, suite, false));
}
Ok(key_schedule)
}
fn emit_fake_ccs(common: &mut CommonState) {
if common.is_quic() {
return;
}
let m = Message {
version: ProtocolVersion::TLSv1_2,
payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}),
@@ -572,12 +535,10 @@ mod client_hello {
extensions: Vec::new(),
};
req.extensions
.push(HelloRetryExtension::KeyShare(group));
req.extensions
.push(HelloRetryExtension::SupportedVersions(
ProtocolVersion::TLSv1_3,
));
req.extensions.push(HelloRetryExtension::KeyShare(group));
req.extensions.push(HelloRetryExtension::SupportedVersions(
ProtocolVersion::TLSv1_3,
));
let m = Message {
version: ProtocolVersion::TLSv1_2,
@@ -643,12 +604,6 @@ mod client_hello {
if early_data_configured && early_data_possible && !cx.data.early_data.was_rejected() {
EarlyDataDecision::Accepted
} else {
#[cfg(feature = "quic")]
if cx.common.is_quic() {
// Clobber value set in tls13::emit_server_hello
cx.common.quic.early_secret = None;
}
rejected_or_disabled
}
}
@@ -708,25 +663,18 @@ mod client_hello {
extensions: Vec::new(),
};
let schemes = config
.verifier
.supported_verify_schemes();
let schemes = config.verifier.supported_verify_schemes();
cr.extensions
.push(CertReqExtension::SignatureAlgorithms(schemes.to_vec()));
let names = config
.verifier
.client_auth_root_subjects()
.ok_or_else(|| {
debug!("could not determine root subjects based on SNI");
cx.common
.send_fatal_alert(AlertDescription::AccessDenied);
Error::General("client rejected by client_auth_root_subjects".into())
})?;
let names = config.verifier.client_auth_root_subjects().ok_or_else(|| {
debug!("could not determine root subjects based on SNI");
cx.common.send_fatal_alert(AlertDescription::AccessDenied);
Error::General("client rejected by client_auth_root_subjects".into())
})?;
if !names.is_empty() {
cr.extensions
.push(CertReqExtension::AuthorityNames(names));
cr.extensions.push(CertReqExtension::AuthorityNames(names));
}
let m = Message {
@@ -860,12 +808,6 @@ mod client_hello {
.record_layer
.set_message_encrypter(suite.derive_encrypter(&server_key));
#[cfg(feature = "quic")]
{
cx.common.quic.traffic_secrets =
Some(quic::Secrets::new(_client_key, server_key, suite, false));
}
key_schedule_traffic
}
}
@@ -925,8 +867,7 @@ impl State<ServerConnectionData> for ExpectCertificate {
.client_auth_mandatory()
.ok_or_else(|| {
debug!("could not determine if client auth is mandatory based on SNI");
cx.common
.send_fatal_alert(AlertDescription::AccessDenied);
cx.common.send_fatal_alert(AlertDescription::AccessDenied);
Error::General("client rejected by client_auth_mandatory".into())
})?;
@@ -999,8 +940,7 @@ impl State<ServerConnectionData> for ExpectCertificateVerify {
};
if let Err(e) = rc {
cx.common
.send_fatal_alert(AlertDescription::AccessDenied);
cx.common.send_fatal_alert(AlertDescription::AccessDenied);
return Err(e);
}
@@ -1033,11 +973,7 @@ impl State<ServerConnectionData> for ExpectEarlyData {
fn handle(mut self: Box<Self>, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError {
match m.payload {
MessagePayload::ApplicationData(payload) => {
match cx
.data
.early_data
.take_received_plaintext(payload)
{
match cx.data.early_data.take_received_plaintext(payload) {
true => Ok(self),
false => {
cx.common
@@ -1052,12 +988,9 @@ impl State<ServerConnectionData> for ExpectEarlyData {
typ: HandshakeType::EndOfEarlyData,
payload: HandshakePayload::EndOfEarlyData,
}) => {
cx.common
.record_layer
.set_message_decrypter(
self.suite
.derive_decrypter(self.key_schedule.client_key()),
);
cx.common.record_layer.set_message_decrypter(
self.suite.derive_decrypter(self.key_schedule.client_key()),
);
self.transcript.add_message(&m);
Ok(Box::new(ExpectFinished {
@@ -1138,9 +1071,7 @@ impl ExpectFinished {
(ticket, config.ticketer.lifetime())
} else {
let id = rand::random_vec(32)?;
let stored = config
.session_storage
.put(id.clone(), plain);
let stored = config.session_storage.put(id.clone(), plain);
if !stored {
trace!("resumption not available; not issuing ticket");
return Ok(());
@@ -1153,11 +1084,9 @@ impl ExpectFinished {
if config.max_early_data_size > 0 {
if !stateless {
payload
.exts
.push(NewSessionTicketExtension::EarlyData(
config.max_early_data_size,
));
payload.exts.push(NewSessionTicketExtension::EarlyData(
config.max_early_data_size,
));
} else {
// We implement RFC8446 section 8.1: by enforcing that 0-RTT is
// only possible if using stateful resumption
@@ -1186,14 +1115,12 @@ impl State<ServerConnectionData> for ExpectFinished {
require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?;
let handshake_hash = self.transcript.get_current_hash();
let (key_schedule_traffic, expect_verify_data, client_key) = self
.key_schedule
.sign_client_finish(&handshake_hash);
let (key_schedule_traffic, expect_verify_data, client_key) =
self.key_schedule.sign_client_finish(&handshake_hash);
let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0)
.map_err(|_| {
cx.common
.send_fatal_alert(AlertDescription::DecryptError);
cx.common.send_fatal_alert(AlertDescription::DecryptError);
warn!("Finished wrong");
Error::DecryptError
})
@@ -1223,16 +1150,6 @@ impl State<ServerConnectionData> for ExpectFinished {
// Application data may now flow, even if we have client auth enabled.
cx.common.start_traffic();
#[cfg(feature = "quic")]
{
if cx.common.protocol == Protocol::Quic {
return Ok(Box::new(ExpectQuicTraffic {
key_schedule: key_schedule_traffic,
_fin_verified: fin,
}));
}
}
Ok(Box::new(ExpectTraffic {
suite: self.suite,
key_schedule: key_schedule_traffic,
@@ -1256,16 +1173,6 @@ impl ExpectTraffic {
common: &mut CommonState,
kur: &KeyUpdateRequest,
) -> Result<(), Error> {
#[cfg(feature = "quic")]
{
if let Protocol::Quic = common.protocol {
common.send_fatal_alert(AlertDescription::UnexpectedMessage);
let msg = "KeyUpdate received in QUIC connection".to_string();
warn!("{}", msg);
return Err(Error::PeerMisbehavedError(msg));
}
}
common.check_aligned_handshake()?;
match kur {
@@ -1280,15 +1187,10 @@ impl ExpectTraffic {
}
// Update our read-side keys.
let new_read_key = self
.key_schedule
.next_client_application_traffic_secret();
let new_read_key = self.key_schedule.next_client_application_traffic_secret();
common
.record_layer
.set_message_decrypter(
self.suite
.derive_decrypter(&new_read_key),
);
.set_message_decrypter(self.suite.derive_decrypter(&new_read_key));
Ok(())
}
@@ -1297,9 +1199,7 @@ impl ExpectTraffic {
impl State<ServerConnectionData> for ExpectTraffic {
fn handle(mut self: Box<Self>, cx: &mut ServerContext, m: Message) -> hs::NextStateOrError {
match m.payload {
MessagePayload::ApplicationData(payload) => cx
.common
.take_received_plaintext(payload),
MessagePayload::ApplicationData(payload) => cx.common.take_received_plaintext(payload),
MessagePayload::Handshake(HandshakeMessagePayload {
payload: HandshakePayload::KeyUpdate(key_update),
..
@@ -1331,36 +1231,10 @@ impl State<ServerConnectionData> for ExpectTraffic {
self.want_write_key_update = false;
common.send_msg_encrypt(Message::build_key_update_notify().into());
let write_key = self
.key_schedule
.next_server_application_traffic_secret();
let write_key = self.key_schedule.next_server_application_traffic_secret();
common
.record_layer
.set_message_encrypter(self.suite.derive_encrypter(&write_key));
}
}
}
#[cfg(feature = "quic")]
struct ExpectQuicTraffic {
key_schedule: KeyScheduleTraffic,
_fin_verified: verify::FinishedMessageVerified,
}
#[cfg(feature = "quic")]
impl State<ServerConnectionData> for ExpectQuicTraffic {
fn handle(self: Box<Self>, _cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError {
// reject all messages
Err(inappropriate_message(&m.payload, &[]))
}
fn export_keying_material(
&self,
output: &mut [u8],
label: &[u8],
context: Option<&[u8]>,
) -> Result<(), Error> {
self.key_schedule
.export_keying_material(output, label, context)
}
}

View File

@@ -25,10 +25,6 @@ pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &
aead_algorithm: &ring::aead::CHACHA20_POLY1305,
},
hkdf_algorithm: ring::hkdf::HKDF_SHA256,
#[cfg(feature = "quic")]
confidentiality_limit: u64::MAX,
#[cfg(feature = "quic")]
integrity_limit: 1 << 36,
};
/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384
@@ -40,10 +36,6 @@ pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite =
aead_algorithm: &ring::aead::AES_256_GCM,
},
hkdf_algorithm: ring::hkdf::HKDF_SHA384,
#[cfg(feature = "quic")]
confidentiality_limit: 1 << 23,
#[cfg(feature = "quic")]
integrity_limit: 1 << 52,
});
/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256
@@ -57,10 +49,6 @@ pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13C
aead_algorithm: &ring::aead::AES_128_GCM,
},
hkdf_algorithm: ring::hkdf::HKDF_SHA256,
#[cfg(feature = "quic")]
confidentiality_limit: 1 << 23,
#[cfg(feature = "quic")]
integrity_limit: 1 << 52,
};
/// A TLS 1.3 cipher suite supported by rustls.
@@ -68,10 +56,6 @@ pub struct Tls13CipherSuite {
/// Common cipher suite fields.
pub common: CipherSuiteCommon,
pub(crate) hkdf_algorithm: ring::hkdf::Algorithm,
#[cfg(feature = "quic")]
pub(crate) confidentiality_limit: u64,
#[cfg(feature = "quic")]
pub(crate) integrity_limit: u64,
}
impl Tls13CipherSuite {
@@ -99,9 +83,7 @@ impl Tls13CipherSuite {
/// Which hash function to use with this suite.
pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm {
self.hkdf_algorithm
.hmac_algorithm()
.digest_algorithm()
self.hkdf_algorithm.hmac_algorithm().digest_algorithm()
}
/// Can a session using suite self resume from suite prev?

File diff suppressed because it is too large Load Diff