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

Side by Side Diff: net/base/transport_security_state.cc

Issue 9415040: Refactor TransportSecurityState. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 9 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/transport_security_state.h" 5 #include "net/base/transport_security_state.h"
6 6
7 #if defined(USE_OPENSSL) 7 #if defined(USE_OPENSSL)
8 #include <openssl/ecdsa.h> 8 #include <openssl/ecdsa.h>
9 #include <openssl/ssl.h> 9 #include <openssl/ssl.h>
10 #else // !defined(USE_OPENSSL) 10 #else // !defined(USE_OPENSSL)
11 #include <cryptohi.h> 11 #include <cryptohi.h>
12 #include <hasht.h> 12 #include <hasht.h>
13 #include <keyhi.h> 13 #include <keyhi.h>
14 #include <pk11pub.h> 14 #include <pk11pub.h>
15 #include <nspr.h> 15 #include <nspr.h>
16 #endif 16 #endif
17 17
18 #include <algorithm> 18 #include <algorithm>
19 #include <utility> 19 #include <utility>
20 20
21 #include "base/base64.h" 21 #include "base/base64.h"
22 #include "base/json/json_reader.h"
23 #include "base/json/json_writer.h"
24 #include "base/logging.h" 22 #include "base/logging.h"
25 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
26 #include "base/metrics/histogram.h" 24 #include "base/metrics/histogram.h"
27 #include "base/sha1.h" 25 #include "base/sha1.h"
28 #include "base/string_number_conversions.h" 26 #include "base/string_number_conversions.h"
29 #include "base/string_tokenizer.h" 27 #include "base/string_tokenizer.h"
30 #include "base/string_util.h" 28 #include "base/string_util.h"
31 #include "base/time.h" 29 #include "base/time.h"
32 #include "base/utf_string_conversions.h" 30 #include "base/utf_string_conversions.h"
33 #include "base/values.h" 31 #include "base/values.h"
34 #include "crypto/sha2.h" 32 #include "crypto/sha2.h"
35 #include "googleurl/src/gurl.h" 33 #include "googleurl/src/gurl.h"
36 #include "net/base/asn1_util.h"
37 #include "net/base/dns_util.h" 34 #include "net/base/dns_util.h"
38 #include "net/base/public_key_hashes.h" 35 #include "net/base/public_key_hashes.h"
39 #include "net/base/ssl_info.h" 36 #include "net/base/ssl_info.h"
40 #include "net/base/x509_certificate.h" 37 #include "net/base/x509_certificate.h"
41 #include "net/http/http_util.h" 38 #include "net/http/http_util.h"
42 39
43 #if defined(USE_OPENSSL) 40 #if defined(USE_OPENSSL)
44 #include "crypto/openssl_util.h" 41 #include "crypto/openssl_util.h"
45 #endif 42 #endif
46 43
47 namespace net { 44 namespace net {
48 45
49 const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year 46 const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year
50 47
48 /* XXX
Ryan Sleevi 2012/03/28 00:50:32 Delete?
palmer 2012/04/10 23:25:51 Done.
51 TransportSecurityState::TransportSecurityState(const std::string& hsts_hosts) 49 TransportSecurityState::TransportSecurityState(const std::string& hsts_hosts)
52 : delegate_(NULL) { 50 : delegate_(NULL) {
53 if (!hsts_hosts.empty()) { 51 if (!hsts_hosts.empty()) {
54 bool dirty; 52 bool dirty;
55 Deserialise(hsts_hosts, &dirty, &forced_hosts_); 53 Deserialise(hsts_hosts, &dirty, &forced_hosts_);
56 } 54 }
57 } 55 }*/
58 56
59 static std::string HashHost(const std::string& canonicalized_host) { 57 static std::string HashHost(const std::string& canonicalized_host) {
60 char hashed[crypto::kSHA256Length]; 58 char hashed[crypto::kSHA256Length];
61 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); 59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
62 return std::string(hashed, sizeof(hashed)); 60 return std::string(hashed, sizeof(hashed));
63 } 61 }
64 62
63 TransportSecurityState::TransportSecurityState(
64 TransportSecurityState::Delegate* delegate)
65 : delegate_(delegate) { }
66
67 TransportSecurityState::TransportSecurityState()
68 : delegate_(NULL) { }
69
65 void TransportSecurityState::SetDelegate( 70 void TransportSecurityState::SetDelegate(
66 TransportSecurityState::Delegate* delegate) { 71 TransportSecurityState::Delegate* delegate) {
67 delegate_ = delegate; 72 delegate_ = delegate;
68 } 73 }
69 74
70 void TransportSecurityState::EnableHost(const std::string& host, 75 void TransportSecurityState::EnableHost(const std::string& host,
71 const DomainState& state) { 76 const DomainState& state) {
72 DCHECK(CalledOnValidThread()); 77 DCHECK(CalledOnValidThread());
73 78
74 const std::string canonicalized_host = CanonicalizeHost(host); 79 const std::string canonicalized_host = CanonicalizeHost(host);
75 if (canonicalized_host.empty()) 80 if (canonicalized_host.empty())
76 return; 81 return;
77 82
83 DomainState existing_state;
84
78 // Only override a preloaded state if the new state describes a more strict 85 // Only override a preloaded state if the new state describes a more strict
79 // policy. TODO(palmer): Reconsider this? 86 // policy. TODO(palmer): Reconsider this?
80 DomainState existing_state; 87 /*if (GetStaticDomainState(canonicalized_host, true, &existing_state) &&
81 if (IsPreloadedSTS(canonicalized_host, true, &existing_state) &&
82 canonicalized_host == CanonicalizeHost(existing_state.domain) && 88 canonicalized_host == CanonicalizeHost(existing_state.domain) &&
83 existing_state.IsMoreStrict(state)) { 89 existing_state.IsMoreStrict(state)) {
84 return; 90 return;
85 } 91 }*/
Ryan Sleevi 2012/03/28 00:50:32 Delete?
palmer 2012/04/10 23:25:51 Done.
86 92
87 // Use the original creation date if we already have this host. 93 // Use the original creation date if we already have this host.
88 DomainState state_copy(state); 94 DomainState state_copy(state);
89 if (GetDomainState(&existing_state, host, true) && 95 if (GetDomainState(host, true, &existing_state) &&
Ryan Sleevi 2012/03/28 00:50:32 nit: GetDomainState(host, true /*sni_enabled*/, &e
palmer 2012/04/10 23:25:51 It doesn't really matter, since statically-defined
90 !existing_state.created.is_null()) { 96 !existing_state.created.is_null()) {
91 state_copy.created = existing_state.created; 97 state_copy.created = existing_state.created;
92 } 98 }
93 99
94 // We don't store these values. 100 // We don't store this value.
Ryan Sleevi 2012/03/28 00:50:32 nit: Drop the "we", expand on why this value isn't
palmer 2012/04/10 23:25:51 Done.
95 state_copy.preloaded = false;
96 state_copy.domain.clear(); 101 state_copy.domain.clear();
97 102
98 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; 103 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
99 DirtyNotify(); 104 DirtyNotify();
100 } 105 }
101 106
102 bool TransportSecurityState::DeleteHost(const std::string& host) { 107 bool TransportSecurityState::DeleteHost(const std::string& host) {
103 DCHECK(CalledOnValidThread()); 108 DCHECK(CalledOnValidThread());
104 109
105 const std::string canonicalized_host = CanonicalizeHost(host); 110 const std::string canonicalized_host = CanonicalizeHost(host);
106 if (canonicalized_host.empty()) 111 if (canonicalized_host.empty())
107 return false; 112 return false;
108 113
109 std::map<std::string, DomainState>::iterator i = enabled_hosts_.find( 114 std::map<std::string, DomainState>::iterator i = enabled_hosts_.find(
110 HashHost(canonicalized_host)); 115 HashHost(canonicalized_host));
111 if (i != enabled_hosts_.end()) { 116 if (i != enabled_hosts_.end()) {
112 enabled_hosts_.erase(i); 117 enabled_hosts_.erase(i);
113 DirtyNotify(); 118 DirtyNotify();
114 return true; 119 return true;
115 } 120 }
116 return false; 121 return false;
117 } 122 }
118 123
119 bool TransportSecurityState::HasPinsForHost(DomainState* result, 124 bool TransportSecurityState::GetDomainState(const std::string& host,
120 const std::string& host, 125 bool sni_enabled,
121 bool sni_available) { 126 DomainState* result) {
122 DCHECK(CalledOnValidThread());
123
124 return HasMetadata(result, host, sni_available) &&
125 (!result->dynamic_spki_hashes.empty() ||
126 !result->preloaded_spki_hashes.empty());
127 }
128
129 bool TransportSecurityState::GetDomainState(DomainState* result,
130 const std::string& host,
131 bool sni_available) {
132 DCHECK(CalledOnValidThread());
133
134 return HasMetadata(result, host, sni_available);
135 }
136
137 bool TransportSecurityState::HasMetadata(DomainState* result,
138 const std::string& host,
139 bool sni_available) {
140 DCHECK(CalledOnValidThread()); 127 DCHECK(CalledOnValidThread());
141 128
142 DomainState state; 129 DomainState state;
143 const std::string canonicalized_host = CanonicalizeHost(host); 130 const std::string canonicalized_host = CanonicalizeHost(host);
144 if (canonicalized_host.empty()) 131 if (canonicalized_host.empty())
145 return false; 132 return false;
146 133
147 bool has_preload = IsPreloadedSTS(canonicalized_host, sni_available, &state); 134 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled,
135 &state);
148 std::string canonicalized_preload = CanonicalizeHost(state.domain); 136 std::string canonicalized_preload = CanonicalizeHost(state.domain);
149 137
150 base::Time current_time(base::Time::Now()); 138 base::Time current_time(base::Time::Now());
151 139
152 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 140 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
153 std::string host_sub_chunk(&canonicalized_host[i], 141 std::string host_sub_chunk(&canonicalized_host[i],
154 canonicalized_host.size() - i); 142 canonicalized_host.size() - i);
155 // Exact match of a preload always wins. 143 // Exact match of a preload always wins.
156 if (has_preload && host_sub_chunk == canonicalized_preload) { 144 if (has_preload && host_sub_chunk == canonicalized_preload) {
157 *result = state; 145 *result = state;
158 return true; 146 return true;
159 } 147 }
160 148
161 std::map<std::string, DomainState>::iterator j = 149 std::map<std::string, DomainState>::iterator j =
162 enabled_hosts_.find(HashHost(host_sub_chunk)); 150 enabled_hosts_.find(HashHost(host_sub_chunk));
163 if (j == enabled_hosts_.end()) 151 if (j == enabled_hosts_.end())
164 continue; 152 continue;
165 153
166 if (current_time > j->second.expiry && 154 if (current_time > j->second.upgrade_expiry &&
167 current_time > j->second.dynamic_spki_hashes_expiry) { 155 current_time > j->second.dynamic_spki_hashes_expiry) {
168 enabled_hosts_.erase(j); 156 enabled_hosts_.erase(j);
169 DirtyNotify(); 157 DirtyNotify();
170 continue; 158 continue;
171 } 159 }
172 160
173 state = j->second; 161 state = j->second;
174 state.domain = DNSDomainToString(host_sub_chunk); 162 state.domain = DNSDomainToString(host_sub_chunk);
175 163
176 // Succeed if we matched the domain exactly or if subdomain matches are 164 // Succeed if we matched the domain exactly or if subdomain matches are
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 if (!base::Base64Decode(unquoted, &decoded) || 272 if (!base::Base64Decode(unquoted, &decoded) ||
285 decoded.size() != arraysize(fp.data)) { 273 decoded.size() != arraysize(fp.data)) {
286 return false; 274 return false;
287 } 275 }
288 276
289 memcpy(fp.data, decoded.data(), arraysize(fp.data)); 277 memcpy(fp.data, decoded.data(), arraysize(fp.data));
290 fingerprints->push_back(fp); 278 fingerprints->push_back(fp);
291 return true; 279 return true;
292 } 280 }
293 281
294 // static
295 bool TransportSecurityState::GetPublicKeyHash(
296 const X509Certificate& cert, SHA1Fingerprint* spki_hash) {
297 std::string der_bytes;
298 if (!X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der_bytes))
299 return false;
300
301 base::StringPiece spki;
302 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki))
303 return false;
304
305 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()),
306 spki.size(), spki_hash->data);
307
308 return true;
309 }
310
311 struct FingerprintsEqualPredicate { 282 struct FingerprintsEqualPredicate {
312 explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) : 283 explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) :
313 fingerprint_(fingerprint) {} 284 fingerprint_(fingerprint) {}
314 285
315 bool operator()(const SHA1Fingerprint& other) const { 286 bool operator()(const SHA1Fingerprint& other) const {
316 return fingerprint_.Equals(other); 287 return fingerprint_.Equals(other);
317 } 288 }
318 289
319 const SHA1Fingerprint& fingerprint_; 290 const SHA1Fingerprint& fingerprint_;
320 }; 291 };
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 const FingerprintVector& from_cert_chain = ssl_info.public_key_hashes; 332 const FingerprintVector& from_cert_chain = ssl_info.public_key_hashes;
362 if (from_cert_chain.empty()) 333 if (from_cert_chain.empty())
363 return false; 334 return false;
364 335
365 return IsBackupPinPresent(pins, from_cert_chain) && 336 return IsBackupPinPresent(pins, from_cert_chain) &&
366 HashesIntersect(pins, from_cert_chain); 337 HashesIntersect(pins, from_cert_chain);
367 } 338 }
368 339
369 // "Public-Key-Pins" ":" 340 // "Public-Key-Pins" ":"
370 // "max-age" "=" delta-seconds ";" 341 // "max-age" "=" delta-seconds ";"
371 // "pin-" algo "=" base64 [ ";" ... ] 342 // "pin-" algo "=" base64 [ ";" ... ]
Ryan Sleevi 2012/03/28 00:50:32 Update the ABNF for -01.
palmer 2012/04/10 23:25:51 Done.
372 // 343 bool TransportSecurityState::DomainState::ParsePinsHeader(
373 // static 344 const base::Time& now,
374 bool TransportSecurityState::ParsePinsHeader(const std::string& value, 345 const std::string& value,
375 const SSLInfo& ssl_info, 346 const SSLInfo& ssl_info) {
376 DomainState* state) {
377 bool parsed_max_age = false; 347 bool parsed_max_age = false;
378 int max_age = 0; 348 int max_age_candidate = 0;
379 FingerprintVector pins; 349 FingerprintVector pins;
380 350
381 std::string source = value; 351 std::string source = value;
382 352
383 while (!source.empty()) { 353 while (!source.empty()) {
384 StringPair semicolon = Split(source, ';'); 354 StringPair semicolon = Split(source, ';');
385 semicolon.first = Strip(semicolon.first); 355 semicolon.first = Strip(semicolon.first);
386 semicolon.second = Strip(semicolon.second); 356 semicolon.second = Strip(semicolon.second);
387 StringPair equals = Split(semicolon.first, '='); 357 StringPair equals = Split(semicolon.first, '=');
388 equals.first = Strip(equals.first); 358 equals.first = Strip(equals.first);
389 equals.second = Strip(equals.second); 359 equals.second = Strip(equals.second);
390 360
391 if (LowerCaseEqualsASCII(equals.first, "max-age")) { 361 if (LowerCaseEqualsASCII(equals.first, "max-age")) {
392 if (equals.second.empty() || 362 if (equals.second.empty() ||
393 !MaxAgeToInt(equals.second.begin(), equals.second.end(), &max_age)) { 363 !MaxAgeToInt(equals.second.begin(), equals.second.end(),
364 &max_age_candidate)) {
394 return false; 365 return false;
395 } 366 }
396 if (max_age > kMaxHSTSAgeSecs) 367 if (max_age_candidate > kMaxHSTSAgeSecs)
397 max_age = kMaxHSTSAgeSecs; 368 max_age_candidate = kMaxHSTSAgeSecs;
398 parsed_max_age = true; 369 parsed_max_age = true;
399 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) { 370 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
400 if (!ParseAndAppendPin(equals.second, &pins)) 371 if (!ParseAndAppendPin(equals.second, &pins))
401 return false; 372 return false;
402 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) { 373 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
403 // TODO(palmer) 374 // TODO(palmer)
404 } else { 375 } else {
405 // Silently ignore unknown directives for forward compatibility. 376 // Silently ignore unknown directives for forward compatibility.
406 } 377 }
407 378
408 source = semicolon.second; 379 source = semicolon.second;
409 } 380 }
410 381
411 if (!parsed_max_age || !IsPinListValid(pins, ssl_info)) 382 if (!parsed_max_age || !IsPinListValid(pins, ssl_info))
412 return false; 383 return false;
413 384
414 state->max_age = max_age; 385 dynamic_spki_hashes_expiry =
415 state->dynamic_spki_hashes_expiry = 386 now + base::TimeDelta::FromSeconds(max_age_candidate);
416 base::Time::Now() + base::TimeDelta::FromSeconds(max_age);
417 387
418 state->dynamic_spki_hashes.clear(); 388 dynamic_spki_hashes.clear();
419 if (max_age > 0) { 389 if (max_age_candidate > 0) {
420 for (FingerprintVector::const_iterator i = pins.begin(); 390 for (FingerprintVector::const_iterator i = pins.begin();
421 i != pins.end(); i++) { 391 i != pins.end(); ++i) {
422 state->dynamic_spki_hashes.push_back(*i); 392 dynamic_spki_hashes.push_back(*i);
423 } 393 }
424 } 394 }
425 395
426 return true; 396 return true;
427 } 397 }
428 398
429 // "Strict-Transport-Security" ":" 399 // "Strict-Transport-Security" ":"
430 // "max-age" "=" delta-seconds [ ";" "includeSubDomains" ] 400 // "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
Ryan Sleevi 2012/03/28 00:50:32 Definitely update this guy
palmer 2012/04/10 23:25:51 What is wrong about this comment, other than being
431 // 401 bool TransportSecurityState::DomainState::ParseSTSHeader(
432 // static 402 const base::Time& now,
433 bool TransportSecurityState::ParseHeader(const std::string& value, 403 const std::string& value) {
434 int* max_age,
435 bool* include_subdomains) {
436 DCHECK(max_age);
437 DCHECK(include_subdomains);
438
439 int max_age_candidate = 0; 404 int max_age_candidate = 0;
440 405
441 enum ParserState { 406 enum ParserState {
442 START, 407 START,
443 AFTER_MAX_AGE_LABEL, 408 AFTER_MAX_AGE_LABEL,
444 AFTER_MAX_AGE_EQUALS, 409 AFTER_MAX_AGE_EQUALS,
445 AFTER_MAX_AGE, 410 AFTER_MAX_AGE,
446 AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER, 411 AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER,
447 AFTER_INCLUDE_SUBDOMAINS, 412 AFTER_INCLUDE_SUBDOMAINS,
448 } state = START; 413 } state = START;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 } 470 }
506 } 471 }
507 472
508 // We've consumed all the input. Let's see what state we ended up in. 473 // We've consumed all the input. Let's see what state we ended up in.
509 switch (state) { 474 switch (state) {
510 case START: 475 case START:
511 case AFTER_MAX_AGE_LABEL: 476 case AFTER_MAX_AGE_LABEL:
512 case AFTER_MAX_AGE_EQUALS: 477 case AFTER_MAX_AGE_EQUALS:
513 return false; 478 return false;
514 case AFTER_MAX_AGE: 479 case AFTER_MAX_AGE:
515 *max_age = max_age_candidate; 480 upgrade_expiry =
516 *include_subdomains = false; 481 now + base::TimeDelta::FromSeconds(max_age_candidate);
482 include_subdomains = false;
483 upgrade_mode = MODE_FORCE_HTTPS;
517 return true; 484 return true;
518 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER: 485 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
519 return false; 486 return false;
520 case AFTER_INCLUDE_SUBDOMAINS: 487 case AFTER_INCLUDE_SUBDOMAINS:
521 *max_age = max_age_candidate; 488 upgrade_expiry =
522 *include_subdomains = true; 489 now + base::TimeDelta::FromSeconds(max_age_candidate);
490 include_subdomains = true;
491 upgrade_mode = MODE_FORCE_HTTPS;
523 return true; 492 return true;
524 default: 493 default:
525 NOTREACHED(); 494 NOTREACHED();
526 return false; 495 return false;
527 } 496 }
528 } 497 }
529 498
530 // Side pinning and superfluous certificates:
531 //
532 // In SSLClientSocketNSS::DoVerifyCertComplete we look for certificates with a
533 // Subject of CN=meta. When we find one we'll currently try and parse side
534 // pinned key from it.
535 //
536 // A side pin is a key which can be pinned to, but also can be kept offline and
537 // still held by the site owner. The CN=meta certificate is just a backwards
538 // compatiable method of carrying a lump of bytes to the client. (We could use
539 // a TLS extension just as well, but it's a lot easier for admins to add extra
540 // certificates to the chain.)
541
542 // A TagMap represents the simple key-value structure that we use. Keys are
543 // 32-bit ints. Values are byte strings.
544 typedef std::map<uint32, base::StringPiece> TagMap;
545
546 // ParseTags parses a list of key-value pairs from |in| to |out| and advances
547 // |in| past the data. The key-value pair data is:
548 // u16le num_tags
549 // u32le tag[num_tags]
550 // u16le lengths[num_tags]
551 // ...data...
552 static bool ParseTags(base::StringPiece* in, TagMap *out) {
553 // Many part of Chrome already assume little-endian. This is just to help
554 // anyone who should try to port it in the future.
555 #if defined(__BYTE_ORDER)
556 // Linux check
557 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
558 #elif defined(__BIG_ENDIAN__)
559 // Mac check
560 #error assumes little endian
561 #endif
562
563 uint16 num_tags_16;
564 if (in->size() < sizeof(num_tags_16))
565 return false;
566
567 memcpy(&num_tags_16, in->data(), sizeof(num_tags_16));
568 in->remove_prefix(sizeof(num_tags_16));
569 unsigned num_tags = num_tags_16;
570
571 if (in->size() < 6 * num_tags)
572 return false;
573
574 const uint32* tags = reinterpret_cast<const uint32*>(in->data());
575 const uint16* lens = reinterpret_cast<const uint16*>(
576 in->data() + 4*num_tags);
577 in->remove_prefix(6*num_tags);
578
579 uint32 prev_tag = 0;
580 for (unsigned i = 0; i < num_tags; i++) {
581 size_t len = lens[i];
582 uint32 tag = tags[i];
583
584 if (in->size() < len)
585 return false;
586 // tags must be in ascending order.
587 if (i > 0 && prev_tag >= tag)
588 return false;
589 (*out)[tag] = base::StringPiece(in->data(), len);
590 in->remove_prefix(len);
591 prev_tag = tag;
592 }
593
594 return true;
595 }
596
597 // GetTag extracts the data associated with |tag| in |tags|.
598 static bool GetTag(uint32 tag, const TagMap& tags, base::StringPiece* out) {
599 TagMap::const_iterator i = tags.find(tag);
600 if (i == tags.end())
601 return false;
602
603 *out = i->second;
604 return true;
605 }
606
607 // kP256SubjectPublicKeyInfoPrefix can be prepended onto a P256 elliptic curve
608 // point in X9.62 format in order to make a valid SubjectPublicKeyInfo. The
609 // ASN.1 interpretation of these bytes is:
610 //
611 // 0:d=0 hl=2 l= 89 cons: SEQUENCE
612 // 2:d=1 hl=2 l= 19 cons: SEQUENCE
613 // 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
614 // 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
615 // 23:d=1 hl=2 l= 66 prim: BIT STRING
616 static const uint8 kP256SubjectPublicKeyInfoPrefix[] = {
617 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
618 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
619 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
620 0x42, 0x00,
621 };
622
623 // VerifySignature returns true iff |sig| is a valid signature of
624 // |hash| by |pubkey|. The actual implementation is crypto library
625 // specific.
626 static bool VerifySignature(const base::StringPiece& pubkey,
627 const base::StringPiece& sig,
628 const base::StringPiece& hash);
629
630 #if defined(USE_OPENSSL)
631
632 static EVP_PKEY* DecodeX962P256PublicKey(
633 const base::StringPiece& pubkey_bytes) {
634 // The public key is an X9.62 encoded P256 point.
635 if (pubkey_bytes.size() != 1 + 2*32)
636 return NULL;
637
638 std::string pubkey_spki(
639 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
640 sizeof(kP256SubjectPublicKeyInfoPrefix));
641 pubkey_spki += pubkey_bytes.as_string();
642
643 EVP_PKEY* ret = NULL;
644 const unsigned char* der_pubkey =
645 reinterpret_cast<const unsigned char*>(pubkey_spki.data());
646 d2i_PUBKEY(&ret, &der_pubkey, pubkey_spki.size());
647 return ret;
648 }
649
650 static bool VerifySignature(const base::StringPiece& pubkey,
651 const base::StringPiece& sig,
652 const base::StringPiece& hash) {
653 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> secpubkey(
654 DecodeX962P256PublicKey(pubkey));
655 if (!secpubkey.get())
656 return false;
657
658
659 crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(
660 EVP_PKEY_get1_EC_KEY(secpubkey.get()));
661 if (!ec_key.get())
662 return false;
663
664 return ECDSA_verify(0, reinterpret_cast<const unsigned char*>(hash.data()),
665 hash.size(),
666 reinterpret_cast<const unsigned char*>(sig.data()),
667 sig.size(), ec_key.get()) == 1;
668 }
669
670 #else
671
672 // DecodeX962P256PublicKey parses an uncompressed, X9.62 format, P256 elliptic
673 // curve point from |pubkey_bytes| and returns it as a SECKEYPublicKey.
674 static SECKEYPublicKey* DecodeX962P256PublicKey(
675 const base::StringPiece& pubkey_bytes) {
676 // The public key is an X9.62 encoded P256 point.
677 if (pubkey_bytes.size() != 1 + 2*32)
678 return NULL;
679
680 std::string pubkey_spki(
681 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
682 sizeof(kP256SubjectPublicKeyInfoPrefix));
683 pubkey_spki += pubkey_bytes.as_string();
684
685 SECItem der;
686 memset(&der, 0, sizeof(der));
687 der.data = reinterpret_cast<uint8*>(const_cast<char*>(pubkey_spki.data()));
688 der.len = pubkey_spki.size();
689
690 CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
691 if (!spki)
692 return NULL;
693 SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
694 SECKEY_DestroySubjectPublicKeyInfo(spki);
695
696 return public_key;
697 }
698
699 static bool VerifySignature(const base::StringPiece& pubkey,
700 const base::StringPiece& sig,
701 const base::StringPiece& hash) {
702 SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey);
703 if (!secpubkey)
704 return false;
705
706 SECItem sigitem;
707 memset(&sigitem, 0, sizeof(sigitem));
708 sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data()));
709 sigitem.len = sig.size();
710
711 // |decoded_sigitem| is newly allocated, as is the data that it points to.
712 SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen(
713 &sigitem, SECKEY_SignatureLen(secpubkey));
714
715 if (!decoded_sigitem) {
716 SECKEY_DestroyPublicKey(secpubkey);
717 return false;
718 }
719
720 SECItem hashitem;
721 memset(&hashitem, 0, sizeof(hashitem));
722 hashitem.data = reinterpret_cast<unsigned char*>(
723 const_cast<char*>(hash.data()));
724 hashitem.len = hash.size();
725
726 SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL);
727 SECKEY_DestroyPublicKey(secpubkey);
728 SECITEM_FreeItem(decoded_sigitem, PR_TRUE);
729 return rv == SECSuccess;
730 }
731
732 #endif // !defined(USE_OPENSSL)
733
734 // These are the tag values that we use. Tags are little-endian on the wire and
735 // these values correspond to the ASCII of the name.
736 static const uint32 kTagALGO = 0x4f474c41;
737 static const uint32 kTagP256 = 0x36353250;
738 static const uint32 kTagPUBK = 0x4b425550;
739 static const uint32 kTagSIG = 0x474953;
740 static const uint32 kTagSPIN = 0x4e495053;
741
742 // static
743 bool TransportSecurityState::ParseSidePin(
744 const base::StringPiece& leaf_spki,
745 const base::StringPiece& in_side_info,
746 FingerprintVector* out_pub_key_hash) {
747 base::StringPiece side_info(in_side_info);
748
749 TagMap outer;
750 if (!ParseTags(&side_info, &outer))
751 return false;
752 // trailing data is not allowed
753 if (side_info.size())
754 return false;
755
756 base::StringPiece side_pin_bytes;
757 if (!GetTag(kTagSPIN, outer, &side_pin_bytes))
758 return false;
759
760 bool have_parsed_a_key = false;
761 uint8 leaf_spki_hash[crypto::kSHA256Length];
762 bool have_leaf_spki_hash = false;
763
764 while (side_pin_bytes.size() > 0) {
765 TagMap side_pin;
766 if (!ParseTags(&side_pin_bytes, &side_pin))
767 return false;
768
769 base::StringPiece algo, pubkey, sig;
770 if (!GetTag(kTagALGO, side_pin, &algo) ||
771 !GetTag(kTagPUBK, side_pin, &pubkey) ||
772 !GetTag(kTagSIG, side_pin, &sig)) {
773 return false;
774 }
775
776 if (algo.size() != sizeof(kTagP256) ||
777 0 != memcmp(algo.data(), &kTagP256, sizeof(kTagP256))) {
778 // We don't support anything but P256 at the moment.
779 continue;
780 }
781
782 if (!have_leaf_spki_hash) {
783 crypto::SHA256HashString(
784 leaf_spki.as_string(), leaf_spki_hash, sizeof(leaf_spki_hash));
785 have_leaf_spki_hash = true;
786 }
787
788 if (VerifySignature(pubkey, sig, base::StringPiece(
789 reinterpret_cast<const char*>(leaf_spki_hash),
790 sizeof(leaf_spki_hash)))) {
791 SHA1Fingerprint fpr;
792 base::SHA1HashBytes(
793 reinterpret_cast<const uint8*>(pubkey.data()),
794 pubkey.size(),
795 fpr.data);
796 out_pub_key_hash->push_back(fpr);
797 have_parsed_a_key = true;
798 }
799 }
800
801 return have_parsed_a_key;
802 }
803
804 // This function converts the binary hashes, which we store in
805 // |enabled_hosts_|, to a base64 string which we can include in a JSON file.
806 static std::string HashedDomainToExternalString(const std::string& hashed) {
807 std::string out;
808 CHECK(base::Base64Encode(hashed, &out));
809 return out;
810 }
811
812 // This inverts |HashedDomainToExternalString|, above. It turns an external
813 // string (from a JSON file) into an internal (binary) string.
814 static std::string ExternalStringToHashedDomain(const std::string& external) {
815 std::string out;
816 if (!base::Base64Decode(external, &out) ||
817 out.size() != crypto::kSHA256Length) {
818 return std::string();
819 }
820
821 return out;
822 }
823
824 static ListValue* SPKIHashesToListValue(const FingerprintVector& hashes) {
825 ListValue* pins = new ListValue;
826
827 for (FingerprintVector::const_iterator i = hashes.begin();
828 i != hashes.end(); ++i) {
829 std::string hash_str(reinterpret_cast<const char*>(i->data),
830 sizeof(i->data));
831 std::string b64;
832 base::Base64Encode(hash_str, &b64);
833 pins->Append(new StringValue("sha1/" + b64));
834 }
835
836 return pins;
837 }
838
839 bool TransportSecurityState::Serialise(std::string* output) {
840 DCHECK(CalledOnValidThread());
841
842 DictionaryValue toplevel;
843 base::Time now = base::Time::Now();
844 for (std::map<std::string, DomainState>::const_iterator
845 i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
846 DictionaryValue* state = new DictionaryValue;
847 state->SetBoolean("include_subdomains", i->second.include_subdomains);
848 state->SetDouble("created", i->second.created.ToDoubleT());
849 state->SetDouble("expiry", i->second.expiry.ToDoubleT());
850 state->SetDouble("dynamic_spki_hashes_expiry",
851 i->second.dynamic_spki_hashes_expiry.ToDoubleT());
852
853 switch (i->second.mode) {
854 case DomainState::MODE_STRICT:
855 state->SetString("mode", "strict");
856 break;
857 case DomainState::MODE_SPDY_ONLY:
858 state->SetString("mode", "spdy-only");
859 break;
860 case DomainState::MODE_PINNING_ONLY:
861 state->SetString("mode", "pinning-only");
862 break;
863 default:
864 NOTREACHED() << "DomainState with unknown mode";
865 delete state;
866 continue;
867 }
868
869 state->Set("preloaded_spki_hashes",
870 SPKIHashesToListValue(i->second.preloaded_spki_hashes));
871
872 if (now < i->second.dynamic_spki_hashes_expiry) {
873 state->Set("dynamic_spki_hashes",
874 SPKIHashesToListValue(i->second.dynamic_spki_hashes));
875 }
876
877 toplevel.Set(HashedDomainToExternalString(i->first), state);
878 }
879
880 base::JSONWriter::WriteWithOptions(&toplevel,
881 base::JSONWriter::OPTIONS_PRETTY_PRINT,
882 output);
883 return true;
884 }
885
886 bool TransportSecurityState::LoadEntries(const std::string& input,
887 bool* dirty) {
888 DCHECK(CalledOnValidThread());
889
890 enabled_hosts_.clear();
891 return Deserialise(input, dirty, &enabled_hosts_);
892 }
893
894 static bool AddHash(const std::string& type_and_base64, 499 static bool AddHash(const std::string& type_and_base64,
895 FingerprintVector* out) { 500 FingerprintVector* out) {
896 SHA1Fingerprint hash; 501 SHA1Fingerprint hash;
897 502
898 if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) 503 if (!TransportSecurityState::ParsePin(type_and_base64, &hash))
899 return false; 504 return false;
900 505
901 out->push_back(hash); 506 out->push_back(hash);
902 return true; 507 return true;
903 } 508 }
904 509
905 static void SPKIHashesFromListValue(FingerprintVector* hashes,
906 const ListValue& pins) {
907 size_t num_pins = pins.GetSize();
908 for (size_t i = 0; i < num_pins; ++i) {
909 std::string type_and_base64;
910 if (pins.GetString(i, &type_and_base64))
911 AddHash(type_and_base64, hashes);
912 }
913 }
914
915 // static
916 bool TransportSecurityState::Deserialise(
917 const std::string& input,
918 bool* dirty,
919 std::map<std::string, DomainState>* out) {
920 scoped_ptr<Value> value(
921 base::JSONReader::Read(input, false /* do not allow trailing commas */));
922 if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY))
923 return false;
924
925 DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get());
926 const base::Time current_time(base::Time::Now());
927 bool dirtied = false;
928
929 for (DictionaryValue::key_iterator i = dict_value->begin_keys();
930 i != dict_value->end_keys(); ++i) {
931 DictionaryValue* state;
932 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state))
933 continue;
934
935 bool include_subdomains;
936 std::string mode_string;
937 double created;
938 double expiry;
939 double dynamic_spki_hashes_expiry = 0.0;
940
941 if (!state->GetBoolean("include_subdomains", &include_subdomains) ||
942 !state->GetString("mode", &mode_string) ||
943 !state->GetDouble("expiry", &expiry)) {
944 continue;
945 }
946
947 // Don't fail if this key is not present.
948 (void) state->GetDouble("dynamic_spki_hashes_expiry",
949 &dynamic_spki_hashes_expiry);
950
951 ListValue* pins_list = NULL;
952 FingerprintVector preloaded_spki_hashes;
953 if (state->GetList("preloaded_spki_hashes", &pins_list))
954 SPKIHashesFromListValue(&preloaded_spki_hashes, *pins_list);
955
956 FingerprintVector dynamic_spki_hashes;
957 if (state->GetList("dynamic_spki_hashes", &pins_list))
958 SPKIHashesFromListValue(&dynamic_spki_hashes, *pins_list);
959
960 DomainState::Mode mode;
961 if (mode_string == "strict") {
962 mode = DomainState::MODE_STRICT;
963 } else if (mode_string == "spdy-only") {
964 mode = DomainState::MODE_SPDY_ONLY;
965 } else if (mode_string == "pinning-only") {
966 mode = DomainState::MODE_PINNING_ONLY;
967 } else {
968 LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
969 << mode_string;
970 continue;
971 }
972
973 base::Time expiry_time = base::Time::FromDoubleT(expiry);
974 base::Time dynamic_spki_hashes_expiry_time =
975 base::Time::FromDoubleT(dynamic_spki_hashes_expiry);
976 base::Time created_time;
977 if (state->GetDouble("created", &created)) {
978 created_time = base::Time::FromDoubleT(created);
979 } else {
980 // We're migrating an old entry with no creation date. Make sure we
981 // write the new date back in a reasonable time frame.
982 dirtied = true;
983 created_time = base::Time::Now();
984 }
985
986 if (expiry_time <= current_time &&
987 dynamic_spki_hashes_expiry_time <= current_time) {
988 // Make sure we dirty the state if we drop an entry.
989 dirtied = true;
990 continue;
991 }
992
993 std::string hashed = ExternalStringToHashedDomain(*i);
994 if (hashed.empty()) {
995 dirtied = true;
996 continue;
997 }
998
999 DomainState new_state;
1000 new_state.mode = mode;
1001 new_state.created = created_time;
1002 new_state.expiry = expiry_time;
1003 new_state.include_subdomains = include_subdomains;
1004 new_state.preloaded_spki_hashes = preloaded_spki_hashes;
1005 new_state.dynamic_spki_hashes = dynamic_spki_hashes;
1006 new_state.dynamic_spki_hashes_expiry = dynamic_spki_hashes_expiry_time;
1007 (*out)[hashed] = new_state;
1008 }
1009
1010 *dirty = dirtied;
1011 return true;
1012 }
1013
1014 TransportSecurityState::~TransportSecurityState() { 510 TransportSecurityState::~TransportSecurityState() {
1015 } 511 }
1016 512
1017 void TransportSecurityState::DirtyNotify() { 513 void TransportSecurityState::DirtyNotify() {
1018 DCHECK(CalledOnValidThread()); 514 DCHECK(CalledOnValidThread());
1019 515
1020 if (delegate_) 516 if (delegate_)
1021 delegate_->StateIsDirty(this); 517 delegate_->StateIsDirty(this);
1022 } 518 }
1023 519
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 for (size_t j = 0; j < num_entries; j++) { 613 for (size_t j = 0; j < num_entries; j++) {
1118 if (entries[j].length == canonicalized_host.size() - i && 614 if (entries[j].length == canonicalized_host.size() - i &&
1119 memcmp(entries[j].dns_name, &canonicalized_host[i], 615 memcmp(entries[j].dns_name, &canonicalized_host[i],
1120 entries[j].length) == 0) { 616 entries[j].length) == 0) {
1121 if (!entries[j].include_subdomains && i != 0) { 617 if (!entries[j].include_subdomains && i != 0) {
1122 *ret = false; 618 *ret = false;
1123 } else { 619 } else {
1124 out->include_subdomains = entries[j].include_subdomains; 620 out->include_subdomains = entries[j].include_subdomains;
1125 *ret = true; 621 *ret = true;
1126 if (!entries[j].https_required) 622 if (!entries[j].https_required)
1127 out->mode = TransportSecurityState::DomainState::MODE_PINNING_ONLY; 623 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT;
1128 if (entries[j].pins.required_hashes) { 624 if (entries[j].pins.required_hashes) {
1129 const char* const* hash = entries[j].pins.required_hashes; 625 const char* const* hash = entries[j].pins.required_hashes;
1130 while (*hash) { 626 while (*hash) {
1131 bool ok = AddHash(*hash, &out->preloaded_spki_hashes); 627 bool ok = AddHash(*hash, &out->static_spki_hashes);
1132 DCHECK(ok) << " failed to parse " << *hash; 628 DCHECK(ok) << " failed to parse " << *hash;
1133 hash++; 629 hash++;
1134 } 630 }
1135 } 631 }
1136 if (entries[j].pins.excluded_hashes) { 632 if (entries[j].pins.excluded_hashes) {
1137 const char* const* hash = entries[j].pins.excluded_hashes; 633 const char* const* hash = entries[j].pins.excluded_hashes;
1138 while (*hash) { 634 while (*hash) {
1139 bool ok = AddHash(*hash, &out->bad_preloaded_spki_hashes); 635 bool ok = AddHash(*hash, &out->bad_static_spki_hashes);
1140 DCHECK(ok) << " failed to parse " << *hash; 636 DCHECK(ok) << " failed to parse " << *hash;
1141 hash++; 637 hash++;
1142 } 638 }
1143 } 639 }
1144 } 640 }
1145 return true; 641 return true;
1146 } 642 }
1147 } 643 }
1148 return false; 644 return false;
1149 } 645 }
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
1253 kSPKIHash_UTNUSERFirstHardware, 749 kSPKIHash_UTNUSERFirstHardware,
1254 kSPKIHash_UTNUSERFirstObject, 750 kSPKIHash_UTNUSERFirstObject,
1255 kSPKIHash_GTECyberTrustGlobalRoot, 751 kSPKIHash_GTECyberTrustGlobalRoot,
1256 NULL, 752 NULL,
1257 }; 753 };
1258 #define kTwitterCDNPins { \ 754 #define kTwitterCDNPins { \
1259 kTwitterCDNAcceptableCerts, \ 755 kTwitterCDNAcceptableCerts, \
1260 kNoRejectedPublicKeys, \ 756 kNoRejectedPublicKeys, \
1261 } 757 }
1262 758
759 // These are the tag values that we use. Tags are little-endian on the wire and
760 // these values correspond to the ASCII of the name.
761 static const uint32 kTagALGO = 0x4f474c41;
762 static const uint32 kTagP256 = 0x36353250;
763 static const uint32 kTagPUBK = 0x4b425550;
764 static const uint32 kTagSIG = 0x474953;
765 static const uint32 kTagSPIN = 0x4e495053;
Ryan Sleevi 2012/03/28 00:50:32 This was related to side pinning - delete?
palmer 2012/04/10 23:25:51 Done.
766
1263 // kTestAcceptableCerts doesn't actually match any public keys and is used 767 // kTestAcceptableCerts doesn't actually match any public keys and is used
1264 // with "pinningtest.appspot.com", below, to test if pinning is active. 768 // with "pinningtest.appspot.com", below, to test if pinning is active.
1265 static const char* const kTestAcceptableCerts[] = { 769 static const char* const kTestAcceptableCerts[] = {
1266 "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=", 770 "sha1/AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
1267 NULL, 771 NULL,
1268 }; 772 };
1269 #define kTestPins { \ 773 #define kTestPins { \
1270 kTestAcceptableCerts, \ 774 kTestAcceptableCerts, \
1271 kNoRejectedPublicKeys, \ 775 kNoRejectedPublicKeys, \
1272 } 776 }
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
1514 return entry; 1018 return entry;
1515 } 1019 }
1516 } 1020 }
1517 } 1021 }
1518 1022
1519 return NULL; 1023 return NULL;
1520 } 1024 }
1521 1025
1522 // static 1026 // static
1523 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, 1027 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host,
1524 bool sni_available) { 1028 bool sni_enabled) {
1525 std::string canonicalized_host = CanonicalizeHost(host); 1029 std::string canonicalized_host = CanonicalizeHost(host);
1526 const struct HSTSPreload* entry = 1030 const struct HSTSPreload* entry =
1527 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 1031 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
1528 1032
1529 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 1033 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
1530 return true; 1034 return true;
1531 1035
1532 if (sni_available) { 1036 if (sni_enabled) {
1533 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 1037 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
1534 kNumPreloadedSNISTS); 1038 kNumPreloadedSNISTS);
1535 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 1039 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
1536 return true; 1040 return true;
1537 } 1041 }
1538 1042
1539 return false; 1043 return false;
1540 } 1044 }
1541 1045
1542 // static 1046 // static
1543 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { 1047 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
1544 std::string canonicalized_host = CanonicalizeHost(host); 1048 std::string canonicalized_host = CanonicalizeHost(host);
1545 1049
1546 const struct HSTSPreload* entry = 1050 const struct HSTSPreload* entry =
1547 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 1051 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
1548 1052
1549 if (!entry) { 1053 if (!entry) {
1550 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 1054 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
1551 kNumPreloadedSNISTS); 1055 kNumPreloadedSNISTS);
1552 } 1056 }
1553 1057
1554 DCHECK(entry); 1058 DCHECK(entry);
1555 DCHECK(entry->pins.required_hashes); 1059 DCHECK(entry->pins.required_hashes);
1556 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); 1060 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
1557 1061
1558 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", 1062 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
1559 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); 1063 entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
1560 } 1064 }
1561 1065
1562 // IsPreloadedSTS returns true if the canonicalized hostname should always be 1066 bool TransportSecurityState::GetStaticDomainState(
1563 // considered to have STS enabled.
1564 bool TransportSecurityState::IsPreloadedSTS(
1565 const std::string& canonicalized_host, 1067 const std::string& canonicalized_host,
1566 bool sni_available, 1068 bool sni_enabled,
1567 DomainState* out) { 1069 DomainState* out) {
1568 DCHECK(CalledOnValidThread()); 1070 DCHECK(CalledOnValidThread());
1569 1071
1570 out->preloaded = true; 1072 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS;
1571 out->mode = DomainState::MODE_STRICT;
1572 out->include_subdomains = false; 1073 out->include_subdomains = false;
1573 1074
1574 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 1075 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
1575 std::string host_sub_chunk(&canonicalized_host[i], 1076 std::string host_sub_chunk(&canonicalized_host[i],
1576 canonicalized_host.size() - i); 1077 canonicalized_host.size() - i);
1577 out->domain = DNSDomainToString(host_sub_chunk); 1078 out->domain = DNSDomainToString(host_sub_chunk);
1578 std::string hashed_host(HashHost(host_sub_chunk)); 1079 std::string hashed_host(HashHost(host_sub_chunk));
1579 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) { 1080 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) {
1580 *out = forced_hosts_[hashed_host]; 1081 *out = forced_hosts_[hashed_host];
1581 out->domain = DNSDomainToString(host_sub_chunk); 1082 out->domain = DNSDomainToString(host_sub_chunk);
1582 out->preloaded = true;
1583 return true; 1083 return true;
1584 } 1084 }
1585 bool ret; 1085 bool ret;
1586 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, 1086 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
1587 &ret)) { 1087 &ret)) {
1588 return ret; 1088 return ret;
1589 } 1089 }
1590 if (sni_available && 1090 if (sni_enabled &&
1591 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, 1091 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
1592 out, &ret)) { 1092 out, &ret)) {
1593 return ret; 1093 return ret;
1594 } 1094 }
1595 } 1095 }
1596 1096
1597 return false; 1097 return false;
1598 } 1098 }
1599 1099
1600 static std::string HashesToBase64String( 1100 static std::string HashesToBase64String(
1601 const FingerprintVector& hashes) { 1101 const FingerprintVector& hashes) {
1602 std::vector<std::string> hashes_strs; 1102 std::vector<std::string> hashes_strs;
1603 for (FingerprintVector::const_iterator 1103 for (FingerprintVector::const_iterator
1604 i = hashes.begin(); i != hashes.end(); i++) { 1104 i = hashes.begin(); i != hashes.end(); i++) {
1605 std::string s; 1105 std::string s;
1606 const std::string hash_str(reinterpret_cast<const char*>(i->data), 1106 const std::string hash_str(reinterpret_cast<const char*>(i->data),
1607 sizeof(i->data)); 1107 sizeof(i->data));
1608 base::Base64Encode(hash_str, &s); 1108 base::Base64Encode(hash_str, &s);
1609 hashes_strs.push_back(s); 1109 hashes_strs.push_back(s);
1610 } 1110 }
1611 1111
1612 return JoinString(hashes_strs, ','); 1112 return JoinString(hashes_strs, ',');
1613 } 1113 }
1614 1114
1615 TransportSecurityState::DomainState::DomainState() 1115 TransportSecurityState::DomainState::DomainState()
1616 : mode(MODE_STRICT), 1116 : upgrade_mode(MODE_FORCE_HTTPS),
1617 created(base::Time::Now()), 1117 created(base::Time::Now()),
1618 include_subdomains(false), 1118 include_subdomains(false) {
1619 preloaded(false) {
1620 } 1119 }
1621 1120
1622 TransportSecurityState::DomainState::~DomainState() { 1121 TransportSecurityState::DomainState::~DomainState() {
1623 } 1122 }
1624 1123
1625 bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted( 1124 bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted(
1626 const FingerprintVector& hashes) { 1125 const FingerprintVector& hashes) const {
1627 1126 if (HashesIntersect(bad_static_spki_hashes, hashes)) {
1628 if (HashesIntersect(bad_preloaded_spki_hashes, hashes)) {
1629 LOG(ERROR) << "Rejecting public key chain for domain " << domain 1127 LOG(ERROR) << "Rejecting public key chain for domain " << domain
1630 << ". Validated chain: " << HashesToBase64String(hashes) 1128 << ". Validated chain: " << HashesToBase64String(hashes)
1631 << ", matches one or more bad hashes: " 1129 << ", matches one or more bad hashes: "
1632 << HashesToBase64String(bad_preloaded_spki_hashes); 1130 << HashesToBase64String(bad_static_spki_hashes);
1633 return false; 1131 return false;
1634 } 1132 }
1635 1133
1636 if (!(dynamic_spki_hashes.empty() && preloaded_spki_hashes.empty()) && 1134 if (!(dynamic_spki_hashes.empty() && static_spki_hashes.empty()) &&
1637 !HashesIntersect(dynamic_spki_hashes, hashes) && 1135 !HashesIntersect(dynamic_spki_hashes, hashes) &&
1638 !HashesIntersect(preloaded_spki_hashes, hashes)) { 1136 !HashesIntersect(static_spki_hashes, hashes)) {
1639 LOG(ERROR) << "Rejecting public key chain for domain " << domain 1137 LOG(ERROR) << "Rejecting public key chain for domain " << domain
1640 << ". Validated chain: " << HashesToBase64String(hashes) 1138 << ". Validated chain: " << HashesToBase64String(hashes)
1641 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) 1139 << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
1642 << " or: " << HashesToBase64String(preloaded_spki_hashes); 1140 << " or: " << HashesToBase64String(static_spki_hashes);
1643 1141
1644 return false; 1142 return false;
1645 } 1143 }
1646 1144
1647 return true; 1145 return true;
1648 } 1146 }
1649 1147
1650 bool TransportSecurityState::DomainState::IsMoreStrict(
1651 const TransportSecurityState::DomainState& other) {
1652 if (this->dynamic_spki_hashes.empty() && !other.dynamic_spki_hashes.empty())
1653 return false;
1654
1655 if (!this->include_subdomains && other.include_subdomains)
1656 return false;
1657
1658 return true;
1659 }
1660
1661 bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() 1148 bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS()
1662 const { 1149 const {
1663 return mode == MODE_STRICT; 1150 return upgrade_mode == MODE_FORCE_HTTPS;
1664 } 1151 }
1665 1152
1666 } // namespace 1153 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698