普通文本  |  205行  |  5.59 KB

// Copyright (c) 2010 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_host_info.h"

#include "base/metrics/histogram.h"
#include "base/pickle.h"
#include "base/string_piece.h"
#include "net/base/dns_util.h"
#include "net/base/dnsrr_resolver.h"
#include "net/base/ssl_config_service.h"
#include "net/base/x509_certificate.h"
#include "net/socket/ssl_client_socket.h"

namespace net {

SSLHostInfo::State::State() {}

SSLHostInfo::State::~State() {}

void SSLHostInfo::State::Clear() {
  certs.clear();
}

SSLHostInfo::SSLHostInfo(
    const std::string& hostname,
    const SSLConfig& ssl_config,
    CertVerifier* cert_verifier)
    : cert_verification_complete_(false),
      cert_verification_error_(ERR_CERT_INVALID),
      hostname_(hostname),
      cert_parsing_failed_(false),
      cert_verification_callback_(NULL),
      rev_checking_enabled_(ssl_config.rev_checking_enabled),
      verify_ev_cert_(ssl_config.verify_ev_cert),
      verifier_(cert_verifier),
      callback_(new CancelableCompletionCallback<SSLHostInfo>(
                        ALLOW_THIS_IN_INITIALIZER_LIST(this),
                        &SSLHostInfo::VerifyCallback)),
      dnsrr_resolver_(NULL),
      dns_callback_(NULL),
      dns_handle_(DnsRRResolver::kInvalidHandle) {
}

SSLHostInfo::~SSLHostInfo() {
  if (dns_handle_ != DnsRRResolver::kInvalidHandle) {
    dnsrr_resolver_->CancelResolve(dns_handle_);
    delete dns_callback_;
  }
}

void SSLHostInfo::StartDnsLookup(DnsRRResolver* dnsrr_resolver) {
  dnsrr_resolver_ = dnsrr_resolver;
  // Note: currently disabled.
}

const SSLHostInfo::State& SSLHostInfo::state() const {
  return state_;
}

SSLHostInfo::State* SSLHostInfo::mutable_state() {
  return &state_;
}

bool SSLHostInfo::Parse(const std::string& data) {
  State* state = mutable_state();

  state->Clear();
  cert_verification_complete_ = false;

  bool r = ParseInner(data);
  if (!r)
    state->Clear();
  return r;
}

bool SSLHostInfo::ParseInner(const std::string& data) {
  State* state = mutable_state();

  Pickle p(data.data(), data.size());
  void* iter = NULL;

  int num_der_certs;
  if (!p.ReadInt(&iter, &num_der_certs) ||
      num_der_certs < 0) {
    return false;
  }

  for (int i = 0; i < num_der_certs; i++) {
    std::string der_cert;
    if (!p.ReadString(&iter, &der_cert))
      return false;
    state->certs.push_back(der_cert);
  }

  std::string throwaway_string;
  bool throwaway_bool;
  if (!p.ReadString(&iter, &throwaway_string))
    return false;

  if (!p.ReadBool(&iter, &throwaway_bool))
    return false;

  if (throwaway_bool) {
    int throwaway_int;
    if (!p.ReadInt(&iter, &throwaway_int) ||
        !p.ReadString(&iter, &throwaway_string)) {
      return false;
    }
  }

  if (!state->certs.empty()) {
    std::vector<base::StringPiece> der_certs(state->certs.size());
    for (size_t i = 0; i < state->certs.size(); i++)
      der_certs[i] = state->certs[i];
    cert_ = X509Certificate::CreateFromDERCertChain(der_certs);
    if (cert_.get()) {
      int flags = 0;
      if (verify_ev_cert_)
        flags |= X509Certificate::VERIFY_EV_CERT;
      if (rev_checking_enabled_)
        flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
      VLOG(1) << "Kicking off verification for " << hostname_;
      verification_start_time_ = base::TimeTicks::Now();
      verification_end_time_ = base::TimeTicks();
      int rv = verifier_.Verify(cert_.get(), hostname_, flags,
                           &cert_verify_result_, callback_);
      if (rv != ERR_IO_PENDING)
        VerifyCallback(rv);
    } else {
      cert_parsing_failed_ = true;
      DCHECK(!cert_verification_callback_);
    }
  }

  return true;
}

std::string SSLHostInfo::Serialize() const {
  Pickle p(sizeof(Pickle::Header));

  static const unsigned kMaxCertificatesSize = 32 * 1024;
  unsigned der_certs_size = 0;

  for (std::vector<std::string>::const_iterator
       i = state_.certs.begin(); i != state_.certs.end(); i++) {
    der_certs_size += i->size();
  }

  // We don't care to save the certificates over a certain size.
  if (der_certs_size > kMaxCertificatesSize)
    return "";

  if (!p.WriteInt(state_.certs.size()))
    return "";

  for (std::vector<std::string>::const_iterator
       i = state_.certs.begin(); i != state_.certs.end(); i++) {
    if (!p.WriteString(*i))
      return "";
  }

  if (!p.WriteString("") ||
      !p.WriteBool(false)) {
    return "";
  }

  return std::string(reinterpret_cast<const char *>(p.data()), p.size());
}

const CertVerifyResult& SSLHostInfo::cert_verify_result() const {
  return cert_verify_result_;
}

int SSLHostInfo::WaitForCertVerification(CompletionCallback* callback) {
  if (cert_verification_complete_)
    return cert_verification_error_;
  DCHECK(!cert_parsing_failed_);
  DCHECK(!cert_verification_callback_);
  DCHECK(!state_.certs.empty());
  cert_verification_callback_ = callback;
  return ERR_IO_PENDING;
}

void SSLHostInfo::VerifyCallback(int rv) {
  DCHECK(!verification_start_time_.is_null());
  base::TimeTicks now = base::TimeTicks::Now();
  const base::TimeDelta duration = now - verification_start_time();
  UMA_HISTOGRAM_TIMES("Net.SSLHostInfoVerificationTimeMs", duration);
  VLOG(1) << "Verification took " << duration.InMilliseconds() << "ms";
  verification_end_time_ = now;
  cert_verification_complete_ = true;
  cert_verification_error_ = rv;
  if (cert_verification_callback_) {
    CompletionCallback* callback = cert_verification_callback_;
    cert_verification_callback_ = NULL;
    callback->Run(rv);
  }
}

SSLHostInfoFactory::~SSLHostInfoFactory() {}

}  // namespace net