1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// found in the LICENSE file.
4201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
5201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/socket/dns_cert_provenance_checker.h"
6201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
7201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#if !defined(USE_OPENSSL)
8201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
9201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <nspr.h>
10201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
11201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <hasht.h>
12201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <keyhi.h>
13201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <pk11pub.h>
14201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <sechash.h>
15201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
16201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <set>
17201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include <string>
18201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/base64.h"
20201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/basictypes.h"
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h"
23201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "base/pickle.h"
243f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/non_thread_safe.h"
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/encryptor.h"
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/symmetric_key.h"
27201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/base/completion_callback.h"
28201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/base/dns_util.h"
29201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/base/dnsrr_resolver.h"
30201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/base/net_errors.h"
31201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "net/base/net_log.h"
32201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
33201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace net {
34201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
35201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace {
36201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
37201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// A DER encoded SubjectPublicKeyInfo structure containing the server's public
38201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// key.
39201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst uint8 kServerPublicKey[] = {
40201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
41201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
42201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x04, 0xc7, 0xea, 0x88, 0x60, 0x52, 0xe3, 0xa3, 0x3e, 0x39, 0x92, 0x0f, 0xa4,
43201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x3d, 0xba, 0xd8, 0x02, 0x2d, 0x06, 0x4d, 0x64, 0x98, 0x66, 0xb4, 0x82, 0xf0,
44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x23, 0xa6, 0xd8, 0x37, 0x55, 0x7c, 0x01, 0xbf, 0x18, 0xd8, 0x16, 0x9e, 0x66,
45201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0xdc, 0x49, 0xbf, 0x2e, 0x86, 0xe3, 0x99, 0xbd, 0xb3, 0x75, 0x25, 0x61, 0x04,
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  0x6c, 0x2e, 0xfb, 0x32, 0x42, 0x27, 0xe4, 0x23, 0xea, 0xcd, 0x81, 0x62, 0xc1,
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
48201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
49201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst unsigned kMaxUploadsPerSession = 10;
50201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// DnsCertLimits is a singleton class which keeps track of which hosts we have
52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// uploaded reports for in this session. Since some users will be behind MITM
53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// proxies, they would otherwise upload for every host and we don't wish to
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// spam the upload server.
55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochclass DnsCertLimits {
56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch public:
57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DnsCertLimits() { }
58201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
59201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // HaveReachedMaxUploads returns true iff we have uploaded the maximum number
60201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // of DNS certificate reports for this session.
61201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool HaveReachedMaxUploads() {
62201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return uploaded_hostnames_.size() >= kMaxUploadsPerSession;
63201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
64201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
65201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // HaveReachedMaxUploads returns true iff we have already uploaded a report
66201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // about the given hostname in this session.
67201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool HaveUploadedForHostname(const std::string& hostname) {
68201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return uploaded_hostnames_.count(hostname) > 0;
69201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
70201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
71201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void DidUpload(const std::string& hostname) {
72201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    uploaded_hostnames_.insert(hostname);
73201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
74201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
75201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch private:
7621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  friend struct base::DefaultLazyInstanceTraits<DnsCertLimits>;
77201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
78201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::set<std::string> uploaded_hostnames_;
79201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
80201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(DnsCertLimits);
81201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
82201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
8321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<DnsCertLimits> g_dns_cert_limits(
8421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::LINKER_INITIALIZED);
8521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
86201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// DnsCertProvenanceCheck performs the DNS lookup of the certificate. This
87201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// class is self-deleting.
883f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass DnsCertProvenanceCheck : public base::NonThreadSafe {
89201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch public:
90201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DnsCertProvenanceCheck(
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      const std::string& hostname,
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      DnsRRResolver* dnsrr_resolver,
93201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      DnsCertProvenanceChecker::Delegate* delegate,
94201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      const std::vector<base::StringPiece>& der_certs)
95201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      : hostname_(hostname),
96201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        dnsrr_resolver_(dnsrr_resolver),
97201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        delegate_(delegate),
98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        der_certs_(der_certs.size()),
99201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        handle_(DnsRRResolver::kInvalidHandle),
100201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        ALLOW_THIS_IN_INITIALIZER_LIST(callback_(
101201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              this, &DnsCertProvenanceCheck::ResolutionComplete)) {
102201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    for (size_t i = 0; i < der_certs.size(); i++)
103201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      der_certs_[i] = der_certs[i].as_string();
104201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
105201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
106201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void Start() {
107201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DCHECK(CalledOnValidThread());
108201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
109201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (der_certs_.empty())
110201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return;
111201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DnsCertLimits* const limits = g_dns_cert_limits.Pointer();
113201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (limits->HaveReachedMaxUploads() ||
114201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        limits->HaveUploadedForHostname(hostname_)) {
115201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return;
116201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
117201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
118201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    uint8 fingerprint[SHA1_LENGTH];
119201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    SECStatus rv = HASH_HashBuf(
120201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(),
121201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        der_certs_[0].size());
122201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DCHECK_EQ(SECSuccess, rv);
123201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    char fingerprint_hex[SHA1_LENGTH * 2 + 1];
124201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    for (unsigned i = 0; i < sizeof(fingerprint); i++) {
125201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      static const char hextable[] = "0123456789abcdef";
126201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      fingerprint_hex[i*2] = hextable[fingerprint[i] >> 4];
127201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      fingerprint_hex[i*2 + 1] = hextable[fingerprint[i] & 15];
128201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
129201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    fingerprint_hex[SHA1_LENGTH * 2] = 0;
130201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    static const char kBaseCertName[] = ".certs.googlednstest.com";
132201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    domain_.assign(fingerprint_hex);
133201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    domain_.append(kBaseCertName);
134201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
135201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    handle_ = dnsrr_resolver_->Resolve(
136201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        domain_, kDNS_TXT, 0 /* flags */, &callback_, &response_,
137201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        0 /* priority */, BoundNetLog());
138201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (handle_ == DnsRRResolver::kInvalidHandle) {
139201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Failed to resolve " << domain_ << " for " << hostname_;
140201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      delete this;
141201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
142201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
143201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
144201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch private:
145201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  void ResolutionComplete(int status) {
146201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DCHECK(CalledOnValidThread());
147201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
148201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (status == ERR_NAME_NOT_RESOLVED ||
149201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        (status == OK && response_.rrdatas.empty())) {
150201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "FAILED"
151201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << " hostname:" << hostname_
152201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << " domain:" << domain_;
15321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      g_dns_cert_limits.Get().DidUpload(hostname_);
15421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      LogCertificates(der_certs_);
155201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      delegate_->OnDnsCertLookupFailed(hostname_, der_certs_);
156201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    } else if (status == OK) {
157201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "GOOD"
158201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << " hostname:" << hostname_
159201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                 << " resp:" << response_.rrdatas[0];
160201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    } else {
161201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(ERROR) << "Unknown error " << status << " for " << domain_;
162201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
163201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
164201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    delete this;
165201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
166201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
16721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // LogCertificates writes a certificate chain, in PEM format, to LOG(ERROR).
16821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  static void LogCertificates(
16921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      const std::vector<std::string>& der_certs) {
17021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    std::string dump;
17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    bool first = true;
17221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (std::vector<std::string>::const_iterator
17421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen         i = der_certs.begin(); i != der_certs.end(); i++) {
17521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!first)
17621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        dump += "\n";
17721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      first = false;
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
17921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      dump += "-----BEGIN CERTIFICATE-----\n";
18021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      std::string b64_encoded;
18121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      base::Base64Encode(*i, &b64_encoded);
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      for (size_t i = 0; i < b64_encoded.size();) {
18321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        size_t todo = b64_encoded.size() - i;
18421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        if (todo > 64)
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          todo = 64;
18621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        dump += b64_encoded.substr(i, todo);
18721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        dump += "\n";
18821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        i += todo;
18921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
19021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      dump += "-----END CERTIFICATE-----";
19121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    LOG(ERROR) << "Offending certificates:\n" << dump;
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
19521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
196201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  const std::string hostname_;
197201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string domain_;
198201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DnsRRResolver* dnsrr_resolver_;
199201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DnsCertProvenanceChecker::Delegate* const delegate_;
200201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::vector<std::string> der_certs_;
201201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  RRResponse response_;
202201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DnsRRResolver::Handle handle_;
203201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CompletionCallbackImpl<DnsCertProvenanceCheck> callback_;
204201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
205201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
206201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSECKEYPublicKey* GetServerPubKey() {
207201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECItem der;
208201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  memset(&der, 0, sizeof(der));
209201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  der.data = const_cast<uint8*>(kServerPublicKey);
210201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  der.len = sizeof(kServerPublicKey);
211201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
212201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
213201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
214201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEY_DestroySubjectPublicKeyInfo(spki);
215201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
216201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return public_key;
217201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
218201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
219201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace
220201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDnsCertProvenanceChecker::Delegate::~Delegate() {
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid DnsCertProvenanceChecker::DoAsyncLookup(
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& hostname,
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::vector<base::StringPiece>& der_certs,
23072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DnsRRResolver* dnsrr_resolver,
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Delegate* delegate) {
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DnsCertProvenanceCheck* check = new DnsCertProvenanceCheck(
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      hostname, dnsrr_resolver, delegate, der_certs);
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  check->Start();
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
237201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// static
238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstd::string DnsCertProvenanceChecker::BuildEncryptedReport(
239201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const std::string& hostname,
240201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const std::vector<std::string>& der_certs) {
241201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static const int kVersion = 0;
242201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static const unsigned kKeySizeInBytes = 16;  // AES-128
243201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static const unsigned kIVSizeInBytes = 16;  // AES's block size
244201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static const unsigned kPadSize = 4096; // we pad up to 4KB,
245201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // This is a DER encoded, ANSI X9.62 CurveParams object which simply
246201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // specifies P256.
247201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  static const uint8 kANSIX962CurveParams[] = {
248201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
249201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  };
250201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
251201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  Pickle p;
252201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  p.WriteString(hostname);
253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  p.WriteInt(der_certs.size());
254201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (std::vector<std::string>::const_iterator
255201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch       i = der_certs.begin(); i != der_certs.end(); i++) {
256201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    p.WriteString(*i);
257201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
258201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // We pad to eliminate the possibility that someone could see the size of
259201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // an upload and use that information to reduce the anonymity set of the
260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // certificate chain.
261201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // The "2*sizeof(uint32)" here covers the padding length which we add next
262201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // and Pickle's internal length which it includes at the beginning of the
263201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // data.
264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  unsigned pad_bytes = kPadSize - ((p.size() + 2*sizeof(uint32)) % kPadSize);
265201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  p.WriteUInt32(pad_bytes);
266201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  char* padding = new char[pad_bytes];
267201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  memset(padding, 0, pad_bytes);
268201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  p.WriteData(padding, pad_bytes);
269201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  delete[] padding;
270201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // We generate a random public value and perform a DH key agreement with
272201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // the server's fixed value.
273201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEYPublicKey* pub_key = NULL;
274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEYPrivateKey* priv_key = NULL;
275201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECItem ec_der_params;
276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  memset(&ec_der_params, 0, sizeof(ec_der_params));
277201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ec_der_params.data = const_cast<uint8*>(kANSIX962CurveParams);
278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ec_der_params.len = sizeof(kANSIX962CurveParams);
279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  priv_key = SECKEY_CreateECPrivateKey(&ec_der_params, &pub_key, NULL);
280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEYPublicKey* server_pub_key = GetServerPubKey();
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
282201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // This extracts the big-endian, x value of the shared point.
283201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // The values of the arguments match ssl3_SendECDHClientKeyExchange in NSS
284201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // 3.12.8's lib/ssl/ssl3ecc.c
285201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PK11SymKey* pms = PK11_PubDeriveWithKDF(
286201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      priv_key, server_pub_key, PR_FALSE /* is sender */,
287201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      NULL /* random a */, NULL /* random b */, CKM_ECDH1_DERIVE,
288201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      CKM_TLS_MASTER_KEY_DERIVE_DH, CKA_DERIVE, 0 /* key size */,
289201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      CKD_NULL /* KDF */, NULL /* shared data */, NULL /* wincx */);
290201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEY_DestroyPublicKey(server_pub_key);
291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECStatus rv = PK11_ExtractKeyValue(pms);
292201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_EQ(SECSuccess, rv);
293201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECItem* x_data = PK11_GetKeyData(pms);
294201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // The key and IV are 128-bits and generated from a SHA256 hash of the x
296201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // value.
297201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  char key_data[SHA256_LENGTH];
298201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  HASH_HashBuf(HASH_AlgSHA256, reinterpret_cast<uint8*>(key_data),
299201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch               x_data->data, x_data->len);
300201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PK11_FreeSymKey(pms);
301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
302201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK_GE(sizeof(key_data), kKeySizeInBytes + kIVSizeInBytes);
303201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string raw_key(key_data, kKeySizeInBytes);
304201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_ptr<crypto::SymmetricKey> symkey(
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string iv(key_data + kKeySizeInBytes, kIVSizeInBytes);
308201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  crypto::Encryptor encryptor;
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool r = encryptor.Init(symkey.get(), crypto::Encryptor::CBC, iv);
311201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CHECK(r);
312201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
313201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string plaintext(reinterpret_cast<const char*>(p.data()), p.size());
314201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string ciphertext;
315201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  encryptor.Encrypt(plaintext, &ciphertext);
316201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
317201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // We use another Pickle object to serialise the 'outer' wrapping of the
318201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // plaintext.
319201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  Pickle outer;
320201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  outer.WriteInt(kVersion);
321201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
322201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECItem* pub_key_serialized = SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key);
323201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  outer.WriteString(
324201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string(reinterpret_cast<char*>(pub_key_serialized->data),
325201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  pub_key_serialized->len));
326201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECITEM_FreeItem(pub_key_serialized, PR_TRUE);
327201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
328201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  outer.WriteString(ciphertext);
329201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
330201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEY_DestroyPublicKey(pub_key);
331201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SECKEY_DestroyPrivateKey(priv_key);
332201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
333201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return std::string(reinterpret_cast<const char*>(outer.data()),
334201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                     outer.size());
335201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
336201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
337201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace net
338201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
339201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#else  // USE_OPENSSL
340201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
341201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace net {
342201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
34372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDnsCertProvenanceChecker::Delegate::~Delegate() {
34472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenDnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
347201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
348201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
349201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid DnsCertProvenanceChecker::DoAsyncLookup(
350201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const std::string& hostname,
351201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    const std::vector<base::StringPiece>& der_certs,
352201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DnsRRResolver* dnsrr_resolver,
353201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    Delegate* delegate) {
354201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
355201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::string DnsCertProvenanceChecker::BuildEncryptedReport(
35772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& hostname,
35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::vector<std::string>& der_certs) {
35972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return "";
360201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
361201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
362201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace net
363201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
364201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#endif  // USE_OPENSSL
365