| Index: net/socket/dns_cert_provenance_checker.cc
|
| diff --git a/net/socket/dns_cert_provenance_checker.cc b/net/socket/dns_cert_provenance_checker.cc
|
| deleted file mode 100644
|
| index b05a38260eb6b0e83996229d1377502603d14f76..0000000000000000000000000000000000000000
|
| --- a/net/socket/dns_cert_provenance_checker.cc
|
| +++ /dev/null
|
| @@ -1,364 +0,0 @@
|
| -// Copyright (c) 2011 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/dns_cert_provenance_checker.h"
|
| -
|
| -#if !defined(USE_OPENSSL)
|
| -
|
| -#include <nspr.h>
|
| -
|
| -#include <hasht.h>
|
| -#include <keyhi.h>
|
| -#include <pk11pub.h>
|
| -#include <sechash.h>
|
| -
|
| -#include <set>
|
| -#include <string>
|
| -
|
| -#include "base/base64.h"
|
| -#include "base/basictypes.h"
|
| -#include "base/bind.h"
|
| -#include "base/lazy_instance.h"
|
| -#include "base/memory/scoped_ptr.h"
|
| -#include "base/pickle.h"
|
| -#include "base/threading/non_thread_safe.h"
|
| -#include "crypto/encryptor.h"
|
| -#include "crypto/symmetric_key.h"
|
| -#include "net/base/completion_callback.h"
|
| -#include "net/base/dns_util.h"
|
| -#include "net/base/dnsrr_resolver.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/net_log.h"
|
| -
|
| -namespace net {
|
| -
|
| -namespace {
|
| -
|
| -// A DER encoded SubjectPublicKeyInfo structure containing the server's public
|
| -// key.
|
| -const uint8 kServerPublicKey[] = {
|
| - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
|
| - 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
|
| - 0x04, 0xc7, 0xea, 0x88, 0x60, 0x52, 0xe3, 0xa3, 0x3e, 0x39, 0x92, 0x0f, 0xa4,
|
| - 0x3d, 0xba, 0xd8, 0x02, 0x2d, 0x06, 0x4d, 0x64, 0x98, 0x66, 0xb4, 0x82, 0xf0,
|
| - 0x23, 0xa6, 0xd8, 0x37, 0x55, 0x7c, 0x01, 0xbf, 0x18, 0xd8, 0x16, 0x9e, 0x66,
|
| - 0xdc, 0x49, 0xbf, 0x2e, 0x86, 0xe3, 0x99, 0xbd, 0xb3, 0x75, 0x25, 0x61, 0x04,
|
| - 0x6c, 0x2e, 0xfb, 0x32, 0x42, 0x27, 0xe4, 0x23, 0xea, 0xcd, 0x81, 0x62, 0xc1,
|
| -};
|
| -
|
| -const unsigned kMaxUploadsPerSession = 10;
|
| -
|
| -// DnsCertLimits is a singleton class which keeps track of which hosts we have
|
| -// uploaded reports for in this session. Since some users will be behind MITM
|
| -// proxies, they would otherwise upload for every host and we don't wish to
|
| -// spam the upload server.
|
| -class DnsCertLimits {
|
| - public:
|
| - DnsCertLimits() { }
|
| -
|
| - // HaveReachedMaxUploads returns true iff we have uploaded the maximum number
|
| - // of DNS certificate reports for this session.
|
| - bool HaveReachedMaxUploads() {
|
| - return uploaded_hostnames_.size() >= kMaxUploadsPerSession;
|
| - }
|
| -
|
| - // HaveReachedMaxUploads returns true iff we have already uploaded a report
|
| - // about the given hostname in this session.
|
| - bool HaveUploadedForHostname(const std::string& hostname) {
|
| - return uploaded_hostnames_.count(hostname) > 0;
|
| - }
|
| -
|
| - void DidUpload(const std::string& hostname) {
|
| - uploaded_hostnames_.insert(hostname);
|
| - }
|
| -
|
| - private:
|
| - friend struct base::DefaultLazyInstanceTraits<DnsCertLimits>;
|
| -
|
| - std::set<std::string> uploaded_hostnames_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(DnsCertLimits);
|
| -};
|
| -
|
| -static base::LazyInstance<DnsCertLimits> g_dns_cert_limits =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -
|
| -// DnsCertProvenanceCheck performs the DNS lookup of the certificate. This
|
| -// class is self-deleting.
|
| -class DnsCertProvenanceCheck : public base::NonThreadSafe {
|
| - public:
|
| - DnsCertProvenanceCheck(
|
| - const std::string& hostname,
|
| - DnsRRResolver* dnsrr_resolver,
|
| - DnsCertProvenanceChecker::Delegate* delegate,
|
| - const std::vector<base::StringPiece>& der_certs)
|
| - : hostname_(hostname),
|
| - dnsrr_resolver_(dnsrr_resolver),
|
| - delegate_(delegate),
|
| - der_certs_(der_certs.size()),
|
| - handle_(DnsRRResolver::kInvalidHandle) {
|
| - for (size_t i = 0; i < der_certs.size(); i++)
|
| - der_certs_[i] = der_certs[i].as_string();
|
| - }
|
| -
|
| - void Start() {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - if (der_certs_.empty())
|
| - return;
|
| -
|
| - DnsCertLimits* const limits = g_dns_cert_limits.Pointer();
|
| - if (limits->HaveReachedMaxUploads() ||
|
| - limits->HaveUploadedForHostname(hostname_)) {
|
| - return;
|
| - }
|
| -
|
| - uint8 fingerprint[SHA1_LENGTH];
|
| - SECStatus rv = HASH_HashBuf(
|
| - HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(),
|
| - der_certs_[0].size());
|
| - DCHECK_EQ(SECSuccess, rv);
|
| - char fingerprint_hex[SHA1_LENGTH * 2 + 1];
|
| - for (unsigned i = 0; i < sizeof(fingerprint); i++) {
|
| - static const char hextable[] = "0123456789abcdef";
|
| - fingerprint_hex[i*2] = hextable[fingerprint[i] >> 4];
|
| - fingerprint_hex[i*2 + 1] = hextable[fingerprint[i] & 15];
|
| - }
|
| - fingerprint_hex[SHA1_LENGTH * 2] = 0;
|
| -
|
| - static const char kBaseCertName[] = ".certs.googlednstest.com";
|
| - domain_.assign(fingerprint_hex);
|
| - domain_.append(kBaseCertName);
|
| -
|
| - handle_ = dnsrr_resolver_->Resolve(
|
| - domain_, kDNS_TXT, 0 /* flags */,
|
| - base::Bind(&DnsCertProvenanceCheck::ResolutionComplete,
|
| - base::Unretained(this)),
|
| - &response_, 0 /* priority */, BoundNetLog());
|
| - if (handle_ == DnsRRResolver::kInvalidHandle) {
|
| - LOG(ERROR) << "Failed to resolve " << domain_ << " for " << hostname_;
|
| - delete this;
|
| - }
|
| - }
|
| -
|
| - private:
|
| - void ResolutionComplete(int status) {
|
| - DCHECK(CalledOnValidThread());
|
| -
|
| - if (status == ERR_NAME_NOT_RESOLVED ||
|
| - (status == OK && response_.rrdatas.empty())) {
|
| - LOG(ERROR) << "FAILED"
|
| - << " hostname:" << hostname_
|
| - << " domain:" << domain_;
|
| - g_dns_cert_limits.Get().DidUpload(hostname_);
|
| - LogCertificates(der_certs_);
|
| - delegate_->OnDnsCertLookupFailed(hostname_, der_certs_);
|
| - } else if (status == OK) {
|
| - LOG(ERROR) << "GOOD"
|
| - << " hostname:" << hostname_
|
| - << " resp:" << response_.rrdatas[0];
|
| - } else {
|
| - LOG(ERROR) << "Unknown error " << status << " for " << domain_;
|
| - }
|
| -
|
| - delete this;
|
| - }
|
| -
|
| - // LogCertificates writes a certificate chain, in PEM format, to LOG(ERROR).
|
| - static void LogCertificates(
|
| - const std::vector<std::string>& der_certs) {
|
| - std::string dump;
|
| - bool first = true;
|
| -
|
| - for (std::vector<std::string>::const_iterator
|
| - i = der_certs.begin(); i != der_certs.end(); i++) {
|
| - if (!first)
|
| - dump += "\n";
|
| - first = false;
|
| -
|
| - dump += "-----BEGIN CERTIFICATE-----\n";
|
| - std::string b64_encoded;
|
| - base::Base64Encode(*i, &b64_encoded);
|
| - for (size_t i = 0; i < b64_encoded.size();) {
|
| - size_t todo = b64_encoded.size() - i;
|
| - if (todo > 64)
|
| - todo = 64;
|
| - dump += b64_encoded.substr(i, todo);
|
| - dump += "\n";
|
| - i += todo;
|
| - }
|
| - dump += "-----END CERTIFICATE-----";
|
| - }
|
| -
|
| - LOG(ERROR) << "Offending certificates:\n" << dump;
|
| - }
|
| -
|
| - const std::string hostname_;
|
| - std::string domain_;
|
| - DnsRRResolver* dnsrr_resolver_;
|
| - DnsCertProvenanceChecker::Delegate* const delegate_;
|
| - std::vector<std::string> der_certs_;
|
| - RRResponse response_;
|
| - DnsRRResolver::Handle handle_;
|
| -};
|
| -
|
| -SECKEYPublicKey* GetServerPubKey() {
|
| - SECItem der;
|
| - memset(&der, 0, sizeof(der));
|
| - der.data = const_cast<uint8*>(kServerPublicKey);
|
| - der.len = sizeof(kServerPublicKey);
|
| -
|
| - CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
|
| - SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
|
| - SECKEY_DestroySubjectPublicKeyInfo(spki);
|
| -
|
| - return public_key;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -DnsCertProvenanceChecker::Delegate::~Delegate() {
|
| -}
|
| -
|
| -DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
|
| -}
|
| -
|
| -void DnsCertProvenanceChecker::DoAsyncLookup(
|
| - const std::string& hostname,
|
| - const std::vector<base::StringPiece>& der_certs,
|
| - DnsRRResolver* dnsrr_resolver,
|
| - Delegate* delegate) {
|
| - DnsCertProvenanceCheck* check = new DnsCertProvenanceCheck(
|
| - hostname, dnsrr_resolver, delegate, der_certs);
|
| - check->Start();
|
| -}
|
| -
|
| -// static
|
| -std::string DnsCertProvenanceChecker::BuildEncryptedReport(
|
| - const std::string& hostname,
|
| - const std::vector<std::string>& der_certs) {
|
| - static const int kVersion = 0;
|
| - static const unsigned kKeySizeInBytes = 16; // AES-128
|
| - static const unsigned kIVSizeInBytes = 16; // AES's block size
|
| - static const unsigned kPadSize = 4096; // we pad up to 4KB,
|
| - // This is a DER encoded, ANSI X9.62 CurveParams object which simply
|
| - // specifies P256.
|
| - static const uint8 kANSIX962CurveParams[] = {
|
| - 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
|
| - };
|
| -
|
| - Pickle p;
|
| - p.WriteString(hostname);
|
| - p.WriteInt(der_certs.size());
|
| - for (std::vector<std::string>::const_iterator
|
| - i = der_certs.begin(); i != der_certs.end(); i++) {
|
| - p.WriteString(*i);
|
| - }
|
| - // We pad to eliminate the possibility that someone could see the size of
|
| - // an upload and use that information to reduce the anonymity set of the
|
| - // certificate chain.
|
| - // The "2*sizeof(uint32)" here covers the padding length which we add next
|
| - // and Pickle's internal length which it includes at the beginning of the
|
| - // data.
|
| - unsigned pad_bytes = kPadSize - ((p.size() + 2*sizeof(uint32)) % kPadSize);
|
| - p.WriteUInt32(pad_bytes);
|
| - char* padding = new char[pad_bytes];
|
| - memset(padding, 0, pad_bytes);
|
| - p.WriteData(padding, pad_bytes);
|
| - delete[] padding;
|
| -
|
| - // We generate a random public value and perform a DH key agreement with
|
| - // the server's fixed value.
|
| - SECKEYPublicKey* pub_key = NULL;
|
| - SECKEYPrivateKey* priv_key = NULL;
|
| - SECItem ec_der_params;
|
| - memset(&ec_der_params, 0, sizeof(ec_der_params));
|
| - ec_der_params.data = const_cast<uint8*>(kANSIX962CurveParams);
|
| - ec_der_params.len = sizeof(kANSIX962CurveParams);
|
| - priv_key = SECKEY_CreateECPrivateKey(&ec_der_params, &pub_key, NULL);
|
| - SECKEYPublicKey* server_pub_key = GetServerPubKey();
|
| -
|
| - // This extracts the big-endian, x value of the shared point.
|
| - // The values of the arguments match ssl3_SendECDHClientKeyExchange in NSS
|
| - // 3.12.8's lib/ssl/ssl3ecc.c
|
| - PK11SymKey* pms = PK11_PubDeriveWithKDF(
|
| - priv_key, server_pub_key, PR_FALSE /* is sender */,
|
| - NULL /* random a */, NULL /* random b */, CKM_ECDH1_DERIVE,
|
| - CKM_TLS_MASTER_KEY_DERIVE_DH, CKA_DERIVE, 0 /* key size */,
|
| - CKD_NULL /* KDF */, NULL /* shared data */, NULL /* wincx */);
|
| - SECKEY_DestroyPublicKey(server_pub_key);
|
| - SECStatus rv = PK11_ExtractKeyValue(pms);
|
| - DCHECK_EQ(SECSuccess, rv);
|
| - SECItem* x_data = PK11_GetKeyData(pms);
|
| -
|
| - // The key and IV are 128-bits and generated from a SHA256 hash of the x
|
| - // value.
|
| - char key_data[SHA256_LENGTH];
|
| - HASH_HashBuf(HASH_AlgSHA256, reinterpret_cast<uint8*>(key_data),
|
| - x_data->data, x_data->len);
|
| - PK11_FreeSymKey(pms);
|
| -
|
| - DCHECK_GE(sizeof(key_data), kKeySizeInBytes + kIVSizeInBytes);
|
| - std::string raw_key(key_data, kKeySizeInBytes);
|
| -
|
| - scoped_ptr<crypto::SymmetricKey> symkey(
|
| - crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
|
| - std::string iv(key_data + kKeySizeInBytes, kIVSizeInBytes);
|
| -
|
| - crypto::Encryptor encryptor;
|
| - bool r = encryptor.Init(symkey.get(), crypto::Encryptor::CBC, iv);
|
| - CHECK(r);
|
| -
|
| - std::string plaintext(reinterpret_cast<const char*>(p.data()), p.size());
|
| - std::string ciphertext;
|
| - encryptor.Encrypt(plaintext, &ciphertext);
|
| -
|
| - // We use another Pickle object to serialise the 'outer' wrapping of the
|
| - // plaintext.
|
| - Pickle outer;
|
| - outer.WriteInt(kVersion);
|
| -
|
| - SECItem* pub_key_serialized = SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key);
|
| - outer.WriteString(
|
| - std::string(reinterpret_cast<char*>(pub_key_serialized->data),
|
| - pub_key_serialized->len));
|
| - SECITEM_FreeItem(pub_key_serialized, PR_TRUE);
|
| -
|
| - outer.WriteString(ciphertext);
|
| -
|
| - SECKEY_DestroyPublicKey(pub_key);
|
| - SECKEY_DestroyPrivateKey(priv_key);
|
| -
|
| - return std::string(reinterpret_cast<const char*>(outer.data()),
|
| - outer.size());
|
| -}
|
| -
|
| -} // namespace net
|
| -
|
| -#else // USE_OPENSSL
|
| -
|
| -namespace net {
|
| -
|
| -DnsCertProvenanceChecker::Delegate::~Delegate() {
|
| -}
|
| -
|
| -DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
|
| -}
|
| -
|
| -void DnsCertProvenanceChecker::DoAsyncLookup(
|
| - const std::string& hostname,
|
| - const std::vector<base::StringPiece>& der_certs,
|
| - DnsRRResolver* dnsrr_resolver,
|
| - Delegate* delegate) {
|
| -}
|
| -
|
| -std::string DnsCertProvenanceChecker::BuildEncryptedReport(
|
| - const std::string& hostname,
|
| - const std::vector<std::string>& der_certs) {
|
| - return "";
|
| -}
|
| -
|
| -} // namespace net
|
| -
|
| -#endif // USE_OPENSSL
|
|
|