From c57a939653d9935b20cab8285860d3da67b1b2ce Mon Sep 17 00:00:00 2001 From: Joseph Birr-Pixton Date: Tue, 14 May 2019 19:39:58 +0100 Subject: [PATCH] Move more from server::hs into server::tls13 --- rustls-mio/tests/common/mod.rs | 2 +- src/client/hs.rs | 1 - src/server/hs.rs | 850 +++++++-------------------------- src/server/tls13.rs | 573 +++++++++++++++++++++- 4 files changed, 741 insertions(+), 685 deletions(-) diff --git a/rustls-mio/tests/common/mod.rs b/rustls-mio/tests/common/mod.rs index 2257ac65..0c7fb8ce 100644 --- a/rustls-mio/tests/common/mod.rs +++ b/rustls-mio/tests/common/mod.rs @@ -122,7 +122,7 @@ fn unused_port(mut port: u16) -> u16 { // Note we skipped this test. pub fn skipped(why: &str) { - use std::io::{self, Write}; + use std::io; let mut stdout = io::stdout(); write!(&mut stdout, "[ SKIPPED ] because: {}\n -- UNTESTED: ", diff --git a/src/client/hs.rs b/src/client/hs.rs index 644ccdd9..7bbc6ca4 100644 --- a/src/client/hs.rs +++ b/src/client/hs.rs @@ -26,7 +26,6 @@ use crate::error::TLSError; use crate::handshake::check_handshake_message; #[cfg(feature = "quic")] use crate::{ - quic, msgs::base::PayloadU16, session::Protocol }; diff --git a/src/server/hs.rs b/src/server/hs.rs index 99361f64..28eb1c3d 100644 --- a/src/server/hs.rs +++ b/src/server/hs.rs @@ -1,9 +1,8 @@ use crate::msgs::enums::{ContentType, HandshakeType, ProtocolVersion}; use crate::msgs::enums::{Compression, NamedGroup, ECPointFormat, CipherSuite}; use crate::msgs::enums::{ExtensionType, AlertDescription}; -use crate::msgs::enums::{ClientCertificateType, SignatureScheme, PSKKeyExchangeMode}; +use crate::msgs::enums::{ClientCertificateType, SignatureScheme}; use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::base::{Payload, PayloadU8}; use crate::msgs::handshake::{HandshakePayload, SupportedSignatureSchemes}; use crate::msgs::handshake::{HandshakeMessagePayload, ServerHelloPayload, Random}; use crate::msgs::handshake::{ClientHelloPayload, ServerExtension, SessionID}; @@ -13,39 +12,27 @@ use crate::msgs::handshake::{ECPointFormatList, SupportedPointFormats}; use crate::msgs::handshake::{ServerECDHParams, DigitallySignedStruct}; use crate::msgs::handshake::{ServerKeyExchangePayload, ECDHEServerKeyExchange}; use crate::msgs::handshake::CertificateRequestPayload; -use crate::msgs::handshake::CertificateRequestPayloadTLS13; -use crate::msgs::handshake::{HelloRetryRequest, HelloRetryExtension, KeyShareEntry}; -use crate::msgs::handshake::{CertificatePayloadTLS13, CertificateEntry}; -use crate::msgs::handshake::{CertificateStatus, CertificateExtension}; -use crate::msgs::handshake::CertReqExtension; -use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::handshake::CertificateStatus; use crate::msgs::codec::Codec; use crate::msgs::persist; use crate::session::SessionSecrets; -use crate::cipher; use crate::server::ServerSessionImpl; -use crate::key_schedule::{KeySchedule, SecretKind}; use crate::suites; use crate::verify; use crate::util; use crate::rand; use crate::sign; #[cfg(feature = "logging")] -use crate::log::{warn, trace, debug}; +use crate::log::{trace, debug}; use crate::error::TLSError; use crate::handshake::check_handshake_message; use webpki; #[cfg(feature = "quic")] -use crate::{ - quic, - session::Protocol -}; +use crate::session::Protocol; use crate::server::common::{HandshakeDetails, ServerKXDetails}; use crate::server::{tls12, tls13}; -use ring::constant_time; - macro_rules! extract_handshake( ( $m:expr, $t:path ) => ( match $m.payload { @@ -77,19 +64,19 @@ fn bad_version(sess: &mut ServerSessionImpl, why: &str) -> TLSError { TLSError::PeerIncompatibleError(why.to_string()) } -fn illegal_param(sess: &mut ServerSessionImpl, why: &str) -> TLSError { +pub fn illegal_param(sess: &mut ServerSessionImpl, why: &str) -> TLSError { sess.common.send_fatal_alert(AlertDescription::IllegalParameter); TLSError::PeerMisbehavedError(why.to_string()) } -fn decode_error(sess: &mut ServerSessionImpl, why: &str) -> TLSError { +pub fn decode_error(sess: &mut ServerSessionImpl, why: &str) -> TLSError { sess.common.send_fatal_alert(AlertDescription::DecodeError); TLSError::PeerMisbehavedError(why.to_string()) } -fn can_resume(sess: &ServerSessionImpl, - handshake: &HandshakeDetails, - resumedata: &Option) -> bool { +pub fn can_resume(sess: &ServerSessionImpl, + handshake: &HandshakeDetails, + resumedata: &Option) -> bool { // The RFCs underspecify what happens if we try to resume to // an unoffered/varying suite. We merely don't resume in weird cases. // @@ -135,12 +122,153 @@ pub fn check_aligned_handshake(sess: &mut ServerSessionImpl) -> Result<(), TLSEr } } +pub fn save_sni(sess: &mut ServerSessionImpl, + sni: Option) { + if let Some(sni) = sni { + // Save the SNI into the session. + sess.set_sni(sni); + } +} + +#[derive(Default)] +pub struct ExtensionProcessing { + // extensions to reply with + pub exts: Vec, + + // effects on later handshake steps + pub send_cert_status: bool, + pub send_sct: bool, + pub send_ticket: bool, +} + +impl ExtensionProcessing { + pub fn new() -> Self { Default::default() } + + pub fn process_common(&mut self, + sess: &mut ServerSessionImpl, + server_key: Option<&mut sign::CertifiedKey>, + hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>, + handshake: &HandshakeDetails) + -> Result<(), TLSError> { + // ALPN + let our_protocols = &sess.config.alpn_protocols; + let maybe_their_protocols = hello.get_alpn_extension(); + if let Some(their_protocols) = maybe_their_protocols { + let their_proto_vecs = their_protocols.to_vecs(); + + if their_proto_vecs.iter().any(Vec::is_empty) { + return Err(TLSError::PeerMisbehavedError("client offered empty ALPN protocol" + .to_string())); + } + + sess.alpn_protocol = util::first_in_both(our_protocols, &their_proto_vecs); + if let Some(ref selected_protocol) = sess.alpn_protocol { + debug!("Chosen ALPN protocol {:?}", selected_protocol); + self.exts.push(ServerExtension::make_alpn(&[selected_protocol])); + } + } + + #[cfg(feature = "quic")] { + if sess.common.protocol == Protocol::Quic { + if let Some(params) = hello.get_quic_params_extension() { + sess.common.quic.params = Some(params); + } + + if let Some(resume) = resumedata { + if sess.config.max_early_data_size > 0 + && hello.early_data_extension_offered() + && resume.version == sess.common.negotiated_version.unwrap() + && resume.cipher_suite == sess.common.get_suite_assert().suite + && resume.alpn.as_ref().map(|x| &x.0) == sess.alpn_protocol.as_ref() + { + self.exts.push(ServerExtension::EarlyData); + } else { + // Clobber value set in tls13::emit_server_hello + sess.common.quic.early_secret = None; + } + } + } + } + + let for_resume = resumedata.is_some(); + // SNI + if !for_resume && hello.get_sni_extension().is_some() { + self.exts.push(ServerExtension::ServerNameAck); + } + + // Send status_request response if we have one. This is not allowed + // if we're resuming, and is only triggered if we have an OCSP response + // to send. + if !for_resume && + hello.find_extension(ExtensionType::StatusRequest).is_some() && + server_key.is_some() && + server_key.as_ref().unwrap().has_ocsp() { + self.send_cert_status = true; + + if !sess.common.is_tls13() { + // Only TLS1.2 sends confirmation in ServerHello + self.exts.push(ServerExtension::CertificateStatusAck); + } + } + + if !for_resume && + hello.find_extension(ExtensionType::SCT).is_some() && + server_key.is_some() && + server_key.as_ref().unwrap().has_sct_list() { + self.send_sct = true; + + if !sess.common.is_tls13() { + let sct_list = server_key + .unwrap() + .take_sct_list() + .unwrap(); + self.exts.push(ServerExtension::make_sct(sct_list)); + } + } + + if !sess.common.is_tls13() { + } + + self.exts.extend(handshake.extra_exts.iter().cloned()); + + Ok(()) + } + + fn process_tls12(&mut self, sess: &ServerSessionImpl, hello: &ClientHelloPayload, + handshake: &HandshakeDetails) { + // Renegotiation. + // (We don't do reneg at all, but would support the secure version if we did.) + let secure_reneg_offered = + hello.find_extension(ExtensionType::RenegotiationInfo).is_some() || + hello.cipher_suites.contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + + if secure_reneg_offered { + self.exts.push(ServerExtension::make_empty_renegotiation_info()); + } + + // Tickets: + // If we get any SessionTicket extension and have tickets enabled, + // we send an ack. + if hello.find_extension(ExtensionType::SessionTicket).is_some() && + sess.config.ticketer.enabled() { + self.send_ticket = true; + self.exts.push(ServerExtension::SessionTicketAck); + } + + // Confirm use of EMS if offered. + if handshake.using_ems { + self.exts.push(ServerExtension::ExtendedMasterSecretAck); + } + } +} + pub struct ExpectClientHello { - handshake: HandshakeDetails, - done_retry: bool, - send_cert_status: bool, - send_sct: bool, - send_ticket: bool, + pub handshake: HandshakeDetails, + pub done_retry: bool, + pub send_cert_status: bool, + pub send_sct: bool, + pub send_ticket: bool, } impl ExpectClientHello { @@ -162,28 +290,14 @@ impl ExpectClientHello { }) } - fn into_expect_retried_client_hello(self) -> NextState { - Box::new(ExpectClientHello { + fn into_complete_tls13_client_hello_handling(self) -> tls13::CompleteClientHelloHandling { + tls13::CompleteClientHelloHandling { handshake: self.handshake, - done_retry: true, + done_retry: self.done_retry, send_cert_status: self.send_cert_status, send_sct: self.send_sct, send_ticket: self.send_ticket, - }) - } - - fn into_expect_tls13_certificate(self) -> NextState { - Box::new(tls13::ExpectCertificate { - handshake: self.handshake, - send_ticket: self.send_ticket, - }) - } - - fn into_expect_tls13_finished(self) -> NextState { - Box::new(tls13::ExpectFinished { - handshake: self.handshake, - send_ticket: self.send_ticket, - }) + } } fn into_expect_tls12_certificate(self, kx: suites::KeyExchange) -> NextState { @@ -203,486 +317,19 @@ impl ExpectClientHello { }) } - fn process_extensions(&mut self, - sess: &mut ServerSessionImpl, - server_key: Option<&mut sign::CertifiedKey>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>) - -> Result, TLSError> { - let mut ret = Vec::new(); - - // ALPN - let our_protocols = &sess.config.alpn_protocols; - let maybe_their_protocols = hello.get_alpn_extension(); - if let Some(their_protocols) = maybe_their_protocols { - let their_proto_vecs = their_protocols.to_vecs(); - - if their_proto_vecs.iter().any(Vec::is_empty) { - return Err(TLSError::PeerMisbehavedError("client offered empty ALPN protocol" - .to_string())); - } - - sess.alpn_protocol = util::first_in_both(our_protocols, &their_proto_vecs); - if let Some(ref selected_protocol) = sess.alpn_protocol { - debug!("Chosen ALPN protocol {:?}", selected_protocol); - ret.push(ServerExtension::make_alpn(&[selected_protocol])); - } - } - - #[cfg(feature = "quic")] { - if sess.common.protocol == Protocol::Quic { - if let Some(params) = hello.get_quic_params_extension() { - sess.common.quic.params = Some(params); - } - - if let Some(resume) = resumedata { - if sess.config.max_early_data_size > 0 - && hello.early_data_extension_offered() - && resume.version == sess.common.negotiated_version.unwrap() - && resume.cipher_suite == sess.common.get_suite_assert().suite - && resume.alpn.as_ref().map(|x| &x.0) == sess.alpn_protocol.as_ref() - { - ret.push(ServerExtension::EarlyData); - } else { - // Clobber value set in emit_server_hello_tls13 - sess.common.quic.early_secret = None; - } - } - } - } - - let for_resume = resumedata.is_some(); - // SNI - if !for_resume && hello.get_sni_extension().is_some() { - ret.push(ServerExtension::ServerNameAck); - } - - // Send status_request response if we have one. This is not allowed - // if we're resuming, and is only triggered if we have an OCSP response - // to send. - if !for_resume && - hello.find_extension(ExtensionType::StatusRequest).is_some() && - server_key.is_some() && - server_key.as_ref().unwrap().has_ocsp() { - self.send_cert_status = true; - - if !sess.common.is_tls13() { - // Only TLS1.2 sends confirmation in ServerHello - ret.push(ServerExtension::CertificateStatusAck); - } - } - - if !for_resume && - hello.find_extension(ExtensionType::SCT).is_some() && - server_key.is_some() && - server_key.as_ref().unwrap().has_sct_list() { - self.send_sct = true; - - if !sess.common.is_tls13() { - let sct_list = server_key - .unwrap() - .take_sct_list() - .unwrap(); - ret.push(ServerExtension::make_sct(sct_list)); - } - } - - if !sess.common.is_tls13() { - // Renegotiation. - // (We don't do reneg at all, but would support the secure version if we did.) - let secure_reneg_offered = - hello.find_extension(ExtensionType::RenegotiationInfo).is_some() || - hello.cipher_suites.contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - - if secure_reneg_offered { - ret.push(ServerExtension::make_empty_renegotiation_info()); - } - - // Tickets: - // If we get any SessionTicket extension and have tickets enabled, - // we send an ack. - if hello.find_extension(ExtensionType::SessionTicket).is_some() && - sess.config.ticketer.enabled() { - self.send_ticket = true; - ret.push(ServerExtension::SessionTicketAck); - } - - // Confirm use of EMS if offered. - if self.handshake.using_ems { - ret.push(ServerExtension::ExtendedMasterSecretAck); - } - - } - - ret.extend(self.handshake.extra_exts.iter().cloned()); - - Ok(ret) - } - - fn check_binder(&self, - sess: &mut ServerSessionImpl, - client_hello: &Message, - psk: &[u8], - binder: &[u8]) - -> bool { - let binder_plaintext = match client_hello.payload { - MessagePayload::Handshake(ref hmp) => hmp.get_encoding_for_binder_signing(), - _ => unreachable!(), - }; - - let suite_hash = sess.common.get_suite_assert().get_hash(); - let handshake_hash = sess.common.hs_transcript.get_hash_given(suite_hash, &binder_plaintext); - - let mut key_schedule = KeySchedule::new(suite_hash); - key_schedule.input_secret(psk); - 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); - - constant_time::verify_slices_are_equal(&real_binder, binder).is_ok() - } - - fn emit_server_hello_tls13(&mut self, - sess: &mut ServerSessionImpl, - session_id: &SessionID, - share: &KeyShareEntry, - chosen_psk_idx: Option, - resuming_psk: Option<&[u8]>) - -> Result<(), TLSError> { - let mut extensions = Vec::new(); - - // Do key exchange - let kxr = suites::KeyExchange::start_ecdhe(share.group) - .and_then(|kx| kx.complete(&share.payload.0)) - .ok_or_else(|| TLSError::PeerMisbehavedError("key exchange failed".to_string()))?; - - let kse = KeyShareEntry::new(share.group, kxr.pubkey.as_ref()); - extensions.push(ServerExtension::KeyShare(kse)); - extensions.push(ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); - - if let Some(psk_idx) = chosen_psk_idx { - extensions.push(ServerExtension::PresharedKey(psk_idx as u16)); - } - - let sh = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::ServerHello, - payload: HandshakePayload::ServerHello(ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from_slice(&self.handshake.randoms.server), - session_id: *session_id, - cipher_suite: sess.common.get_suite_assert().suite, - compression_method: Compression::Null, - extensions, - }), - }), - }; - - check_aligned_handshake(sess)?; - - #[cfg(feature = "quic")] - let client_hello_hash = sess.common.hs_transcript - .get_hash_given(sess.common.get_suite_assert().get_hash(), &[]); - - trace!("sending server hello {:?}", sh); - sess.common.hs_transcript.add_message(&sh); - sess.common.send_msg(sh, false); - - // Start key schedule - let suite = sess.common.get_suite_assert(); - let mut key_schedule = KeySchedule::new(suite.get_hash()); - if let Some(psk) = resuming_psk { - key_schedule.input_secret(psk); - - #[cfg(feature = "quic")] { - if sess.common.protocol == Protocol::Quic { - let client_early_traffic_secret = key_schedule - .derive(SecretKind::ClientEarlyTrafficSecret, &client_hello_hash); - sess.config.key_log.log(sess.common.protocol.labels().client_early_traffic_secret, - &self.handshake.randoms.client, - &client_early_traffic_secret); - // If 0-RTT should be rejected, this will be clobbered by process_extensions - // before the application can see. - sess.common.quic.early_secret = Some(client_early_traffic_secret); - } - } - } else { - key_schedule.input_empty(); - } - key_schedule.input_secret(&kxr.premaster_secret); - - let handshake_hash = sess.common.hs_transcript.get_current_hash(); - let write_key = key_schedule.derive(SecretKind::ServerHandshakeTrafficSecret, &handshake_hash); - let read_key = key_schedule.derive(SecretKind::ClientHandshakeTrafficSecret, &handshake_hash); - sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key)); - 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, - &self.handshake.randoms.client, - &write_key); - sess.config.key_log.log(sess.common.protocol.labels().client_handshake_traffic_secret, - &self.handshake.randoms.client, - &read_key); - - #[cfg(feature = "quic")] { - sess.common.quic.hs_secrets = Some(quic::Secrets { - client: read_key.clone(), - server: write_key.clone(), - }); - } - - key_schedule.current_client_traffic_secret = read_key; - key_schedule.current_server_traffic_secret = write_key; - sess.common.set_key_schedule(key_schedule); - - Ok(()) - } - - 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, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}) - }; - sess.common.send_msg(m, false); - } - - fn emit_hello_retry_request(&mut self, - sess: &mut ServerSessionImpl, - group: NamedGroup) { - let mut req = HelloRetryRequest { - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionID::empty(), - cipher_suite: sess.common.get_suite_assert().suite, - extensions: Vec::new(), - }; - - req.extensions.push(HelloRetryExtension::KeyShare(group)); - req.extensions.push(HelloRetryExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); - - let m = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::HelloRetryRequest, - payload: HandshakePayload::HelloRetryRequest(req), - }), - }; - - trace!("Requesting retry {:?}", m); - sess.common.hs_transcript.rollup_for_hrr(); - sess.common.hs_transcript.add_message(&m); - sess.common.send_msg(m, false); - } - - fn emit_encrypted_extensions(&mut self, - sess: &mut ServerSessionImpl, - server_key: &mut sign::CertifiedKey, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>) - -> Result<(), TLSError> { - let encrypted_exts = self.process_extensions(sess, Some(server_key), hello, resumedata)?; - let ee = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::EncryptedExtensions, - payload: HandshakePayload::EncryptedExtensions(encrypted_exts), - }), - }; - - trace!("sending encrypted extensions {:?}", ee); - sess.common.hs_transcript.add_message(&ee); - sess.common.send_msg(ee, true); - Ok(()) - } - - fn emit_certificate_req_tls13(&mut self, sess: &mut ServerSessionImpl) -> bool { - if !sess.config.verifier.offer_client_auth() { - return false; - } - - let mut cr = CertificateRequestPayloadTLS13 { - context: PayloadU8::empty(), - extensions: Vec::new(), - }; - - let schemes = verify::supported_verify_schemes(); - cr.extensions.push(CertReqExtension::SignatureAlgorithms(schemes.to_vec())); - - let names = sess.config.verifier.client_auth_root_subjects(); - if !names.is_empty() { - cr.extensions.push(CertReqExtension::AuthorityNames(names)); - } - - let m = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateRequest, - payload: HandshakePayload::CertificateRequestTLS13(cr), - }), - }; - - trace!("Sending CertificateRequest {:?}", m); - sess.common.hs_transcript.add_message(&m); - sess.common.send_msg(m, true); - true - } - - fn emit_certificate_tls13(&mut self, - sess: &mut ServerSessionImpl, - server_key: &mut sign::CertifiedKey) { - let mut cert_entries = vec![]; - for cert in server_key.take_cert() { - let entry = CertificateEntry { - cert, - exts: Vec::new(), - }; - - cert_entries.push(entry); - } - - if let Some(end_entity_cert) = cert_entries.first_mut() { - // Apply OCSP response to first certificate (we don't support OCSP - // except for leaf certs). - if self.send_cert_status { - if let Some(ocsp) = server_key.take_ocsp() { - let cst = CertificateStatus::new(ocsp); - end_entity_cert.exts.push(CertificateExtension::CertificateStatus(cst)); - } - } - - // Likewise, SCT - if self.send_sct { - if let Some(sct_list) = server_key.take_sct_list() { - end_entity_cert.exts.push(CertificateExtension::make_sct(sct_list)); - } - } - } - - let cert_body = CertificatePayloadTLS13::new(cert_entries); - let c = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::Certificate, - payload: HandshakePayload::CertificateTLS13(cert_body), - }), - }; - - trace!("sending certificate {:?}", c); - sess.common.hs_transcript.add_message(&c); - sess.common.send_msg(c, true); - } - - fn emit_certificate_verify_tls13(&mut self, - sess: &mut ServerSessionImpl, - server_key: &mut sign::CertifiedKey, - schemes: &[SignatureScheme]) - -> Result<(), TLSError> { - let mut message = Vec::new(); - message.resize(64, 0x20u8); - message.extend_from_slice(b"TLS 1.3, server CertificateVerify\x00"); - message.extend_from_slice(&sess.common.hs_transcript.get_current_hash()); - - let signing_key = &server_key.key; - let signer = signing_key.choose_scheme(schemes) - .ok_or_else(|| incompatible(sess, "no overlapping sigschemes"))?; - - let scheme = signer.get_scheme(); - let sig = signer.sign(&message)?; - - let cv = DigitallySignedStruct::new(scheme, sig); - - let m = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::CertificateVerify, - payload: HandshakePayload::CertificateVerify(cv), - }), - }; - - trace!("sending certificate-verify {:?}", m); - sess.common.hs_transcript.add_message(&m); - sess.common.send_msg(m, true); - Ok(()) - } - - fn emit_finished_tls13(&mut self, sess: &mut ServerSessionImpl) { - let handshake_hash = sess.common.hs_transcript.get_current_hash(); - let verify_data = sess.common - .get_key_schedule() - .sign_finish(SecretKind::ServerHandshakeTrafficSecret, &handshake_hash); - let verify_data_payload = Payload::new(verify_data); - - let m = Message { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake(HandshakeMessagePayload { - typ: HandshakeType::Finished, - payload: HandshakePayload::Finished(verify_data_payload), - }), - }; - - trace!("sending finished {:?}", m); - sess.common.hs_transcript.add_message(&m); - self.handshake.hash_at_server_fin = sess.common.hs_transcript.get_current_hash(); - sess.common.send_msg(m, true); - - // Now move to application data keys. - sess.common.get_mut_key_schedule().input_empty(); - let write_key = sess.common - .get_key_schedule() - .derive(SecretKind::ServerApplicationTrafficSecret, - &self.handshake.hash_at_server_fin); - let suite = sess.common.get_suite_assert(); - sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key)); - sess.config.key_log.log(sess.common.protocol.labels().server_traffic_secret_0, - &self.handshake.randoms.client, - &write_key); - - #[cfg(feature = "quic")] { - let read_key = sess.common - .get_key_schedule() - .derive(SecretKind::ClientApplicationTrafficSecret, - &self.handshake.hash_at_server_fin); - sess.common.quic.traffic_secrets = Some(quic::Secrets { - client: read_key, - server: write_key.clone(), - }); - } - - sess.common - .get_mut_key_schedule() - .current_server_traffic_secret = write_key; - - - let exporter_secret = sess.common - .get_key_schedule() - .derive(SecretKind::ExporterMasterSecret, - &self.handshake.hash_at_server_fin); - sess.config.key_log.log(sess.common.protocol.labels().exporter_secret, - &self.handshake.randoms.client, - &exporter_secret); - sess.common - .get_mut_key_schedule() - .current_exporter_secret = exporter_secret; - } - fn emit_server_hello(&mut self, sess: &mut ServerSessionImpl, server_key: Option<&mut sign::CertifiedKey>, hello: &ClientHelloPayload, resumedata: Option<&persist::ServerSessionValue>) -> Result<(), TLSError> { - let extensions = self.process_extensions(sess, server_key, hello, resumedata)?; + let mut ep = ExtensionProcessing::new(); + ep.process_common(sess, server_key, hello, resumedata, &self.handshake)?; + ep.process_tls12(sess, hello, &self.handshake); + + self.send_ticket = ep.send_ticket; + self.send_cert_status = ep.send_cert_status; + self.send_sct = ep.send_sct; let sh = Message { typ: ContentType::Handshake, @@ -695,7 +342,7 @@ impl ExpectClientHello { session_id: self.handshake.session_id, cipher_suite: sess.common.get_suite_assert().suite, compression_method: Compression::Null, - extensions, + extensions: ep.exts, }), }), }; @@ -834,22 +481,6 @@ impl ExpectClientHello { sess.common.send_msg(m, false); } - fn attempt_tls13_ticket_decryption(&mut self, - sess: &mut ServerSessionImpl, - ticket: &[u8]) -> Option { - if sess.config.ticketer.enabled() { - sess.config - .ticketer - .decrypt(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) - } else { - sess.config - .session_storage - .take(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) - } - } - fn start_resumption(mut self, sess: &mut ServerSessionImpl, client_hello: &ClientHelloPayload, @@ -887,148 +518,6 @@ impl ExpectClientHello { Ok(self.into_expect_tls12_ccs()) } - fn handle_client_hello_tls13(mut self, - sess: &mut ServerSessionImpl, - sni: Option, - mut server_key: sign::CertifiedKey, - chm: &Message) - -> NextStateOrError { - let client_hello = extract_handshake!(chm, HandshakePayload::ClientHello).unwrap(); - - if client_hello.compression_methods.len() != 1 { - return Err(illegal_param(sess, "client offered wrong compressions")); - } - - let groups_ext = client_hello.get_namedgroups_extension() - .ok_or_else(|| incompatible(sess, "client didn't describe groups"))?; - - let mut sigschemes_ext = client_hello.get_sigalgs_extension() - .ok_or_else(|| incompatible(sess, "client didn't describe sigschemes"))? - .clone(); - - let tls13_schemes = sign::supported_sign_tls13(); - sigschemes_ext.retain(|scheme| tls13_schemes.contains(scheme)); - - let shares_ext = client_hello.get_keyshare_extension() - .ok_or_else(|| incompatible(sess, "client didn't send keyshares"))?; - - if client_hello.has_keyshare_extension_with_duplicates() { - return Err(illegal_param(sess, "client sent duplicate keyshares")); - } - - let share_groups: Vec = shares_ext.iter() - .map(|share| share.group) - .collect(); - - let supported_groups = suites::KeyExchange::supported_groups(); - let chosen_group = util::first_in_both(supported_groups, &share_groups); - if chosen_group.is_none() { - // We don't have a suitable key share. Choose a suitable group and - // send a HelloRetryRequest. - let retry_group_maybe = util::first_in_both(supported_groups, groups_ext); - sess.common.hs_transcript.add_message(chm); - - if let Some(group) = retry_group_maybe { - if self.done_retry { - return Err(illegal_param(sess, "did not follow retry request")); - } - - self.emit_hello_retry_request(sess, group); - self.emit_fake_ccs(sess); - return Ok(self.into_expect_retried_client_hello()); - } - - return Err(incompatible(sess, "no kx group overlap with client")); - } - - self.save_sni(sess, sni); - - let chosen_group = chosen_group.unwrap(); - let chosen_share = shares_ext.iter() - .find(|share| share.group == chosen_group) - .unwrap(); - - let mut chosen_psk_index = None; - let mut resumedata = None; - if let Some(psk_offer) = client_hello.get_psk() { - if !client_hello.check_psk_ext_is_last() { - return Err(illegal_param(sess, "psk extension in wrong position")); - } - - if psk_offer.binders.is_empty() { - return Err(decode_error(sess, "psk extension missing binder")); - } - - if psk_offer.binders.len() != psk_offer.identities.len() { - return Err(illegal_param(sess, "psk extension mismatched ids/binders")); - } - - for (i, psk_id) in psk_offer.identities.iter().enumerate() { - let maybe_resume = self.attempt_tls13_ticket_decryption(sess, &psk_id.identity.0); - - if !can_resume(sess, &self.handshake, &maybe_resume) { - continue; - } - - let resume = maybe_resume.unwrap(); - - if !self.check_binder(sess, chm, &resume.master_secret.0, &psk_offer.binders[i].0) { - sess.common.send_fatal_alert(AlertDescription::DecryptError); - return Err(TLSError::PeerMisbehavedError("client sent wrong binder".to_string())); - } - - chosen_psk_index = Some(i); - resumedata = Some(resume); - break; - } - } - - if !client_hello.psk_mode_offered(PSKKeyExchangeMode::PSK_DHE_KE) { - warn!("Resumption ignored, DHE_KE not offered"); - self.send_ticket = false; - chosen_psk_index = None; - resumedata = None; - } else { - self.send_ticket = true; - } - - let full_handshake = resumedata.is_none(); - sess.common.hs_transcript.add_message(chm); - self.emit_server_hello_tls13(sess, &client_hello.session_id, - chosen_share, chosen_psk_index, - resumedata.as_ref().map(|x| &x.master_secret.0[..]))?; - if !self.done_retry { - self.emit_fake_ccs(sess); - } - self.emit_encrypted_extensions(sess, &mut server_key, client_hello, resumedata.as_ref())?; - - let doing_client_auth = if full_handshake { - let client_auth = self.emit_certificate_req_tls13(sess); - self.emit_certificate_tls13(sess, &mut server_key); - self.emit_certificate_verify_tls13(sess, &mut server_key, &sigschemes_ext)?; - client_auth - } else { - false - }; - - check_aligned_handshake(sess)?; - self.emit_finished_tls13(sess); - - if doing_client_auth { - Ok(self.into_expect_tls13_certificate()) - } else { - Ok(self.into_expect_tls13_finished()) - } - } - - fn save_sni(&self, - sess: &mut ServerSessionImpl, - sni: Option) { - if let Some(sni) = sni { - // Save the SNI into the session. - sess.set_sni(sni); - } - } } impl State for ExpectClientHello { @@ -1140,11 +629,12 @@ impl State for ExpectClientHello { client_hello.random.write_slice(&mut self.handshake.randoms.client); if sess.common.is_tls13() { - return self.handle_client_hello_tls13(sess, sni, certkey, &m); + return self.into_complete_tls13_client_hello_handling() + .handle_client_hello(sess, sni, certkey, &m); } // -- TLS1.2 only from hereon in -- - self.save_sni(sess, sni.clone()); + save_sni(sess, sni.clone()); sess.common.hs_transcript.add_message(&m); if client_hello.ems_support_offered() { diff --git a/src/server/tls13.rs b/src/server/tls13.rs index 7166a4ac..32378b67 100644 --- a/src/server/tls13.rs +++ b/src/server/tls13.rs @@ -1,22 +1,44 @@ use crate::msgs::enums::{ContentType, HandshakeType, ProtocolVersion}; -use crate::msgs::enums::AlertDescription; +use crate::msgs::enums::{AlertDescription, SignatureScheme, NamedGroup}; +use crate::msgs::enums::{Compression, PSKKeyExchangeMode}; use crate::msgs::message::{Message, MessagePayload}; use crate::msgs::handshake::HandshakePayload; use crate::msgs::handshake::HandshakeMessagePayload; use crate::msgs::handshake::NewSessionTicketPayloadTLS13; +use crate::msgs::handshake::CertificateEntry; +use crate::msgs::handshake::CertificateExtension; +use crate::msgs::handshake::CertificateStatus; +use crate::msgs::handshake::CertificatePayloadTLS13; +use crate::msgs::handshake::CertificateRequestPayloadTLS13; +use crate::msgs::handshake::CertReqExtension; +use crate::msgs::handshake::ClientHelloPayload; +use crate::msgs::handshake::HelloRetryRequest; +use crate::msgs::handshake::HelloRetryExtension; +use crate::msgs::handshake::ServerHelloPayload; +use crate::msgs::handshake::KeyShareEntry; +use crate::msgs::handshake::SessionID; +use crate::msgs::handshake::ServerExtension; +use crate::msgs::handshake::Random; +use crate::msgs::handshake::DigitallySignedStruct; +use crate::msgs::ccs::ChangeCipherSpecPayload; +use crate::msgs::base::{Payload, PayloadU8}; use crate::msgs::codec::Codec; use crate::msgs::persist; -use crate::cipher; use crate::server::ServerSessionImpl; -use crate::key_schedule::SecretKind; +use crate::key_schedule::{KeySchedule, SecretKind}; +use crate::cipher; use crate::verify; use crate::rand; +use crate::sign; +use crate::suites; +use crate::util; #[cfg(feature = "logging")] use crate::log::{warn, trace, debug}; use crate::error::TLSError; use crate::handshake::{check_handshake_message, check_message}; #[cfg(feature = "quic")] use crate::{ + quic, msgs::handshake::NewSessionTicketExtension, session::Protocol }; @@ -26,6 +48,551 @@ use crate::server::hs; use ring::constant_time; +pub struct CompleteClientHelloHandling { + pub handshake: HandshakeDetails, + pub done_retry: bool, + pub send_cert_status: bool, + pub send_sct: bool, + pub send_ticket: bool, +} + +impl CompleteClientHelloHandling { + fn check_binder(&self, + sess: &mut ServerSessionImpl, + client_hello: &Message, + psk: &[u8], + binder: &[u8]) + -> bool { + let binder_plaintext = match client_hello.payload { + MessagePayload::Handshake(ref hmp) => hmp.get_encoding_for_binder_signing(), + _ => unreachable!(), + }; + + let suite_hash = sess.common.get_suite_assert().get_hash(); + let handshake_hash = sess.common.hs_transcript.get_hash_given(suite_hash, &binder_plaintext); + + let mut key_schedule = KeySchedule::new(suite_hash); + key_schedule.input_secret(psk); + 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); + + constant_time::verify_slices_are_equal(&real_binder, binder).is_ok() + } + + fn into_expect_retried_client_hello(self) -> hs::NextState { + Box::new(hs::ExpectClientHello { + handshake: self.handshake, + done_retry: true, + send_cert_status: self.send_cert_status, + send_sct: self.send_sct, + send_ticket: self.send_ticket, + }) + } + + fn into_expect_certificate(self) -> hs::NextState { + Box::new(ExpectCertificate { + handshake: self.handshake, + send_ticket: self.send_ticket, + }) + } + + fn into_expect_finished(self) -> hs::NextState { + Box::new(ExpectFinished { + handshake: self.handshake, + send_ticket: self.send_ticket, + }) + } + + fn emit_server_hello(&mut self, + sess: &mut ServerSessionImpl, + session_id: &SessionID, + share: &KeyShareEntry, + chosen_psk_idx: Option, + resuming_psk: Option<&[u8]>) + -> Result<(), TLSError> { + let mut extensions = Vec::new(); + + // Do key exchange + let kxr = suites::KeyExchange::start_ecdhe(share.group) + .and_then(|kx| kx.complete(&share.payload.0)) + .ok_or_else(|| TLSError::PeerMisbehavedError("key exchange failed".to_string()))?; + + let kse = KeyShareEntry::new(share.group, kxr.pubkey.as_ref()); + extensions.push(ServerExtension::KeyShare(kse)); + extensions.push(ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); + + if let Some(psk_idx) = chosen_psk_idx { + extensions.push(ServerExtension::PresharedKey(psk_idx as u16)); + } + + let sh = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::ServerHello, + payload: HandshakePayload::ServerHello(ServerHelloPayload { + legacy_version: ProtocolVersion::TLSv1_2, + random: Random::from_slice(&self.handshake.randoms.server), + session_id: *session_id, + cipher_suite: sess.common.get_suite_assert().suite, + compression_method: Compression::Null, + extensions, + }), + }), + }; + + hs::check_aligned_handshake(sess)?; + + #[cfg(feature = "quic")] + let client_hello_hash = sess.common.hs_transcript + .get_hash_given(sess.common.get_suite_assert().get_hash(), &[]); + + trace!("sending server hello {:?}", sh); + sess.common.hs_transcript.add_message(&sh); + sess.common.send_msg(sh, false); + + // Start key schedule + let suite = sess.common.get_suite_assert(); + let mut key_schedule = KeySchedule::new(suite.get_hash()); + if let Some(psk) = resuming_psk { + key_schedule.input_secret(psk); + + #[cfg(feature = "quic")] { + if sess.common.protocol == Protocol::Quic { + let client_early_traffic_secret = key_schedule + .derive(SecretKind::ClientEarlyTrafficSecret, &client_hello_hash); + sess.config.key_log.log(sess.common.protocol.labels().client_early_traffic_secret, + &self.handshake.randoms.client, + &client_early_traffic_secret); + // If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing + // before the application can see. + sess.common.quic.early_secret = Some(client_early_traffic_secret); + } + } + } else { + key_schedule.input_empty(); + } + key_schedule.input_secret(&kxr.premaster_secret); + + let handshake_hash = sess.common.hs_transcript.get_current_hash(); + let write_key = key_schedule.derive(SecretKind::ServerHandshakeTrafficSecret, &handshake_hash); + let read_key = key_schedule.derive(SecretKind::ClientHandshakeTrafficSecret, &handshake_hash); + sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key)); + 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, + &self.handshake.randoms.client, + &write_key); + sess.config.key_log.log(sess.common.protocol.labels().client_handshake_traffic_secret, + &self.handshake.randoms.client, + &read_key); + + #[cfg(feature = "quic")] { + sess.common.quic.hs_secrets = Some(quic::Secrets { + client: read_key.clone(), + server: write_key.clone(), + }); + } + + key_schedule.current_client_traffic_secret = read_key; + key_schedule.current_server_traffic_secret = write_key; + sess.common.set_key_schedule(key_schedule); + + Ok(()) + } + + 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, + payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}) + }; + sess.common.send_msg(m, false); + } + + fn emit_hello_retry_request(&mut self, + sess: &mut ServerSessionImpl, + group: NamedGroup) { + let mut req = HelloRetryRequest { + legacy_version: ProtocolVersion::TLSv1_2, + session_id: SessionID::empty(), + cipher_suite: sess.common.get_suite_assert().suite, + extensions: Vec::new(), + }; + + req.extensions.push(HelloRetryExtension::KeyShare(group)); + req.extensions.push(HelloRetryExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); + + let m = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_2, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::HelloRetryRequest, + payload: HandshakePayload::HelloRetryRequest(req), + }), + }; + + trace!("Requesting retry {:?}", m); + sess.common.hs_transcript.rollup_for_hrr(); + sess.common.hs_transcript.add_message(&m); + sess.common.send_msg(m, false); + } + + fn emit_encrypted_extensions(&mut self, + sess: &mut ServerSessionImpl, + server_key: &mut sign::CertifiedKey, + hello: &ClientHelloPayload, + resumedata: Option<&persist::ServerSessionValue>) + -> Result<(), TLSError> { + let mut ep = hs::ExtensionProcessing::new(); + ep.process_common(sess, Some(server_key), hello, resumedata, &self.handshake)?; + + self.send_cert_status = ep.send_cert_status; + self.send_sct = ep.send_sct; + + let ee = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::EncryptedExtensions, + payload: HandshakePayload::EncryptedExtensions(ep.exts), + }), + }; + + trace!("sending encrypted extensions {:?}", ee); + sess.common.hs_transcript.add_message(&ee); + sess.common.send_msg(ee, true); + Ok(()) + } + + fn emit_certificate_req_tls13(&mut self, sess: &mut ServerSessionImpl) -> bool { + if !sess.config.verifier.offer_client_auth() { + return false; + } + + let mut cr = CertificateRequestPayloadTLS13 { + context: PayloadU8::empty(), + extensions: Vec::new(), + }; + + let schemes = verify::supported_verify_schemes(); + cr.extensions.push(CertReqExtension::SignatureAlgorithms(schemes.to_vec())); + + let names = sess.config.verifier.client_auth_root_subjects(); + if !names.is_empty() { + cr.extensions.push(CertReqExtension::AuthorityNames(names)); + } + + let m = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateRequest, + payload: HandshakePayload::CertificateRequestTLS13(cr), + }), + }; + + trace!("Sending CertificateRequest {:?}", m); + sess.common.hs_transcript.add_message(&m); + sess.common.send_msg(m, true); + true + } + + fn emit_certificate_tls13(&mut self, + sess: &mut ServerSessionImpl, + server_key: &mut sign::CertifiedKey) { + let mut cert_entries = vec![]; + for cert in server_key.take_cert() { + let entry = CertificateEntry { + cert, + exts: Vec::new(), + }; + + cert_entries.push(entry); + } + + if let Some(end_entity_cert) = cert_entries.first_mut() { + // Apply OCSP response to first certificate (we don't support OCSP + // except for leaf certs). + if self.send_cert_status { + if let Some(ocsp) = server_key.take_ocsp() { + let cst = CertificateStatus::new(ocsp); + end_entity_cert.exts.push(CertificateExtension::CertificateStatus(cst)); + } + } + + // Likewise, SCT + if self.send_sct { + if let Some(sct_list) = server_key.take_sct_list() { + end_entity_cert.exts.push(CertificateExtension::make_sct(sct_list)); + } + } + } + + let cert_body = CertificatePayloadTLS13::new(cert_entries); + let c = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::Certificate, + payload: HandshakePayload::CertificateTLS13(cert_body), + }), + }; + + trace!("sending certificate {:?}", c); + sess.common.hs_transcript.add_message(&c); + sess.common.send_msg(c, true); + } + + fn emit_certificate_verify_tls13(&mut self, + sess: &mut ServerSessionImpl, + server_key: &mut sign::CertifiedKey, + schemes: &[SignatureScheme]) + -> Result<(), TLSError> { + let mut message = Vec::new(); + message.resize(64, 0x20u8); + message.extend_from_slice(b"TLS 1.3, server CertificateVerify\x00"); + message.extend_from_slice(&sess.common.hs_transcript.get_current_hash()); + + let signing_key = &server_key.key; + let signer = signing_key.choose_scheme(schemes) + .ok_or_else(|| hs::incompatible(sess, "no overlapping sigschemes"))?; + + let scheme = signer.get_scheme(); + let sig = signer.sign(&message)?; + + let cv = DigitallySignedStruct::new(scheme, sig); + + let m = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::CertificateVerify, + payload: HandshakePayload::CertificateVerify(cv), + }), + }; + + trace!("sending certificate-verify {:?}", m); + sess.common.hs_transcript.add_message(&m); + sess.common.send_msg(m, true); + Ok(()) + } + + fn emit_finished_tls13(&mut self, sess: &mut ServerSessionImpl) { + let handshake_hash = sess.common.hs_transcript.get_current_hash(); + let verify_data = sess.common + .get_key_schedule() + .sign_finish(SecretKind::ServerHandshakeTrafficSecret, &handshake_hash); + let verify_data_payload = Payload::new(verify_data); + + let m = Message { + typ: ContentType::Handshake, + version: ProtocolVersion::TLSv1_3, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::Finished, + payload: HandshakePayload::Finished(verify_data_payload), + }), + }; + + trace!("sending finished {:?}", m); + sess.common.hs_transcript.add_message(&m); + self.handshake.hash_at_server_fin = sess.common.hs_transcript.get_current_hash(); + sess.common.send_msg(m, true); + + // Now move to application data keys. + sess.common.get_mut_key_schedule().input_empty(); + let write_key = sess.common + .get_key_schedule() + .derive(SecretKind::ServerApplicationTrafficSecret, + &self.handshake.hash_at_server_fin); + let suite = sess.common.get_suite_assert(); + sess.common.set_message_encrypter(cipher::new_tls13_write(suite, &write_key)); + sess.config.key_log.log(sess.common.protocol.labels().server_traffic_secret_0, + &self.handshake.randoms.client, + &write_key); + + #[cfg(feature = "quic")] { + let read_key = sess.common + .get_key_schedule() + .derive(SecretKind::ClientApplicationTrafficSecret, + &self.handshake.hash_at_server_fin); + sess.common.quic.traffic_secrets = Some(quic::Secrets { + client: read_key, + server: write_key.clone(), + }); + } + + sess.common + .get_mut_key_schedule() + .current_server_traffic_secret = write_key; + + + let exporter_secret = sess.common + .get_key_schedule() + .derive(SecretKind::ExporterMasterSecret, + &self.handshake.hash_at_server_fin); + sess.config.key_log.log(sess.common.protocol.labels().exporter_secret, + &self.handshake.randoms.client, + &exporter_secret); + sess.common + .get_mut_key_schedule() + .current_exporter_secret = exporter_secret; + } + + fn attempt_tls13_ticket_decryption(&mut self, + sess: &mut ServerSessionImpl, + ticket: &[u8]) -> Option { + if sess.config.ticketer.enabled() { + sess.config + .ticketer + .decrypt(ticket) + .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) + } else { + sess.config + .session_storage + .take(ticket) + .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain)) + } + } + + pub fn handle_client_hello(mut self, + sess: &mut ServerSessionImpl, + sni: Option, + mut server_key: sign::CertifiedKey, + chm: &Message) -> hs::NextStateOrError { + let client_hello = extract_handshake!(chm, HandshakePayload::ClientHello).unwrap(); + + if client_hello.compression_methods.len() != 1 { + return Err(hs::illegal_param(sess, "client offered wrong compressions")); + } + + let groups_ext = client_hello.get_namedgroups_extension() + .ok_or_else(|| hs::incompatible(sess, "client didn't describe groups"))?; + + let mut sigschemes_ext = client_hello.get_sigalgs_extension() + .ok_or_else(|| hs::incompatible(sess, "client didn't describe sigschemes"))? + .clone(); + + let tls13_schemes = sign::supported_sign_tls13(); + sigschemes_ext.retain(|scheme| tls13_schemes.contains(scheme)); + + let shares_ext = client_hello.get_keyshare_extension() + .ok_or_else(|| hs::incompatible(sess, "client didn't send keyshares"))?; + + if client_hello.has_keyshare_extension_with_duplicates() { + return Err(hs::illegal_param(sess, "client sent duplicate keyshares")); + } + + let share_groups: Vec = shares_ext.iter() + .map(|share| share.group) + .collect(); + + let supported_groups = suites::KeyExchange::supported_groups(); + let chosen_group = util::first_in_both(supported_groups, &share_groups); + if chosen_group.is_none() { + // We don't have a suitable key share. Choose a suitable group and + // send a HelloRetryRequest. + let retry_group_maybe = util::first_in_both(supported_groups, groups_ext); + sess.common.hs_transcript.add_message(chm); + + if let Some(group) = retry_group_maybe { + if self.done_retry { + return Err(hs::illegal_param(sess, "did not follow retry request")); + } + + self.emit_hello_retry_request(sess, group); + self.emit_fake_ccs(sess); + return Ok(self.into_expect_retried_client_hello()); + } + + return Err(hs::incompatible(sess, "no kx group overlap with client")); + } + + hs::save_sni(sess, sni); + + let chosen_group = chosen_group.unwrap(); + let chosen_share = shares_ext.iter() + .find(|share| share.group == chosen_group) + .unwrap(); + + let mut chosen_psk_index = None; + let mut resumedata = None; + if let Some(psk_offer) = client_hello.get_psk() { + if !client_hello.check_psk_ext_is_last() { + return Err(hs::illegal_param(sess, "psk extension in wrong position")); + } + + if psk_offer.binders.is_empty() { + return Err(hs::decode_error(sess, "psk extension missing binder")); + } + + if psk_offer.binders.len() != psk_offer.identities.len() { + return Err(hs::illegal_param(sess, "psk extension mismatched ids/binders")); + } + + for (i, psk_id) in psk_offer.identities.iter().enumerate() { + let maybe_resume = self.attempt_tls13_ticket_decryption(sess, &psk_id.identity.0); + + if !hs::can_resume(sess, &self.handshake, &maybe_resume) { + continue; + } + + let resume = maybe_resume.unwrap(); + + if !self.check_binder(sess, chm, &resume.master_secret.0, &psk_offer.binders[i].0) { + sess.common.send_fatal_alert(AlertDescription::DecryptError); + return Err(TLSError::PeerMisbehavedError("client sent wrong binder".to_string())); + } + + chosen_psk_index = Some(i); + resumedata = Some(resume); + break; + } + } + + if !client_hello.psk_mode_offered(PSKKeyExchangeMode::PSK_DHE_KE) { + warn!("Resumption ignored, DHE_KE not offered"); + self.send_ticket = false; + chosen_psk_index = None; + resumedata = None; + } else { + self.send_ticket = true; + } + + let full_handshake = resumedata.is_none(); + sess.common.hs_transcript.add_message(chm); + self.emit_server_hello(sess, &client_hello.session_id, + chosen_share, chosen_psk_index, + resumedata.as_ref().map(|x| &x.master_secret.0[..]))?; + if !self.done_retry { + self.emit_fake_ccs(sess); + } + self.emit_encrypted_extensions(sess, &mut server_key, client_hello, resumedata.as_ref())?; + + let doing_client_auth = if full_handshake { + let client_auth = self.emit_certificate_req_tls13(sess); + self.emit_certificate_tls13(sess, &mut server_key); + self.emit_certificate_verify_tls13(sess, &mut server_key, &sigschemes_ext)?; + client_auth + } else { + false + }; + + hs::check_aligned_handshake(sess)?; + self.emit_finished_tls13(sess); + + if doing_client_auth { + Ok(self.into_expect_certificate()) + } else { + Ok(self.into_expect_finished()) + } + } +} + pub struct ExpectCertificate { pub handshake: HandshakeDetails, pub send_ticket: bool,