in rustls-0.21.2/rustls/src/client/hs.rs [192:365]
fn emit_client_hello_for_retry(
mut transcript_buffer: HandshakeHashBuffer,
retryreq: Option<&HelloRetryRequest>,
key_share: Option<kx::KeyExchange>,
extra_exts: Vec<ClientExtension>,
may_send_sct_list: bool,
suite: Option<SupportedCipherSuite>,
mut input: ClientHelloInput,
cx: &mut ClientContext<'_>,
) -> NextState {
let config = &input.config;
let support_tls12 = config.supports_version(ProtocolVersion::TLSv1_2) && !cx.common.is_quic();
let support_tls13 = config.supports_version(ProtocolVersion::TLSv1_3);
let mut supported_versions = Vec::new();
if support_tls13 {
supported_versions.push(ProtocolVersion::TLSv1_3);
}
if support_tls12 {
supported_versions.push(ProtocolVersion::TLSv1_2);
}
// should be unreachable thanks to config builder
assert!(!supported_versions.is_empty());
let mut exts = vec![
ClientExtension::SupportedVersions(supported_versions),
ClientExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()),
ClientExtension::NamedGroups(
config
.kx_groups
.iter()
.map(|skxg| skxg.name)
.collect(),
),
ClientExtension::SignatureAlgorithms(
config
.verifier
.supported_verify_schemes(),
),
ClientExtension::ExtendedMasterSecretRequest,
ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()),
];
if let (Some(sni_name), true) = (input.server_name.for_sni(), config.enable_sni) {
exts.push(ClientExtension::make_sni(sni_name));
}
if may_send_sct_list {
exts.push(ClientExtension::SignedCertificateTimestampRequest);
}
if let Some(key_share) = &key_share {
debug_assert!(support_tls13);
let key_share = KeyShareEntry::new(key_share.group(), key_share.pubkey.as_ref());
exts.push(ClientExtension::KeyShare(vec![key_share]));
}
if let Some(cookie) = retryreq.and_then(HelloRetryRequest::get_cookie) {
exts.push(ClientExtension::Cookie(cookie.clone()));
}
if support_tls13 {
// We could support PSK_KE here too. Such connections don't
// have forward secrecy, and are similar to TLS1.2 resumption.
let psk_modes = vec![PSKKeyExchangeMode::PSK_DHE_KE];
exts.push(ClientExtension::PresharedKeyModes(psk_modes));
}
if !config.alpn_protocols.is_empty() {
exts.push(ClientExtension::Protocols(Vec::from_slices(
&config
.alpn_protocols
.iter()
.map(|proto| &proto[..])
.collect::<Vec<_>>(),
)));
}
// Extra extensions must be placed before the PSK extension
exts.extend(extra_exts.iter().cloned());
// Do we have a SessionID or ticket cached for this host?
let tls13_session = prepare_resumption(&input.resuming, &mut exts, suite, cx, config);
// Note what extensions we sent.
input.hello.sent_extensions = exts
.iter()
.map(ClientExtension::get_type)
.collect();
let mut cipher_suites: Vec<_> = config
.cipher_suites
.iter()
.map(|cs| cs.suite())
.collect();
// We don't do renegotiation at all, in fact.
cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
let mut chp = HandshakeMessagePayload {
typ: HandshakeType::ClientHello,
payload: HandshakePayload::ClientHello(ClientHelloPayload {
client_version: ProtocolVersion::TLSv1_2,
random: input.random,
session_id: input.session_id,
cipher_suites,
compression_methods: vec![Compression::Null],
extensions: exts,
}),
};
let early_key_schedule = if let Some(resuming) = tls13_session {
let schedule = tls13::fill_in_psk_binder(&resuming, &transcript_buffer, &mut chp);
Some((resuming.suite(), schedule))
} else {
None
};
let ch = Message {
// "This value MUST be set to 0x0303 for all records generated
// by a TLS 1.3 implementation other than an initial ClientHello
// (i.e., one not generated after a HelloRetryRequest)"
version: if retryreq.is_some() {
ProtocolVersion::TLSv1_2
} else {
ProtocolVersion::TLSv1_0
},
payload: MessagePayload::handshake(chp),
};
if retryreq.is_some() {
// send dummy CCS to fool middleboxes prior
// to second client hello
tls13::emit_fake_ccs(&mut input.sent_tls13_fake_ccs, cx.common);
}
trace!("Sending ClientHello {:#?}", ch);
transcript_buffer.add_message(&ch);
cx.common.send_msg(ch, false);
// Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret
let early_key_schedule = early_key_schedule.map(|(resuming_suite, schedule)| {
if !cx.data.early_data.is_enabled() {
return schedule;
}
tls13::derive_early_traffic_secret(
&*config.key_log,
cx,
resuming_suite,
&schedule,
&mut input.sent_tls13_fake_ccs,
&transcript_buffer,
&input.random.0,
);
schedule
});
let next = ExpectServerHello {
input,
transcript_buffer,
early_key_schedule,
offered_key_share: key_share,
suite,
};
if support_tls13 && retryreq.is_none() {
Box::new(ExpectServerHelloOrHelloRetryRequest { next, extra_exts })
} else {
Box::new(next)
}
}