static int SSL3_STATE_from_bytes()

in ssl/ssl_transfer_asn1.cc [450:837]


static int SSL3_STATE_from_bytes(SSL *ssl, CBS *cbs, const SSL_CTX *ctx) {
  // We expect the caller to have configured |ssl| with the protocol
  // version prior to calling us.
  uint16_t protocol_version;
  if (!ssl_protocol_version_from_wire(&protocol_version, ssl->version)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  bool is_tls13 = protocol_version >= TLS1_3_VERSION;

  SSL3_STATE *out = ssl->s3;
  CBS s3, read_seq, write_seq, server_random, client_random, send_alert,
      pending_app_data, read_buffer;
  CBS previous_client_finished, previous_server_finished;
  int session_reused, channel_id_valid, send_connection_binding, not_resumable;
  uint64_t serde_version, early_data_reason, previous_client_finished_len,
      previous_server_finished_len;
  uint64_t empty_record_count, warning_alert_count, total_renegotiations;
  int64_t rwstate;
  int pending_app_data_present, read_buffer_present;
  if (!CBS_get_asn1(cbs, &s3, CBS_ASN1_SEQUENCE) ||
      !CBS_get_asn1_uint64(&s3, &serde_version) ||
      serde_version > SSL3_STATE_SERDE_VERSION_TWO ||
      (is_tls13 && serde_version < SSL3_STATE_SERDE_VERSION_TWO) ||
      !CBS_get_asn1(&s3, &read_seq, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&read_seq) != TLS_SEQ_NUM_SIZE ||
      !CBS_get_asn1(&s3, &write_seq, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&write_seq) != TLS_SEQ_NUM_SIZE ||
      !CBS_get_asn1(&s3, &server_random, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&server_random) != SSL3_RANDOM_SIZE ||
      !CBS_get_asn1(&s3, &client_random, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&client_random) != SSL3_RANDOM_SIZE ||
      !CBS_get_asn1(&s3, &send_alert, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&send_alert) != SSL3_SEND_ALERT_SIZE ||
      !CBS_get_asn1_int64(&s3, &rwstate) ||
      !CBS_get_asn1_uint64(&s3, &early_data_reason) ||
      early_data_reason > ssl_early_data_reason_max_value ||
      !CBS_get_asn1(&s3, &previous_client_finished, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&previous_client_finished) > PREV_FINISHED_MAX_SIZE ||
      !CBS_get_asn1_uint64(&s3, &previous_client_finished_len) ||
      previous_client_finished_len > PREV_FINISHED_MAX_SIZE ||
      !CBS_get_asn1(&s3, &previous_server_finished, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&previous_server_finished) > PREV_FINISHED_MAX_SIZE ||
      !CBS_get_asn1_uint64(&s3, &previous_server_finished_len) ||
      previous_server_finished_len > PREV_FINISHED_MAX_SIZE ||
      !CBS_get_asn1_uint64(&s3, &empty_record_count) ||
      !CBS_get_asn1_uint64(&s3, &warning_alert_count) ||
      !CBS_get_asn1_uint64(&s3, &total_renegotiations) ||
      !SSL3_STATE_parse_session(&s3, &(out->established_session), ctx) ||
      !CBS_get_optional_asn1_bool(&s3, &session_reused, kS3SessionReusedTag,
                                  0 /* default to false */) ||
      !parse_optional_string(&s3, &(out->hostname), kS3HostNameTag,
                             SSL_R_SERIALIZATION_INVALID_SSL3_STATE) ||
      !SSL3_STATE_parse_octet_string(&s3, &(out->alpn_selected),
                                     kS3ALPNSelectedTag) ||
      !SSL3_STATE_parse_octet_string(&s3, &(out->next_proto_negotiated),
                                     kS3NextProtoNegotiatedTag) ||
      !CBS_get_optional_asn1_bool(&s3, &channel_id_valid, kS3ChannelIdValidTag,
                                  0 /* default to false */) ||
      !SSL3_STATE_get_optional_octet_string(
          &s3, out->channel_id, kS3ChannelIdTag, SSL3_CHANNEL_ID_SIZE) ||
      !CBS_get_optional_asn1_bool(&s3, &send_connection_binding,
                                  kS3SendConnectionBindingTag,
                                  0 /* default to false */) ||
      !CBS_get_optional_asn1(&s3, &pending_app_data, &pending_app_data_present,
                             kS3PendingAppDataTag) ||
      !CBS_get_optional_asn1(&s3, &read_buffer, &read_buffer_present,
                             kS3ReadBufferTag) ||
      !CBS_get_optional_asn1_bool(&s3, &not_resumable, kS3NotResumableTag,
                                  0 /* default to false */)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  bool is_v2 = (serde_version == SSL3_STATE_SERDE_VERSION_TWO);

  // We should have no more data at this point if we are deserializing v1
  // encoding.
  if (!is_v2 && CBS_len(&s3) > 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  uint64_t early_data_skipped;
  if (!CBS_get_optional_asn1_uint64(&s3, &early_data_skipped,
                                    kS3EarlyDataSkippedTag,
                                    0 /* default to 0 */) ||
      early_data_skipped > UINT16_MAX) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  out->early_data_skipped = static_cast<uint16_t>(early_data_skipped);

  int delegated_credential_used;
  if (!CBS_get_optional_asn1_bool(&s3, &delegated_credential_used,
                                  kS3DelegatedCredentialUsedTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  out->delegated_credential_used = delegated_credential_used != 0;

  int early_data_accepted;
  if (!CBS_get_optional_asn1_bool(&s3, &early_data_accepted,
                                  kS3EarlyDataAcceptedTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  out->early_data_accepted = early_data_accepted != 0;

  int used_hello_retry_request;
  if (!CBS_get_optional_asn1_bool(&s3, &used_hello_retry_request,
                                  kS3UsedHelloRetryRequestTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  out->used_hello_retry_request = used_hello_retry_request != 0;

  int64_t ticket_age_skew;
  if (!CBS_get_optional_asn1_int64(&s3, &ticket_age_skew, kS3TicketAgeSkewTag,
                                   0) ||
      ticket_age_skew > INT32_MAX) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  out->ticket_age_skew = static_cast<int32_t>(ticket_age_skew);

  CBS write_traffic_secret;
  int write_traffic_secret_present;
  if (!CBS_get_optional_asn1_octet_string(&s3, &write_traffic_secret,
                                          &write_traffic_secret_present,
                                          kS3WriteTrafficSecretTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  uint64_t write_traffic_secret_len;
  if (!CBS_get_optional_asn1_uint64(&s3, &write_traffic_secret_len,
                                    kS3WriteTrafficSecretLenTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS read_traffic_secret;
  int read_traffic_secret_present;
  if (!CBS_get_optional_asn1_octet_string(&s3, &read_traffic_secret,
                                          &read_traffic_secret_present,
                                          kS3ReadTrafficSecretTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  uint64_t read_traffic_secret_len;
  if (!CBS_get_optional_asn1_uint64(&s3, &read_traffic_secret_len,
                                    kS3ReadTrafficSecretLenTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS exporter_secret;
  int exporter_secret_present;
  if (!CBS_get_optional_asn1_octet_string(&s3, &exporter_secret,
                                          &exporter_secret_present,
                                          kS3ExporterSecretTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  uint64_t exporter_secret_len;
  if (!CBS_get_optional_asn1_uint64(&s3, &exporter_secret_len,
                                    kS3ExporterSecretLenTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS hs_buf;
  int hs_buf_present;
  if (!CBS_get_optional_asn1_octet_string(&s3, &hs_buf, &hs_buf_present,
                                          kS3HandshakeBufferTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  uint64_t ech_status;
  if (!CBS_get_optional_asn1_uint64(&s3, &ech_status, kS3EchStatusTag,
                                    ssl_ech_none)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS pending_hs_data;
  int pending_hs_data_present;
  if (!CBS_get_optional_asn1_octet_string(&s3, &pending_hs_data,
                                          &pending_hs_data_present,
                                          kS3PendingHsDataTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS pending_flight;
  int pending_flight_present;
  if (!CBS_get_optional_asn1_octet_string(
          &s3, &pending_flight, &pending_flight_present, kS3PendingFlightTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS aead_read_ctx;
  int aead_read_ctx_present;
  if (!CBS_get_optional_asn1(&s3, &aead_read_ctx, &aead_read_ctx_present,
                             kS3AeadReadCtxTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  CBS aead_write_ctx;
  int aead_write_ctx_present;
  if (!CBS_get_optional_asn1(&s3, &aead_write_ctx, &aead_write_ctx_present,
                             kS3AeadWriteCtxTag)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  if (is_tls13) {
    if (!write_traffic_secret_present ||
        CBS_len(&write_traffic_secret) != SSL_MAX_MD_SIZE ||
        !write_traffic_secret_len || write_traffic_secret_len > UINT8_MAX ||
        !read_traffic_secret_present ||
        CBS_len(&read_traffic_secret) != SSL_MAX_MD_SIZE ||
        !read_traffic_secret_len || read_traffic_secret_len > UINT8_MAX ||
        !exporter_secret_present ||
        CBS_len(&exporter_secret) != SSL_MAX_MD_SIZE || !exporter_secret_len ||
        exporter_secret_len > UINT8_MAX || ech_status > ssl_ech_rejected ||
        !aead_read_ctx_present || !aead_write_ctx_present) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
      return 0;
    }

    OPENSSL_memcpy(out->exporter_secret, CBS_data(&exporter_secret),
                   SSL_MAX_MD_SIZE);
    out->exporter_secret_len = exporter_secret_len;

    out->hs_buf.reset(BUF_MEM_new());
    if (hs_buf_present) {
      if (!BUF_MEM_append(out->hs_buf.get(), CBS_data(&hs_buf),
                          CBS_len(&hs_buf))) {
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        return 0;
      }
    }

    out->ech_status = static_cast<ssl_ech_status_t>(ech_status);
  } else if (write_traffic_secret_present || write_traffic_secret_len ||
             read_traffic_secret_present || read_traffic_secret_len ||
             exporter_secret_present || exporter_secret_len || hs_buf_present ||
             ech_status || pending_hs_data_present || pending_flight_present) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  if (read_buffer_present &&
      !out->read_buffer.DoDeserialization(&read_buffer)) {
    return 0;
  }
  // If |pending_app_data_size| is not zero, it needs to point to |read_buffer|.
  if (pending_app_data_present) {
    if (!read_buffer_present) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
      return 0;
    }
    CBS app_seq;
    uint64_t pending_app_data_offset, pending_app_data_size;
    if (!CBS_get_asn1(&pending_app_data, &app_seq, CBS_ASN1_SEQUENCE) ||
        !CBS_get_asn1_uint64(&app_seq, &pending_app_data_offset) ||
        !CBS_get_asn1_uint64(&app_seq, &pending_app_data_size)) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
      return 0;
    }
    if (pending_app_data_size > out->read_buffer.buf_size()) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
      return 0;
    }
    out->pending_app_data =
        MakeSpan(out->read_buffer.buf_ptr() + pending_app_data_offset,
                 pending_app_data_size);
  }

  if (CBS_len(&s3)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }

  // Initialize some states before call |tls1_configure_aead|.
  // Below comment is copied from |SSL_do_handshake|.
  // Destroy the handshake object if the handshake has completely finished.
  out->hs.reset();
  // have_version is true if the connection's final version is known. Otherwise
  // the version has not been negotiated yet.
  out->have_version = true;
  OPENSSL_memcpy(out->server_random, CBS_data(&server_random),
                 SSL3_RANDOM_SIZE);
  OPENSSL_memcpy(out->client_random, CBS_data(&client_random),
                 SSL3_RANDOM_SIZE);
  SSL_SESSION *session = out->established_session.get();
  if (is_tls13) {
    if (!tls13_set_traffic_key(ssl, ssl_encryption_application, evp_aead_seal,
                               session,
                               MakeSpan(CBS_data(&write_traffic_secret),
                                        write_traffic_secret_len))) {
      return 0;
    }
    if (!tls13_set_traffic_key(ssl, ssl_encryption_application, evp_aead_open,
                               session,
                               MakeSpan(CBS_data(&read_traffic_secret),
                                        read_traffic_secret_len))) {
      return 0;
    }

    // !! We set pending_hs_data and pending_hs_flight after as to avoid
    // tls13_set_traffic_key from trying to flush their contents if they are not
    // empty !!

    out->pending_hs_data.reset(BUF_MEM_new());
    if (pending_hs_data_present) {
      if (!BUF_MEM_append(out->pending_hs_data.get(),
                          CBS_data(&pending_hs_data),
                          CBS_len(&pending_hs_data))) {
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        return 0;
      }
    }

    out->pending_flight.reset(BUF_MEM_new());
    if (pending_flight_present) {
      if (!BUF_MEM_append(out->pending_flight.get(), CBS_data(&pending_flight),
                          CBS_len(&pending_flight))) {
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        return 0;
      }
    }
  } else {
    // the impl of |SSL_serialize_handback|, which only fetch IV when it's
    // TLS 1.
    Array<uint8_t> key_block1, key_block2;
    if (!tls1_configure_aead(ssl, evp_aead_seal, &key_block1, session, {})) {
      return 0;
    }
    if (!tls1_configure_aead(ssl, evp_aead_open, &key_block2, session, {})) {
      return 0;
    }
  }
  if (aead_read_ctx_present &&
      !out->aead_read_ctx->DeserializeState(&aead_read_ctx)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  if (aead_write_ctx_present &&
      !out->aead_write_ctx->DeserializeState(&aead_write_ctx)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_SERIALIZATION_INVALID_SSL3_STATE);
    return 0;
  }
  // read_sequence & write_sequence must be set AFTER setting the traffic keys,
  // otherwise would be reset back to zero.
  OPENSSL_memcpy(out->read_sequence, CBS_data(&read_seq), TLS_SEQ_NUM_SIZE);
  OPENSSL_memcpy(out->write_sequence, CBS_data(&write_seq), TLS_SEQ_NUM_SIZE);
  OPENSSL_memcpy(out->send_alert, CBS_data(&send_alert), SSL3_SEND_ALERT_SIZE);
  OPENSSL_memcpy(out->previous_client_finished,
                 CBS_data(&previous_client_finished), PREV_FINISHED_MAX_SIZE);
  OPENSSL_memcpy(out->previous_server_finished,
                 CBS_data(&previous_server_finished), PREV_FINISHED_MAX_SIZE);
  out->early_data_reason =
      static_cast<ssl_early_data_reason_t>(early_data_reason);
  out->rwstate = rwstate;
  out->session_reused = !!session_reused;
  if (out->session_reused) {
    ssl->session = UpRef(out->established_session);
  }
  out->channel_id_valid = !!channel_id_valid;
  out->previous_client_finished_len = previous_client_finished_len;
  out->previous_server_finished_len = previous_server_finished_len;
  out->v2_hello_done = true;
  out->initial_handshake_complete = true;
  out->empty_record_count = empty_record_count;
  out->warning_alert_count = warning_alert_count;
  out->total_renegotiations = total_renegotiations;
  out->send_connection_binding = !!send_connection_binding;
  out->established_session.get()->not_resumable = !!not_resumable;
  return 1;
}