// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef QUICHE_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_
#define QUICHE_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_

#include <string>

#include "quiche/quic/core/proto/cached_network_parameters_proto.h"
#include "quiche/quic/core/proto/source_address_token_proto.h"
#include "quiche/quic/core/quic_crypto_handshaker.h"
#include "quiche/quic/core/quic_crypto_server_stream_base.h"
#include "quiche/quic/core/quic_session.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/platform/api/quic_export.h"

namespace quic {

namespace test {
class QuicCryptoServerStreamPeer;
}  // namespace test

class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
    : public QuicCryptoServerStreamBase,
      public QuicCryptoHandshaker {
 public:
  QuicCryptoServerStream(const QuicCryptoServerStream&) = delete;
  QuicCryptoServerStream& operator=(const QuicCryptoServerStream&) = delete;

  ~QuicCryptoServerStream() override;

  // From QuicCryptoServerStreamBase
  void CancelOutstandingCallbacks() override;
  bool GetBase64SHA256ClientChannelID(std::string* output) const override;
  void SendServerConfigUpdate(
      const CachedNetworkParameters* cached_network_params) override;
  bool DisableResumption() override;
  bool IsZeroRtt() const override;
  bool IsResumption() const override;
  bool ResumptionAttempted() const override;
  bool EarlyDataAttempted() const override;
  int NumServerConfigUpdateMessagesSent() const override;
  const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
  void SetPreviousCachedNetworkParams(
      CachedNetworkParameters cached_network_params) override;
  void OnPacketDecrypted(EncryptionLevel level) override;
  void OnOneRttPacketAcknowledged() override {}
  void OnHandshakePacketSent() override {}
  void OnConnectionClosed(QuicErrorCode /*error*/,
                          ConnectionCloseSource /*source*/) override {}
  void OnHandshakeDoneReceived() override;
  void OnNewTokenReceived(absl::string_view token) override;
  std::string GetAddressToken(
      const CachedNetworkParameters* /*cached_network_params*/) const override;
  bool ValidateAddressToken(absl::string_view token) const override;
  bool ShouldSendExpectCTHeader() const override;
  bool DidCertMatchSni() const override;
  const ProofSource::Details* ProofSourceDetails() const override;

  // From QuicCryptoStream
  ssl_early_data_reason_t EarlyDataReason() const override;
  bool encryption_established() const override;
  bool one_rtt_keys_available() const override;
  const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
      const override;
  CryptoMessageParser* crypto_message_parser() override;
  HandshakeState GetHandshakeState() const override;
  void SetServerApplicationStateForResumption(
      std::unique_ptr<ApplicationState> state) override;
  size_t BufferSizeLimitForLevel(EncryptionLevel level) const override;
  std::unique_ptr<QuicDecrypter> AdvanceKeysAndCreateCurrentOneRttDecrypter()
      override;
  std::unique_ptr<QuicEncrypter> CreateCurrentOneRttEncrypter() override;
  SSL* GetSsl() const override;
  bool IsCryptoFrameExpectedForEncryptionLevel(
      EncryptionLevel level) const override;
  EncryptionLevel GetEncryptionLevelToSendCryptoDataOfSpace(
      PacketNumberSpace space) const override;

  // From QuicCryptoHandshaker
  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;

 protected:
  QUIC_EXPORT_PRIVATE friend std::unique_ptr<QuicCryptoServerStreamBase>
  CreateCryptoServerStream(const QuicCryptoServerConfig* crypto_config,
                           QuicCompressedCertsCache* compressed_certs_cache,
                           QuicSession* session,
                           QuicCryptoServerStreamBase::Helper* helper);

  // |crypto_config| must outlive the stream.
  // |session| must outlive the stream.
  // |helper| must outlive the stream.
  QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config,
                         QuicCompressedCertsCache* compressed_certs_cache,
                         QuicSession* session,
                         QuicCryptoServerStreamBase::Helper* helper);

  virtual void ProcessClientHello(
      quiche::QuicheReferenceCountedPointer<
          ValidateClientHelloResultCallback::Result>
          result,
      std::unique_ptr<ProofSource::Details> proof_source_details,
      std::shared_ptr<ProcessClientHelloResultCallback> done_cb);

  // Hook that allows the server to set QuicConfig defaults just
  // before going through the parameter negotiation step.
  virtual void OverrideQuicConfigDefaults(QuicConfig* config);

  // Returns client address used to generate and validate source address token.
  virtual const QuicSocketAddress GetClientAddress();

  // Returns the QuicSession that this stream belongs to.
  QuicSession* session() const { return session_; }

  void set_encryption_established(bool encryption_established) {
    encryption_established_ = encryption_established;
  }

  void set_one_rtt_keys_available(bool one_rtt_keys_available) {
    one_rtt_keys_available_ = one_rtt_keys_available;
  }

 private:
  friend class test::QuicCryptoServerStreamPeer;

  class QUIC_EXPORT_PRIVATE ValidateCallback
      : public ValidateClientHelloResultCallback {
   public:
    explicit ValidateCallback(QuicCryptoServerStream* parent);
    ValidateCallback(const ValidateCallback&) = delete;
    ValidateCallback& operator=(const ValidateCallback&) = delete;
    // To allow the parent to detach itself from the callback before deletion.
    void Cancel();

    // From ValidateClientHelloResultCallback
    void Run(quiche::QuicheReferenceCountedPointer<Result> result,
             std::unique_ptr<ProofSource::Details> details) override;

   private:
    QuicCryptoServerStream* parent_;
  };

  class SendServerConfigUpdateCallback
      : public BuildServerConfigUpdateMessageResultCallback {
   public:
    explicit SendServerConfigUpdateCallback(QuicCryptoServerStream* parent);
    SendServerConfigUpdateCallback(const SendServerConfigUpdateCallback&) =
        delete;
    void operator=(const SendServerConfigUpdateCallback&) = delete;

    // To allow the parent to detach itself from the callback before deletion.
    void Cancel();

    // From BuildServerConfigUpdateMessageResultCallback
    void Run(bool ok, const CryptoHandshakeMessage& message) override;

   private:
    QuicCryptoServerStream* parent_;
  };

  // Invoked by ValidateCallback::RunImpl once initial validation of
  // the client hello is complete.  Finishes processing of the client
  // hello message and handles handshake success/failure.
  void FinishProcessingHandshakeMessage(
      quiche::QuicheReferenceCountedPointer<
          ValidateClientHelloResultCallback::Result>
          result,
      std::unique_ptr<ProofSource::Details> details);

  class ProcessClientHelloCallback;
  friend class ProcessClientHelloCallback;

  // Portion of FinishProcessingHandshakeMessage which executes after
  // ProcessClientHello has been called.
  void FinishProcessingHandshakeMessageAfterProcessClientHello(
      const ValidateClientHelloResultCallback::Result& result,
      QuicErrorCode error, const std::string& error_details,
      std::unique_ptr<CryptoHandshakeMessage> reply,
      std::unique_ptr<DiversificationNonce> diversification_nonce,
      std::unique_ptr<ProofSource::Details> proof_source_details);

  // Invoked by SendServerConfigUpdateCallback::RunImpl once the proof has been
  // received.  |ok| indicates whether or not the proof was successfully
  // acquired, and |message| holds the partially-constructed message from
  // SendServerConfigUpdate.
  void FinishSendServerConfigUpdate(bool ok,
                                    const CryptoHandshakeMessage& message);

  // Returns the QuicTransportVersion of the connection.
  QuicTransportVersion transport_version() const {
    return session_->transport_version();
  }

  QuicSession* session_;
  HandshakerDelegateInterface* delegate_;

  // crypto_config_ contains crypto parameters for the handshake.
  const QuicCryptoServerConfig* crypto_config_;

  // compressed_certs_cache_ contains a set of most recently compressed certs.
  // Owned by QuicDispatcher.
  QuicCompressedCertsCache* compressed_certs_cache_;

  // Server's certificate chain and signature of the server config, as provided
  // by ProofSource::GetProof.
  quiche::QuicheReferenceCountedPointer<QuicSignedServerConfig> signed_config_;

  // Hash of the last received CHLO message which can be used for generating
  // server config update messages.
  std::string chlo_hash_;

  // Pointer to the helper for this crypto stream. Must outlive this stream.
  QuicCryptoServerStreamBase::Helper* helper_;

  // Number of handshake messages received by this stream.
  uint8_t num_handshake_messages_;

  // Number of handshake messages received by this stream that contain
  // server nonces (indicating that this is a non-zero-RTT handshake
  // attempt).
  uint8_t num_handshake_messages_with_server_nonces_;

  // Pointer to the active callback that will receive the result of
  // BuildServerConfigUpdateMessage and forward it to
  // FinishSendServerConfigUpdate.  nullptr if no update message is currently
  // being built.
  SendServerConfigUpdateCallback* send_server_config_update_cb_;

  // Number of server config update (SCUP) messages sent by this stream.
  int num_server_config_update_messages_sent_;

  // If the client provides CachedNetworkParameters in the STK in the CHLO, then
  // store here, and send back in future STKs if we have no better bandwidth
  // estimate to send.
  std::unique_ptr<CachedNetworkParameters> previous_cached_network_params_;

  // Contains any source address tokens which were present in the CHLO.
  SourceAddressTokens previous_source_address_tokens_;

  // True if client attempts 0-rtt handshake (which can succeed or fail).
  bool zero_rtt_attempted_;

  // Size of the packet containing the most recently received CHLO.
  QuicByteCount chlo_packet_size_;

  // Pointer to the active callback that will receive the result of the client
  // hello validation request and forward it to FinishProcessingHandshakeMessage
  // for processing.  nullptr if no handshake message is being validated.  Note
  // that this field is mutually exclusive with process_client_hello_cb_.
  ValidateCallback* validate_client_hello_cb_;

  // Pointer to the active callback which will receive the results of
  // ProcessClientHello and forward it to
  // FinishProcessingHandshakeMessageAfterProcessClientHello.  Note that this
  // field is mutually exclusive with validate_client_hello_cb_.
  std::weak_ptr<ProcessClientHelloCallback> process_client_hello_cb_;

  // The ProofSource::Details from this connection.
  std::unique_ptr<ProofSource::Details> proof_source_details_;

  bool encryption_established_;
  bool one_rtt_keys_available_;
  bool one_rtt_packet_decrypted_;
  quiche::QuicheReferenceCountedPointer<QuicCryptoNegotiatedParameters>
      crypto_negotiated_params_;
};

}  // namespace quic

#endif  // QUICHE_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_
