diff --git a/rustls/src/quic.rs b/rustls/src/quic.rs index 554cbf05..d2dcbdf0 100644 --- a/rustls/src/quic.rs +++ b/rustls/src/quic.rs @@ -5,29 +5,40 @@ use crate::msgs::handshake::{ClientExtension, ServerExtension}; use crate::msgs::message::{Message, MessagePayload}; use crate::server::{ServerConfig, ServerSession, ServerSessionImpl}; use crate::error::TLSError; -use crate::key_schedule; +use crate::key_schedule::hkdf_expand; use crate::session::{SessionCommon, Protocol}; +use crate::suites::{BulkAlgorithm, SupportedCipherSuite, TLS13_AES_128_GCM_SHA256}; use std::sync::Arc; -use ring::hkdf; +use ring::{aead, hkdf}; use webpki; /// Secrets used to encrypt/decrypt traffic #[derive(Clone, Debug)] -pub struct Secrets { +pub(crate) struct Secrets { /// Secret used to encrypt packets transmitted by the client pub client: hkdf::Prk, /// Secret used to encrypt packets transmitted by the server pub server: hkdf::Prk, } +impl Secrets { + fn local_remote(&self, is_client: bool) -> (&hkdf::Prk, &hkdf::Prk) { + if 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. fn get_quic_transport_parameters(&self) -> Option<&[u8]>; - /// Return the early traffic secret, used to encrypt 0-RTT data. - fn get_early_secret(&self) -> Option<&hkdf::Prk>; + /// Compute the keys for encrypting/decrypting 0-RTT packets, if available + fn get_0rtt_keys(&self) -> Option; /// Consume unencrypted TLS handshake data. /// @@ -36,17 +47,18 @@ pub trait QuicExt { /// Emit unencrypted TLS handshake data. /// - /// When this returns `Some(_)`, the keys used for future handshake data must be derived from - /// the new secrets. - fn write_hs(&mut self, buf: &mut Vec) -> Option; + /// When this returns `Some(_)`, the new keys must be used for future handshake data. + fn write_hs(&mut self, buf: &mut Vec) -> Option; /// Emit the TLS description code of a fatal alert, if one has arisen. /// /// Check after `read_hs` returns `Err(_)`. fn get_alert(&self) -> Option; - /// Compute the secrets to use following a 1-RTT key update from their previous values. - fn update_secrets(&self, client: &hkdf::Prk, server: &hkdf::Prk) -> Secrets; + /// Compute the keys to use following a 1-RTT key update + /// + /// Must not be called until the handshake is complete + fn next_1rtt_keys(&mut self) -> PacketKeySet; } impl QuicExt for ClientSession { @@ -54,19 +66,24 @@ impl QuicExt for ClientSession { self.imp.common.quic.params.as_ref().map(|v| v.as_ref()) } - fn get_early_secret(&self) -> Option<&hkdf::Prk> { - self.imp.common.quic.early_secret.as_ref() + fn get_0rtt_keys(&self) -> Option { + Some(DirectionalKeys::new( + self.imp.resumption_ciphersuite?, + self.imp.common.quic.early_secret.as_ref()?, + )) } fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), TLSError> { read_hs(&mut self.imp.common, plaintext)?; self.imp.process_new_handshake_messages() } - fn write_hs(&mut self, buf: &mut Vec) -> Option { write_hs(&mut self.imp.common, buf) } + fn write_hs(&mut self, buf: &mut Vec) -> Option { write_hs(&mut self.imp.common, buf) } fn get_alert(&self) -> Option { self.imp.common.quic.alert } - fn update_secrets(&self, client: &hkdf::Prk, server: &hkdf::Prk) -> Secrets { update_secrets(&self.imp.common, client, server) } + fn next_1rtt_keys(&mut self) -> PacketKeySet { + next_1rtt_keys(&mut self.imp.common) + } } impl QuicExt for ServerSession { @@ -74,19 +91,143 @@ impl QuicExt for ServerSession { self.imp.common.quic.params.as_ref().map(|v| v.as_ref()) } - fn get_early_secret(&self) -> Option<&hkdf::Prk> { - self.imp.common.quic.early_secret.as_ref() + fn get_0rtt_keys(&self) -> Option { + Some(DirectionalKeys::new( + self.imp.common.get_suite()?, + self.imp.common.quic.early_secret.as_ref()?, + )) } fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), TLSError> { read_hs(&mut self.imp.common, plaintext)?; self.imp.process_new_handshake_messages() } - fn write_hs(&mut self, buf: &mut Vec) -> Option { write_hs(&mut self.imp.common, buf) } + fn write_hs(&mut self, buf: &mut Vec) -> Option { write_hs(&mut self.imp.common, buf) } fn get_alert(&self) -> Option { self.imp.common.quic.alert } - fn update_secrets(&self, client: &hkdf::Prk, server: &hkdf::Prk) -> Secrets { update_secrets(&self.imp.common, client, server) } + fn next_1rtt_keys(&mut self) -> PacketKeySet { + next_1rtt_keys(&mut self.imp.common) + } +} + +/// Keys used to communicate in a single direction +pub struct DirectionalKeys { + /// Encrypts or decrypts a packet's headers + pub header: aead::quic::HeaderProtectionKey, + /// Encrypts or decrypts the payload of a packet + pub packet: PacketKey, +} + +impl DirectionalKeys { + fn new(suite: &'static SupportedCipherSuite, secret: &hkdf::Prk) -> Self { + let hp_alg = match suite.bulk { + BulkAlgorithm::AES_128_GCM => &aead::quic::AES_128, + BulkAlgorithm::AES_256_GCM => &aead::quic::AES_256, + BulkAlgorithm::CHACHA20_POLY1305 => &aead::quic::CHACHA20, + }; + + Self { + header: hkdf_expand(secret, hp_alg, b"quic hp", &[]), + packet: PacketKey::new(suite, secret), + } + } +} + +/// Keys to encrypt or decrypt the payload of a packet +pub struct PacketKey { + /// Encrypts or decrypts a packet's payload + pub key: aead::LessSafeKey, + /// Computes unique nonces for each packet + pub iv: Iv, +} + +impl PacketKey { + fn new(suite: &'static SupportedCipherSuite, secret: &hkdf::Prk) -> Self { + Self { + key: aead::LessSafeKey::new(hkdf_expand( + secret, + suite.get_aead_alg(), + b"quic key", + &[], + )), + iv: hkdf_expand(secret, IvLen, b"quic iv", &[]), + } + } +} + +/// Packet protection keys for bidirectional 1-RTT communication +pub struct PacketKeySet { + /// Encrypts outgoing packets + pub local: PacketKey, + /// Decrypts incoming packets + pub remote: PacketKey, +} + +/// Computes unique nonces for each packet +pub struct Iv([u8; aead::NONCE_LEN]); + +impl Iv { + /// Compute the nonce to use for encrypting or decrypting `packet_number` + pub fn nonce_for(&self, packet_number: u64) -> 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(self.0.iter()) { + *out ^= inp; + } + aead::Nonce::assume_unique_for_key(out) + } +} + +impl From> for Iv { + fn from(okm: hkdf::Okm) -> Self { + let mut iv = [0; aead::NONCE_LEN]; + okm.fill(&mut iv[..]).unwrap(); + Iv(iv) + } +} + +struct IvLen; + +impl hkdf::KeyType for IvLen { + fn len(&self) -> usize { + aead::NONCE_LEN + } +} + +/// 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( + initial_salt: &hkdf::Salt, + client_dst_connection_id: &[u8], + is_client: bool, + ) -> Self { + const CLIENT_LABEL: &[u8] = b"client in"; + const SERVER_LABEL: &[u8] = b"server in"; + let hs_secret = initial_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, &[]), + }; + Self::new(&TLS13_AES_128_GCM_SHA256, is_client, &secrets) + } + + fn new(suite: &'static SupportedCipherSuite, is_client: bool, secrets: &Secrets) -> Self { + let (local, remote) = secrets.local_remote(is_client); + Keys { + local: DirectionalKeys::new(suite, local), + remote: DirectionalKeys::new(suite, remote), + } + } } fn read_hs(this: &mut SessionCommon, plaintext: &[u8]) -> Result<(), TLSError> { @@ -104,7 +245,7 @@ fn read_hs(this: &mut SessionCommon, plaintext: &[u8]) -> Result<(), TLSError> { Ok(()) } -fn write_hs(this: &mut SessionCommon, buf: &mut Vec) -> Option { +fn write_hs(this: &mut SessionCommon, buf: &mut Vec) -> Option { while let Some((_, msg)) = this.quic.hs_queue.pop_front() { buf.extend_from_slice(&msg); if let Some(&(true, _)) = this.quic.hs_queue.front() { @@ -115,30 +256,41 @@ fn write_hs(this: &mut SessionCommon, buf: &mut Vec) -> Option { } } if let Some(secrets) = this.quic.hs_secrets.take() { - return Some(secrets); + return Some(Keys::new(this.get_suite_assert(), this.is_client, &secrets)); } - if let Some(secrets) = this.quic.traffic_secrets.take() { - return Some(secrets); + if let Some(secrets) = this.quic.traffic_secrets.as_ref() { + if !this.quic.returned_traffic_keys { + this.quic.returned_traffic_keys = true; + return Some(Keys::new(this.get_suite_assert(), this.is_client, &secrets)); + } } None } -fn update_secrets(this: &SessionCommon, client: &hkdf::Prk, server: &hkdf::Prk) -> Secrets { - let hkdf_alg= this.get_suite_assert().hkdf_algorithm; - let client = key_schedule::hkdf_expand( - client, - hkdf_alg, - b"quic ku", - &[]); - let server = key_schedule::hkdf_expand( - server, - hkdf_alg, - b"quic ku", - &[]); +fn next_1rtt_keys(this: &mut SessionCommon) -> PacketKeySet { + let hkdf_alg = this.get_suite_assert().hkdf_algorithm; + let secrets = this + .quic + .traffic_secrets + .as_ref() + .expect("traffic keys not yet available"); + let next = next_1rtt_secrets(hkdf_alg, secrets); + + let (local, remote) = secrets.local_remote(this.is_client); + let keys = PacketKeySet { + local: PacketKey::new(this.get_suite_assert(), local), + remote: PacketKey::new(this.get_suite_assert(), remote), + }; + + this.quic.traffic_secrets = Some(next); + keys +} + +fn next_1rtt_secrets(hkdf_alg: hkdf::Algorithm, prev: &Secrets) -> Secrets { Secrets { - client, - server, + client: hkdf_expand(&prev.client, hkdf_alg, b"quic ku", &[]), + server: hkdf_expand(&prev.server, hkdf_alg, b"quic ku", &[]), } } @@ -178,3 +330,199 @@ pub trait ServerQuicExt { } impl ServerQuicExt for ServerSession {} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn initial_keys_test_vectors() { + // Test vectors based on draft 27 + const INITIAL_SALT: [u8; 20] = [ + 0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7, 0xd2, 0x43, 0x2b, 0xb4, + 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02, + ]; + + const CONNECTION_ID: &[u8] = &[0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; + const PACKET_NUMBER: u64 = 42; + + let initial_salt = hkdf::Salt::new(hkdf::HKDF_SHA256, &INITIAL_SALT); + let server_keys = Keys::initial(&initial_salt, &CONNECTION_ID, false); + let client_keys = Keys::initial(&initial_salt, &CONNECTION_ID, true); + + // Nonces + const SERVER_NONCE: [u8; 12] = [ + 0x5e, 0x5a, 0xe6, 0x51, 0xfd, 0x1e, 0x84, 0x95, 0xaf, 0x13, 0x50, 0xa1, + ]; + assert_eq!( + server_keys + .local + .packet + .iv + .nonce_for(PACKET_NUMBER) + .as_ref(), + &SERVER_NONCE + ); + assert_eq!( + client_keys + .remote + .packet + .iv + .nonce_for(PACKET_NUMBER) + .as_ref(), + &SERVER_NONCE + ); + const CLIENT_NONCE: [u8; 12] = [ + 0x86, 0x81, 0x35, 0x94, 0x10, 0xa7, 0x0b, 0xb9, 0xc9, 0x2f, 0x04, 0x0a, + ]; + assert_eq!( + server_keys + .remote + .packet + .iv + .nonce_for(PACKET_NUMBER) + .as_ref(), + &CLIENT_NONCE + ); + assert_eq!( + client_keys + .local + .packet + .iv + .nonce_for(PACKET_NUMBER) + .as_ref(), + &CLIENT_NONCE + ); + + // Header encryption mask + const SAMPLE: &[u8] = &[ + 0x70, 0x02, 0x59, 0x6f, 0x99, 0xae, 0x67, 0xab, 0xf6, 0x5a, 0x58, 0x52, 0xf5, 0x4f, + 0x58, 0xc3, + ]; + + const SERVER_MASK: [u8; 5] = [0x38, 0x16, 0x8a, 0x0c, 0x25]; + assert_eq!( + server_keys.local.header.new_mask(SAMPLE).unwrap(), + SERVER_MASK + ); + assert_eq!( + client_keys.remote.header.new_mask(SAMPLE).unwrap(), + SERVER_MASK + ); + const CLIENT_MASK: [u8; 5] = [0xae, 0x96, 0x2e, 0x67, 0xec]; + assert_eq!( + server_keys.remote.header.new_mask(SAMPLE).unwrap(), + CLIENT_MASK + ); + assert_eq!( + client_keys.local.header.new_mask(SAMPLE).unwrap(), + CLIENT_MASK + ); + + const AAD: &[u8] = &[ + 0xc9, 0xff, 0x00, 0x00, 0x1b, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, + 0xb5, 0x00, 0x40, 0x74, 0x16, 0x8b, + ]; + let aad = aead::Aad::from(AAD); + const PLAINTEXT: [u8; 12] = [ + 0x0d, 0x00, 0x00, 0x00, 0x00, 0x18, 0x41, 0x0a, 0x02, 0x00, 0x00, 0x56, + ]; + let mut payload = PLAINTEXT; + let server_nonce = server_keys.local.packet.iv.nonce_for(PACKET_NUMBER); + let tag = server_keys + .local + .packet + .key + .seal_in_place_separate_tag(server_nonce, aad, &mut payload) + .unwrap(); + assert_eq!( + payload, + [0x0d, 0x91, 0x96, 0x31, 0xc0, 0xeb, 0x84, 0xf2, 0x88, 0x59, 0xfe, 0xc0] + ); + assert_eq!( + tag.as_ref(), + &[ + 0xdf, 0xee, 0x06, 0x81, 0x9e, 0x7a, 0x08, 0x34, 0xe4, 0x94, 0x19, 0x79, 0x5f, 0xe0, + 0xd7, 0x3f + ] + ); + + let aad = aead::Aad::from(AAD); + let mut payload = PLAINTEXT; + let client_nonce = client_keys.local.packet.iv.nonce_for(PACKET_NUMBER); + let tag = client_keys + .local + .packet + .key + .seal_in_place_separate_tag(client_nonce, aad, &mut payload) + .unwrap(); + assert_eq!( + payload, + [0x89, 0x6c, 0x66, 0x91, 0xe0, 0x9f, 0x47, 0x7a, 0x91, 0x42, 0xa4, 0x46] + ); + assert_eq!( + tag.as_ref(), + &[ + 0xb6, 0xff, 0xef, 0x89, 0xd5, 0xcb, 0x53, 0xd0, 0x98, 0xf7, 0x40, 0xa, 0x8d, 0x97, + 0x72, 0x6e + ] + ); + } + + #[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 initial = 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, + ], + ), + }; + let updated = next_1rtt_secrets(hkdf::HKDF_SHA256, &initial); + + assert!(equal_prk( + &updated.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( + &updated.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 + ] + ) + )); + } +} diff --git a/rustls/src/session.rs b/rustls/src/session.rs index 7bf4c06d..a73cdfd1 100644 --- a/rustls/src/session.rs +++ b/rustls/src/session.rs @@ -742,6 +742,8 @@ pub(crate) struct Quic { pub early_secret: Option, pub hs_secrets: Option, pub traffic_secrets: Option, + /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation + pub returned_traffic_keys: bool, } #[cfg(feature = "quic")] @@ -754,6 +756,7 @@ impl Quic { early_secret: None, hs_secrets: None, traffic_secrets: None, + returned_traffic_keys: false, } } } diff --git a/rustls/tests/api.rs b/rustls/tests/api.rs index 799372eb..6af56491 100644 --- a/rustls/tests/api.rs +++ b/rustls/tests/api.rs @@ -22,8 +22,6 @@ use rustls::KeyLog; use rustls::ClientHello; #[cfg(feature = "quic")] use rustls::quic::{self, QuicExt, ClientQuicExt, ServerQuicExt}; -#[cfg(feature = "quic")] -use ring::hkdf; #[cfg(feature = "dangerous_configuration")] use rustls::ClientCertVerified; @@ -2015,7 +2013,7 @@ mod test_quic { use super::*; // Returns the sender's next secrets to use, or the receiver's error. - fn step(send: &mut dyn Session, recv: &mut dyn Session) -> Result, TLSError> { + fn step(send: &mut dyn Session, recv: &mut dyn Session) -> Result, TLSError> { let mut buf = Vec::new(); let secrets = loop { let prev = buf.len(); @@ -2036,18 +2034,13 @@ mod test_quic { #[test] fn test_quic_handshake() { - fn equal_prk(x: &ring::hkdf::Prk, y: &ring::hkdf::Prk) -> bool { - let mut x_data = [0; 16]; - let mut y_data = [0; 16]; - let x_okm = x.expand(&[b"info"], &ring::aead::quic::AES_128).unwrap(); - x_okm.fill(&mut x_data[..]).unwrap(); - let y_okm = y.expand(&[b"info"], &ring::aead::quic::AES_128).unwrap(); - y_okm.fill(&mut y_data[..]).unwrap(); - x_data == y_data + fn equal_dir_keys(x: &quic::DirectionalKeys, y: &quic::DirectionalKeys) -> bool { + // Check that these two sets of keys are equal. The quic module's unit tests validate + // that the IV and the keys are consistent, so we can just check the IV here. + x.packet.iv.nonce_for(42).as_ref() == y.packet.iv.nonce_for(42).as_ref() } - - fn equal_secrets(x: &quic::Secrets, y: &quic::Secrets) -> bool { - equal_prk(&x.client, &y.client) && equal_prk(&x.server, &y.server) + fn compatible_keys(x: &quic::Keys, y: &quic::Keys) -> bool { + equal_dir_keys(&x.local, &y.remote) && equal_dir_keys(&x.remote, &y.local) } let kt = KeyType::RSA; @@ -2069,12 +2062,12 @@ mod test_quic { let mut server = ServerSession::new_quic(&server_config, server_params.into()); let client_initial = step(&mut client, &mut server).unwrap(); assert!(client_initial.is_none()); - assert!(client.get_early_secret().is_none()); + assert!(client.get_0rtt_keys().is_none()); assert_eq!(server.get_quic_transport_parameters(), Some(client_params)); let server_hs = step(&mut server, &mut client).unwrap().unwrap(); - assert!(server.get_early_secret().is_none()); + assert!(server.get_0rtt_keys().is_none()); let client_hs = step(&mut client, &mut server).unwrap().unwrap(); - assert!(equal_secrets(&server_hs, &client_hs)); + assert!(compatible_keys(&server_hs, &client_hs)); assert!(client.is_handshaking()); let server_1rtt = step(&mut server, &mut client).unwrap().unwrap(); assert!(!client.is_handshaking()); @@ -2082,45 +2075,11 @@ mod test_quic { assert!(server.is_handshaking()); let client_1rtt = step(&mut client, &mut server).unwrap().unwrap(); assert!(!server.is_handshaking()); - assert!(equal_secrets(&server_1rtt, &client_1rtt)); - assert!(!equal_secrets(&server_hs, &server_1rtt)); + assert!(compatible_keys(&server_1rtt, &client_1rtt)); + assert!(!compatible_keys(&server_hs, &server_1rtt)); assert!(step(&mut client, &mut server).unwrap().is_none()); assert!(step(&mut server, &mut client).unwrap().is_none()); - // key update - let initial = quic::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, - ]), - }; - let updated = client.update_secrets(&initial.client, &initial.server); - // The expected values will need to be updated if the negotiated hash function changes. Pull the - // values from ring's `hmac::Key::construct` with a debugger. - assert!(equal_prk( - &updated.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( - &updated.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 - ])) - ); - // 0-RTT handshake let mut client = ClientSession::new_quic(&client_config, dns_name("localhost"), client_params.into()); @@ -2129,9 +2088,9 @@ mod test_quic { step(&mut client, &mut server).unwrap(); assert_eq!(client.get_quic_transport_parameters(), Some(server_params)); { - let client_early = client.get_early_secret().unwrap(); - let server_early = server.get_early_secret().unwrap(); - assert!(equal_prk(client_early, server_early)); + let client_early = client.get_0rtt_keys().unwrap(); + let server_early = server.get_0rtt_keys().unwrap(); + assert!(equal_dir_keys(&client_early, &server_early)); } step(&mut server, &mut client).unwrap().unwrap(); step(&mut client, &mut server).unwrap().unwrap(); @@ -2142,13 +2101,16 @@ mod test_quic { { let mut client_config = (*client_config).clone(); client_config.alpn_protocols = vec!["foo".into()]; - let mut client = - ClientSession::new_quic(&Arc::new(client_config), dns_name("localhost"), client_params.into()); + let mut client = ClientSession::new_quic( + &Arc::new(client_config), + dns_name("localhost"), + client_params.into(), + ); let mut server = ServerSession::new_quic(&server_config, server_params.into()); step(&mut client, &mut server).unwrap(); assert_eq!(client.get_quic_transport_parameters(), Some(server_params)); - assert!(client.get_early_secret().is_some()); - assert!(server.get_early_secret().is_none()); + assert!(client.get_0rtt_keys().is_some()); + assert!(server.get_0rtt_keys().is_none()); step(&mut server, &mut client).unwrap().unwrap(); step(&mut client, &mut server).unwrap().unwrap(); step(&mut server, &mut client).unwrap().unwrap(); @@ -2164,7 +2126,7 @@ mod test_quic { let mut server = ServerSession::new_quic(&server_config, server_params.into()); step(&mut client, &mut server).unwrap(); step(&mut server, &mut client).unwrap().unwrap(); - step(&mut server, &mut client).unwrap_err(); + assert!(step(&mut server, &mut client).is_err()); assert_eq!( client.get_alert(), Some(rustls::internal::msgs::enums::AlertDescription::BadCertificate) @@ -2193,7 +2155,7 @@ mod test_quic { let mut server = ServerSession::new_quic(&server_config, server_params.into()); - assert_eq!(step(&mut client, &mut server).unwrap_err(), + assert_eq!(step(&mut client, &mut server).err().unwrap(), TLSError::NoApplicationProtocol); assert_eq!(server.get_alert(),