in rustls-0.19.1/rustls/src/client/hs.rs [498:746]
fn handle(mut self: Box<Self>, sess: &mut ClientSessionImpl, m: Message) -> NextStateOrError {
let server_hello =
require_handshake_msg!(m, HandshakeType::ServerHello, HandshakePayload::ServerHello)?;
trace!("We got ServerHello {:#?}", server_hello);
use crate::ProtocolVersion::{TLSv1_2, TLSv1_3};
let tls13_supported = sess.config.supports_version(TLSv1_3);
let server_version = if server_hello.legacy_version == TLSv1_2 {
server_hello
.get_supported_versions()
.unwrap_or(server_hello.legacy_version)
} else {
server_hello.legacy_version
};
match server_version {
TLSv1_3 if tls13_supported => {
sess.common.negotiated_version = Some(TLSv1_3);
}
TLSv1_2 if sess.config.supports_version(TLSv1_2) => {
if sess.early_data.is_enabled() && sess.common.early_traffic {
// The client must fail with a dedicated error code if the server
// responds with TLS 1.2 when offering 0-RTT.
return Err(TLSError::PeerMisbehavedError(
"server chose v1.2 when offering 0-rtt".to_string(),
));
}
sess.common.negotiated_version = Some(TLSv1_2);
if server_hello
.get_supported_versions()
.is_some()
{
return Err(illegal_param(
sess,
"server chose v1.2 using v1.3 extension",
));
}
}
_ => {
sess.common
.send_fatal_alert(AlertDescription::ProtocolVersion);
return Err(TLSError::PeerIncompatibleError(
"server does not support TLS v1.2/v1.3".to_string(),
));
}
};
if server_hello.compression_method != Compression::Null {
return Err(illegal_param(sess, "server chose non-Null compression"));
}
if server_hello.has_duplicate_extension() {
sess.common
.send_fatal_alert(AlertDescription::DecodeError);
return Err(TLSError::PeerMisbehavedError(
"server sent duplicate extensions".to_string(),
));
}
let allowed_unsolicited = [ExtensionType::RenegotiationInfo];
if self
.hello
.server_sent_unsolicited_extensions(&server_hello.extensions, &allowed_unsolicited)
{
sess.common
.send_fatal_alert(AlertDescription::UnsupportedExtension);
return Err(TLSError::PeerMisbehavedError(
"server sent unsolicited extension".to_string(),
));
}
// Extract ALPN protocol
if !sess.common.is_tls13() {
process_alpn_protocol(sess, server_hello.get_alpn_protocol())?;
}
// If ECPointFormats extension is supplied by the server, it must contain
// Uncompressed. But it's allowed to be omitted.
if let Some(point_fmts) = server_hello.get_ecpoints_extension() {
if !point_fmts.contains(&ECPointFormat::Uncompressed) {
sess.common
.send_fatal_alert(AlertDescription::HandshakeFailure);
return Err(TLSError::PeerMisbehavedError(
"server does not support uncompressed points".to_string(),
));
}
}
let scs = sess.find_cipher_suite(server_hello.cipher_suite);
if scs.is_none() {
sess.common
.send_fatal_alert(AlertDescription::HandshakeFailure);
return Err(TLSError::PeerMisbehavedError(
"server chose non-offered ciphersuite".to_string(),
));
}
debug!("Using ciphersuite {:?}", server_hello.cipher_suite);
if !sess.common.set_suite(scs.unwrap()) {
return Err(illegal_param(sess, "server varied selected ciphersuite"));
}
let version = sess.common.negotiated_version.unwrap();
if !sess
.common
.get_suite_assert()
.usable_for_version(version)
{
return Err(illegal_param(
sess,
"server chose unusable ciphersuite for version",
));
}
// Start our handshake hash, and input the server-hello.
let starting_hash = sess
.common
.get_suite_assert()
.get_hash();
self.handshake
.transcript
.start_hash(starting_hash);
self.handshake
.transcript
.add_message(&m);
// For TLS1.3, start message encryption using
// handshake_traffic_secret.
if sess.common.is_tls13() {
tls13::validate_server_hello(sess, &server_hello)?;
let key_schedule = tls13::start_handshake_traffic(
sess,
self.early_key_schedule.take(),
&server_hello,
&mut self.handshake,
&mut self.hello,
)?;
tls13::emit_fake_ccs(&mut self.handshake, sess);
return Ok(self.into_expect_tls13_encrypted_extensions(key_schedule));
}
// TLS1.2 only from here-on
// Save ServerRandom and SessionID
server_hello
.random
.write_slice(&mut self.handshake.randoms.server);
self.handshake.session_id = server_hello.session_id;
// Look for TLS1.3 downgrade signal in server random
if tls13_supported
&& self
.handshake
.randoms
.has_tls12_downgrade_marker()
{
return Err(illegal_param(
sess,
"downgrade to TLS1.2 when TLS1.3 is supported",
));
}
// Doing EMS?
if server_hello.ems_support_acked() {
self.handshake.using_ems = true;
}
// Might the server send a ticket?
let with_tickets = if server_hello
.find_extension(ExtensionType::SessionTicket)
.is_some()
{
debug!("Server supports tickets");
true
} else {
false
};
self.must_issue_new_ticket = with_tickets;
// Might the server send a CertificateStatus between Certificate and
// ServerKeyExchange?
if server_hello
.find_extension(ExtensionType::StatusRequest)
.is_some()
{
debug!("Server may staple OCSP response");
self.may_send_cert_status = true;
}
// Save any sent SCTs for verification against the certificate.
if let Some(sct_list) = server_hello.get_sct_list() {
debug!("Server sent {:?} SCTs", sct_list.len());
if sct_list_is_invalid(sct_list) {
let error_msg = "server sent invalid SCT list".to_string();
return Err(TLSError::PeerMisbehavedError(error_msg));
}
self.server_cert.scts = Some(sct_list.clone());
}
// See if we're successfully resuming.
if let Some(ref resuming) = self.handshake.resuming_session {
if resuming.session_id == self.handshake.session_id {
debug!("Server agreed to resume");
// Is the server telling lies about the ciphersuite?
if resuming.cipher_suite != scs.unwrap().suite {
let error_msg = "abbreviated handshake offered, but with varied cs".to_string();
return Err(TLSError::PeerMisbehavedError(error_msg));
}
// And about EMS support?
if resuming.extended_ms != self.handshake.using_ems {
let error_msg = "server varied ems support over resume".to_string();
return Err(TLSError::PeerMisbehavedError(error_msg));
}
let secrets = SessionSecrets::new_resume(
&self.handshake.randoms,
scs.unwrap().get_hash(),
&resuming.master_secret.0,
);
sess.config.key_log.log(
"CLIENT_RANDOM",
&secrets.randoms.client,
&secrets.master_secret,
);
sess.common
.start_encryption_tls12(&secrets);
// Since we're resuming, we verified the certificate and
// proof of possession in the prior session.
sess.server_cert_chain = resuming.server_cert_chain.clone();
let certv = verify::ServerCertVerified::assertion();
let sigv = verify::HandshakeSignatureValid::assertion();
return if self.must_issue_new_ticket {
Ok(self.into_expect_tls12_new_ticket_resume(secrets, certv, sigv))
} else {
Ok(self.into_expect_tls12_ccs_resume(secrets, certv, sigv))
};
}
}
Ok(self.into_expect_tls12_certificate())
}