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