Skip to content

Commit

Permalink
Merge e3e9a6e into 559070b
Browse files Browse the repository at this point in the history
  • Loading branch information
Ralith committed Nov 25, 2018
2 parents 559070b + e3e9a6e commit 774435d
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 30 deletions.
5 changes: 2 additions & 3 deletions bogo/config.json
Expand Up @@ -88,7 +88,8 @@
"ALPN*SelectEmpty-*": "",
"Draft-Downgrade-Server": "not implemented; TODO",
"EarlyData-*ALPN*-*": "no alpn change in resumed sessions",
"*EarlyKeyingMaterial-Client-*": "early exporter NYI"
"*EarlyKeyingMaterial-Client-*": "early exporter NYI",
"QUICTransportParams-*-TLS12": "QUIC support requires TLS >= 1.3"
},
"ErrorMap": {
":HTTP_REQUEST:": ":GARBAGE:",
Expand Down Expand Up @@ -281,8 +282,6 @@
"CurveTest-Server-Compressed-P-384-TLS12": ":PEER_MISBEHAVIOUR:",
"CurveTest-Client-Compressed-P-384-TLS13": ":PEER_MISBEHAVIOUR:",
"CurveTest-Server-Compressed-P-384-TLS13": ":PEER_MISBEHAVIOUR:",
"QUICTransportParams-Client-Rejected-TLS12": ":PEER_MISBEHAVIOUR:",
"QUICTransportParams-Server-Rejected-TLS12": "missing peer quic transport params",
"ExtendedMasterSecret-NoToYes-Client": ":PEER_MISBEHAVIOUR:",
"ExtendedMasterSecret-YesToNo-Server": ":PEER_MISBEHAVIOUR:",
"ExtendedMasterSecret-YesToNo-Client": ":PEER_MISBEHAVIOUR:",
Expand Down
23 changes: 12 additions & 11 deletions src/client/hs.rs
Expand Up @@ -20,7 +20,7 @@ use msgs::codec::Codec;
use msgs::persist;
use msgs::ccs::ChangeCipherSpecPayload;
use client::ClientSessionImpl;
use session::SessionSecrets;
use session::{SessionSecrets, Protocol};
use key_schedule::{KeySchedule, SecretKind};
use cipher;
use suites;
Expand Down Expand Up @@ -202,6 +202,11 @@ struct ExpectServerHello {
struct ExpectServerHelloOrHelloRetryRequest(ExpectServerHello);

fn emit_fake_ccs(hs: &mut HandshakeDetails, sess: &mut ClientSessionImpl) {
#[cfg(feature = "quic")]
{
if let Protocol::Quic = sess.common.protocol { return; }
}

if hs.sent_tls13_fake_ccs {
return;
}
Expand Down Expand Up @@ -696,13 +701,6 @@ impl State for ExpectServerHello {
process_alpn_protocol(sess, server_hello.get_alpn_protocol())?;
}

// Reject QUIC if TLS1.2 is in use.
if !sess.common.is_tls13() &&
server_hello.find_extension(ExtensionType::TransportParameters).is_some() {
sess.common.send_fatal_alert(AlertDescription::UnsupportedExtension);
return Err(TLSError::PeerMisbehavedError("server wants to do quic+tls1.2".to_string()));
}

// If ECPointFormats extension is supplied by the server, it must contain
// Uncompressed. But it's allowed to be omitted.
if let Some(point_fmts) = server_hello.get_ecpoints_extension() {
Expand Down Expand Up @@ -1004,9 +1002,12 @@ impl State for ExpectTLS13EncryptedExtensions {
validate_encrypted_extensions(sess, &self.hello, exts)?;
process_alpn_protocol(sess, exts.get_alpn_protocol())?;

// QUIC transport parameters
if let Some(params) = exts.get_quic_params_extension() {
sess.quic_params = Some(params);
#[cfg(feature = "quic")]
{
// QUIC transport parameters
if let Some(params) = exts.get_quic_params_extension() {
sess.common.quic.params = Some(params);
}
}

if self.handshake.resuming_session.is_some() {
Expand Down
4 changes: 1 addition & 3 deletions src/client/mod.rs
Expand Up @@ -360,7 +360,6 @@ impl<'a> io::Write for WriteEarlyData<'a> {
pub struct ClientSessionImpl {
pub config: Arc<ClientConfig>,
pub alpn_protocol: Option<String>,
pub quic_params: Option<Vec<u8>>,
pub common: SessionCommon,
pub error: Option<TLSError>,
pub state: Option<Box<hs::State + Send + Sync>>,
Expand All @@ -379,7 +378,6 @@ impl ClientSessionImpl {
ClientSessionImpl {
config: config.clone(),
alpn_protocol: None,
quic_params: None,
common: SessionCommon::new(config.mtu, true),
error: None,
state: None,
Expand Down Expand Up @@ -478,7 +476,7 @@ impl ClientSessionImpl {
self.process_main_protocol(msg)
}

fn process_new_handshake_messages(&mut self) -> Result<(), TLSError> {
pub fn process_new_handshake_messages(&mut self) -> Result<(), TLSError> {
while let Some(msg) = self.common.handshake_joiner.frames.pop_front() {
self.process_main_protocol(msg)?;
}
Expand Down
126 changes: 119 additions & 7 deletions src/quic.rs
@@ -1,29 +1,138 @@
/// This module contains optional APIs for implementing QUIC TLS.
use client::{ClientConfig, ClientSession, ClientSessionImpl};
use msgs::base::Payload;
use msgs::enums::ExtensionType;
use msgs::enums::{ExtensionType, ContentType, ProtocolVersion, AlertDescription};
use msgs::handshake::{ClientExtension, ServerExtension, UnknownExtension};
use msgs::message::{Message, MessagePayload};
use server::{ServerConfig, ServerSession, ServerSessionImpl};
use error::TLSError;
use key_schedule::SecretKind;
use session::{SessionCommon, Protocol};

use std::sync::Arc;
use webpki;

/// Secrets used to encrypt/decrypt traffic
pub struct Secrets {
/// Secret used to encrypt packets transmitted by the client
pub client: Vec<u8>,
/// Secret used to encrypt packets transmitted by the server
pub server: Vec<u8>,
}

/// Generic methods for QUIC sessions
pub trait QuicExt {
/// Return the TLS-encoded transport parameters for the session's peer.
fn get_quic_transport_parameters(&self) -> Option<&[u8]>;

/// Consume unencrypted TLS handshake data
fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), TLSError>;

/// Emit unencrypted TLS handshake data
fn write_hs(&mut self, buf: &mut Vec<u8>);

/// Emit the TLS description code of a fatal alert, if one has arisen
fn take_alert(&mut self) -> Option<AlertDescription>;

/// Get the secrets used to encrypt/decrypt handshake traffic, if available
fn get_handshake_secrets(&self) -> Option<Secrets>;

/// Get the secrets used to encrypt/decrypt 1-RTT traffic, if available
fn get_1rtt_secrets(&self) -> Option<Secrets>;

/// Get 1-RTT secrets for use following a key update.
///
/// This should only be called after `get_1rtt_secrets` has returned `Some(_)`.
///
/// # Panics
/// - If called before the handshake completes.
fn update_1rtt_secrets(&mut self) -> Secrets;
}

impl QuicExt for ClientSession {
fn get_quic_transport_parameters(&self) -> Option<&[u8]> {
self.imp.quic_params.as_ref().map(|v| v.as_ref())
self.imp.common.quic.params.as_ref().map(|v| v.as_ref())
}

fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), TLSError> {
self.imp.common
.handshake_joiner
.take_message(Message {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_3,
payload: MessagePayload::new_opaque(plaintext.into()),
});
self.imp.process_new_handshake_messages()?;
Ok(())
}

fn write_hs(&mut self, buf: &mut Vec<u8>) {
self.imp.common.sendable_tls.write_to(buf).unwrap();
}

fn take_alert(&mut self) -> Option<AlertDescription> { self.imp.common.quic.alert.take() }

fn get_handshake_secrets(&self) -> Option<Secrets> { get_handshake_secrets(&self.imp.common) }

fn get_1rtt_secrets(&self) -> Option<Secrets> { get_1rtt_secrets(&self.imp.common) }

fn update_1rtt_secrets(&mut self) -> Secrets { update_1rtt_secrets(&mut self.imp.common) }
}

impl QuicExt for ServerSession {
fn get_quic_transport_parameters(&self) -> Option<&[u8]> {
self.imp.quic_params.as_ref().map(|v| v.as_ref())
self.imp.common.quic.params.as_ref().map(|v| v.as_ref())
}

fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), TLSError> {
self.imp.common
.handshake_joiner
.take_message(Message {
typ: ContentType::Handshake,
version: ProtocolVersion::TLSv1_3,
payload: MessagePayload::new_opaque(plaintext.into()),
});
self.imp.process_new_handshake_messages()?;
Ok(())
}

fn write_hs(&mut self, buf: &mut Vec<u8>) {
self.imp.common.sendable_tls.write_to(buf).unwrap();
}

fn take_alert(&mut self) -> Option<AlertDescription> { self.imp.common.quic.alert.take() }

fn get_handshake_secrets(&self) -> Option<Secrets> { get_handshake_secrets(&self.imp.common) }

fn get_1rtt_secrets(&self) -> Option<Secrets> { get_1rtt_secrets(&self.imp.common) }

fn update_1rtt_secrets(&mut self) -> Secrets { update_1rtt_secrets(&mut self.imp.common) }
}

fn get_handshake_secrets(this: &SessionCommon) -> Option<Secrets> {
let key_schedule = this.key_schedule.as_ref()?;
let handshake_hash = this.hs_transcript.get_current_hash();
let client = key_schedule.derive(SecretKind::ClientHandshakeTrafficSecret, &handshake_hash);
let server = key_schedule.derive(SecretKind::ServerHandshakeTrafficSecret, &handshake_hash);
Some(Secrets { client, server })
}

fn get_1rtt_secrets(this: &SessionCommon) -> Option<Secrets> {
if !this.traffic { return None; }
let key_schedule = this.key_schedule.as_ref().unwrap();
Some(Secrets {
client: key_schedule.current_client_traffic_secret.clone(),
server: key_schedule.current_server_traffic_secret.clone(),
})
}

fn update_1rtt_secrets(this: &mut SessionCommon) -> Secrets {
{
let key_schedule = this.key_schedule.as_mut().unwrap();
key_schedule.current_client_traffic_secret = key_schedule.derive_next(SecretKind::ClientApplicationTrafficSecret);
key_schedule.current_server_traffic_secret = key_schedule.derive_next(SecretKind::ServerApplicationTrafficSecret);
}
get_1rtt_secrets(this).expect("handshake incomplete")
}

/// Methods specific to QUIC client sessions
Expand All @@ -33,7 +142,9 @@ pub trait ClientQuicExt {
/// TLS-encoded transport parameters to send.
fn new_quic(config: &Arc<ClientConfig>, hostname: webpki::DNSNameRef, params: Vec<u8>)
-> ClientSession {
assert!(config.versions.iter().all(|x| x.get_u16() >= ProtocolVersion::TLSv1_3.get_u16()), "QUIC requires TLS version >= 1.3");
let mut imp = ClientSessionImpl::new(config);
imp.common.protocol = Protocol::Quic;
imp.start_handshake(hostname.into(), vec![
ClientExtension::Unknown(UnknownExtension {
typ: ExtensionType::TransportParameters,
Expand All @@ -52,14 +163,15 @@ pub trait ServerQuicExt {
/// in that it takes an extra argument, `params`, which contains the
/// TLS-encoded transport parameters to send.
fn new_quic(config: &Arc<ServerConfig>, params: Vec<u8>) -> ServerSession {
ServerSession {
imp: ServerSessionImpl::new(config, vec![
assert!(config.versions.iter().all(|x| x.get_u16() >= ProtocolVersion::TLSv1_3.get_u16()), "QUIC requires TLS version >= 1.3");
let mut imp = ServerSessionImpl::new(config, vec![
ServerExtension::Unknown(UnknownExtension {
typ: ExtensionType::TransportParameters,
payload: Payload::new(params),
}),
]),
}
]);
imp.common.protocol = Protocol::Quic;
ServerSession { imp }
}
}

Expand Down
15 changes: 11 additions & 4 deletions src/server/hs.rs
Expand Up @@ -21,7 +21,7 @@ use msgs::handshake::{CertReqExtension, SupportedMandatedSignatureSchemes};
use msgs::ccs::ChangeCipherSpecPayload;
use msgs::codec::Codec;
use msgs::persist;
use session::SessionSecrets;
use session::{SessionSecrets, Protocol};
use cipher;
use server::ServerSessionImpl;
use key_schedule::{KeySchedule, SecretKind};
Expand Down Expand Up @@ -216,9 +216,12 @@ impl ExpectClientHello {
}
}

// QUIC transport parameters
if let (Some(params), true) = (hello.get_quic_params_extension(), sess.common.is_tls13()) {
sess.quic_params = Some(params);
#[cfg(feature = "quic")]
{
// QUIC transport parameters
if let Some(params) = hello.get_quic_params_extension() {
sess.common.quic.params = Some(params);
}
}

// SNI
Expand Down Expand Up @@ -385,6 +388,10 @@ impl ExpectClientHello {

fn emit_fake_ccs(&mut self,
sess: &mut ServerSessionImpl) {
#[cfg(feature = "quic")]
{
if let Protocol::Quic = sess.common.protocol { return; }
}
let m = Message {
typ: ContentType::ChangeCipherSpec,
version: ProtocolVersion::TLSv1_2,
Expand Down
2 changes: 1 addition & 1 deletion src/server/mod.rs
Expand Up @@ -341,7 +341,7 @@ impl ServerSessionImpl {
self.process_main_protocol(msg)
}

fn process_new_handshake_messages(&mut self) -> Result<(), TLSError> {
pub fn process_new_handshake_messages(&mut self) -> Result<(), TLSError> {
while let Some(msg) = self.common.handshake_joiner.frames.pop_front() {
self.process_main_protocol(msg)?;
}
Expand Down

0 comments on commit 774435d

Please sign in to comment.