// 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 NET_THIRD_PARTY_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_
#define NET_THIRD_PARTY_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_

#include <cstdint>
#include <memory>

#include "base/macros.h"
#include "net/third_party/quic/core/crypto/crypto_handshake.h"
#include "net/third_party/quic/core/crypto/quic_compressed_certs_cache.h"
#include "net/third_party/quic/core/crypto/quic_crypto_server_config.h"
#include "net/third_party/quic/core/quic_config.h"
#include "net/third_party/quic/core/quic_crypto_handshaker.h"
#include "net/third_party/quic/core/quic_crypto_stream.h"
#include "net/third_party/quic/core/quic_session.h"
#include "net/third_party/quic/platform/api/quic_export.h"
#include "net/third_party/quic/platform/api/quic_string.h"

namespace quic {

class CachedNetworkParameters;
class CryptoHandshakeMessage;
class QuicCryptoServerConfig;
class QuicCryptoServerStreamBase;

// TODO(alyssar) see what can be moved out of QuicCryptoServerStream with
// various code and test refactoring.
class QUIC_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream {
 public:
  explicit QuicCryptoServerStreamBase(QuicSession* session);

  ~QuicCryptoServerStreamBase() override {}

  // Cancel any outstanding callbacks, such as asynchronous validation of client
  // hello.
  virtual void CancelOutstandingCallbacks() = 0;

  // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
  // SHA-256 hash of the client's ChannelID key and returns true, if the client
  // presented a ChannelID. Otherwise it returns false.
  virtual bool GetBase64SHA256ClientChannelID(QuicString* output) const = 0;

  virtual int NumServerConfigUpdateMessagesSent() const = 0;

  // Sends the latest server config and source-address token to the client.
  virtual void SendServerConfigUpdate(
      const CachedNetworkParameters* cached_network_params) = 0;

  // These are all accessors and setters to their respective counters.
  virtual uint8_t NumHandshakeMessages() const = 0;
  virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0;
  virtual bool UseStatelessRejectsIfPeerSupported() const = 0;
  virtual bool PeerSupportsStatelessRejects() const = 0;
  virtual bool ZeroRttAttempted() const = 0;
  virtual void SetPeerSupportsStatelessRejects(bool set) = 0;
  virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
      const = 0;
  virtual void SetPreviousCachedNetworkParams(
      CachedNetworkParameters cached_network_params) = 0;

  // Checks the options on the handshake-message to see whether the
  // peer supports stateless-rejects.
  static bool DoesPeerSupportStatelessRejects(
      const CryptoHandshakeMessage& message);
};

class QUIC_EXPORT_PRIVATE QuicCryptoServerStream
    : public QuicCryptoServerStreamBase {
 public:
  // QuicCryptoServerStream creates a HandshakerDelegate at construction time
  // based on the QuicTransportVersion of the connection. Different
  // HandshakerDelegates provide implementations of different crypto handshake
  // protocols. Currently QUIC crypto is the only protocol implemented; a future
  // HandshakerDelegate will use TLS as the handshake protocol.
  // QuicCryptoServerStream delegates all of its public methods to its
  // HandshakerDelegate.
  //
  // This setup of the crypto stream delegating its implementation to the
  // handshaker results in the handshaker reading and writing bytes on the
  // crypto stream, instead of the handshake rpassing the stream bytes to send.
  class QUIC_EXPORT_PRIVATE HandshakerDelegate {
   public:
    virtual ~HandshakerDelegate() {}

    // Cancel any outstanding callbacks, such as asynchronous validation of
    // client hello.
    virtual void CancelOutstandingCallbacks() = 0;

    // GetBase64SHA256ClientChannelID sets |*output| to the base64 encoded,
    // SHA-256 hash of the client's ChannelID key and returns true, if the
    // client presented a ChannelID. Otherwise it returns false.
    virtual bool GetBase64SHA256ClientChannelID(QuicString* output) const = 0;

    // Sends the latest server config and source-address token to the client.
    virtual void SendServerConfigUpdate(
        const CachedNetworkParameters* cached_network_params) = 0;

    // These are all accessors and setters to their respective counters.
    virtual uint8_t NumHandshakeMessages() const = 0;
    virtual uint8_t NumHandshakeMessagesWithServerNonces() const = 0;
    virtual int NumServerConfigUpdateMessagesSent() const = 0;
    virtual const CachedNetworkParameters* PreviousCachedNetworkParams()
        const = 0;
    virtual bool ZeroRttAttempted() const = 0;
    virtual void SetPreviousCachedNetworkParams(
        CachedNetworkParameters cached_network_params) = 0;

    // NOTE: Indicating that the Expect-CT header should be sent here presents a
    // layering violation to some extent. The Expect-CT header only applies to
    // HTTP connections, while this class can be used for non-HTTP applications.
    // However, it is exposed here because that is the only place where the
    // configuration for the certificate used in the connection is accessible.
    virtual bool ShouldSendExpectCTHeader() const = 0;

    // Returns true once any encrypter (initial/0RTT or final/1RTT) has been set
    // for the connection.
    virtual bool encryption_established() const = 0;

    // Returns true once the crypto handshake has completed.
    virtual bool handshake_confirmed() const = 0;

    // Returns the parameters negotiated in the crypto handshake.
    virtual const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
        const = 0;

    // Used by QuicCryptoStream to parse data received on this stream.
    virtual CryptoMessageParser* crypto_message_parser() = 0;

    // Returns long header type for next sending handshake message.
    virtual QuicLongHeaderType GetLongHeaderType(
        QuicStreamOffset offset) const = 0;
  };

  class Helper {
   public:
    virtual ~Helper() {}

    // Given the current connection_id, generates a new ConnectionId to
    // be returned with a stateless reject.
    virtual QuicConnectionId GenerateConnectionIdForReject(
        QuicConnectionId connection_id) const = 0;

    // Returns true if |message|, which was received on |self_address| is
    // acceptable according to the visitor's policy. Otherwise, returns false
    // and populates |error_details|.
    virtual bool CanAcceptClientHello(const CryptoHandshakeMessage& message,
                                      const QuicSocketAddress& client_address,
                                      const QuicSocketAddress& peer_address,
                                      const QuicSocketAddress& self_address,
                                      QuicString* error_details) const = 0;
  };

  // |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,
                         bool use_stateless_rejects_if_peer_supported,
                         QuicSession* session,
                         Helper* helper);
  QuicCryptoServerStream(const QuicCryptoServerStream&) = delete;
  QuicCryptoServerStream& operator=(const QuicCryptoServerStream&) = delete;

  ~QuicCryptoServerStream() override;

  // From QuicCryptoServerStreamBase
  void CancelOutstandingCallbacks() override;
  bool GetBase64SHA256ClientChannelID(QuicString* output) const override;
  void SendServerConfigUpdate(
      const CachedNetworkParameters* cached_network_params) override;
  uint8_t NumHandshakeMessages() const override;
  uint8_t NumHandshakeMessagesWithServerNonces() const override;
  int NumServerConfigUpdateMessagesSent() const override;
  const CachedNetworkParameters* PreviousCachedNetworkParams() const override;
  bool UseStatelessRejectsIfPeerSupported() const override;
  bool PeerSupportsStatelessRejects() const override;
  bool ZeroRttAttempted() const override;
  void SetPeerSupportsStatelessRejects(
      bool peer_supports_stateless_rejects) override;
  void SetPreviousCachedNetworkParams(
      CachedNetworkParameters cached_network_params) override;

  // NOTE: Indicating that the Expect-CT header should be sent here presents
  // a layering violation to some extent. The Expect-CT header only applies to
  // HTTP connections, while this class can be used for non-HTTP applications.
  // However, it is exposed here because that is the only place where the
  // configuration for the certificate used in the connection is accessible.
  bool ShouldSendExpectCTHeader() const;

  QuicLongHeaderType GetLongHeaderType(QuicStreamOffset offset) const override;
  bool encryption_established() const override;
  bool handshake_confirmed() const override;
  const QuicCryptoNegotiatedParameters& crypto_negotiated_params()
      const override;
  CryptoMessageParser* crypto_message_parser() override;
  void OnSuccessfulVersionNegotiation(
      const ParsedQuicVersion& version) override;

 protected:
  // Provided so that subclasses can provide their own handshaker.
  virtual HandshakerDelegate* handshaker() const;

 private:
  std::unique_ptr<HandshakerDelegate> handshaker_;

  // If true, the server should use stateless rejects, so long as the
  // client supports them, as indicated by
  // peer_supports_stateless_rejects_.
  bool use_stateless_rejects_if_peer_supported_;

  // Set to true, once the server has received information from the
  // client that it supports stateless reject.
  //  TODO(jokulik): Remove once client stateless reject support
  // becomes the default.
  bool peer_supports_stateless_rejects_;

  // Arguments from QuicCryptoServerStream constructor that might need to be
  // passed to the HandshakerDelegate constructor in its late construction.
  const QuicCryptoServerConfig* crypto_config_;
  QuicCompressedCertsCache* compressed_certs_cache_;
  Helper* helper_;
};

}  // namespace quic

#endif  // NET_THIRD_PARTY_QUIC_CORE_QUIC_CRYPTO_SERVER_STREAM_H_
