Skip to content

Commit

Permalink
Update for draft 19 key schedule changes
Browse files Browse the repository at this point in the history
This includes extra tests generated with openssl, having
fixed a bug there.
  • Loading branch information
ctz committed Mar 19, 2017
1 parent b993d00 commit bc262d3
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 29 deletions.
10 changes: 5 additions & 5 deletions src/cipher.rs
Expand Up @@ -8,7 +8,7 @@ use msgs::fragmenter::MAX_FRAGMENT_LEN;
use error::TLSError;
use session::SessionSecrets;
use suites::{SupportedCipherSuite, BulkAlgorithm};
use key_schedule::hkdf_expand_label;
use key_schedule::{derive_traffic_key, derive_traffic_iv};

// accum[i] ^= offset[i] for all i in 0..len(accum)
fn xor(accum: &mut [u8], offset: &[u8]) {
Expand Down Expand Up @@ -113,8 +113,8 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite,
pub fn new_tls13_read(scs: &'static SupportedCipherSuite,
secret: &[u8]) -> Box<MessageDecrypter> {
let hash = scs.get_hash();
let key = hkdf_expand_label(hash, secret, b"key", &[], scs.enc_key_len as u16);
let iv = hkdf_expand_label(hash, secret, b"iv", &[], scs.fixed_iv_len as u16);
let key = derive_traffic_key(hash, secret, scs.enc_key_len);
let iv = derive_traffic_iv(hash, secret, scs.fixed_iv_len);
let aead_alg = scs.get_aead_alg();

Box::new(TLS13MessageDecrypter::new(aead_alg, &key, &iv))
Expand All @@ -123,8 +123,8 @@ pub fn new_tls13_read(scs: &'static SupportedCipherSuite,
pub fn new_tls13_write(scs: &'static SupportedCipherSuite,
secret: &[u8]) -> Box<MessageEncrypter> {
let hash = scs.get_hash();
let key = hkdf_expand_label(hash, secret, b"key", &[], scs.enc_key_len as u16);
let iv = hkdf_expand_label(hash, secret, b"iv", &[], scs.fixed_iv_len as u16);
let key = derive_traffic_key(hash, secret, scs.enc_key_len);
let iv = derive_traffic_iv(hash, secret, scs.fixed_iv_len);
let aead_alg = scs.get_aead_alg();

Box::new(TLS13MessageEncrypter::new(aead_alg, &key, &iv))
Expand Down
180 changes: 162 additions & 18 deletions src/key_schedule.rs
Expand Up @@ -12,6 +12,7 @@ pub enum SecretKind {
ClientApplicationTrafficSecret,
ServerApplicationTrafficSecret,
ResumptionMasterSecret,
DerivedSecret,
}

impl SecretKind {
Expand All @@ -23,6 +24,7 @@ impl SecretKind {
SecretKind::ClientApplicationTrafficSecret => b"client application traffic secret",
SecretKind::ServerApplicationTrafficSecret => b"server application traffic secret",
SecretKind::ResumptionMasterSecret => b"resumption master secret",
SecretKind::DerivedSecret => b"derived secret",
}
}
}
Expand All @@ -32,22 +34,35 @@ impl SecretKind {
/// own lineage of keys over successive key updates.
pub struct KeySchedule {
current: hmac::SigningKey,
need_derive_for_extract: bool,
hash: &'static digest::Algorithm,
hash_of_empty_message: [u8; digest::MAX_OUTPUT_LEN],
pub current_client_traffic_secret: Vec<u8>,
pub current_server_traffic_secret: Vec<u8>,
}

impl KeySchedule {
pub fn new(hash: &'static digest::Algorithm) -> KeySchedule {
let zeroes = [0u8; digest::MAX_OUTPUT_LEN];

let mut empty_hash = [0u8; digest::MAX_OUTPUT_LEN];
empty_hash[..hash.output_len]
.clone_from_slice(digest::digest(hash, &[]).as_ref());

KeySchedule {
current: hmac::SigningKey::new(hash, &zeroes[..hash.output_len]),
need_derive_for_extract: false,
hash: hash,
hash_of_empty_message: empty_hash,
current_server_traffic_secret: Vec::new(),
current_client_traffic_secret: Vec::new(),
}
}

pub fn get_hash_of_empty_message(&self) -> &[u8] {
&self.hash_of_empty_message[..self.hash.output_len]
}

/// Input the empty secret.
pub fn input_empty(&mut self) {
let zeroes = [0u8; digest::MAX_OUTPUT_LEN];
Expand All @@ -57,6 +72,12 @@ impl KeySchedule {

/// Input the given secret.
pub fn input_secret(&mut self, secret: &[u8]) {
if self.need_derive_for_extract {
let derived = self.derive(SecretKind::DerivedSecret,
self.get_hash_of_empty_message());
self.current = hmac::SigningKey::new(self.hash, &derived);
}
self.need_derive_for_extract = true;
let new = hkdf::extract(&self.current, secret);
self.current = new
}
Expand Down Expand Up @@ -94,11 +115,10 @@ impl KeySchedule {
pub fn sign_verify_data(&self, base_key: &[u8], hs_hash: &[u8]) -> Vec<u8> {
debug_assert!(hs_hash.len() == self.hash.output_len);

let hmac_key = hkdf_expand_label(self.hash,
base_key,
b"finished",
&[],
self.hash.output_len as u16);
let hmac_key = _hkdf_expand_label(&hmac::SigningKey::new(self.hash, base_key),
b"finished",
&[],
self.hash.output_len as u16);

hmac::sign(&hmac::SigningKey::new(self.hash, &hmac_key), hs_hash)
.as_ref()
Expand All @@ -109,11 +129,10 @@ impl KeySchedule {
/// it.
pub fn derive_next(&self, kind: SecretKind) -> Vec<u8> {
let base_key = self.current_traffic_secret(kind);
hkdf_expand_label(self.hash,
base_key,
b"application traffic secret",
&[],
self.hash.output_len as u16)
_hkdf_expand_label(&hmac::SigningKey::new(self.hash, base_key),
b"application traffic secret",
&[],
self.hash.output_len as u16)
}
}

Expand All @@ -139,18 +158,17 @@ fn _hkdf_expand_label(secret: &hmac::SigningKey,
out
}

pub fn hkdf_expand_label(hash: &'static digest::Algorithm,
secret: &[u8],
label: &[u8],
context: &[u8],
len: u16)
-> Vec<u8> {
_hkdf_expand_label(&hmac::SigningKey::new(hash, secret), label, context, len)
pub fn derive_traffic_key(hash: &'static digest::Algorithm, secret: &[u8], len: usize) -> Vec<u8> {
_hkdf_expand_label(&hmac::SigningKey::new(hash, secret), b"key", &[], len as u16)
}

pub fn derive_traffic_iv(hash: &'static digest::Algorithm, secret: &[u8], len: usize) -> Vec<u8> {
_hkdf_expand_label(&hmac::SigningKey::new(hash, secret), b"iv", &[], len as u16)
}

#[cfg(test)]
mod test {
use super::{KeySchedule, SecretKind};
use super::{KeySchedule, SecretKind, derive_traffic_key, derive_traffic_iv};
use ring::digest;

#[test]
Expand All @@ -172,4 +190,130 @@ mod test {
&fake_handshake_hash);
ks.derive(SecretKind::ResumptionMasterSecret, &fake_handshake_hash);
}

#[test]
fn test_vectors() {
/* These test vectors generated with OpenSSL. */
let hs_start_hash = [
0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e,
0x41, 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74,
0x82, 0xaf, 0x75, 0x88, 0x1c, 0x0a
];

let hs_full_hash = [
0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91,
0x8e, 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30,
0xac, 0x30, 0xbb, 0xeb, 0x23, 0xe2
];

let ecdhe_secret = [
0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6,
0x9d, 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15,
0xe3, 0x12, 0x71, 0xdf, 0x4b, 0x40
];

let client_hts = [
0xd7, 0x58, 0x9f, 0x10, 0xa8, 0x30, 0xf3, 0x85, 0x63, 0x6f, 0xd9, 0xb0, 0x61,
0xd5, 0x20, 0x19, 0xb1, 0x45, 0x96, 0x82, 0x24, 0x8e, 0x36, 0x45, 0xf7, 0x5a,
0xd7, 0x2f, 0x31, 0xec, 0x57, 0xf7
];

let client_hts_key = [
0xcc, 0x8b, 0xda, 0xbf, 0x83, 0x74, 0x2d, 0xf4, 0x53, 0x44, 0xff, 0xbc, 0xa4,
0x43, 0xc8, 0x2a
];

let client_hts_iv = [
0xa4, 0x83, 0x46, 0x11, 0xc2, 0x78, 0xea, 0x0f, 0x94, 0x52, 0x1d, 0xca
];

let server_hts = [
0xba, 0x7c, 0x3b, 0x74, 0x0d, 0x1e, 0x84, 0x82, 0xd6, 0x6f, 0x3e, 0x5e, 0x1d,
0x6e, 0x25, 0xdc, 0x87, 0x1f, 0x48, 0x74, 0x2f, 0x65, 0xa4, 0x40, 0x39, 0xda,
0xdc, 0x02, 0x2a, 0x16, 0x19, 0x5c
];

let server_hts_key = [
0x7d, 0x22, 0x2a, 0x3f, 0x72, 0x37, 0x92, 0xd9, 0x95, 0x9a, 0xe1, 0x66, 0x32,
0x6f, 0x0d, 0xc9
];

let server_hts_iv = [
0xa2, 0x73, 0xcd, 0x4e, 0x20, 0xe7, 0xe1, 0xe3, 0xcb, 0x0e, 0x18, 0x9e
];

let client_ats = [
0xc3, 0x60, 0x5f, 0xb3, 0xc4, 0x4b, 0xc2, 0x25, 0xd2, 0xaf, 0x36, 0xad, 0x99,
0xa1, 0xcd, 0xcf, 0x71, 0xc4, 0xb9, 0xa2, 0x3d, 0xd2, 0x3e, 0xe6, 0xff, 0xca,
0x2c, 0x71, 0x86, 0x3d, 0x1f, 0x85
];

let client_ats_key = [
0x3a, 0x25, 0x23, 0x12, 0xde, 0x0f, 0x53, 0xc7, 0xa0, 0xb2, 0xcf, 0x71, 0xb7,
0x1a, 0x0d, 0xc7
];

let client_ats_iv = [
0xbd, 0x0d, 0x3c, 0x26, 0x9d, 0x2d, 0xa6, 0x52, 0x1b, 0x8d, 0x45, 0xef
];

let server_ats = [
0x27, 0x8d, 0x96, 0x76, 0x95, 0x9e, 0x3e, 0x39, 0xa4, 0xa9, 0xfc, 0x46, 0x9c,
0x32, 0x9f, 0xe0, 0x29, 0x50, 0x22, 0x45, 0x39, 0x82, 0xdd, 0x1c, 0xc5, 0xfb,
0xa9, 0x0a, 0x68, 0x29, 0x4e, 0x80
];

let server_ats_key = [
0x78, 0xbd, 0xd7, 0xc6, 0xb0, 0xf1, 0x50, 0x5e, 0xae, 0x54, 0xff, 0xa5, 0xf2,
0xed, 0x0b, 0x77
];

let server_ats_iv = [
0xb1, 0x7b, 0x1c, 0xa2, 0xca, 0xbe, 0xe4, 0xac, 0xb5, 0xf3, 0x91, 0x7e
];

let hash = &digest::SHA256;
let mut ks = KeySchedule::new(hash);
ks.input_empty();
ks.input_secret(&ecdhe_secret);

let got_client_hts = ks.derive(SecretKind::ClientHandshakeTrafficSecret,
&hs_start_hash);
assert_eq!(got_client_hts,
client_hts.to_vec());
assert_eq!(derive_traffic_key(hash, &got_client_hts, client_hts_key.len()),
client_hts_key.to_vec());
assert_eq!(derive_traffic_iv(hash, &got_client_hts, client_hts_iv.len()),
client_hts_iv.to_vec());

let got_server_hts = ks.derive(SecretKind::ServerHandshakeTrafficSecret,
&hs_start_hash);
assert_eq!(got_server_hts,
server_hts.to_vec());
assert_eq!(derive_traffic_key(hash, &got_server_hts, server_hts_key.len()),
server_hts_key.to_vec());
assert_eq!(derive_traffic_iv(hash, &got_server_hts, server_hts_iv.len()),
server_hts_iv.to_vec());

ks.input_empty();

let got_client_ats = ks.derive(SecretKind::ClientApplicationTrafficSecret,
&hs_full_hash);
assert_eq!(got_client_ats,
client_ats.to_vec());
assert_eq!(derive_traffic_key(hash, &got_client_ats, client_ats_key.len()),
client_ats_key.to_vec());
assert_eq!(derive_traffic_iv(hash, &got_client_ats, client_ats_iv.len()),
client_ats_iv.to_vec());

let got_server_ats = ks.derive(SecretKind::ServerApplicationTrafficSecret,
&hs_full_hash);
assert_eq!(got_server_ats,
server_ats.to_vec());
assert_eq!(derive_traffic_key(hash, &got_server_ats, server_ats_key.len()),
server_ats_key.to_vec());
assert_eq!(derive_traffic_iv(hash, &got_server_ats, server_ats_iv.len()),
server_ats_iv.to_vec());

}
}
8 changes: 2 additions & 6 deletions src/server_hs.rs
Expand Up @@ -25,7 +25,6 @@ use cipher;
use server::ServerSessionImpl;
use key_schedule::{KeySchedule, SecretKind};
use suites;
use hash_hs;
use sign;
use ring;
use verify;
Expand Down Expand Up @@ -572,13 +571,10 @@ fn check_binder(sess: &mut ServerSessionImpl,
let handshake_hash =
sess.handshake_data.transcript.get_hash_given(suite_hash, &binder_plaintext);

let mut empty_hash_ctx = hash_hs::HandshakeHash::new();
empty_hash_ctx.start_hash(suite_hash);
let empty_hash = empty_hash_ctx.get_current_hash();

let mut key_schedule = KeySchedule::new(suite_hash);
key_schedule.input_secret(psk);
let base_key = key_schedule.derive(SecretKind::ResumptionPSKBinderKey, &empty_hash);
let base_key = key_schedule.derive(SecretKind::ResumptionPSKBinderKey,
key_schedule.get_hash_of_empty_message());
let real_binder = key_schedule.sign_verify_data(&base_key, &handshake_hash);

ring::constant_time::verify_slices_are_equal(&real_binder, binder).is_ok()
Expand Down

0 comments on commit bc262d3

Please sign in to comment.