| Index: net/socket/ssl_server_socket_nss.cc
 | 
| diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
 | 
| deleted file mode 100644
 | 
| index 17f7d62fc97e126f787e567cd4df0125e5b3f98f..0000000000000000000000000000000000000000
 | 
| --- a/net/socket/ssl_server_socket_nss.cc
 | 
| +++ /dev/null
 | 
| @@ -1,982 +0,0 @@
 | 
| -// 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.
 | 
| -
 | 
| -#include "net/socket/ssl_server_socket_nss.h"
 | 
| -
 | 
| -#include <utility>
 | 
| -
 | 
| -#if defined(OS_WIN)
 | 
| -#include <winsock2.h>
 | 
| -#endif
 | 
| -
 | 
| -#if defined(USE_SYSTEM_SSL)
 | 
| -#include <dlfcn.h>
 | 
| -#endif
 | 
| -#if defined(OS_MACOSX)
 | 
| -#include <Security/Security.h>
 | 
| -#endif
 | 
| -#include <certdb.h>
 | 
| -#include <cryptohi.h>
 | 
| -#include <hasht.h>
 | 
| -#include <keyhi.h>
 | 
| -#include <nspr.h>
 | 
| -#include <nss.h>
 | 
| -#include <pk11pub.h>
 | 
| -#include <secerr.h>
 | 
| -#include <sechash.h>
 | 
| -#include <ssl.h>
 | 
| -#include <sslerr.h>
 | 
| -#include <sslproto.h>
 | 
| -
 | 
| -#include <limits>
 | 
| -
 | 
| -#include "base/callback_helpers.h"
 | 
| -#include "base/lazy_instance.h"
 | 
| -#include "base/logging.h"
 | 
| -#include "base/memory/ref_counted.h"
 | 
| -#include "crypto/nss_util_internal.h"
 | 
| -#include "crypto/rsa_private_key.h"
 | 
| -#include "net/base/io_buffer.h"
 | 
| -#include "net/base/net_errors.h"
 | 
| -#include "net/log/net_log.h"
 | 
| -#include "net/socket/nss_ssl_util.h"
 | 
| -
 | 
| -// SSL plaintext fragments are shorter than 16KB. Although the record layer
 | 
| -// overhead is allowed to be 2K + 5 bytes, in practice the overhead is much
 | 
| -// smaller than 1KB. So a 17KB buffer should be large enough to hold an
 | 
| -// entire SSL record.
 | 
| -static const int kRecvBufferSize = 17 * 1024;
 | 
| -static const int kSendBufferSize = 17 * 1024;
 | 
| -
 | 
| -#define GotoState(s) next_handshake_state_ = s
 | 
| -
 | 
| -namespace net {
 | 
| -
 | 
| -namespace {
 | 
| -
 | 
| -bool g_nss_server_sockets_init = false;
 | 
| -
 | 
| -class NSSSSLServerInitSingleton {
 | 
| - public:
 | 
| -  NSSSSLServerInitSingleton() {
 | 
| -    EnsureNSSSSLInit();
 | 
| -
 | 
| -    SSL_ConfigServerSessionIDCache(64, 28800, 28800, NULL);
 | 
| -    g_nss_server_sockets_init = true;
 | 
| -  }
 | 
| -
 | 
| -  ~NSSSSLServerInitSingleton() {
 | 
| -    SSL_ShutdownServerSessionIDCache();
 | 
| -    g_nss_server_sockets_init = false;
 | 
| -  }
 | 
| -};
 | 
| -
 | 
| -static base::LazyInstance<NSSSSLServerInitSingleton>::Leaky
 | 
| -    g_nss_ssl_server_init_singleton = LAZY_INSTANCE_INITIALIZER;
 | 
| -
 | 
| -class SSLServerSocketNSS : public SSLServerSocket {
 | 
| - public:
 | 
| -  // See comments on CreateSSLServerSocket for details of how these
 | 
| -  // parameters are used.
 | 
| -  SSLServerSocketNSS(std::unique_ptr<StreamSocket> socket,
 | 
| -                     X509Certificate* certificate,
 | 
| -                     const crypto::RSAPrivateKey& key,
 | 
| -                     const SSLServerConfig& ssl_server_config);
 | 
| -  ~SSLServerSocketNSS() override;
 | 
| -
 | 
| -  // SSLServerSocket interface.
 | 
| -  int Handshake(const CompletionCallback& callback) override;
 | 
| -
 | 
| -  // SSLSocket interface.
 | 
| -  int ExportKeyingMaterial(const base::StringPiece& label,
 | 
| -                           bool has_context,
 | 
| -                           const base::StringPiece& context,
 | 
| -                           unsigned char* out,
 | 
| -                           unsigned int outlen) override;
 | 
| -
 | 
| -  // Socket interface (via StreamSocket).
 | 
| -  int Read(IOBuffer* buf,
 | 
| -           int buf_len,
 | 
| -           const CompletionCallback& callback) override;
 | 
| -  int Write(IOBuffer* buf,
 | 
| -            int buf_len,
 | 
| -            const CompletionCallback& callback) override;
 | 
| -  int SetReceiveBufferSize(int32_t size) override;
 | 
| -  int SetSendBufferSize(int32_t size) override;
 | 
| -
 | 
| -  // StreamSocket implementation.
 | 
| -  int Connect(const CompletionCallback& callback) override;
 | 
| -  void Disconnect() override;
 | 
| -  bool IsConnected() const override;
 | 
| -  bool IsConnectedAndIdle() const override;
 | 
| -  int GetPeerAddress(IPEndPoint* address) const override;
 | 
| -  int GetLocalAddress(IPEndPoint* address) const override;
 | 
| -  const BoundNetLog& NetLog() const override;
 | 
| -  void SetSubresourceSpeculation() override;
 | 
| -  void SetOmniboxSpeculation() override;
 | 
| -  bool WasEverUsed() const override;
 | 
| -  bool WasNpnNegotiated() const override;
 | 
| -  NextProto GetNegotiatedProtocol() const override;
 | 
| -  bool GetSSLInfo(SSLInfo* ssl_info) override;
 | 
| -  void GetConnectionAttempts(ConnectionAttempts* out) const override;
 | 
| -  void ClearConnectionAttempts() override {}
 | 
| -  void AddConnectionAttempts(const ConnectionAttempts& attempts) override {}
 | 
| -  int64_t GetTotalReceivedBytes() const override;
 | 
| -
 | 
| - private:
 | 
| -  enum State {
 | 
| -    STATE_NONE,
 | 
| -    STATE_HANDSHAKE,
 | 
| -  };
 | 
| -
 | 
| -  int InitializeSSLOptions();
 | 
| -
 | 
| -  void OnSendComplete(int result);
 | 
| -  void OnRecvComplete(int result);
 | 
| -  void OnHandshakeIOComplete(int result);
 | 
| -
 | 
| -  int BufferSend();
 | 
| -  void BufferSendComplete(int result);
 | 
| -  int BufferRecv();
 | 
| -  void BufferRecvComplete(int result);
 | 
| -  bool DoTransportIO();
 | 
| -  int DoPayloadRead();
 | 
| -  int DoPayloadWrite();
 | 
| -
 | 
| -  int DoHandshakeLoop(int last_io_result);
 | 
| -  int DoReadLoop(int result);
 | 
| -  int DoWriteLoop(int result);
 | 
| -  int DoHandshake();
 | 
| -  void DoHandshakeCallback(int result);
 | 
| -  void DoReadCallback(int result);
 | 
| -  void DoWriteCallback(int result);
 | 
| -
 | 
| -  static SECStatus OwnAuthCertHandler(void* arg,
 | 
| -                                      PRFileDesc* socket,
 | 
| -                                      PRBool checksig,
 | 
| -                                      PRBool is_server);
 | 
| -  static void HandshakeCallback(PRFileDesc* socket, void* arg);
 | 
| -
 | 
| -  int Init();
 | 
| -
 | 
| -  // Members used to send and receive buffer.
 | 
| -  bool transport_send_busy_;
 | 
| -  bool transport_recv_busy_;
 | 
| -
 | 
| -  scoped_refptr<IOBuffer> recv_buffer_;
 | 
| -
 | 
| -  BoundNetLog net_log_;
 | 
| -
 | 
| -  CompletionCallback user_handshake_callback_;
 | 
| -  CompletionCallback user_read_callback_;
 | 
| -  CompletionCallback user_write_callback_;
 | 
| -
 | 
| -  // Used by Read function.
 | 
| -  scoped_refptr<IOBuffer> user_read_buf_;
 | 
| -  int user_read_buf_len_;
 | 
| -
 | 
| -  // Used by Write function.
 | 
| -  scoped_refptr<IOBuffer> user_write_buf_;
 | 
| -  int user_write_buf_len_;
 | 
| -
 | 
| -  // The NSS SSL state machine
 | 
| -  PRFileDesc* nss_fd_;
 | 
| -
 | 
| -  // Buffers for the network end of the SSL state machine
 | 
| -  memio_Private* nss_bufs_;
 | 
| -
 | 
| -  // StreamSocket for sending and receiving data.
 | 
| -  std::unique_ptr<StreamSocket> transport_socket_;
 | 
| -
 | 
| -  // Options for the SSL socket.
 | 
| -  SSLServerConfig ssl_server_config_;
 | 
| -
 | 
| -  // Certificate for the server.
 | 
| -  scoped_refptr<X509Certificate> cert_;
 | 
| -
 | 
| -  // Private key used by the server.
 | 
| -  std::unique_ptr<crypto::RSAPrivateKey> key_;
 | 
| -
 | 
| -  State next_handshake_state_;
 | 
| -  bool completed_handshake_;
 | 
| -
 | 
| -  DISALLOW_COPY_AND_ASSIGN(SSLServerSocketNSS);
 | 
| -};
 | 
| -
 | 
| -SSLServerSocketNSS::SSLServerSocketNSS(
 | 
| -    std::unique_ptr<StreamSocket> transport_socket,
 | 
| -    X509Certificate* cert,
 | 
| -    const crypto::RSAPrivateKey& key,
 | 
| -    const SSLServerConfig& ssl_server_config)
 | 
| -    : transport_send_busy_(false),
 | 
| -      transport_recv_busy_(false),
 | 
| -      user_read_buf_len_(0),
 | 
| -      user_write_buf_len_(0),
 | 
| -      nss_fd_(NULL),
 | 
| -      nss_bufs_(NULL),
 | 
| -      transport_socket_(std::move(transport_socket)),
 | 
| -      ssl_server_config_(ssl_server_config),
 | 
| -      cert_(cert),
 | 
| -      key_(key.Copy()),
 | 
| -      next_handshake_state_(STATE_NONE),
 | 
| -      completed_handshake_(false) {
 | 
| -  CHECK(key_);
 | 
| -}
 | 
| -
 | 
| -SSLServerSocketNSS::~SSLServerSocketNSS() {
 | 
| -  if (nss_fd_ != NULL) {
 | 
| -    PR_Close(nss_fd_);
 | 
| -    nss_fd_ = NULL;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::Handshake(const CompletionCallback& callback) {
 | 
| -  net_log_.BeginEvent(NetLog::TYPE_SSL_SERVER_HANDSHAKE);
 | 
| -
 | 
| -  int rv = Init();
 | 
| -  if (rv != OK) {
 | 
| -    LOG(ERROR) << "Failed to initialize NSS";
 | 
| -    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
 | 
| -    return rv;
 | 
| -  }
 | 
| -
 | 
| -  rv = InitializeSSLOptions();
 | 
| -  if (rv != OK) {
 | 
| -    LOG(ERROR) << "Failed to initialize SSL options";
 | 
| -    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
 | 
| -    return rv;
 | 
| -  }
 | 
| -
 | 
| -  // Set peer address. TODO(hclam): This should be in a separate method.
 | 
| -  PRNetAddr peername;
 | 
| -  memset(&peername, 0, sizeof(peername));
 | 
| -  peername.raw.family = AF_INET;
 | 
| -  memio_SetPeerName(nss_fd_, &peername);
 | 
| -
 | 
| -  GotoState(STATE_HANDSHAKE);
 | 
| -  rv = DoHandshakeLoop(OK);
 | 
| -  if (rv == ERR_IO_PENDING) {
 | 
| -    user_handshake_callback_ = callback;
 | 
| -  } else {
 | 
| -    net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
 | 
| -  }
 | 
| -
 | 
| -  return rv > OK ? OK : rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::ExportKeyingMaterial(const base::StringPiece& label,
 | 
| -                                             bool has_context,
 | 
| -                                             const base::StringPiece& context,
 | 
| -                                             unsigned char* out,
 | 
| -                                             unsigned int outlen) {
 | 
| -  if (!IsConnected())
 | 
| -    return ERR_SOCKET_NOT_CONNECTED;
 | 
| -  SECStatus result = SSL_ExportKeyingMaterial(
 | 
| -      nss_fd_, label.data(), label.size(), has_context,
 | 
| -      reinterpret_cast<const unsigned char*>(context.data()),
 | 
| -      context.length(), out, outlen);
 | 
| -  if (result != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_ExportKeyingMaterial", "");
 | 
| -    return MapNSSError(PORT_GetError());
 | 
| -  }
 | 
| -  return OK;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::Connect(const CompletionCallback& callback) {
 | 
| -  NOTIMPLEMENTED();
 | 
| -  return ERR_NOT_IMPLEMENTED;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::Read(IOBuffer* buf,
 | 
| -                             int buf_len,
 | 
| -                             const CompletionCallback& callback) {
 | 
| -  DCHECK(user_read_callback_.is_null());
 | 
| -  DCHECK(user_handshake_callback_.is_null());
 | 
| -  DCHECK(!user_read_buf_);
 | 
| -  DCHECK(nss_bufs_);
 | 
| -  DCHECK(!callback.is_null());
 | 
| -
 | 
| -  user_read_buf_ = buf;
 | 
| -  user_read_buf_len_ = buf_len;
 | 
| -
 | 
| -  DCHECK(completed_handshake_);
 | 
| -
 | 
| -  int rv = DoReadLoop(OK);
 | 
| -
 | 
| -  if (rv == ERR_IO_PENDING) {
 | 
| -    user_read_callback_ = callback;
 | 
| -  } else {
 | 
| -    user_read_buf_ = NULL;
 | 
| -    user_read_buf_len_ = 0;
 | 
| -  }
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::Write(IOBuffer* buf,
 | 
| -                              int buf_len,
 | 
| -                              const CompletionCallback& callback) {
 | 
| -  DCHECK(user_write_callback_.is_null());
 | 
| -  DCHECK(!user_write_buf_);
 | 
| -  DCHECK(nss_bufs_);
 | 
| -  DCHECK(!callback.is_null());
 | 
| -
 | 
| -  user_write_buf_ = buf;
 | 
| -  user_write_buf_len_ = buf_len;
 | 
| -
 | 
| -  int rv = DoWriteLoop(OK);
 | 
| -
 | 
| -  if (rv == ERR_IO_PENDING) {
 | 
| -    user_write_callback_ = callback;
 | 
| -  } else {
 | 
| -    user_write_buf_ = NULL;
 | 
| -    user_write_buf_len_ = 0;
 | 
| -  }
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::SetReceiveBufferSize(int32_t size) {
 | 
| -  return transport_socket_->SetReceiveBufferSize(size);
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::SetSendBufferSize(int32_t size) {
 | 
| -  return transport_socket_->SetSendBufferSize(size);
 | 
| -}
 | 
| -
 | 
| -bool SSLServerSocketNSS::IsConnected() const {
 | 
| -  // TODO(wtc): Find out if we should check transport_socket_->IsConnected()
 | 
| -  // as well.
 | 
| -  return completed_handshake_;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::Disconnect() {
 | 
| -  transport_socket_->Disconnect();
 | 
| -}
 | 
| -
 | 
| -bool SSLServerSocketNSS::IsConnectedAndIdle() const {
 | 
| -  return completed_handshake_ && transport_socket_->IsConnectedAndIdle();
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::GetPeerAddress(IPEndPoint* address) const {
 | 
| -  if (!IsConnected())
 | 
| -    return ERR_SOCKET_NOT_CONNECTED;
 | 
| -  return transport_socket_->GetPeerAddress(address);
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::GetLocalAddress(IPEndPoint* address) const {
 | 
| -  if (!IsConnected())
 | 
| -    return ERR_SOCKET_NOT_CONNECTED;
 | 
| -  return transport_socket_->GetLocalAddress(address);
 | 
| -}
 | 
| -
 | 
| -const BoundNetLog& SSLServerSocketNSS::NetLog() const {
 | 
| -  return net_log_;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::SetSubresourceSpeculation() {
 | 
| -  transport_socket_->SetSubresourceSpeculation();
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::SetOmniboxSpeculation() {
 | 
| -  transport_socket_->SetOmniboxSpeculation();
 | 
| -}
 | 
| -
 | 
| -bool SSLServerSocketNSS::WasEverUsed() const {
 | 
| -  return transport_socket_->WasEverUsed();
 | 
| -}
 | 
| -
 | 
| -bool SSLServerSocketNSS::WasNpnNegotiated() const {
 | 
| -  NOTIMPLEMENTED();
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -NextProto SSLServerSocketNSS::GetNegotiatedProtocol() const {
 | 
| -  // NPN is not supported by this class.
 | 
| -  return kProtoUnknown;
 | 
| -}
 | 
| -
 | 
| -bool SSLServerSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
 | 
| -  NOTIMPLEMENTED();
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::GetConnectionAttempts(ConnectionAttempts* out) const {
 | 
| -  out->clear();
 | 
| -}
 | 
| -
 | 
| -int64_t SSLServerSocketNSS::GetTotalReceivedBytes() const {
 | 
| -  NOTIMPLEMENTED();
 | 
| -  return 0;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::InitializeSSLOptions() {
 | 
| -  // Transport connected, now hook it up to nss
 | 
| -  nss_fd_ = memio_CreateIOLayer(kRecvBufferSize, kSendBufferSize);
 | 
| -  if (nss_fd_ == NULL) {
 | 
| -    return ERR_OUT_OF_MEMORY;  // TODO(port): map NSPR error code.
 | 
| -  }
 | 
| -
 | 
| -  // Grab pointer to buffers
 | 
| -  nss_bufs_ = memio_GetSecret(nss_fd_);
 | 
| -
 | 
| -  /* Create SSL state machine */
 | 
| -  /* Push SSL onto our fake I/O socket */
 | 
| -  nss_fd_ = SSL_ImportFD(NULL, nss_fd_);
 | 
| -  if (nss_fd_ == NULL) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_ImportFD", "");
 | 
| -    return ERR_OUT_OF_MEMORY;  // TODO(port): map NSPR/NSS error code.
 | 
| -  }
 | 
| -  // TODO(port): set more ssl options!  Check errors!
 | 
| -
 | 
| -  int rv;
 | 
| -
 | 
| -  if (ssl_server_config_.client_cert_type ==
 | 
| -      SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT) {
 | 
| -    rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_TRUE);
 | 
| -    if (rv != SECSuccess) {
 | 
| -      LogFailedNSSFunction(net_log_, "SSL_OptionSet",
 | 
| -                           "SSL_REQUEST_CERTIFICATE");
 | 
| -      return ERR_UNEXPECTED;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_SECURITY, PR_TRUE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_SECURITY");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SSL2, PR_FALSE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_SSL2");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  SSLVersionRange version_range;
 | 
| -  version_range.min = ssl_server_config_.version_min;
 | 
| -  version_range.max = ssl_server_config_.version_max;
 | 
| -  rv = SSL_VersionRangeSet(nss_fd_, &version_range);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_VersionRangeSet", "");
 | 
| -    return ERR_NO_SSL_VERSIONS_ENABLED;
 | 
| -  }
 | 
| -
 | 
| -  if (ssl_server_config_.require_ecdhe) {
 | 
| -    const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers();
 | 
| -    const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers();
 | 
| -
 | 
| -    // Iterate over the cipher suites and disable those that don't use ECDHE.
 | 
| -    for (unsigned i = 0; i < num_ciphers; i++) {
 | 
| -      SSLCipherSuiteInfo info;
 | 
| -      if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) ==
 | 
| -          SECSuccess) {
 | 
| -        if (strcmp(info.keaTypeName, "ECDHE") != 0) {
 | 
| -          SSL_CipherPrefSet(nss_fd_, ssl_ciphers[i], PR_FALSE);
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  for (std::vector<uint16_t>::const_iterator it =
 | 
| -           ssl_server_config_.disabled_cipher_suites.begin();
 | 
| -       it != ssl_server_config_.disabled_cipher_suites.end(); ++it) {
 | 
| -    // This will fail if the specified cipher is not implemented by NSS, but
 | 
| -    // the failure is harmless.
 | 
| -    SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE);
 | 
| -  }
 | 
| -
 | 
| -  // Server socket doesn't need session tickets.
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_FALSE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(
 | 
| -        net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS");
 | 
| -  }
 | 
| -
 | 
| -  // Doing this will force PR_Accept perform handshake as server.
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_CLIENT, PR_FALSE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_CLIENT");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_HANDSHAKE_AS_SERVER");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_REQUEST_CERTIFICATE, PR_FALSE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUEST_CERTIFICATE");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_OptionSet(nss_fd_, SSL_REQUIRE_CERTIFICATE, PR_FALSE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_REQUIRE_CERTIFICATE");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_AuthCertificateHook(nss_fd_, OwnAuthCertHandler, this);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_AuthCertificateHook", "");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  rv = SSL_HandshakeCallback(nss_fd_, HandshakeCallback, this);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_HandshakeCallback", "");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  // Get a certificate of CERTCertificate structure.
 | 
| -  std::string der_string;
 | 
| -  if (!X509Certificate::GetDEREncoded(cert_->os_cert_handle(), &der_string))
 | 
| -    return ERR_UNEXPECTED;
 | 
| -
 | 
| -  SECItem der_cert;
 | 
| -  der_cert.data = reinterpret_cast<unsigned char*>(const_cast<char*>(
 | 
| -      der_string.data()));
 | 
| -  der_cert.len  = der_string.length();
 | 
| -  der_cert.type = siDERCertBuffer;
 | 
| -
 | 
| -  // Parse into a CERTCertificate structure.
 | 
| -  CERTCertificate* cert = CERT_NewTempCertificate(
 | 
| -      CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE);
 | 
| -  if (!cert) {
 | 
| -    LogFailedNSSFunction(net_log_, "CERT_NewTempCertificate", "");
 | 
| -    return MapNSSError(PORT_GetError());
 | 
| -  }
 | 
| -
 | 
| -  // Get a key of SECKEYPrivateKey* structure.
 | 
| -  std::vector<uint8_t> key_vector;
 | 
| -  if (!key_->ExportPrivateKey(&key_vector)) {
 | 
| -    CERT_DestroyCertificate(cert);
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  SECKEYPrivateKeyStr* private_key = NULL;
 | 
| -  PK11SlotInfo* slot = PK11_GetInternalSlot();
 | 
| -  if (!slot) {
 | 
| -    CERT_DestroyCertificate(cert);
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  SECItem der_private_key_info;
 | 
| -  der_private_key_info.data =
 | 
| -      const_cast<unsigned char*>(&key_vector.front());
 | 
| -  der_private_key_info.len = key_vector.size();
 | 
| -  // The server's RSA private key must be imported into NSS with the
 | 
| -  // following key usage bits:
 | 
| -  // - KU_KEY_ENCIPHERMENT, required for the RSA key exchange algorithm.
 | 
| -  // - KU_DIGITAL_SIGNATURE, required for the DHE_RSA and ECDHE_RSA key
 | 
| -  //   exchange algorithms.
 | 
| -  const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
 | 
| -  rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(
 | 
| -      slot, &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE,
 | 
| -      key_usage, &private_key, NULL);
 | 
| -  PK11_FreeSlot(slot);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    CERT_DestroyCertificate(cert);
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  // Assign server certificate and private key.
 | 
| -  SSLKEAType cert_kea = NSS_FindCertKEAType(cert);
 | 
| -  rv = SSL_ConfigSecureServer(nss_fd_, cert, private_key, cert_kea);
 | 
| -  CERT_DestroyCertificate(cert);
 | 
| -  SECKEY_DestroyPrivateKey(private_key);
 | 
| -
 | 
| -  if (rv != SECSuccess) {
 | 
| -    PRErrorCode prerr = PR_GetError();
 | 
| -    LOG(ERROR) << "Failed to config SSL server: " << prerr;
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_ConfigureSecureServer", "");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  // Tell SSL we're a server; needed if not letting NSPR do socket I/O
 | 
| -  rv = SSL_ResetHandshake(nss_fd_, PR_TRUE);
 | 
| -  if (rv != SECSuccess) {
 | 
| -    LogFailedNSSFunction(net_log_, "SSL_ResetHandshake", "");
 | 
| -    return ERR_UNEXPECTED;
 | 
| -  }
 | 
| -
 | 
| -  return OK;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::OnSendComplete(int result) {
 | 
| -  if (next_handshake_state_ == STATE_HANDSHAKE) {
 | 
| -    // In handshake phase.
 | 
| -    OnHandshakeIOComplete(result);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // TODO(byungchul): This state machine is not correct. Copy the state machine
 | 
| -  // of SSLClientSocketNSS::OnSendComplete() which handles it better.
 | 
| -  if (!completed_handshake_)
 | 
| -    return;
 | 
| -
 | 
| -  if (user_write_buf_) {
 | 
| -    int rv = DoWriteLoop(result);
 | 
| -    if (rv != ERR_IO_PENDING)
 | 
| -      DoWriteCallback(rv);
 | 
| -  } else {
 | 
| -    // Ensure that any queued ciphertext is flushed.
 | 
| -    DoTransportIO();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::OnRecvComplete(int result) {
 | 
| -  if (next_handshake_state_ == STATE_HANDSHAKE) {
 | 
| -    // In handshake phase.
 | 
| -    OnHandshakeIOComplete(result);
 | 
| -    return;
 | 
| -  }
 | 
| -
 | 
| -  // Network layer received some data, check if client requested to read
 | 
| -  // decrypted data.
 | 
| -  if (!user_read_buf_ || !completed_handshake_)
 | 
| -    return;
 | 
| -
 | 
| -  int rv = DoReadLoop(result);
 | 
| -  if (rv != ERR_IO_PENDING)
 | 
| -    DoReadCallback(rv);
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::OnHandshakeIOComplete(int result) {
 | 
| -  int rv = DoHandshakeLoop(result);
 | 
| -  if (rv == ERR_IO_PENDING)
 | 
| -    return;
 | 
| -
 | 
| -  net_log_.EndEventWithNetErrorCode(NetLog::TYPE_SSL_SERVER_HANDSHAKE, rv);
 | 
| -  if (!user_handshake_callback_.is_null())
 | 
| -    DoHandshakeCallback(rv);
 | 
| -}
 | 
| -
 | 
| -// Return 0 for EOF,
 | 
| -// > 0 for bytes transferred immediately,
 | 
| -// < 0 for error (or the non-error ERR_IO_PENDING).
 | 
| -int SSLServerSocketNSS::BufferSend(void) {
 | 
| -  if (transport_send_busy_)
 | 
| -    return ERR_IO_PENDING;
 | 
| -
 | 
| -  const char* buf1;
 | 
| -  const char* buf2;
 | 
| -  unsigned int len1, len2;
 | 
| -  if (memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2)) {
 | 
| -    // The error code itself is ignored, so just return ERR_ABORTED.
 | 
| -    return ERR_ABORTED;
 | 
| -  }
 | 
| -  const size_t len = len1 + len2;
 | 
| -
 | 
| -  int rv = 0;
 | 
| -  if (len) {
 | 
| -    scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len));
 | 
| -    memcpy(send_buffer->data(), buf1, len1);
 | 
| -    memcpy(send_buffer->data() + len1, buf2, len2);
 | 
| -    rv = transport_socket_->Write(
 | 
| -        send_buffer.get(), len,
 | 
| -        base::Bind(&SSLServerSocketNSS::BufferSendComplete,
 | 
| -                   base::Unretained(this)));
 | 
| -    if (rv == ERR_IO_PENDING) {
 | 
| -      transport_send_busy_ = true;
 | 
| -    } else {
 | 
| -      memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::BufferSendComplete(int result) {
 | 
| -  memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result));
 | 
| -  transport_send_busy_ = false;
 | 
| -  OnSendComplete(result);
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::BufferRecv(void) {
 | 
| -  if (transport_recv_busy_) return ERR_IO_PENDING;
 | 
| -
 | 
| -  char* buf;
 | 
| -  int nb = memio_GetReadParams(nss_bufs_, &buf);
 | 
| -  int rv;
 | 
| -  if (!nb) {
 | 
| -    // buffer too full to read into, so no I/O possible at moment
 | 
| -    rv = ERR_IO_PENDING;
 | 
| -  } else {
 | 
| -    recv_buffer_ = new IOBuffer(nb);
 | 
| -    rv = transport_socket_->Read(
 | 
| -        recv_buffer_.get(), nb,
 | 
| -        base::Bind(&SSLServerSocketNSS::BufferRecvComplete,
 | 
| -                   base::Unretained(this)));
 | 
| -    if (rv == ERR_IO_PENDING) {
 | 
| -      transport_recv_busy_ = true;
 | 
| -    } else {
 | 
| -      if (rv > 0)
 | 
| -        memcpy(buf, recv_buffer_->data(), rv);
 | 
| -      memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
 | 
| -      recv_buffer_ = NULL;
 | 
| -    }
 | 
| -  }
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::BufferRecvComplete(int result) {
 | 
| -  if (result > 0) {
 | 
| -    char* buf;
 | 
| -    memio_GetReadParams(nss_bufs_, &buf);
 | 
| -    memcpy(buf, recv_buffer_->data(), result);
 | 
| -  }
 | 
| -  recv_buffer_ = NULL;
 | 
| -  memio_PutReadResult(nss_bufs_, MapErrorToNSS(result));
 | 
| -  transport_recv_busy_ = false;
 | 
| -  OnRecvComplete(result);
 | 
| -}
 | 
| -
 | 
| -// Do as much network I/O as possible between the buffer and the
 | 
| -// transport socket. Return true if some I/O performed, false
 | 
| -// otherwise (error or ERR_IO_PENDING).
 | 
| -bool SSLServerSocketNSS::DoTransportIO() {
 | 
| -  bool network_moved = false;
 | 
| -  if (nss_bufs_ != NULL) {
 | 
| -    int rv;
 | 
| -    // Read and write as much data as we can. The loop is neccessary
 | 
| -    // because Write() may return synchronously.
 | 
| -    do {
 | 
| -      rv = BufferSend();
 | 
| -      if (rv > 0)
 | 
| -        network_moved = true;
 | 
| -    } while (rv > 0);
 | 
| -    if (BufferRecv() >= 0)
 | 
| -      network_moved = true;
 | 
| -  }
 | 
| -  return network_moved;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoPayloadRead() {
 | 
| -  DCHECK(user_read_buf_);
 | 
| -  DCHECK_GT(user_read_buf_len_, 0);
 | 
| -  int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
 | 
| -  if (rv >= 0)
 | 
| -    return rv;
 | 
| -  PRErrorCode prerr = PR_GetError();
 | 
| -  if (prerr == PR_WOULD_BLOCK_ERROR) {
 | 
| -    return ERR_IO_PENDING;
 | 
| -  }
 | 
| -  rv = MapNSSError(prerr);
 | 
| -  net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
 | 
| -                    CreateNetLogSSLErrorCallback(rv, prerr));
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoPayloadWrite() {
 | 
| -  DCHECK(user_write_buf_);
 | 
| -  int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_);
 | 
| -  if (rv >= 0)
 | 
| -    return rv;
 | 
| -  PRErrorCode prerr = PR_GetError();
 | 
| -  if (prerr == PR_WOULD_BLOCK_ERROR) {
 | 
| -    return ERR_IO_PENDING;
 | 
| -  }
 | 
| -  rv = MapNSSError(prerr);
 | 
| -  net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
 | 
| -                    CreateNetLogSSLErrorCallback(rv, prerr));
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoHandshakeLoop(int last_io_result) {
 | 
| -  int rv = last_io_result;
 | 
| -  do {
 | 
| -    // Default to STATE_NONE for next state.
 | 
| -    // (This is a quirk carried over from the windows
 | 
| -    // implementation.  It makes reading the logs a bit harder.)
 | 
| -    // State handlers can and often do call GotoState just
 | 
| -    // to stay in the current state.
 | 
| -    State state = next_handshake_state_;
 | 
| -    GotoState(STATE_NONE);
 | 
| -    switch (state) {
 | 
| -      case STATE_HANDSHAKE:
 | 
| -        rv = DoHandshake();
 | 
| -        break;
 | 
| -      case STATE_NONE:
 | 
| -      default:
 | 
| -        rv = ERR_UNEXPECTED;
 | 
| -        LOG(DFATAL) << "unexpected state " << state;
 | 
| -        break;
 | 
| -    }
 | 
| -
 | 
| -    // Do the actual network I/O
 | 
| -    bool network_moved = DoTransportIO();
 | 
| -    if (network_moved && next_handshake_state_ == STATE_HANDSHAKE) {
 | 
| -      // In general we exit the loop if rv is ERR_IO_PENDING.  In this
 | 
| -      // special case we keep looping even if rv is ERR_IO_PENDING because
 | 
| -      // the transport IO may allow DoHandshake to make progress.
 | 
| -      rv = OK;  // This causes us to stay in the loop.
 | 
| -    }
 | 
| -  } while (rv != ERR_IO_PENDING && next_handshake_state_ != STATE_NONE);
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoReadLoop(int result) {
 | 
| -  DCHECK(completed_handshake_);
 | 
| -  DCHECK(next_handshake_state_ == STATE_NONE);
 | 
| -
 | 
| -  if (result < 0)
 | 
| -    return result;
 | 
| -
 | 
| -  if (!nss_bufs_) {
 | 
| -    LOG(DFATAL) << "!nss_bufs_";
 | 
| -    int rv = ERR_UNEXPECTED;
 | 
| -    net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
 | 
| -                      CreateNetLogSSLErrorCallback(rv, 0));
 | 
| -    return rv;
 | 
| -  }
 | 
| -
 | 
| -  bool network_moved;
 | 
| -  int rv;
 | 
| -  do {
 | 
| -    rv = DoPayloadRead();
 | 
| -    network_moved = DoTransportIO();
 | 
| -  } while (rv == ERR_IO_PENDING && network_moved);
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoWriteLoop(int result) {
 | 
| -  DCHECK(completed_handshake_);
 | 
| -  DCHECK_EQ(next_handshake_state_, STATE_NONE);
 | 
| -
 | 
| -  if (result < 0)
 | 
| -    return result;
 | 
| -
 | 
| -  if (!nss_bufs_) {
 | 
| -    LOG(DFATAL) << "!nss_bufs_";
 | 
| -    int rv = ERR_UNEXPECTED;
 | 
| -    net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
 | 
| -                      CreateNetLogSSLErrorCallback(rv, 0));
 | 
| -    return rv;
 | 
| -  }
 | 
| -
 | 
| -  bool network_moved;
 | 
| -  int rv;
 | 
| -  do {
 | 
| -    rv = DoPayloadWrite();
 | 
| -    network_moved = DoTransportIO();
 | 
| -  } while (rv == ERR_IO_PENDING && network_moved);
 | 
| -  return rv;
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::DoHandshake() {
 | 
| -  int net_error = OK;
 | 
| -  SECStatus rv = SSL_ForceHandshake(nss_fd_);
 | 
| -
 | 
| -  if (rv == SECSuccess) {
 | 
| -    completed_handshake_ = true;
 | 
| -  } else {
 | 
| -    PRErrorCode prerr = PR_GetError();
 | 
| -    net_error = MapNSSError(prerr);
 | 
| -
 | 
| -    // If not done, stay in this state
 | 
| -    if (net_error == ERR_IO_PENDING) {
 | 
| -      GotoState(STATE_HANDSHAKE);
 | 
| -    } else {
 | 
| -      LOG(ERROR) << "handshake failed; NSS error code " << prerr
 | 
| -                 << ", net_error " << net_error;
 | 
| -      net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
 | 
| -                        CreateNetLogSSLErrorCallback(net_error, prerr));
 | 
| -    }
 | 
| -  }
 | 
| -  return net_error;
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::DoHandshakeCallback(int rv) {
 | 
| -  DCHECK_NE(rv, ERR_IO_PENDING);
 | 
| -  base::ResetAndReturn(&user_handshake_callback_).Run(rv > OK ? OK : rv);
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::DoReadCallback(int rv) {
 | 
| -  DCHECK(rv != ERR_IO_PENDING);
 | 
| -  DCHECK(!user_read_callback_.is_null());
 | 
| -
 | 
| -  user_read_buf_ = NULL;
 | 
| -  user_read_buf_len_ = 0;
 | 
| -  base::ResetAndReturn(&user_read_callback_).Run(rv);
 | 
| -}
 | 
| -
 | 
| -void SSLServerSocketNSS::DoWriteCallback(int rv) {
 | 
| -  DCHECK(rv != ERR_IO_PENDING);
 | 
| -  DCHECK(!user_write_callback_.is_null());
 | 
| -
 | 
| -  user_write_buf_ = NULL;
 | 
| -  user_write_buf_len_ = 0;
 | 
| -  base::ResetAndReturn(&user_write_callback_).Run(rv);
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -// NSS calls this if an incoming certificate needs to be verified.
 | 
| -// Do nothing but return SECSuccess.
 | 
| -// This is called only in full handshake mode.
 | 
| -// Peer certificate is retrieved in HandshakeCallback() later, which is called
 | 
| -// in full handshake mode or in resumption handshake mode.
 | 
| -SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg,
 | 
| -                                                 PRFileDesc* socket,
 | 
| -                                                 PRBool checksig,
 | 
| -                                                 PRBool is_server) {
 | 
| -  // TODO(hclam): Implement.
 | 
| -  // Tell NSS to not verify the certificate.
 | 
| -  return SECSuccess;
 | 
| -}
 | 
| -
 | 
| -// static
 | 
| -// NSS calls this when handshake is completed.
 | 
| -// After the SSL handshake is finished we need to verify the certificate.
 | 
| -void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket, void* arg) {
 | 
| -  // TODO(hclam): Implement.
 | 
| -}
 | 
| -
 | 
| -int SSLServerSocketNSS::Init() {
 | 
| -  // Initialize the NSS SSL library in a threadsafe way.  This also
 | 
| -  // initializes the NSS base library.
 | 
| -  EnsureNSSSSLInit();
 | 
| -  if (!NSS_IsInitialized())
 | 
| -    return ERR_UNEXPECTED;
 | 
| -
 | 
| -  EnableSSLServerSockets();
 | 
| -  return OK;
 | 
| -}
 | 
| -
 | 
| -}  // namespace
 | 
| -
 | 
| -std::unique_ptr<SSLServerContext> CreateSSLServerContext(
 | 
| -    X509Certificate* certificate,
 | 
| -    const crypto::RSAPrivateKey& key,
 | 
| -    const SSLServerConfig& ssl_server_config) {
 | 
| -  return std::unique_ptr<SSLServerContext>(
 | 
| -      new SSLServerContextNSS(certificate, key, ssl_server_config));
 | 
| -}
 | 
| -
 | 
| -SSLServerContextNSS::SSLServerContextNSS(
 | 
| -    X509Certificate* certificate,
 | 
| -    const crypto::RSAPrivateKey& key,
 | 
| -    const SSLServerConfig& ssl_server_config)
 | 
| -    : ssl_server_config_(ssl_server_config),
 | 
| -      cert_(certificate),
 | 
| -      key_(key.Copy()) {
 | 
| -  CHECK(key_);
 | 
| -}
 | 
| -
 | 
| -SSLServerContextNSS::~SSLServerContextNSS() {}
 | 
| -
 | 
| -std::unique_ptr<SSLServerSocket> SSLServerContextNSS::CreateSSLServerSocket(
 | 
| -    std::unique_ptr<StreamSocket> socket) {
 | 
| -  DCHECK(g_nss_server_sockets_init) << "EnableSSLServerSockets() has not been"
 | 
| -                                    << " called yet!";
 | 
| -
 | 
| -  return std::unique_ptr<SSLServerSocket>(new SSLServerSocketNSS(
 | 
| -      std::move(socket), cert_.get(), *key_, ssl_server_config_));
 | 
| -}
 | 
| -
 | 
| -void EnableSSLServerSockets() {
 | 
| -  g_nss_ssl_server_init_singleton.Get();
 | 
| -}
 | 
| -
 | 
| -}  // namespace net
 | 
| 
 |