diff --git a/README.md b/README.md index bd07022a6c..fe0fada562 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ obsolete cryptography. ## Current features -* TLS1.2 and TLS1.3 (draft 18) only. +* TLS1.2 and TLS1.3 (draft 20) only. * ECDSA or RSA server authentication by clients. * RSA server authentication by servers. * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. diff --git a/src/cipher.rs b/src/cipher.rs index 783f5e6dd6..5ed70975cf 100644 --- a/src/cipher.rs +++ b/src/cipher.rs @@ -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]) { @@ -113,8 +113,8 @@ pub fn new_tls12(scs: &'static SupportedCipherSuite, pub fn new_tls13_read(scs: &'static SupportedCipherSuite, secret: &[u8]) -> Box { 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)) @@ -123,8 +123,8 @@ pub fn new_tls13_read(scs: &'static SupportedCipherSuite, pub fn new_tls13_write(scs: &'static SupportedCipherSuite, secret: &[u8]) -> Box { 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)) diff --git a/src/client_hs.rs b/src/client_hs.rs index 3475ebf42f..cd4aab1171 100644 --- a/src/client_hs.rs +++ b/src/client_hs.rs @@ -32,8 +32,8 @@ use handshake::Expectation; use std::mem; -// draft-ietf-tls-tls13-18 -const TLS13_DRAFT: u16 = 0x7f12; +// draft-ietf-tls-tls13-20 +const TLS13_DRAFT: u16 = 0x7f14; macro_rules! extract_handshake( ( $m:expr, $t:path ) => ( @@ -615,7 +615,6 @@ pub static EXPECT_SERVER_HELLO: State = State { fn handle_hello_retry_request(sess: &mut ClientSessionImpl, m: Message) -> StateResult { let hrr = extract_handshake!(m, HandshakePayload::HelloRetryRequest).unwrap(); - sess.handshake_data.transcript.add_message(&m); debug!("Got HRR {:?}", hrr); let has_cookie = hrr.get_cookie().is_some(); @@ -665,6 +664,20 @@ fn handle_hello_retry_request(sess: &mut ClientSessionImpl, } } + // Or asks us to use a ciphersuite we didn't offer. + let maybe_cs = sess.find_cipher_suite(hrr.cipher_suite); + let cs = match maybe_cs { + Some(cs) => cs, + None => { + return Err(illegal_param(sess, "server requested unsupported cs in hrr")); + } + }; + + // This is the draft19 change where the transcript became a tree + sess.handshake_data.transcript.start_hash(cs.get_hash()); + sess.handshake_data.transcript.rollup_for_hrr(); + sess.handshake_data.transcript.add_message(&m); + Ok(emit_client_hello_for_retry(sess, Some(hrr))) } @@ -1019,7 +1032,9 @@ fn handle_certificate_req_tls13(sess: &mut ClientSessionImpl, } let tls13_sign_schemes = SupportedSignatureSchemes::supported_sign_tls13(); - let compat_sigschemes = certreq.sigschemes + let no_sigschemes = Vec::new(); + let compat_sigschemes = certreq.get_sigalgs_extension() + .unwrap_or(&no_sigschemes) .iter() .cloned() .filter(|scheme| tls13_sign_schemes.contains(scheme)) @@ -1030,7 +1045,9 @@ fn handle_certificate_req_tls13(sess: &mut ClientSessionImpl, return Err(TLSError::PeerIncompatibleError("server sent bad certreq schemes".to_string())); } - let canames = certreq.canames + let no_canames = Vec::new(); + let canames = certreq.get_authorities_extension() + .unwrap_or(&no_canames) .iter() .map(|p| p.0.as_slice()) .collect::>(); diff --git a/src/hash_hs.rs b/src/hash_hs.rs index 8d4c6e370b..cc3bb3e55b 100644 --- a/src/hash_hs.rs +++ b/src/hash_hs.rs @@ -2,6 +2,7 @@ use ring::digest; use std::mem; use msgs::codec::Codec; use msgs::message::{Message, MessagePayload}; +use msgs::handshake::HandshakeMessagePayload; /// This deals with keeping a running hash of the handshake /// payloads. This is computed by buffering initially. Once @@ -128,6 +129,17 @@ impl HandshakeHash { ret } + /// Take the current hash value, and encapsulate it in a + /// 'handshake_hash' handshake message. Start this hash + /// again, with that message at the front. + pub fn rollup_for_hrr(&mut self) { + let old_hash = self.ctx.take().unwrap().finish(); + let old_handshake_hash_msg = HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); + + self.ctx = Some(digest::Context::new(self.alg.unwrap())); + self.update_raw(&old_handshake_hash_msg.get_encoding()); + } + /// Get the current hash value. pub fn get_current_hash(&self) -> Vec { let hash = self.ctx.as_ref().unwrap().clone().finish(); diff --git a/src/key_schedule.rs b/src/key_schedule.rs index 15122227a4..d671ea60c3 100644 --- a/src/key_schedule.rs +++ b/src/key_schedule.rs @@ -12,17 +12,19 @@ pub enum SecretKind { ClientApplicationTrafficSecret, ServerApplicationTrafficSecret, ResumptionMasterSecret, + DerivedSecret, } impl SecretKind { fn to_bytes(&self) -> &'static [u8] { match *self { - SecretKind::ResumptionPSKBinderKey => b"resumption psk binder key", - SecretKind::ClientHandshakeTrafficSecret => b"client handshake traffic secret", - SecretKind::ServerHandshakeTrafficSecret => b"server handshake traffic secret", - SecretKind::ClientApplicationTrafficSecret => b"client application traffic secret", - SecretKind::ServerApplicationTrafficSecret => b"server application traffic secret", - SecretKind::ResumptionMasterSecret => b"resumption master secret", + SecretKind::ResumptionPSKBinderKey => b"res binder", + SecretKind::ClientHandshakeTrafficSecret => b"c hs traffic", + SecretKind::ServerHandshakeTrafficSecret => b"s hs traffic", + SecretKind::ClientApplicationTrafficSecret => b"c ap traffic", + SecretKind::ServerApplicationTrafficSecret => b"s ap traffic", + SecretKind::ResumptionMasterSecret => b"res master", + SecretKind::DerivedSecret => b"derived", } } } @@ -32,7 +34,9 @@ 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, pub current_server_traffic_secret: Vec, } @@ -40,14 +44,25 @@ pub struct KeySchedule { 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]; @@ -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 } @@ -94,11 +115,10 @@ impl KeySchedule { pub fn sign_verify_data(&self, base_key: &[u8], hs_hash: &[u8]) -> Vec { 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() @@ -109,11 +129,10 @@ impl KeySchedule { /// it. pub fn derive_next(&self, kind: SecretKind) -> Vec { 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"traffic upd", + &[], + self.hash.output_len as u16) } } @@ -125,7 +144,7 @@ fn _hkdf_expand_label(secret: &hmac::SigningKey, let mut out = Vec::new(); out.resize(len as usize, 0u8); - let label_prefix = b"TLS 1.3, "; + let label_prefix = b"tls13 "; let mut hkdflabel = Vec::new(); codec::encode_u16(out.len() as u16, &mut hkdflabel); @@ -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 { - _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 { + _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 { + _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] @@ -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 = [ + 0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, + 0x66, 0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, + 0x04, 0x01, 0x35, 0xcf, 0x46, 0xab + ]; + + let client_hts_key = [ + 0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, + 0x95, 0x85, 0xa7 + ]; + + let client_hts_iv = [ + 0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9 + ]; + + let server_hts = [ + 0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, + 0x4e, 0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, + 0xdd, 0xcf, 0x29, 0xa8, 0x87, 0x59 + ]; + + let server_hts_key = [ + 0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, + 0xbc, 0xbc, 0x54 + ]; + + let server_hts_iv = [ + 0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09 + ]; + + let client_ats = [ + 0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, + 0x3f, 0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, + 0x71, 0xa8, 0x20, 0x6d, 0xbd, 0xa5 + ]; + + let client_ats_key = [ + 0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, + 0xd7, 0x57, 0x2e + ]; + + let client_ats_iv = [ + 0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b + ]; + + let server_ats = [ + 0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, + 0x48, 0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, + 0x29, 0x0d, 0x4c, 0x23, 0x21, 0x92 + ]; + + let server_ats_key = [ + 0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, + 0xe6, 0x2b, 0xb3 + ]; + + let server_ats_iv = [ + 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c + ]; + + 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()); + + } } diff --git a/src/lib.rs b/src/lib.rs index 862dc3e011..e527b5f256 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ //! //! ## Current features //! -//! * TLS1.2 and TLS1.3 (draft 18) only. +//! * TLS1.2 and TLS1.3 (draft 20) only. //! * ECDSA or RSA server authentication by clients. //! * RSA server authentication by servers. //! * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. diff --git a/src/msgs/handshake.rs b/src/msgs/handshake.rs index bc0c0b8feb..971ee93fad 100644 --- a/src/msgs/handshake.rs +++ b/src/msgs/handshake.rs @@ -996,18 +996,21 @@ impl Codec for HelloRetryExtension { #[derive(Debug)] pub struct HelloRetryRequest { pub server_version: ProtocolVersion, + pub cipher_suite: CipherSuite, pub extensions: Vec, } impl Codec for HelloRetryRequest { fn encode(&self, bytes: &mut Vec) { self.server_version.encode(bytes); + self.cipher_suite.encode(bytes); codec::encode_vec_u16(bytes, &self.extensions); } fn read(r: &mut Reader) -> Option { Some(HelloRetryRequest { server_version: try_ret!(ProtocolVersion::read(r)), + cipher_suite: try_ret!(CipherSuite::read(r)), extensions: try_ret!(codec::read_vec_u16::(r)), }) } @@ -1072,7 +1075,7 @@ pub struct ServerHelloPayload { } fn is_tls13(vers: ProtocolVersion) -> bool { - vers == ProtocolVersion::TLSv1_3 || vers == ProtocolVersion::Unknown(0x7f12) + vers == ProtocolVersion::TLSv1_3 || vers == ProtocolVersion::Unknown(0x7f14) } impl Codec for ServerHelloPayload { @@ -1603,37 +1606,104 @@ impl Codec for CertificateRequestPayload { } } +#[derive(Debug)] +pub enum CertReqExtension { + SignatureAlgorithms(SupportedSignatureSchemes), + AuthorityNames(DistinguishedNames), + Unknown(UnknownExtension), +} + +impl CertReqExtension { + pub fn get_type(&self) -> ExtensionType { + match *self { + CertReqExtension::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, + CertReqExtension::AuthorityNames(_) => ExtensionType::CertificateAuthorities, + CertReqExtension::Unknown(ref r) => r.typ, + } + } +} + +impl Codec for CertReqExtension { + fn encode(&self, bytes: &mut Vec) { + self.get_type().encode(bytes); + + let mut sub: Vec = Vec::new(); + match *self { + CertReqExtension::SignatureAlgorithms(ref r) => r.encode(&mut sub), + CertReqExtension::AuthorityNames(ref r) => r.encode(&mut sub), + CertReqExtension::Unknown(ref r) => r.encode(&mut sub), + } + + codec::encode_u16(sub.len() as u16, bytes); + bytes.append(&mut sub); + } + + fn read(r: &mut Reader) -> Option { + let typ = try_ret!(ExtensionType::read(r)); + let len = try_ret!(codec::read_u16(r)) as usize; + let mut sub = try_ret!(r.sub(len)); + + Some(match typ { + ExtensionType::SignatureAlgorithms => { + let schemes = try_ret!(SupportedSignatureSchemes::read(&mut sub)); + CertReqExtension::SignatureAlgorithms(schemes) + } + ExtensionType::CertificateAuthorities => { + let cas = try_ret!(DistinguishedNames::read(&mut sub)); + CertReqExtension::AuthorityNames(cas) + } + _ => CertReqExtension::Unknown(try_ret!(UnknownExtension::read(typ, &mut sub))), + }) + } +} + +declare_u16_vec!(CertReqExtensions, CertReqExtension); + #[derive(Debug)] pub struct CertificateRequestPayloadTLS13 { pub context: PayloadU8, - pub sigschemes: SupportedSignatureSchemes, - pub canames: DistinguishedNames, - pub extensions: CertificateExtensions, + pub extensions: CertReqExtensions, } impl Codec for CertificateRequestPayloadTLS13 { fn encode(&self, bytes: &mut Vec) { self.context.encode(bytes); - self.sigschemes.encode(bytes); - self.canames.encode(bytes); self.extensions.encode(bytes); } fn read(r: &mut Reader) -> Option { let context = try_ret!(PayloadU8::read(r)); - let sigschemes = try_ret!(SupportedSignatureSchemes::read(r)); - let canames = try_ret!(DistinguishedNames::read(r)); - let extensions = try_ret!(CertificateExtensions::read(r)); + let extensions = try_ret!(CertReqExtensions::read(r)); Some(CertificateRequestPayloadTLS13 { context: context, - sigschemes: sigschemes, - canames: canames, extensions: extensions, }) } } +impl CertificateRequestPayloadTLS13 { + pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> { + self.extensions.iter().find(|x| x.get_type() == ext) + } + + pub fn get_sigalgs_extension(&self) -> Option<&SupportedSignatureSchemes> { + let ext = try_ret!(self.find_extension(ExtensionType::SignatureAlgorithms)); + match *ext { + CertReqExtension::SignatureAlgorithms(ref sa) => Some(sa), + _ => None, + } + } + + pub fn get_authorities_extension(&self) -> Option<&DistinguishedNames> { + let ext = try_ret!(self.find_extension(ExtensionType::CertificateAuthorities)); + match *ext { + CertReqExtension::AuthorityNames(ref an) => Some(an), + _ => None, + } + } +} + // -- NewSessionTicket -- #[derive(Debug)] pub struct NewSessionTicketPayload { @@ -1770,6 +1840,7 @@ pub enum HandshakePayload { EncryptedExtensions(EncryptedExtensions), KeyUpdate(KeyUpdateRequest), Finished(Payload), + MessageHash(Payload), Unknown(Payload), } @@ -1793,6 +1864,7 @@ impl HandshakePayload { HandshakePayload::EncryptedExtensions(ref x) => x.encode(bytes), HandshakePayload::KeyUpdate(ref x) => x.encode(bytes), HandshakePayload::Finished(ref x) => x.encode(bytes), + HandshakePayload::MessageHash(ref x) => x.encode(bytes), HandshakePayload::Unknown(ref x) => x.encode(bytes), } } @@ -1892,6 +1964,10 @@ impl HandshakeMessagePayload { HandshakeType::Finished => { HandshakePayload::Finished(try_ret!(Payload::read(&mut sub))) } + HandshakeType::MessageHash => { + // does not appear on the wire + return None; + } _ => HandshakePayload::Unknown(try_ret!(Payload::read(&mut sub))), }; @@ -1930,4 +2006,11 @@ impl HandshakeMessagePayload { ret.truncate(ret_len); ret } + + pub fn build_handshake_hash(hash: &[u8]) -> HandshakeMessagePayload { + HandshakeMessagePayload { + typ: HandshakeType::MessageHash, + payload: HandshakePayload::MessageHash(Payload::new(hash.to_vec())) + } + } } diff --git a/src/server_hs.rs b/src/server_hs.rs index 436b8da23f..1b783aac64 100644 --- a/src/server_hs.rs +++ b/src/server_hs.rs @@ -16,7 +16,7 @@ use msgs::handshake::{CertificateRequestPayload, NewSessionTicketPayload}; use msgs::handshake::{CertificateRequestPayloadTLS13, NewSessionTicketPayloadTLS13}; use msgs::handshake::{HelloRetryRequest, HelloRetryExtension, KeyShareEntry}; use msgs::handshake::{CertificatePayloadTLS13, CertificateEntry}; -use msgs::handshake::SupportedMandatedSignatureSchemes; +use msgs::handshake::{CertReqExtension, SupportedMandatedSignatureSchemes}; use msgs::ccs::ChangeCipherSpecPayload; use msgs::codec::Codec; use msgs::persist; @@ -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; @@ -36,6 +35,8 @@ use handshake::Expectation; use std::sync::Arc; +const TLS13_DRAFT: u16 = 0x7f14; + macro_rules! extract_handshake( ( $m:expr, $t:path ) => ( match $m.payload { @@ -348,7 +349,7 @@ fn emit_server_hello_tls13(sess: &mut ServerSessionImpl, payload: MessagePayload::Handshake(HandshakeMessagePayload { typ: HandshakeType::ServerHello, payload: HandshakePayload::ServerHello(ServerHelloPayload { - server_version: ProtocolVersion::Unknown(0x7f12), + server_version: ProtocolVersion::Unknown(TLS13_DRAFT), random: Random::from_slice(&sess.handshake_data.randoms.server), session_id: SessionID::empty(), cipher_suite: sess.common.get_suite().suite, @@ -388,7 +389,8 @@ fn emit_server_hello_tls13(sess: &mut ServerSessionImpl, fn emit_hello_retry_request(sess: &mut ServerSessionImpl, group: NamedGroup) { let mut req = HelloRetryRequest { - server_version: ProtocolVersion::Unknown(0x7f12), + server_version: ProtocolVersion::Unknown(TLS13_DRAFT), + cipher_suite: sess.common.get_suite().suite, extensions: Vec::new(), }; @@ -404,6 +406,7 @@ fn emit_hello_retry_request(sess: &mut ServerSessionImpl, group: NamedGroup) { }; debug!("Requesting retry {:?}", m); + sess.handshake_data.transcript.rollup_for_hrr(); sess.handshake_data.transcript.add_message(&m); sess.common.send_msg(m, false); } @@ -432,15 +435,19 @@ fn emit_certificate_req_tls13(sess: &mut ServerSessionImpl) { return; } - let names = sess.config.client_auth_roots.get_subjects(); - - let cr = CertificateRequestPayloadTLS13 { + let mut cr = CertificateRequestPayloadTLS13 { context: PayloadU8::empty(), - sigschemes: SupportedSignatureSchemes::supported_verify(), - canames: names, extensions: Vec::new(), }; + let schemes = SupportedSignatureSchemes::supported_verify(); + cr.extensions.push(CertReqExtension::SignatureAlgorithms(schemes)); + + let names = sess.config.client_auth_roots.get_subjects(); + if !names.is_empty() { + cr.extensions.push(CertReqExtension::AuthorityNames(names)); + } + let m = Message { typ: ContentType::Handshake, version: ProtocolVersion::TLSv1_3, @@ -566,13 +573,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() @@ -725,7 +729,7 @@ fn handle_client_hello(sess: &mut ServerSessionImpl, m: Message) -> StateResult // Are we doing TLS1.3? let maybe_versions_ext = client_hello.get_versions_extension(); if let Some(versions) = maybe_versions_ext { - if versions.contains(&ProtocolVersion::Unknown(0x7f12)) && tls13_enabled { + if versions.contains(&ProtocolVersion::Unknown(TLS13_DRAFT)) && tls13_enabled { sess.common.negotiated_version = Some(ProtocolVersion::TLSv1_3); } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled { sess.common.send_fatal_alert(AlertDescription::ProtocolVersion);