1731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// Use of this source code is governed by a BSD-style license that can be
3731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick// found in the LICENSE file.
4731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
5731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/socket/ssl_host_info.h"
6731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/metrics/histogram.h"
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/pickle.h"
9513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/string_piece.h"
103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "net/base/dns_util.h"
113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "net/base/dnsrr_resolver.h"
12513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "net/base/ssl_config_service.h"
13513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "net/base/x509_certificate.h"
14731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "net/socket/ssl_client_socket.h"
15731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
16731df977c0511bca2206b5f333555b1205ff1f43Iain Merricknamespace net {
17731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenSSLHostInfo::State::State() {}
19513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
20513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSSLHostInfo::State::~State() {}
21513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
2221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid SSLHostInfo::State::Clear() {
2321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  certs.clear();
2421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
26513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSSLHostInfo::SSLHostInfo(
27513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    const std::string& hostname,
2821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const SSLConfig& ssl_config,
2921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    CertVerifier* cert_verifier)
304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    : cert_verification_complete_(false),
314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      cert_verification_error_(ERR_CERT_INVALID),
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      hostname_(hostname),
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      cert_parsing_failed_(false),
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      cert_verification_callback_(NULL),
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      rev_checking_enabled_(ssl_config.rev_checking_enabled),
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      verify_ev_cert_(ssl_config.verify_ev_cert),
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      verifier_(cert_verifier),
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      callback_(new CancelableCompletionCallback<SSLHostInfo>(
39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                        ALLOW_THIS_IN_INITIALIZER_LIST(this),
403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen                        &SSLHostInfo::VerifyCallback)),
413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      dnsrr_resolver_(NULL),
423f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      dns_callback_(NULL),
433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      dns_handle_(DnsRRResolver::kInvalidHandle) {
44731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
45731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
463f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenSSLHostInfo::~SSLHostInfo() {
473f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (dns_handle_ != DnsRRResolver::kInvalidHandle) {
483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    dnsrr_resolver_->CancelResolve(dns_handle_);
493f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    delete dns_callback_;
503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
523f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid SSLHostInfo::StartDnsLookup(DnsRRResolver* dnsrr_resolver) {
543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  dnsrr_resolver_ = dnsrr_resolver;
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Note: currently disabled.
563f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
57731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
58731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickconst SSLHostInfo::State& SSLHostInfo::state() const {
59731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return state_;
60731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
61731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
62731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSSLHostInfo::State* SSLHostInfo::mutable_state() {
63731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return &state_;
64731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
65731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
66731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool SSLHostInfo::Parse(const std::string& data) {
67731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  State* state = mutable_state();
68731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
6921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  state->Clear();
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  cert_verification_complete_ = false;
71731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool r = ParseInner(data);
7321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!r)
7421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    state->Clear();
7521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return r;
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
7721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
7821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SSLHostInfo::ParseInner(const std::string& data) {
7921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  State* state = mutable_state();
8021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Pickle p(data.data(), data.size());
8221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  void* iter = NULL;
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  int num_der_certs;
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!p.ReadInt(&iter, &num_der_certs) ||
8621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      num_der_certs < 0) {
87731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
8821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
89731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (int i = 0; i < num_der_certs; i++) {
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    std::string der_cert;
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!p.ReadString(&iter, &der_cert))
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return false;
9421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    state->certs.push_back(der_cert);
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
9621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string throwaway_string;
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool throwaway_bool;
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!p.ReadString(&iter, &throwaway_string))
10021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
10121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!p.ReadBool(&iter, &throwaway_bool))
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (throwaway_bool) {
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int throwaway_int;
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!p.ReadInt(&iter, &throwaway_int) ||
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        !p.ReadString(&iter, &throwaway_string)) {
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return false;
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!state->certs.empty()) {
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    std::vector<base::StringPiece> der_certs(state->certs.size());
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    for (size_t i = 0; i < state->certs.size(); i++)
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      der_certs[i] = state->certs[i];
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    cert_ = X509Certificate::CreateFromDERCertChain(der_certs);
118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (cert_.get()) {
119513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      int flags = 0;
120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (verify_ev_cert_)
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        flags |= X509Certificate::VERIFY_EV_CERT;
122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (rev_checking_enabled_)
123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
124513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      VLOG(1) << "Kicking off verification for " << hostname_;
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      verification_start_time_ = base::TimeTicks::Now();
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      verification_end_time_ = base::TimeTicks();
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      int rv = verifier_.Verify(cert_.get(), hostname_, flags,
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                           &cert_verify_result_, callback_);
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (rv != ERR_IO_PENDING)
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        VerifyCallback(rv);
131513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else {
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      cert_parsing_failed_ = true;
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      DCHECK(!cert_verification_callback_);
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
137731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
138731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
139731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstd::string SSLHostInfo::Serialize() const {
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  Pickle p(sizeof(Pickle::Header));
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  static const unsigned kMaxCertificatesSize = 32 * 1024;
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  unsigned der_certs_size = 0;
145731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (std::vector<std::string>::const_iterator
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       i = state_.certs.begin(); i != state_.certs.end(); i++) {
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    der_certs_size += i->size();
14921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
15021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // We don't care to save the certificates over a certain size.
15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (der_certs_size > kMaxCertificatesSize)
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return "";
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!p.WriteInt(state_.certs.size()))
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return "";
15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
15821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (std::vector<std::string>::const_iterator
15921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       i = state_.certs.begin(); i != state_.certs.end(); i++) {
16021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (!p.WriteString(*i))
16121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return "";
16221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!p.WriteString("") ||
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !p.WriteBool(false)) {
16621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return "";
167731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
168731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return std::string(reinterpret_cast<const char *>(p.data()), p.size());
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst CertVerifyResult& SSLHostInfo::cert_verify_result() const {
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return cert_verify_result_;
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
176513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint SSLHostInfo::WaitForCertVerification(CompletionCallback* callback) {
177513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (cert_verification_complete_)
1784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return cert_verification_error_;
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(!cert_parsing_failed_);
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(!cert_verification_callback_);
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(!state_.certs.empty());
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  cert_verification_callback_ = callback;
183513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return ERR_IO_PENDING;
184513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
186513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SSLHostInfo::VerifyCallback(int rv) {
187513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(!verification_start_time_.is_null());
188513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::TimeTicks now = base::TimeTicks::Now();
189513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  const base::TimeDelta duration = now - verification_start_time();
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  UMA_HISTOGRAM_TIMES("Net.SSLHostInfoVerificationTimeMs", duration);
191513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  VLOG(1) << "Verification took " << duration.InMilliseconds() << "ms";
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  verification_end_time_ = now;
193513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  cert_verification_complete_ = true;
1944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  cert_verification_error_ = rv;
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (cert_verification_callback_) {
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    CompletionCallback* callback = cert_verification_callback_;
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    cert_verification_callback_ = NULL;
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    callback->Run(rv);
199513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
200513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
201513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
202731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickSSLHostInfoFactory::~SSLHostInfoFactory() {}
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
204731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}  // namespace net
205