fn emit_client_hello_for_retry()

in rustls-0.19.1/rustls/src/client/hs.rs [188:415]


fn emit_client_hello_for_retry(
    sess: &mut ClientSessionImpl,
    mut handshake: HandshakeDetails,
    mut hello: ClientHelloDetails,
    retryreq: Option<&HelloRetryRequest>,
) -> NextState {
    // Do we have a SessionID or ticket cached for this host?
    handshake.resuming_session = find_session(sess, handshake.dns_name.as_ref());
    let (session_id, ticket, resume_version) = if handshake.resuming_session.is_some() {
        let resuming = handshake
            .resuming_session
            .as_mut()
            .unwrap();
        if resuming.version == ProtocolVersion::TLSv1_2 {
            random_sessionid_for_ticket(resuming);
        }
        debug!("Resuming session");
        (
            resuming.session_id,
            resuming.ticket.0.clone(),
            resuming.version,
        )
    } else {
        debug!("Not resuming any session");
        if handshake.session_id.is_empty() && !sess.common.is_quic() {
            handshake.session_id = random_sessionid();
        }
        (
            handshake.session_id,
            Vec::new(),
            ProtocolVersion::Unknown(0),
        )
    };

    let support_tls12 = sess
        .config
        .supports_version(ProtocolVersion::TLSv1_2);
    let support_tls13 = sess
        .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);
    }

    let mut exts = Vec::new();
    if !supported_versions.is_empty() {
        exts.push(ClientExtension::SupportedVersions(supported_versions));
    }
    if sess.config.enable_sni {
        exts.push(ClientExtension::make_sni(handshake.dns_name.as_ref()));
    }
    exts.push(ClientExtension::ECPointFormats(
        ECPointFormatList::supported(),
    ));
    exts.push(ClientExtension::NamedGroups(
        suites::KeyExchange::supported_groups().to_vec(),
    ));
    exts.push(ClientExtension::SignatureAlgorithms(
        sess.config
            .get_verifier()
            .supported_verify_schemes(),
    ));
    exts.push(ClientExtension::ExtendedMasterSecretRequest);
    exts.push(ClientExtension::CertificateStatusRequest(
        CertificateStatusRequest::build_ocsp(),
    ));

    if sess.config.ct_logs.is_some() {
        exts.push(ClientExtension::SignedCertificateTimestampRequest);
    }

    if support_tls13 {
        tls13::choose_kx_groups(sess, &mut exts, &mut hello, &mut handshake, retryreq);
    }

    if let Some(cookie) = retryreq.and_then(HelloRetryRequest::get_cookie) {
        exts.push(ClientExtension::Cookie(cookie.clone()));
    }

    if support_tls13 && sess.config.enable_tickets {
        // 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 !sess.config.alpn_protocols.is_empty() {
        exts.push(ClientExtension::Protocols(ProtocolNameList::from_slices(
            &sess
                .config
                .alpn_protocols
                .iter()
                .map(|proto| &proto[..])
                .collect::<Vec<_>>(),
        )));
    }

    // Extra extensions must be placed before the PSK extension
    exts.extend(handshake.extra_exts.iter().cloned());

    let fill_in_binder = if support_tls13
        && sess.config.enable_tickets
        && resume_version == ProtocolVersion::TLSv1_3
        && !ticket.is_empty()
    {
        tls13::prepare_resumption(sess, ticket, &handshake, &mut exts, retryreq.is_some())
    } else if sess.config.enable_tickets {
        // If we have a ticket, include it.  Otherwise, request one.
        if ticket.is_empty() {
            exts.push(ClientExtension::SessionTicketRequest);
        } else {
            exts.push(ClientExtension::SessionTicketOffer(Payload::new(ticket)));
        }
        false
    } else {
        false
    };

    // Note what extensions we sent.
    hello.sent_extensions = exts
        .iter()
        .map(ClientExtension::get_type)
        .collect();

    let mut chp = HandshakeMessagePayload {
        typ: HandshakeType::ClientHello,
        payload: HandshakePayload::ClientHello(ClientHelloPayload {
            client_version: ProtocolVersion::TLSv1_2,
            random: Random::from_slice(&handshake.randoms.client),
            session_id,
            cipher_suites: sess.get_cipher_suites(),
            compression_methods: vec![Compression::Null],
            extensions: exts,
        }),
    };

    let early_key_schedule = if fill_in_binder {
        Some(tls13::fill_in_psk_binder(sess, &mut handshake, &mut chp))
    } else {
        None
    };

    let ch = Message {
        typ: ContentType::Handshake,
        // "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 handshake, sess);
    }

    trace!("Sending ClientHello {:#?}", ch);

    handshake.transcript.add_message(&ch);
    sess.common.send_msg(ch, false);

    // Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret
    if sess.early_data.is_enabled() {
        // For middlebox compatibility
        tls13::emit_fake_ccs(&mut handshake, sess);

        // It is safe to call unwrap() because fill_in_binder is true.
        let resuming_suite = handshake
            .resuming_session
            .as_ref()
            .and_then(|resume| sess.find_cipher_suite(resume.cipher_suite))
            .unwrap();

        let client_hello_hash = handshake
            .transcript
            .get_hash_given(resuming_suite.get_hash(), &[]);
        let client_early_traffic_secret = early_key_schedule
            .as_ref()
            .unwrap()
            .client_early_traffic_secret(
                &client_hello_hash,
                &*sess.config.key_log,
                &handshake.randoms.client,
            );
        // Set early data encryption key
        sess.common
            .record_layer
            .set_message_encrypter(cipher::new_tls13_write(
                resuming_suite,
                &client_early_traffic_secret,
            ));

        #[cfg(feature = "quic")]
        {
            sess.common.quic.early_secret = Some(client_early_traffic_secret);
        }

        // Now the client can send encrypted early data
        sess.common.early_traffic = true;
        trace!("Starting early data traffic");
    }

    let next = ExpectServerHello {
        handshake,
        hello,
        early_key_schedule,
        server_cert: ServerCertDetails::new(),
        may_send_cert_status: false,
        must_issue_new_ticket: false,
    };

    if support_tls13 && retryreq.is_none() {
        Box::new(ExpectServerHelloOrHelloRetryRequest(next))
    } else {
        Box::new(next)
    }
}