Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Side by Side Diff: net/socket/dns_cert_provenance_checker.cc

Issue 8944001: net: remove DNS certificate checking code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/socket/dns_cert_provenance_checker.h ('k') | net/socket/ssl_client_socket.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/socket/dns_cert_provenance_checker.h"
6
7 #if !defined(USE_OPENSSL)
8
9 #include <nspr.h>
10
11 #include <hasht.h>
12 #include <keyhi.h>
13 #include <pk11pub.h>
14 #include <sechash.h>
15
16 #include <set>
17 #include <string>
18
19 #include "base/base64.h"
20 #include "base/basictypes.h"
21 #include "base/bind.h"
22 #include "base/lazy_instance.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/pickle.h"
25 #include "base/threading/non_thread_safe.h"
26 #include "crypto/encryptor.h"
27 #include "crypto/symmetric_key.h"
28 #include "net/base/completion_callback.h"
29 #include "net/base/dns_util.h"
30 #include "net/base/dnsrr_resolver.h"
31 #include "net/base/net_errors.h"
32 #include "net/base/net_log.h"
33
34 namespace net {
35
36 namespace {
37
38 // A DER encoded SubjectPublicKeyInfo structure containing the server's public
39 // key.
40 const uint8 kServerPublicKey[] = {
41 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
42 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
43 0x04, 0xc7, 0xea, 0x88, 0x60, 0x52, 0xe3, 0xa3, 0x3e, 0x39, 0x92, 0x0f, 0xa4,
44 0x3d, 0xba, 0xd8, 0x02, 0x2d, 0x06, 0x4d, 0x64, 0x98, 0x66, 0xb4, 0x82, 0xf0,
45 0x23, 0xa6, 0xd8, 0x37, 0x55, 0x7c, 0x01, 0xbf, 0x18, 0xd8, 0x16, 0x9e, 0x66,
46 0xdc, 0x49, 0xbf, 0x2e, 0x86, 0xe3, 0x99, 0xbd, 0xb3, 0x75, 0x25, 0x61, 0x04,
47 0x6c, 0x2e, 0xfb, 0x32, 0x42, 0x27, 0xe4, 0x23, 0xea, 0xcd, 0x81, 0x62, 0xc1,
48 };
49
50 const unsigned kMaxUploadsPerSession = 10;
51
52 // DnsCertLimits is a singleton class which keeps track of which hosts we have
53 // uploaded reports for in this session. Since some users will be behind MITM
54 // proxies, they would otherwise upload for every host and we don't wish to
55 // spam the upload server.
56 class DnsCertLimits {
57 public:
58 DnsCertLimits() { }
59
60 // HaveReachedMaxUploads returns true iff we have uploaded the maximum number
61 // of DNS certificate reports for this session.
62 bool HaveReachedMaxUploads() {
63 return uploaded_hostnames_.size() >= kMaxUploadsPerSession;
64 }
65
66 // HaveReachedMaxUploads returns true iff we have already uploaded a report
67 // about the given hostname in this session.
68 bool HaveUploadedForHostname(const std::string& hostname) {
69 return uploaded_hostnames_.count(hostname) > 0;
70 }
71
72 void DidUpload(const std::string& hostname) {
73 uploaded_hostnames_.insert(hostname);
74 }
75
76 private:
77 friend struct base::DefaultLazyInstanceTraits<DnsCertLimits>;
78
79 std::set<std::string> uploaded_hostnames_;
80
81 DISALLOW_COPY_AND_ASSIGN(DnsCertLimits);
82 };
83
84 static base::LazyInstance<DnsCertLimits> g_dns_cert_limits =
85 LAZY_INSTANCE_INITIALIZER;
86
87 // DnsCertProvenanceCheck performs the DNS lookup of the certificate. This
88 // class is self-deleting.
89 class DnsCertProvenanceCheck : public base::NonThreadSafe {
90 public:
91 DnsCertProvenanceCheck(
92 const std::string& hostname,
93 DnsRRResolver* dnsrr_resolver,
94 DnsCertProvenanceChecker::Delegate* delegate,
95 const std::vector<base::StringPiece>& der_certs)
96 : hostname_(hostname),
97 dnsrr_resolver_(dnsrr_resolver),
98 delegate_(delegate),
99 der_certs_(der_certs.size()),
100 handle_(DnsRRResolver::kInvalidHandle) {
101 for (size_t i = 0; i < der_certs.size(); i++)
102 der_certs_[i] = der_certs[i].as_string();
103 }
104
105 void Start() {
106 DCHECK(CalledOnValidThread());
107
108 if (der_certs_.empty())
109 return;
110
111 DnsCertLimits* const limits = g_dns_cert_limits.Pointer();
112 if (limits->HaveReachedMaxUploads() ||
113 limits->HaveUploadedForHostname(hostname_)) {
114 return;
115 }
116
117 uint8 fingerprint[SHA1_LENGTH];
118 SECStatus rv = HASH_HashBuf(
119 HASH_AlgSHA1, fingerprint, (uint8*) der_certs_[0].data(),
120 der_certs_[0].size());
121 DCHECK_EQ(SECSuccess, rv);
122 char fingerprint_hex[SHA1_LENGTH * 2 + 1];
123 for (unsigned i = 0; i < sizeof(fingerprint); i++) {
124 static const char hextable[] = "0123456789abcdef";
125 fingerprint_hex[i*2] = hextable[fingerprint[i] >> 4];
126 fingerprint_hex[i*2 + 1] = hextable[fingerprint[i] & 15];
127 }
128 fingerprint_hex[SHA1_LENGTH * 2] = 0;
129
130 static const char kBaseCertName[] = ".certs.googlednstest.com";
131 domain_.assign(fingerprint_hex);
132 domain_.append(kBaseCertName);
133
134 handle_ = dnsrr_resolver_->Resolve(
135 domain_, kDNS_TXT, 0 /* flags */,
136 base::Bind(&DnsCertProvenanceCheck::ResolutionComplete,
137 base::Unretained(this)),
138 &response_, 0 /* priority */, BoundNetLog());
139 if (handle_ == DnsRRResolver::kInvalidHandle) {
140 LOG(ERROR) << "Failed to resolve " << domain_ << " for " << hostname_;
141 delete this;
142 }
143 }
144
145 private:
146 void ResolutionComplete(int status) {
147 DCHECK(CalledOnValidThread());
148
149 if (status == ERR_NAME_NOT_RESOLVED ||
150 (status == OK && response_.rrdatas.empty())) {
151 LOG(ERROR) << "FAILED"
152 << " hostname:" << hostname_
153 << " domain:" << domain_;
154 g_dns_cert_limits.Get().DidUpload(hostname_);
155 LogCertificates(der_certs_);
156 delegate_->OnDnsCertLookupFailed(hostname_, der_certs_);
157 } else if (status == OK) {
158 LOG(ERROR) << "GOOD"
159 << " hostname:" << hostname_
160 << " resp:" << response_.rrdatas[0];
161 } else {
162 LOG(ERROR) << "Unknown error " << status << " for " << domain_;
163 }
164
165 delete this;
166 }
167
168 // LogCertificates writes a certificate chain, in PEM format, to LOG(ERROR).
169 static void LogCertificates(
170 const std::vector<std::string>& der_certs) {
171 std::string dump;
172 bool first = true;
173
174 for (std::vector<std::string>::const_iterator
175 i = der_certs.begin(); i != der_certs.end(); i++) {
176 if (!first)
177 dump += "\n";
178 first = false;
179
180 dump += "-----BEGIN CERTIFICATE-----\n";
181 std::string b64_encoded;
182 base::Base64Encode(*i, &b64_encoded);
183 for (size_t i = 0; i < b64_encoded.size();) {
184 size_t todo = b64_encoded.size() - i;
185 if (todo > 64)
186 todo = 64;
187 dump += b64_encoded.substr(i, todo);
188 dump += "\n";
189 i += todo;
190 }
191 dump += "-----END CERTIFICATE-----";
192 }
193
194 LOG(ERROR) << "Offending certificates:\n" << dump;
195 }
196
197 const std::string hostname_;
198 std::string domain_;
199 DnsRRResolver* dnsrr_resolver_;
200 DnsCertProvenanceChecker::Delegate* const delegate_;
201 std::vector<std::string> der_certs_;
202 RRResponse response_;
203 DnsRRResolver::Handle handle_;
204 };
205
206 SECKEYPublicKey* GetServerPubKey() {
207 SECItem der;
208 memset(&der, 0, sizeof(der));
209 der.data = const_cast<uint8*>(kServerPublicKey);
210 der.len = sizeof(kServerPublicKey);
211
212 CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
213 SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
214 SECKEY_DestroySubjectPublicKeyInfo(spki);
215
216 return public_key;
217 }
218
219 } // namespace
220
221 DnsCertProvenanceChecker::Delegate::~Delegate() {
222 }
223
224 DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
225 }
226
227 void DnsCertProvenanceChecker::DoAsyncLookup(
228 const std::string& hostname,
229 const std::vector<base::StringPiece>& der_certs,
230 DnsRRResolver* dnsrr_resolver,
231 Delegate* delegate) {
232 DnsCertProvenanceCheck* check = new DnsCertProvenanceCheck(
233 hostname, dnsrr_resolver, delegate, der_certs);
234 check->Start();
235 }
236
237 // static
238 std::string DnsCertProvenanceChecker::BuildEncryptedReport(
239 const std::string& hostname,
240 const std::vector<std::string>& der_certs) {
241 static const int kVersion = 0;
242 static const unsigned kKeySizeInBytes = 16; // AES-128
243 static const unsigned kIVSizeInBytes = 16; // AES's block size
244 static const unsigned kPadSize = 4096; // we pad up to 4KB,
245 // This is a DER encoded, ANSI X9.62 CurveParams object which simply
246 // specifies P256.
247 static const uint8 kANSIX962CurveParams[] = {
248 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
249 };
250
251 Pickle p;
252 p.WriteString(hostname);
253 p.WriteInt(der_certs.size());
254 for (std::vector<std::string>::const_iterator
255 i = der_certs.begin(); i != der_certs.end(); i++) {
256 p.WriteString(*i);
257 }
258 // We pad to eliminate the possibility that someone could see the size of
259 // an upload and use that information to reduce the anonymity set of the
260 // certificate chain.
261 // The "2*sizeof(uint32)" here covers the padding length which we add next
262 // and Pickle's internal length which it includes at the beginning of the
263 // data.
264 unsigned pad_bytes = kPadSize - ((p.size() + 2*sizeof(uint32)) % kPadSize);
265 p.WriteUInt32(pad_bytes);
266 char* padding = new char[pad_bytes];
267 memset(padding, 0, pad_bytes);
268 p.WriteData(padding, pad_bytes);
269 delete[] padding;
270
271 // We generate a random public value and perform a DH key agreement with
272 // the server's fixed value.
273 SECKEYPublicKey* pub_key = NULL;
274 SECKEYPrivateKey* priv_key = NULL;
275 SECItem ec_der_params;
276 memset(&ec_der_params, 0, sizeof(ec_der_params));
277 ec_der_params.data = const_cast<uint8*>(kANSIX962CurveParams);
278 ec_der_params.len = sizeof(kANSIX962CurveParams);
279 priv_key = SECKEY_CreateECPrivateKey(&ec_der_params, &pub_key, NULL);
280 SECKEYPublicKey* server_pub_key = GetServerPubKey();
281
282 // This extracts the big-endian, x value of the shared point.
283 // The values of the arguments match ssl3_SendECDHClientKeyExchange in NSS
284 // 3.12.8's lib/ssl/ssl3ecc.c
285 PK11SymKey* pms = PK11_PubDeriveWithKDF(
286 priv_key, server_pub_key, PR_FALSE /* is sender */,
287 NULL /* random a */, NULL /* random b */, CKM_ECDH1_DERIVE,
288 CKM_TLS_MASTER_KEY_DERIVE_DH, CKA_DERIVE, 0 /* key size */,
289 CKD_NULL /* KDF */, NULL /* shared data */, NULL /* wincx */);
290 SECKEY_DestroyPublicKey(server_pub_key);
291 SECStatus rv = PK11_ExtractKeyValue(pms);
292 DCHECK_EQ(SECSuccess, rv);
293 SECItem* x_data = PK11_GetKeyData(pms);
294
295 // The key and IV are 128-bits and generated from a SHA256 hash of the x
296 // value.
297 char key_data[SHA256_LENGTH];
298 HASH_HashBuf(HASH_AlgSHA256, reinterpret_cast<uint8*>(key_data),
299 x_data->data, x_data->len);
300 PK11_FreeSymKey(pms);
301
302 DCHECK_GE(sizeof(key_data), kKeySizeInBytes + kIVSizeInBytes);
303 std::string raw_key(key_data, kKeySizeInBytes);
304
305 scoped_ptr<crypto::SymmetricKey> symkey(
306 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
307 std::string iv(key_data + kKeySizeInBytes, kIVSizeInBytes);
308
309 crypto::Encryptor encryptor;
310 bool r = encryptor.Init(symkey.get(), crypto::Encryptor::CBC, iv);
311 CHECK(r);
312
313 std::string plaintext(reinterpret_cast<const char*>(p.data()), p.size());
314 std::string ciphertext;
315 encryptor.Encrypt(plaintext, &ciphertext);
316
317 // We use another Pickle object to serialise the 'outer' wrapping of the
318 // plaintext.
319 Pickle outer;
320 outer.WriteInt(kVersion);
321
322 SECItem* pub_key_serialized = SECKEY_EncodeDERSubjectPublicKeyInfo(pub_key);
323 outer.WriteString(
324 std::string(reinterpret_cast<char*>(pub_key_serialized->data),
325 pub_key_serialized->len));
326 SECITEM_FreeItem(pub_key_serialized, PR_TRUE);
327
328 outer.WriteString(ciphertext);
329
330 SECKEY_DestroyPublicKey(pub_key);
331 SECKEY_DestroyPrivateKey(priv_key);
332
333 return std::string(reinterpret_cast<const char*>(outer.data()),
334 outer.size());
335 }
336
337 } // namespace net
338
339 #else // USE_OPENSSL
340
341 namespace net {
342
343 DnsCertProvenanceChecker::Delegate::~Delegate() {
344 }
345
346 DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
347 }
348
349 void DnsCertProvenanceChecker::DoAsyncLookup(
350 const std::string& hostname,
351 const std::vector<base::StringPiece>& der_certs,
352 DnsRRResolver* dnsrr_resolver,
353 Delegate* delegate) {
354 }
355
356 std::string DnsCertProvenanceChecker::BuildEncryptedReport(
357 const std::string& hostname,
358 const std::vector<std::string>& der_certs) {
359 return "";
360 }
361
362 } // namespace net
363
364 #endif // USE_OPENSSL
OLDNEW
« no previous file with comments | « net/socket/dns_cert_provenance_checker.h ('k') | net/socket/ssl_client_socket.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698