summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-10 17:14:23 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-10 17:14:23 +0000
commit15a3ebf01a2e6ea982c1d952abfa60e14e7e0357 (patch)
tree628dd41c14d8dd9bebb1d1f5013827b3a2dbce11
parent5dd2892952df15a938be47e8d6fbf679952733e6 (diff)
downloadchromium_src-15a3ebf01a2e6ea982c1d952abfa60e14e7e0357.zip
chromium_src-15a3ebf01a2e6ea982c1d952abfa60e14e7e0357.tar.gz
chromium_src-15a3ebf01a2e6ea982c1d952abfa60e14e7e0357.tar.bz2
net: add code for encrypting DNS cert check uploads.
(This code isn't live yet.) BUG=none TEST=none http://codereview.chromium.org/4698003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@65677 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/socket/dns_cert_provenance_check.cc138
1 files changed, 137 insertions, 1 deletions
diff --git a/net/socket/dns_cert_provenance_check.cc b/net/socket/dns_cert_provenance_check.cc
index e83cb5e..61b9a04 100644
--- a/net/socket/dns_cert_provenance_check.cc
+++ b/net/socket/dns_cert_provenance_check.cc
@@ -5,22 +5,40 @@
#include "net/socket/dns_cert_provenance_check.h"
#include <nspr.h>
+
#include <hasht.h>
+#include <keyhi.h>
+#include <pk11pub.h>
#include <sechash.h>
#include <string>
+#include "base/crypto/encryptor.h"
+#include "base/crypto/symmetric_key.h"
#include "base/non_thread_safe.h"
+#include "base/pickle.h"
#include "net/base/completion_callback.h"
#include "net/base/dns_util.h"
#include "net/base/dnsrr_resolver.h"
-#include "net/base/net_log.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,
+};
+
class DNSCertProvenanceChecker : public NonThreadSafe {
public:
DNSCertProvenanceChecker(const std::string hostname,
@@ -77,6 +95,7 @@ class DNSCertProvenanceChecker : public NonThreadSafe {
LOG(ERROR) << "FAILED"
<< " hostname:" << hostname_
<< " domain:" << domain_;
+ BuildRecord();
} else if (status == OK) {
LOG(ERROR) << "GOOD"
<< " hostname:" << hostname_
@@ -88,6 +107,123 @@ class DNSCertProvenanceChecker : public NonThreadSafe {
delete this;
}
+ // BuildRecord encrypts the certificate chain to a fixed public key and
+ // returns the encrypted blob. Since this code is reporting a possible HTTPS
+ // failure, it would seem silly to use HTTPS to protect the uploaded report.
+ std::string BuildRecord() {
+ 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
+ };
+
+ DCHECK(CalledOnValidThread());
+
+ 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<base::SymmetricKey> symkey(
+ base::SymmetricKey::Import(base::SymmetricKey::AES, raw_key));
+ std::string iv(key_data + kKeySizeInBytes, kIVSizeInBytes);
+
+ base::Encryptor encryptor;
+ bool r = encryptor.Init(symkey.get(), base::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());
+ }
+
+ SECKEYPublicKey* GetServerPubKey() {
+ DCHECK(CalledOnValidThread());
+
+ 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;
+ }
+
const std::string hostname_;
std::string domain_;
DnsRRResolver* const dnsrr_resolver_;