Skip to content

Commit

Permalink
Merge 90f0377 into f3fdd47
Browse files Browse the repository at this point in the history
  • Loading branch information
briansmith committed Aug 3, 2019
2 parents f3fdd47 + 90f0377 commit 20499a6
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 213 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -13,7 +13,7 @@ categories = ["network-programming", "cryptography"]
[dependencies]
base64 = "0.10"
log = { version = "0.4.4", optional = true }
ring = "0.16.4"
ring = "0.16.5"
sct = "0.6.0"
webpki = "0.21.0"

Expand Down
14 changes: 6 additions & 8 deletions src/cipher.rs
Expand Up @@ -122,19 +122,17 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite,
}

pub fn new_tls13_read(scs: &'static SupportedCipherSuite,
secret: &[u8]) -> Box<dyn MessageDecrypter> {
let secret = hkdf::Prk::new_less_safe(scs.hkdf_algorithm, secret);
let key = derive_traffic_key(&secret, scs.get_aead_alg());
let iv = derive_traffic_iv(&secret);
secret: &hkdf::Prk) -> Box<dyn MessageDecrypter> {
let key = derive_traffic_key(secret, scs.get_aead_alg());
let iv = derive_traffic_iv(secret);

Box::new(TLS13MessageDecrypter::new(key, iv))
}

pub fn new_tls13_write(scs: &'static SupportedCipherSuite,
secret: &[u8]) -> Box<dyn MessageEncrypter> {
let secret = hkdf::Prk::new_less_safe(scs.hkdf_algorithm, secret);
let key = derive_traffic_key(&secret, scs.get_aead_alg());
let iv = derive_traffic_iv(&secret);
secret: &hkdf::Prk) -> Box<dyn MessageEncrypter> {
let key = derive_traffic_key(secret, scs.get_aead_alg());
let iv = derive_traffic_iv(secret);

Box::new(TLS13MessageEncrypter::new(key, iv))
}
Expand Down
9 changes: 4 additions & 5 deletions src/client/hs.rs
Expand Up @@ -330,15 +330,14 @@ fn emit_client_hello_for_retry(sess: &mut ClientSessionImpl,
let client_hello_hash = handshake.transcript.get_hash_given(resuming_suite.get_hash(), &[]);
let client_early_traffic_secret = sess.common
.get_key_schedule()
.derive_bytes(SecretKind::ClientEarlyTrafficSecret, &client_hello_hash);
.derive_logged_secret(SecretKind::ClientEarlyTrafficSecret, &client_hello_hash,
&*sess.config.key_log,
sess.common.protocol.labels().client_early_traffic_secret,
&handshake.randoms.client);
// Set early data encryption key
sess.common
.set_message_encrypter(cipher::new_tls13_write(resuming_suite, &client_early_traffic_secret));

sess.config.key_log.log(sess.common.protocol.labels().client_early_traffic_secret,
&handshake.randoms.client,
&client_early_traffic_secret);

#[cfg(feature = "quic")]
{
sess.common.quic.early_secret = Some(client_early_traffic_secret);
Expand Down
99 changes: 53 additions & 46 deletions src/client/tls13.rs
Expand Up @@ -211,37 +211,38 @@ pub fn start_handshake_traffic(sess: &mut ClientSessionImpl,
if !sess.early_data.is_enabled() {
// Set the client encryption key for handshakes if early data is not used
let write_key = sess.common.get_key_schedule()
.derive_bytes(SecretKind::ClientHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello);
.derive_logged_secret(SecretKind::ClientHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello,
&*sess.config.key_log,
sess.common.protocol.labels().client_handshake_traffic_secret,
&handshake.randoms.client);
sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key));
sess.config.key_log.log(sess.common.protocol.labels().client_handshake_traffic_secret,
&handshake.randoms.client,
&write_key);
sess.common.get_mut_key_schedule().current_client_traffic_secret = write_key;
sess.common.get_mut_key_schedule().current_client_traffic_secret = Some(write_key);
}

let read_key = sess.common.get_key_schedule()
.derive_bytes(SecretKind::ServerHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello);
.derive_logged_secret(SecretKind::ServerHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello,
&*sess.config.key_log,
sess.common.protocol.labels().server_handshake_traffic_secret,
&handshake.randoms.client);
sess.common.set_message_decrypter(cipher::new_tls13_read(suite, &read_key));
sess.config.key_log.log(sess.common.protocol.labels().server_handshake_traffic_secret,
&handshake.randoms.client,
&read_key);
sess.common.get_mut_key_schedule().current_server_traffic_secret = read_key;
sess.common.get_mut_key_schedule().current_server_traffic_secret = Some(read_key);

#[cfg(feature = "quic")] {
let key_schedule = sess.common.key_schedule.as_ref().unwrap();
let client = if sess.early_data.is_enabled() {
// Traffic secret wasn't computed and stored above, so do it here.
sess.common.get_key_schedule()
.derive_bytes(SecretKind::ClientHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello)
sess.common.get_key_schedule().derive(
sess.common.get_key_schedule().algorithm(),
SecretKind::ClientHandshakeTrafficSecret,
&handshake.hash_at_client_recvd_server_hello)
} else {
key_schedule.current_client_traffic_secret.clone()
key_schedule.current_client_traffic_secret.clone().unwrap()
};
sess.common.quic.hs_secrets = Some(quic::Secrets {
client,
server: key_schedule.current_server_traffic_secret.clone(),
server: key_schedule.current_server_traffic_secret.clone().unwrap(),
});
}

Expand Down Expand Up @@ -399,14 +400,15 @@ impl hs::State for ExpectEncryptedExtensions {
// If no early traffic, set the encryption key for handshakes
let suite = sess.common.get_suite_assert();
let write_key = sess.common.get_key_schedule()
.derive_bytes(SecretKind::ClientHandshakeTrafficSecret,
&self.handshake.hash_at_client_recvd_server_hello);
.derive_logged_secret(
SecretKind::ClientHandshakeTrafficSecret,
&self.handshake.hash_at_client_recvd_server_hello,
&*sess.config.key_log,
sess.common.protocol.labels().client_handshake_traffic_secret,
&self.handshake.randoms.client);
sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key));
sess.config.key_log.log(sess.common.protocol.labels().client_handshake_traffic_secret,
&self.handshake.randoms.client,
&write_key);
sess.common.get_mut_key_schedule()
.current_client_traffic_secret = write_key;
.current_client_traffic_secret = Some(write_key);
}
let certv = verify::ServerCertVerified::assertion();
let sigv = verify::HandshakeSignatureValid::assertion();
Expand Down Expand Up @@ -826,8 +828,12 @@ impl hs::State for ExpectFinished {
/* Derive the client-to-server encryption key before key schedule update */
let key = sess.common
.get_key_schedule()
.derive_bytes(SecretKind::ClientHandshakeTrafficSecret,
&st.handshake.hash_at_client_recvd_server_hello);
.derive_logged_secret(
SecretKind::ClientHandshakeTrafficSecret,
&st.handshake.hash_at_client_recvd_server_hello,
&*sess.config.key_log,
sess.common.protocol.labels().client_handshake_traffic_secret,
&st.handshake.randoms.client);
Some(key)
} else {
None
Expand All @@ -842,24 +848,27 @@ impl hs::State for ExpectFinished {
let handshake_hash = st.handshake.transcript.get_current_hash();
let read_key = sess.common
.get_key_schedule()
.derive_bytes(SecretKind::ServerApplicationTrafficSecret, &handshake_hash);
sess.config.key_log.log(sess.common.protocol.labels().server_traffic_secret_0,
&st.handshake.randoms.client,
&read_key);
.derive_logged_secret(
SecretKind::ServerApplicationTrafficSecret,
&handshake_hash,
&*sess.config.key_log,
sess.common.protocol.labels().server_traffic_secret_0,
&st.handshake.randoms.client);
sess.common.set_message_decrypter(cipher::new_tls13_read(suite, &read_key));
sess.common
.get_mut_key_schedule()
.current_server_traffic_secret = read_key;
.current_server_traffic_secret = Some(read_key);

let exporter_secret = sess.common
.get_key_schedule()
.derive_bytes(SecretKind::ExporterMasterSecret, &handshake_hash);
sess.config.key_log.log(sess.common.protocol.labels().exporter_secret,
&st.handshake.randoms.client,
&exporter_secret);
.derive_logged_secret(SecretKind::ExporterMasterSecret,
&handshake_hash,
&*sess.config.key_log,
sess.common.protocol.labels().exporter_secret,
&st.handshake.randoms.client);
sess.common
.get_mut_key_schedule()
.current_exporter_secret = exporter_secret;
.current_exporter_secret = Some(exporter_secret);

/* The EndOfEarlyData message to server is still encrypted with early data keys,
* but appears in the transcript after the server Finished. */
Expand All @@ -868,10 +877,7 @@ impl hs::State for ExpectFinished {
sess.common.early_traffic = false;
sess.early_data.finished();
sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key));
sess.config.key_log.log(sess.common.protocol.labels().client_handshake_traffic_secret,
&st.handshake.randoms.client,
&write_key);
sess.common.get_mut_key_schedule().current_client_traffic_secret = write_key;
sess.common.get_mut_key_schedule().current_client_traffic_secret = Some(write_key);
}

/* Send our authentication/finished messages. These are still encrypted
Expand All @@ -891,14 +897,15 @@ impl hs::State for ExpectFinished {
hs::check_aligned_handshake(sess)?;
let write_key = sess.common
.get_key_schedule()
.derive_bytes(SecretKind::ClientApplicationTrafficSecret, &handshake_hash);
sess.config.key_log.log(sess.common.protocol.labels().client_traffic_secret_0,
&st.handshake.randoms.client,
&write_key);
.derive_logged_secret(SecretKind::ClientApplicationTrafficSecret,
&handshake_hash,
&*sess.config.key_log,
sess.common.protocol.labels().client_traffic_secret_0,
&st.handshake.randoms.client);
sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key));
sess.common
.get_mut_key_schedule()
.current_client_traffic_secret = write_key;
.current_client_traffic_secret = Some(write_key);

sess.common.we_now_encrypting();
sess.common.start_traffic();
Expand All @@ -908,8 +915,8 @@ impl hs::State for ExpectFinished {
if sess.common.protocol == Protocol::Quic {
let key_schedule = sess.common.key_schedule.as_ref().unwrap();
sess.common.quic.traffic_secrets = Some(quic::Secrets {
client: key_schedule.current_client_traffic_secret.clone(),
server: key_schedule.current_server_traffic_secret.clone(),
client: key_schedule.current_client_traffic_secret.clone().unwrap(),
server: key_schedule.current_server_traffic_secret.clone().unwrap(),
});
return Ok(Box::new(ExpectQUICTraffic(st)));
}
Expand Down
86 changes: 37 additions & 49 deletions src/key_schedule.rs
Expand Up @@ -4,6 +4,7 @@ use ring::{aead, hkdf::{self, KeyType as _}, hmac, digest};
use crate::error::TLSError;
use crate::cipher::{Iv, IvLen};
use crate::msgs::base::PayloadU8;
use crate::KeyLog;

/// The kinds of secret we can extract from `KeySchedule`.
#[derive(Debug, Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -41,9 +42,9 @@ impl SecretKind {
pub struct KeySchedule {
current: hkdf::Prk,
algorithm: ring::hkdf::Algorithm,
pub current_client_traffic_secret: Vec<u8>,
pub current_server_traffic_secret: Vec<u8>,
pub current_exporter_secret: Vec<u8>,
pub current_client_traffic_secret: Option<hkdf::Prk>,
pub current_server_traffic_secret: Option<hkdf::Prk>,
pub current_exporter_secret: Option<hkdf::Prk>,
}

impl KeySchedule {
Expand All @@ -54,9 +55,9 @@ impl KeySchedule {
KeySchedule {
current: salt.extract(secret),
algorithm,
current_server_traffic_secret: Vec::new(),
current_client_traffic_secret: Vec::new(),
current_exporter_secret: Vec::new(),
current_server_traffic_secret: None,
current_client_traffic_secret: None,
current_exporter_secret: None,
}
}

Expand Down Expand Up @@ -89,10 +90,16 @@ impl KeySchedule {
hkdf_expand(&self.current, key_type, kind.to_bytes(), hs_hash)
}

pub fn derive_bytes(&self, kind: SecretKind, hs_hash: &[u8]) -> Vec<u8> {
let payload: PayloadU8 =
self.derive(PayloadU8Len(self.algorithm.len()), kind, hs_hash);
payload.into_inner()
pub fn derive_logged_secret(&self, kind: SecretKind, hs_hash: &[u8],
key_log: &dyn KeyLog, log_label: &str, client_random: &[u8; 32])
-> hkdf::Prk
{
if key_log.will_log(log_label) {
let secret = self.derive::<PayloadU8, _>(PayloadU8Len(self.algorithm.len()), kind, hs_hash)
.into_inner();
key_log.log(log_label, client_random, &secret);
}
self.derive(self.algorithm, kind, hs_hash)
}

/// Derive a secret of given `kind` using the hash of the empty string
Expand All @@ -109,13 +116,15 @@ impl KeySchedule {
}

/// Return the current traffic secret, of given `kind`.
fn current_traffic_secret(&self, kind: SecretKind) -> &[u8] {
fn current_traffic_secret(&self, kind: SecretKind) -> &hkdf::Prk {
match kind {
SecretKind::ServerHandshakeTrafficSecret |
SecretKind::ServerApplicationTrafficSecret => &self.current_server_traffic_secret,
SecretKind::ServerApplicationTrafficSecret =>
&self.current_server_traffic_secret.as_ref().unwrap(),
SecretKind::ClientEarlyTrafficSecret |
SecretKind::ClientHandshakeTrafficSecret |
SecretKind::ClientApplicationTrafficSecret => &self.current_client_traffic_secret,
SecretKind::ClientApplicationTrafficSecret =>
&self.current_client_traffic_secret.as_ref().unwrap(),
_ => unreachable!(),
}
}
Expand All @@ -124,8 +133,7 @@ impl KeySchedule {
/// traffic secret.
pub fn sign_finish(&self, kind: SecretKind, hs_hash: &[u8]) -> Vec<u8> {
let base_key = self.current_traffic_secret(kind);
let base_key = hkdf::Prk::new_less_safe(self.algorithm, base_key);
self.sign_verify_data(&base_key, hs_hash)
self.sign_verify_data(base_key, hs_hash)
}

/// Sign the finished message consisting of `hs_hash` using the key material
Expand All @@ -140,12 +148,9 @@ impl KeySchedule {

/// Derive the next application traffic secret of given `kind`, returning
/// it.
pub fn derive_next(&self, kind: SecretKind) -> Vec<u8> {
pub fn derive_next(&self, kind: SecretKind) -> hkdf::Prk {
let base_key = self.current_traffic_secret(kind);
let base_key = hkdf::Prk::new_less_safe(self.algorithm, &base_key);
let payload: PayloadU8 =
hkdf_expand(&base_key, PayloadU8Len(self.algorithm.len()), b"traffic upd", &[]);
payload.into_inner()
hkdf_expand(&base_key, self.algorithm, b"traffic upd", &[])
}

/// Derive the PSK to use given a resumption_master_secret and
Expand All @@ -158,17 +163,13 @@ impl KeySchedule {
pub fn export_keying_material(&self, out: &mut [u8],
label: &[u8],
context: Option<&[u8]>) -> Result<(), TLSError> {
if self.current_exporter_secret.is_empty() {
return Err(TLSError::HandshakeNotComplete);
}

let current_exporter_secret =
self.current_exporter_secret.as_ref().ok_or(TLSError::HandshakeNotComplete)?;
let digest_alg = self.algorithm.hmac_algorithm().digest_algorithm();

let h_empty = digest::digest(digest_alg, &[]);
let current_exporter_secret =
hkdf::Prk::new_less_safe(self.algorithm, &self.current_exporter_secret);
let secret: hkdf::Prk =
hkdf_expand(&current_exporter_secret, self.algorithm, label, h_empty.as_ref());
hkdf_expand(current_exporter_secret, self.algorithm, label, h_empty.as_ref());

let h_context = digest::digest(digest_alg, context.unwrap_or(&[]));

Expand Down Expand Up @@ -232,25 +233,7 @@ pub(crate) fn derive_traffic_iv(secret: &hkdf::Prk) -> Iv {
mod test {
use super::{KeySchedule, SecretKind, derive_traffic_key, derive_traffic_iv};
use ring::{aead, hkdf};

#[test]
fn smoke_test() {
let fake_handshake_hash = [0u8; 32];

let mut ks = KeySchedule::new_with_empty_secret(hkdf::HKDF_SHA256);
ks.derive_bytes(SecretKind::ResumptionPSKBinderKey, &fake_handshake_hash);
ks.input_secret(&[1u8, 2u8, 3u8, 4u8]);
ks.derive_bytes(SecretKind::ClientHandshakeTrafficSecret,
&fake_handshake_hash);
ks.derive_bytes(SecretKind::ServerHandshakeTrafficSecret,
&fake_handshake_hash);
ks.input_empty();
ks.derive_bytes(SecretKind::ClientApplicationTrafficSecret,
&fake_handshake_hash);
ks.derive_bytes(SecretKind::ServerApplicationTrafficSecret,
&fake_handshake_hash);
ks.derive_bytes(SecretKind::ResumptionMasterSecret, &fake_handshake_hash);
}
use crate::KeyLog;

#[test]
fn test_vectors() {
Expand Down Expand Up @@ -380,9 +363,14 @@ mod test {
expected_key: &[u8],
expected_iv: &[u8],
) {
let traffic_secret = ks.derive_bytes(kind, &hash);
assert_eq!(expected_traffic_secret, &traffic_secret[..]);
let traffic_secret = hkdf::Prk::new_less_safe(ks.algorithm(), &traffic_secret);
struct Log<'a>(&'a [u8]);
impl KeyLog for Log<'_> {
fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) {
assert_eq!(self.0, secret);
}
}
let log = Log(expected_traffic_secret);
let traffic_secret = ks.derive_logged_secret(kind, &hash, &log, "", &[0; 32]);

// Since we can't test key equality, we test the output of sealing with the key instead.
let aead_alg = &aead::AES_128_GCM;
Expand Down

0 comments on commit 20499a6

Please sign in to comment.