static enum ssl_hs_wait_t do_read_server_hello()

in ssl/handshake_client.cc [702:918]


static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) {
  SSL *const ssl = hs->ssl;
  SSLMessage msg;
  if (!ssl->method->get_message(ssl, &msg)) {
    return ssl_hs_read_server_hello;
  }

  ParsedServerHello server_hello;
  uint16_t server_version;
  uint8_t alert = SSL_AD_DECODE_ERROR;
  if (!ssl_parse_server_hello(&server_hello, &alert, msg) ||
      !parse_server_version(hs, &server_version, &alert, server_hello)) {
    ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
    return ssl_hs_error;
  }

  if (!ssl_supports_version(hs, server_version)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
    return ssl_hs_error;
  }

  assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
  if (!ssl->s3->have_version) {
    ssl->version = server_version;
    // At this point, the connection's version is known and ssl->version is
    // fixed. Begin enforcing the record-layer version.
    ssl->s3->have_version = true;
    ssl->s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version);
  } else if (server_version != ssl->version) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SSL_VERSION);
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
    return ssl_hs_error;
  }

  if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
    hs->state = state_tls13;
    return ssl_hs_ok;
  }

  // Clear some TLS 1.3 state that no longer needs to be retained.
  hs->key_shares[0].reset();
  hs->key_shares[1].reset();
  ssl_done_writing_client_hello(hs);

  // A TLS 1.2 server would not know to skip the early data we offered. Report
  // an error code sooner. The caller may use this error code to implement the
  // fallback described in RFC 8446 appendix D.3.
  if (hs->early_data_offered) {
    // Disconnect early writes. This ensures subsequent |SSL_write| calls query
    // the handshake which, in turn, will replay the error code rather than fail
    // at the |write_shutdown| check. See https://crbug.com/1078515.
    // TODO(davidben): Should all handshake errors do this? What about record
    // decryption failures?
    hs->can_early_write = false;
    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_ON_EARLY_DATA);
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
    return ssl_hs_error;
  }

  // TLS 1.2 handshakes cannot accept ECH.
  if (hs->selected_ech_config) {
    ssl->s3->ech_status = ssl_ech_rejected;
  }

  // Copy over the server random.
  OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_hello.random),
                 SSL3_RANDOM_SIZE);

  // Enforce the TLS 1.3 anti-downgrade feature.
  if (!ssl->s3->initial_handshake_complete &&
      ssl_supports_version(hs, TLS1_3_VERSION)) {
    static_assert(
        sizeof(kTLS12DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
        "downgrade signals have different size");
    static_assert(
        sizeof(kJDK11DowngradeRandom) == sizeof(kTLS13DowngradeRandom),
        "downgrade signals have different size");
    auto suffix =
        MakeConstSpan(ssl->s3->server_random, sizeof(ssl->s3->server_random))
            .subspan(SSL3_RANDOM_SIZE - sizeof(kTLS13DowngradeRandom));
    if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom ||
        suffix == kJDK11DowngradeRandom) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
      return ssl_hs_error;
    }
  }

  // The cipher must be allowed in the selected version and enabled.
  const SSL_CIPHER *cipher = SSL_get_cipher_by_value(server_hello.cipher_suite);
  uint32_t mask_a, mask_k;
  ssl_get_client_disabled(hs, &mask_a, &mask_k);
  if (cipher == nullptr ||
      (cipher->algorithm_mkey & mask_k) ||
      (cipher->algorithm_auth & mask_a) ||
      SSL_CIPHER_get_min_version(cipher) > ssl_protocol_version(ssl) ||
      SSL_CIPHER_get_max_version(cipher) < ssl_protocol_version(ssl) ||
      !sk_SSL_CIPHER_find_awslc(SSL_get_ciphers(ssl), nullptr, cipher)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
    return ssl_hs_error;
  }

  hs->new_cipher = cipher;

  if (hs->session_id_len != 0 &&
      CBS_mem_equal(&server_hello.session_id, hs->session_id,
                    hs->session_id_len)) {
    // Echoing the ClientHello session ID in TLS 1.2, whether from the session
    // or a synthetic one, indicates resumption. If there was no session (or if
    // the session was only offered in ECH ClientHelloInner), this was the
    // TLS 1.3 compatibility mode session ID. As we know this is not a session
    // the server knows about, any server resuming it is in error. Reject the
    // first connection deterministicly, rather than installing an invalid
    // session into the session cache. https://crbug.com/796910
    if (ssl->session == nullptr || ssl->s3->ech_status == ssl_ech_rejected) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SERVER_ECHOED_INVALID_SESSION_ID);
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
      return ssl_hs_error;
    }
    if (ssl->session->ssl_version != ssl->version) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED);
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
      return ssl_hs_error;
    }
    if (ssl->session->cipher != hs->new_cipher) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
      return ssl_hs_error;
    }
    if (!ssl_session_is_context_valid(hs, ssl->session.get())) {
      // This is actually a client application bug.
      OPENSSL_PUT_ERROR(SSL,
                        SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT);
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
      return ssl_hs_error;
    }
    // We never offer sessions on renegotiation.
    assert(!ssl->s3->initial_handshake_complete);
    ssl->s3->session_reused = true;
  } else {
    // The session wasn't resumed. Create a fresh SSL_SESSION to fill out.
    ssl_set_session(ssl, NULL);
    if (!ssl_get_new_session(hs)) {
      ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
      return ssl_hs_error;
    }

    // Save the session ID from the server. This may be empty if the session
    // isn't resumable, or if we'll receive a session ticket later.
    assert(CBS_len(&server_hello.session_id) <= SSL3_SESSION_ID_SIZE);
    static_assert(SSL3_SESSION_ID_SIZE <= UINT8_MAX,
                  "max session ID is too large");
    hs->new_session->session_id_length =
        static_cast<uint8_t>(CBS_len(&server_hello.session_id));
    OPENSSL_memcpy(hs->new_session->session_id,
                   CBS_data(&server_hello.session_id),
                   CBS_len(&server_hello.session_id));

    hs->new_session->cipher = hs->new_cipher;
  }

  // Now that the cipher is known, initialize the handshake hash and hash the
  // ServerHello.
  if (!hs->transcript.InitHash(ssl_protocol_version(ssl), hs->new_cipher) ||
      !ssl_hash_message(hs, msg)) {
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
    return ssl_hs_error;
  }

  // If doing a full handshake, the server may request a client certificate
  // which requires hashing the handshake transcript. Otherwise, the handshake
  // buffer may be released.
  if (ssl->session != NULL ||
      !ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
    hs->transcript.FreeBuffer();
  }

  // Only the NULL compression algorithm is supported.
  if (server_hello.compression_method != 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM);
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
    return ssl_hs_error;
  }

  if (!ssl_parse_serverhello_tlsext(hs, &server_hello.extensions)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
    return ssl_hs_error;
  }

  if (ssl->session != NULL &&
      hs->extended_master_secret != ssl->session->extended_master_secret) {
    if (ssl->session->extended_master_secret) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
    } else {
      OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION);
    }
    ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
    return ssl_hs_error;
  }

  ssl->method->next_message(ssl);

  if (ssl->session != NULL) {
    if (ssl->ctx->reverify_on_resume &&
        ssl_cipher_uses_certificate_auth(hs->new_cipher)) {
      hs->state = state_reverify_server_certificate;
    } else {
      hs->state = state_read_session_ticket;
    }
    return ssl_hs_ok;
  }

  hs->state = state_read_server_certificate;
  return ssl_hs_ok;
}