fn handle()

in rustls-0.19.1/rustls/src/server/hs.rs [627:959]


    fn handle(mut self: Box<Self>, sess: &mut ServerSessionImpl, m: Message) -> NextStateOrError {
        let client_hello =
            require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?;
        let tls13_enabled = sess
            .config
            .supports_version(ProtocolVersion::TLSv1_3);
        let tls12_enabled = sess
            .config
            .supports_version(ProtocolVersion::TLSv1_2);
        trace!("we got a clienthello {:?}", client_hello);

        if !client_hello
            .compression_methods
            .contains(&Compression::Null)
        {
            sess.common
                .send_fatal_alert(AlertDescription::IllegalParameter);
            return Err(TLSError::PeerIncompatibleError(
                "client did not offer Null compression".to_string(),
            ));
        }

        if client_hello.has_duplicate_extension() {
            return Err(decode_error(sess, "client sent duplicate extensions"));
        }

        // No handshake messages should follow this one in this flight.
        check_aligned_handshake(sess)?;

        // 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::TLSv1_3) && tls13_enabled {
                sess.common.negotiated_version = Some(ProtocolVersion::TLSv1_3);
            } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !tls12_enabled {
                return Err(bad_version(sess, "TLS1.2 not offered/enabled"));
            }
        } else if client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() {
            return Err(bad_version(sess, "Client does not support TLSv1_2"));
        } else if !tls12_enabled && tls13_enabled {
            return Err(bad_version(
                sess,
                "Server requires TLS1.3, but client omitted versions ext",
            ));
        }

        if sess.common.negotiated_version == None {
            sess.common.negotiated_version = Some(ProtocolVersion::TLSv1_2);
        }

        // --- Common to TLS1.2 and TLS1.3: ciphersuite and certificate selection.

        // Extract and validate the SNI DNS name, if any, before giving it to
        // the cert resolver. In particular, if it is invalid then we should
        // send an Illegal Parameter alert instead of the Internal Error alert
        // (or whatever) that we'd send if this were checked later or in a
        // different way.
        let sni: Option<webpki::DNSName> = match client_hello.get_sni_extension() {
            Some(sni) => {
                if sni.has_duplicate_names_for_type() {
                    return Err(decode_error(
                        sess,
                        "ClientHello SNI contains duplicate name types",
                    ));
                }

                if let Some(hostname) = sni.get_single_hostname() {
                    Some(hostname.into())
                } else {
                    return Err(illegal_param(
                        sess,
                        "ClientHello SNI did not contain a hostname",
                    ));
                }
            }
            None => None,
        };

        if !self.done_retry {
            // save only the first SNI
            save_sni(sess, sni.clone());
        }

        // We communicate to the upper layer what kind of key they should choose
        // via the sigschemes value.  Clients tend to treat this extension
        // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not).
        // So: reduce the offered sigschemes to those compatible with the
        // intersection of ciphersuites.
        let mut common_suites = sess.config.ciphersuites.clone();
        common_suites.retain(|scs| {
            client_hello
                .cipher_suites
                .contains(&scs.suite)
        });

        let mut sigschemes_ext = client_hello
            .get_sigalgs_extension()
            .cloned()
            .unwrap_or_else(SupportedSignatureSchemes::default);
        sigschemes_ext
            .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &common_suites));

        let alpn_protocols = client_hello
            .get_alpn_extension()
            .map(|protos| protos.to_slices());

        // Choose a certificate.
        let mut certkey = {
            let sni_ref = sni
                .as_ref()
                .map(webpki::DNSName::as_ref);
            trace!("sni {:?}", sni_ref);
            trace!("sig schemes {:?}", sigschemes_ext);
            trace!("alpn protocols {:?}", alpn_protocols);

            let alpn_slices = match alpn_protocols {
                Some(ref vec) => Some(vec.as_slice()),
                None => None,
            };

            let client_hello = ClientHello::new(sni_ref, &sigschemes_ext, alpn_slices);

            let certkey = sess
                .config
                .cert_resolver
                .resolve(client_hello);
            certkey.ok_or_else(|| {
                sess.common
                    .send_fatal_alert(AlertDescription::AccessDenied);
                TLSError::General("no server certificate chain resolved".to_string())
            })?
        };

        // Reduce our supported ciphersuites by the certificate.
        // (no-op for TLS1.3)
        let suitable_suites =
            suites::reduce_given_sigalg(&sess.config.ciphersuites, certkey.key.algorithm());

        // And version
        let protocol_version = sess.common.negotiated_version.unwrap();
        let suitable_suites = suites::reduce_given_version(&suitable_suites, protocol_version);

        let maybe_ciphersuite = if sess.config.ignore_client_order {
            suites::choose_ciphersuite_preferring_server(
                &client_hello.cipher_suites,
                &suitable_suites,
            )
        } else {
            suites::choose_ciphersuite_preferring_client(
                &client_hello.cipher_suites,
                &suitable_suites,
            )
        };

        if maybe_ciphersuite.is_none() {
            return Err(incompatible(sess, "no ciphersuites in common"));
        }

        debug!(
            "decided upon suite {:?}",
            maybe_ciphersuite.as_ref().unwrap()
        );
        sess.common
            .set_suite(maybe_ciphersuite.unwrap());

        // Start handshake hash.
        let starting_hash = sess
            .common
            .get_suite_assert()
            .get_hash();
        if !self
            .handshake
            .transcript
            .start_hash(starting_hash)
        {
            sess.common
                .send_fatal_alert(AlertDescription::IllegalParameter);
            return Err(TLSError::PeerIncompatibleError(
                "hash differed on retry".to_string(),
            ));
        }

        // Save their Random.
        client_hello
            .random
            .write_slice(&mut self.handshake.randoms.client);

        if sess.common.is_tls13() {
            return self
                .into_complete_tls13_client_hello_handling()
                .handle_client_hello(sess, certkey, &m);
        }

        // -- TLS1.2 only from hereon in --
        self.handshake
            .transcript
            .add_message(&m);

        if client_hello.ems_support_offered() {
            self.handshake.using_ems = true;
        }

        let groups_ext = client_hello
            .get_namedgroups_extension()
            .ok_or_else(|| incompatible(sess, "client didn't describe groups"))?;
        let ecpoints_ext = client_hello
            .get_ecpoints_extension()
            .ok_or_else(|| incompatible(sess, "client didn't describe ec points"))?;

        trace!("namedgroups {:?}", groups_ext);
        trace!("ecpoints {:?}", ecpoints_ext);

        if !ecpoints_ext.contains(&ECPointFormat::Uncompressed) {
            sess.common
                .send_fatal_alert(AlertDescription::IllegalParameter);
            return Err(TLSError::PeerIncompatibleError(
                "client didn't support uncompressed ec points".to_string(),
            ));
        }

        // -- If TLS1.3 is enabled, signal the downgrade in the server random
        if tls13_enabled {
            self.handshake
                .randoms
                .set_tls12_downgrade_marker();
        }

        // -- Check for resumption --
        // We can do this either by (in order of preference):
        // 1. receiving a ticket that decrypts
        // 2. receiving a sessionid that is in our cache
        //
        // If we receive a ticket, the sessionid won't be in our
        // cache, so don't check.
        //
        // If either works, we end up with a ServerSessionValue
        // which is passed to start_resumption and concludes
        // our handling of the ClientHello.
        //
        let mut ticket_received = false;

        if let Some(ticket_ext) = client_hello.get_ticket_extension() {
            if let ClientExtension::SessionTicketOffer(ref ticket) = *ticket_ext {
                ticket_received = true;
                debug!("Ticket received");

                let maybe_resume = sess
                    .config
                    .ticketer
                    .decrypt(&ticket.0)
                    .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain));

                if can_resume(sess, &self.handshake, &maybe_resume) {
                    return self.start_resumption(
                        sess,
                        client_hello,
                        sni.as_ref(),
                        &client_hello.session_id,
                        maybe_resume.unwrap(),
                    );
                } else {
                    debug!("Ticket didn't decrypt");
                }
            }
        }

        // If we're not offered a ticket or a potential session ID,
        // allocate a session ID.
        if self.handshake.session_id.is_empty() && !ticket_received {
            let mut bytes = [0u8; 32];
            rand::fill_random(&mut bytes);
            self.handshake.session_id = SessionID::new(&bytes);
        }

        // Perhaps resume?  If we received a ticket, the sessionid
        // does not correspond to a real session.
        if !client_hello.session_id.is_empty() && !ticket_received {
            let maybe_resume = sess
                .config
                .session_storage
                .get(&client_hello.session_id.get_encoding())
                .and_then(|x| persist::ServerSessionValue::read_bytes(&x));

            if can_resume(sess, &self.handshake, &maybe_resume) {
                return self.start_resumption(
                    sess,
                    client_hello,
                    sni.as_ref(),
                    &client_hello.session_id,
                    maybe_resume.unwrap(),
                );
            }
        }

        // Now we have chosen a ciphersuite, we can make kx decisions.
        let sigschemes = sess
            .common
            .get_suite_assert()
            .resolve_sig_schemes(&sigschemes_ext);

        if sigschemes.is_empty() {
            return Err(incompatible(sess, "no supported sig scheme"));
        }

        let group = suites::KeyExchange::supported_groups()
            .iter()
            .filter(|group| groups_ext.contains(group))
            .nth(0)
            .cloned()
            .ok_or_else(|| incompatible(sess, "no supported group"))?;

        let ecpoint = ECPointFormatList::supported()
            .iter()
            .filter(|format| ecpoints_ext.contains(format))
            .nth(0)
            .cloned()
            .ok_or_else(|| incompatible(sess, "no supported point format"))?;

        debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed);

        self.emit_server_hello(sess, Some(&mut certkey), client_hello, None)?;
        self.emit_certificate(sess, &mut certkey);
        self.emit_cert_status(sess, &mut certkey);
        let kx = self.emit_server_kx(sess, sigschemes, group, &mut certkey)?;
        let doing_client_auth = self.emit_certificate_req(sess)?;
        self.emit_server_hello_done(sess);

        if doing_client_auth {
            Ok(self.into_expect_tls12_certificate(kx))
        } else {
            Ok(self.into_expect_tls12_client_kx(kx))
        }
    }