// 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_SOCKET_SSL_CLIENT_SOCKET_H_
#define NET_SOCKET_SSL_CLIENT_SOCKET_H_

#include <stdint.h>

#include <memory>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "net/base/net_export.h"
#include "net/cert/cert_database.h"
#include "net/socket/ssl_socket.h"
#include "net/ssl/ssl_client_auth_cache.h"
#include "net/ssl/ssl_config_service.h"

namespace net {

class CTPolicyEnforcer;
class CertVerifier;
class HostPortPair;
class SCTAuditingDelegate;
class SSLClientSessionCache;
struct SSLConfig;
class SSLKeyLogger;
class StreamSocket;
class TransportSecurityState;

// A client socket that uses SSL as the transport layer.
//
// NOTE: The SSL handshake occurs within the Connect method after a TCP
// connection is established.  If a SSL error occurs during the handshake,
// Connect will fail.
//
class NET_EXPORT SSLClientSocket : public SSLSocket {
 public:
  SSLClientSocket();

  // Log SSL key material to |logger|. Must be called before any
  // SSLClientSockets are created.
  //
  // TODO(davidben): Switch this to a parameter on the SSLClientSocketContext
  // once https://crbug.com/458365 is resolved.
  static void SetSSLKeyLogger(std::unique_ptr<SSLKeyLogger> logger);

 protected:
  void set_signed_cert_timestamps_received(
      bool signed_cert_timestamps_received) {
    signed_cert_timestamps_received_ = signed_cert_timestamps_received;
  }

  void set_stapled_ocsp_response_received(bool stapled_ocsp_response_received) {
    stapled_ocsp_response_received_ = stapled_ocsp_response_received;
  }

  // Serialize |next_protos| in the wire format for ALPN and NPN: protocols are
  // listed in order, each prefixed by a one-byte length.
  static std::vector<uint8_t> SerializeNextProtos(
      const NextProtoVector& next_protos);

 private:
  FRIEND_TEST_ALL_PREFIXES(SSLClientSocket, SerializeNextProtos);
  // For signed_cert_timestamps_received_ and stapled_ocsp_response_received_.
  FRIEND_TEST_ALL_PREFIXES(SSLClientSocketTest,
                           ConnectSignedCertTimestampsTLSExtension);
  FRIEND_TEST_ALL_PREFIXES(SSLClientSocketVersionTest,
                           ConnectSignedCertTimestampsEnablesOCSP);

  // True if SCTs were received via a TLS extension.
  bool signed_cert_timestamps_received_;
  // True if a stapled OCSP response was received.
  bool stapled_ocsp_response_received_;
};

// Shared state and configuration across multiple SSLClientSockets.
class NET_EXPORT SSLClientContext : public SSLConfigService::Observer,
                                    public CertDatabase::Observer {
 public:
  class NET_EXPORT Observer : public base::CheckedObserver {
   public:
    // Called when SSL configuration for all hosts changed. Newly-created
    // SSLClientSockets will pick up the new configuration. Note that changes
    // which only apply to one server will result in a call to
    // OnSSLConfigForServerChanged() instead.
    virtual void OnSSLConfigChanged(bool is_cert_database_change) = 0;
    // Called when SSL configuration for |server| changed. Newly-created
    // SSLClientSockets to |server| will pick up the new configuration.
    virtual void OnSSLConfigForServerChanged(const HostPortPair& server) = 0;
  };

  // Creates a new SSLClientContext with the specified parameters. The
  // SSLClientContext may not outlive the input parameters.
  //
  // |ssl_config_service| may be null to always use the default
  // SSLContextConfig. |ssl_client_session_cache| may be null to disable session
  // caching. |sct_auditing_delegate| may be null to disable SCT auditing.
  SSLClientContext(SSLConfigService* ssl_config_service,
                   CertVerifier* cert_verifier,
                   TransportSecurityState* transport_security_state,
                   CTPolicyEnforcer* ct_policy_enforcer,
                   SSLClientSessionCache* ssl_client_session_cache,
                   SCTAuditingDelegate* sct_auditing_delegate);
  ~SSLClientContext() override;

  const SSLContextConfig& config() { return config_; }

  SSLConfigService* ssl_config_service() { return ssl_config_service_; }
  CertVerifier* cert_verifier() { return cert_verifier_; }
  TransportSecurityState* transport_security_state() {
    return transport_security_state_;
  }
  CTPolicyEnforcer* ct_policy_enforcer() { return ct_policy_enforcer_; }
  SSLClientSessionCache* ssl_client_session_cache() {
    return ssl_client_session_cache_;
  }
  SCTAuditingDelegate* sct_auditing_delegate() {
    return sct_auditing_delegate_;
  }

  // Creates a new SSLClientSocket which can then be used to establish an SSL
  // connection to |host_and_port| over the already-connected |stream_socket|.
  std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
      std::unique_ptr<StreamSocket> stream_socket,
      const HostPortPair& host_and_port,
      const SSLConfig& ssl_config);

  // Looks up the client certificate preference for |server|. If one is found,
  // returns true and sets |client_cert| and |private_key| to the certificate
  // and key. Note these may be null if the preference is to continue with no
  // client certificate. Returns false if no preferences are configured,
  // which means client certificate requests should be reported as
  // ERR_SSL_CLIENT_AUTH_CERT_NEEDED.
  bool GetClientCertificate(const HostPortPair& server,
                            scoped_refptr<X509Certificate>* client_cert,
                            scoped_refptr<SSLPrivateKey>* private_key);

  // Configures all subsequent connections to |server| to authenticate with
  // |client_cert| and |private_key| when requested. If there is already a
  // client certificate for |server|, it will be overwritten. |client_cert| and
  // |private_key| may be null to indicate that no client certificate should be
  // sent to |server|.
  //
  // Note this method will synchronously call OnSSLConfigForServerChanged() on
  // observers.
  void SetClientCertificate(const HostPortPair& server,
                            scoped_refptr<X509Certificate> client_cert,
                            scoped_refptr<SSLPrivateKey> private_key);

  // Clears a client certificate preference for |server| set by
  // SetClientCertificate(). Returns true if one was removed and false
  // otherwise.
  //
  // Note this method will synchronously call OnSSLConfigForServerChanged() on
  // observers.
  bool ClearClientCertificate(const HostPortPair& server);

  // Add an observer to be notified when configuration has changed.
  // RemoveObserver() must be called before |observer| is destroyed.
  void AddObserver(Observer* observer);

  // Remove an observer added with AddObserver().
  void RemoveObserver(Observer* observer);

  // SSLConfigService::Observer:
  void OnSSLContextConfigChanged() override;

  // CertDatabase::Observer:
  void OnCertDBChanged() override;

 private:
  void NotifySSLConfigChanged(bool is_cert_database_change);
  void NotifySSLConfigForServerChanged(const HostPortPair& server);

  SSLContextConfig config_;

  SSLConfigService* ssl_config_service_;
  CertVerifier* cert_verifier_;
  TransportSecurityState* transport_security_state_;
  CTPolicyEnforcer* ct_policy_enforcer_;
  SSLClientSessionCache* ssl_client_session_cache_;
  SCTAuditingDelegate* sct_auditing_delegate_;

  SSLClientAuthCache ssl_client_auth_cache_;

  base::ObserverList<Observer, true /* check_empty */> observers_;

  DISALLOW_COPY_AND_ASSIGN(SSLClientContext);
};

}  // namespace net

#endif  // NET_SOCKET_SSL_CLIENT_SOCKET_H_
