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

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, 8 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/ssl_info.h" 35 #include "net/base/ssl_info.h"
39 #include "net/base/x509_certificate.h" 36 #include "net/base/x509_certificate.h"
40 #include "net/http/http_util.h" 37 #include "net/http/http_util.h"
41 38
42 #if defined(USE_OPENSSL) 39 #if defined(USE_OPENSSL)
43 #include "crypto/openssl_util.h" 40 #include "crypto/openssl_util.h"
44 #endif 41 #endif
45 42
46 namespace net { 43 namespace net {
47 44
48 const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year 45 const long int TransportSecurityState::kMaxHSTSAgeSecs = 86400 * 365; // 1 year
49 46
50 TransportSecurityState::TransportSecurityState(const std::string& hsts_hosts)
51 : delegate_(NULL) {
52 if (!hsts_hosts.empty()) {
53 bool dirty;
54 Deserialise(hsts_hosts, &dirty, &forced_hosts_);
55 }
56 }
57
58 static std::string HashHost(const std::string& canonicalized_host) { 47 static std::string HashHost(const std::string& canonicalized_host) {
59 char hashed[crypto::kSHA256Length]; 48 char hashed[crypto::kSHA256Length];
60 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); 49 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
61 return std::string(hashed, sizeof(hashed)); 50 return std::string(hashed, sizeof(hashed));
62 } 51 }
63 52
53 TransportSecurityState::TransportSecurityState()
54 : delegate_(NULL) { }
Ryan Sleevi 2012/04/26 19:21:12 nit: move } to a new line
palmer 2012/04/27 23:52:34 Done.
55
64 void TransportSecurityState::SetDelegate( 56 void TransportSecurityState::SetDelegate(
65 TransportSecurityState::Delegate* delegate) { 57 TransportSecurityState::Delegate* delegate) {
66 delegate_ = delegate; 58 delegate_ = delegate;
67 } 59 }
68 60
69 void TransportSecurityState::EnableHost(const std::string& host, 61 void TransportSecurityState::EnableHost(const std::string& host,
70 const DomainState& state) { 62 const DomainState& state) {
71 DCHECK(CalledOnValidThread()); 63 DCHECK(CalledOnValidThread());
72 64
73 const std::string canonicalized_host = CanonicalizeHost(host); 65 const std::string canonicalized_host = CanonicalizeHost(host);
74 if (canonicalized_host.empty()) 66 if (canonicalized_host.empty())
75 return; 67 return;
76 68
77 // Only override a preloaded state if the new state describes a more strict
78 // policy. TODO(palmer): Reconsider this?
79 DomainState existing_state; 69 DomainState existing_state;
80 if (IsPreloadedSTS(canonicalized_host, true, &existing_state) &&
81 canonicalized_host == CanonicalizeHost(existing_state.domain) &&
82 existing_state.IsMoreStrict(state)) {
83 return;
84 }
85 70
86 // Use the original creation date if we already have this host. 71 // Use the original creation date if we already have this host. (But note
72 // that statically-defined states have no |created| date. Therefore, we do
73 // not bother to search the SNI-only static states.)
87 DomainState state_copy(state); 74 DomainState state_copy(state);
88 if (GetDomainState(&existing_state, host, true) && 75 if (GetDomainState(host, false /* sni_enabled */, &existing_state) &&
89 !existing_state.created.is_null()) { 76 !existing_state.created.is_null()) {
90 state_copy.created = existing_state.created; 77 state_copy.created = existing_state.created;
91 } 78 }
92 79
93 // We don't store these values. 80 // No need to store this value since it is redundant. (|canonicalized_host|
94 state_copy.preloaded = false; 81 // is the map key.)
95 state_copy.domain.clear(); 82 state_copy.domain.clear();
96 83
97 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; 84 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
98 DirtyNotify(); 85 DirtyNotify();
99 } 86 }
100 87
101 bool TransportSecurityState::DeleteHost(const std::string& host) { 88 bool TransportSecurityState::DeleteHost(const std::string& host) {
102 DCHECK(CalledOnValidThread()); 89 DCHECK(CalledOnValidThread());
103 90
104 const std::string canonicalized_host = CanonicalizeHost(host); 91 const std::string canonicalized_host = CanonicalizeHost(host);
105 if (canonicalized_host.empty()) 92 if (canonicalized_host.empty())
106 return false; 93 return false;
107 94
108 std::map<std::string, DomainState>::iterator i = enabled_hosts_.find( 95 std::map<std::string, DomainState>::iterator i = enabled_hosts_.find(
109 HashHost(canonicalized_host)); 96 HashHost(canonicalized_host));
110 if (i != enabled_hosts_.end()) { 97 if (i != enabled_hosts_.end()) {
111 enabled_hosts_.erase(i); 98 enabled_hosts_.erase(i);
112 DirtyNotify(); 99 DirtyNotify();
113 return true; 100 return true;
114 } 101 }
115 return false; 102 return false;
116 } 103 }
117 104
118 bool TransportSecurityState::HasPinsForHost(DomainState* result, 105 bool TransportSecurityState::GetDomainState(const std::string& host,
119 const std::string& host, 106 bool sni_enabled,
120 bool sni_available) { 107 DomainState* result) {
121 DCHECK(CalledOnValidThread());
122
123 return HasMetadata(result, host, sni_available) &&
124 (!result->dynamic_spki_hashes.empty() ||
125 !result->preloaded_spki_hashes.empty());
126 }
127
128 bool TransportSecurityState::GetDomainState(DomainState* result,
129 const std::string& host,
130 bool sni_available) {
131 DCHECK(CalledOnValidThread());
132
133 return HasMetadata(result, host, sni_available);
134 }
135
136 bool TransportSecurityState::HasMetadata(DomainState* result,
137 const std::string& host,
138 bool sni_available) {
139 DCHECK(CalledOnValidThread()); 108 DCHECK(CalledOnValidThread());
140 109
141 DomainState state; 110 DomainState state;
142 const std::string canonicalized_host = CanonicalizeHost(host); 111 const std::string canonicalized_host = CanonicalizeHost(host);
143 if (canonicalized_host.empty()) 112 if (canonicalized_host.empty())
144 return false; 113 return false;
145 114
146 bool has_preload = IsPreloadedSTS(canonicalized_host, sni_available, &state); 115 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled,
116 &state);
147 std::string canonicalized_preload = CanonicalizeHost(state.domain); 117 std::string canonicalized_preload = CanonicalizeHost(state.domain);
148 118
149 base::Time current_time(base::Time::Now()); 119 base::Time current_time(base::Time::Now());
150 120
151 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 121 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
152 std::string host_sub_chunk(&canonicalized_host[i], 122 std::string host_sub_chunk(&canonicalized_host[i],
153 canonicalized_host.size() - i); 123 canonicalized_host.size() - i);
154 // Exact match of a preload always wins. 124 // Exact match of a preload always wins.
155 if (has_preload && host_sub_chunk == canonicalized_preload) { 125 if (has_preload && host_sub_chunk == canonicalized_preload) {
156 *result = state; 126 *result = state;
157 return true; 127 return true;
158 } 128 }
159 129
160 std::map<std::string, DomainState>::iterator j = 130 std::map<std::string, DomainState>::iterator j =
161 enabled_hosts_.find(HashHost(host_sub_chunk)); 131 enabled_hosts_.find(HashHost(host_sub_chunk));
162 if (j == enabled_hosts_.end()) 132 if (j == enabled_hosts_.end())
163 continue; 133 continue;
164 134
165 if (current_time > j->second.expiry && 135 if (current_time > j->second.upgrade_expiry &&
166 current_time > j->second.dynamic_spki_hashes_expiry) { 136 current_time > j->second.dynamic_spki_hashes_expiry) {
167 enabled_hosts_.erase(j); 137 enabled_hosts_.erase(j);
168 DirtyNotify(); 138 DirtyNotify();
169 continue; 139 continue;
170 } 140 }
171 141
172 state = j->second; 142 state = j->second;
173 state.domain = DNSDomainToString(host_sub_chunk); 143 state.domain = DNSDomainToString(host_sub_chunk);
174 144
175 // Succeed if we matched the domain exactly or if subdomain matches are 145 // Succeed if we matched the domain exactly or if subdomain matches are
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 if (!base::Base64Decode(unquoted, &decoded) || 253 if (!base::Base64Decode(unquoted, &decoded) ||
284 decoded.size() != arraysize(fp.data)) { 254 decoded.size() != arraysize(fp.data)) {
285 return false; 255 return false;
286 } 256 }
287 257
288 memcpy(fp.data, decoded.data(), arraysize(fp.data)); 258 memcpy(fp.data, decoded.data(), arraysize(fp.data));
289 fingerprints->push_back(fp); 259 fingerprints->push_back(fp);
290 return true; 260 return true;
291 } 261 }
292 262
293 // static
294 bool TransportSecurityState::GetPublicKeyHash(
295 const X509Certificate& cert, SHA1Fingerprint* spki_hash) {
296 std::string der_bytes;
297 if (!X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der_bytes))
298 return false;
299
300 base::StringPiece spki;
301 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki))
302 return false;
303
304 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()),
305 spki.size(), spki_hash->data);
306
307 return true;
308 }
309
310 struct FingerprintsEqualPredicate { 263 struct FingerprintsEqualPredicate {
311 explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) : 264 explicit FingerprintsEqualPredicate(const SHA1Fingerprint& fingerprint) :
312 fingerprint_(fingerprint) {} 265 fingerprint_(fingerprint) {}
313 266
314 bool operator()(const SHA1Fingerprint& other) const { 267 bool operator()(const SHA1Fingerprint& other) const {
315 return fingerprint_.Equals(other); 268 return fingerprint_.Equals(other);
316 } 269 }
317 270
318 const SHA1Fingerprint& fingerprint_; 271 const SHA1Fingerprint& fingerprint_;
319 }; 272 };
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 if (from_cert_chain.empty()) 314 if (from_cert_chain.empty())
362 return false; 315 return false;
363 316
364 return IsBackupPinPresent(pins, from_cert_chain) && 317 return IsBackupPinPresent(pins, from_cert_chain) &&
365 HashesIntersect(pins, from_cert_chain); 318 HashesIntersect(pins, from_cert_chain);
366 } 319 }
367 320
368 // "Public-Key-Pins" ":" 321 // "Public-Key-Pins" ":"
369 // "max-age" "=" delta-seconds ";" 322 // "max-age" "=" delta-seconds ";"
370 // "pin-" algo "=" base64 [ ";" ... ] 323 // "pin-" algo "=" base64 [ ";" ... ]
371 // 324 bool TransportSecurityState::DomainState::ParsePinsHeader(
372 // static 325 const base::Time& now,
373 bool TransportSecurityState::ParsePinsHeader(const std::string& value, 326 const std::string& value,
374 const SSLInfo& ssl_info, 327 const SSLInfo& ssl_info) {
375 DomainState* state) {
376 bool parsed_max_age = false; 328 bool parsed_max_age = false;
377 int max_age = 0; 329 int max_age_candidate = 0;
378 FingerprintVector pins; 330 FingerprintVector pins;
379 331
380 std::string source = value; 332 std::string source = value;
381 333
382 while (!source.empty()) { 334 while (!source.empty()) {
383 StringPair semicolon = Split(source, ';'); 335 StringPair semicolon = Split(source, ';');
384 semicolon.first = Strip(semicolon.first); 336 semicolon.first = Strip(semicolon.first);
385 semicolon.second = Strip(semicolon.second); 337 semicolon.second = Strip(semicolon.second);
386 StringPair equals = Split(semicolon.first, '='); 338 StringPair equals = Split(semicolon.first, '=');
387 equals.first = Strip(equals.first); 339 equals.first = Strip(equals.first);
388 equals.second = Strip(equals.second); 340 equals.second = Strip(equals.second);
389 341
390 if (LowerCaseEqualsASCII(equals.first, "max-age")) { 342 if (LowerCaseEqualsASCII(equals.first, "max-age")) {
391 if (equals.second.empty() || 343 if (equals.second.empty() ||
392 !MaxAgeToInt(equals.second.begin(), equals.second.end(), &max_age)) { 344 !MaxAgeToInt(equals.second.begin(), equals.second.end(),
345 &max_age_candidate)) {
393 return false; 346 return false;
394 } 347 }
395 if (max_age > kMaxHSTSAgeSecs) 348 if (max_age_candidate > kMaxHSTSAgeSecs)
396 max_age = kMaxHSTSAgeSecs; 349 max_age_candidate = kMaxHSTSAgeSecs;
397 parsed_max_age = true; 350 parsed_max_age = true;
398 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) { 351 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha1")) {
399 if (!ParseAndAppendPin(equals.second, &pins)) 352 if (!ParseAndAppendPin(equals.second, &pins))
400 return false; 353 return false;
401 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) { 354 } else if (LowerCaseEqualsASCII(equals.first, "pin-sha256")) {
402 // TODO(palmer) 355 // TODO(palmer)
403 } else { 356 } else {
404 // Silently ignore unknown directives for forward compatibility. 357 // Silently ignore unknown directives for forward compatibility.
405 } 358 }
406 359
407 source = semicolon.second; 360 source = semicolon.second;
408 } 361 }
409 362
410 if (!parsed_max_age || !IsPinListValid(pins, ssl_info)) 363 if (!parsed_max_age || !IsPinListValid(pins, ssl_info))
411 return false; 364 return false;
412 365
413 state->max_age = max_age; 366 dynamic_spki_hashes_expiry =
414 state->dynamic_spki_hashes_expiry = 367 now + base::TimeDelta::FromSeconds(max_age_candidate);
415 base::Time::Now() + base::TimeDelta::FromSeconds(max_age);
416 368
417 state->dynamic_spki_hashes.clear(); 369 dynamic_spki_hashes.clear();
418 if (max_age > 0) { 370 if (max_age_candidate > 0) {
419 for (FingerprintVector::const_iterator i = pins.begin(); 371 for (FingerprintVector::const_iterator i = pins.begin();
420 i != pins.end(); i++) { 372 i != pins.end(); ++i) {
421 state->dynamic_spki_hashes.push_back(*i); 373 dynamic_spki_hashes.push_back(*i);
422 } 374 }
423 } 375 }
424 376
425 return true; 377 return true;
426 } 378 }
427 379
428 // "Strict-Transport-Security" ":" 380 // "Strict-Transport-Security" ":"
429 // "max-age" "=" delta-seconds [ ";" "includeSubDomains" ] 381 // "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
430 // 382 bool TransportSecurityState::DomainState::ParseSTSHeader(
431 // static 383 const base::Time& now,
432 bool TransportSecurityState::ParseHeader(const std::string& value, 384 const std::string& value) {
433 int* max_age,
434 bool* include_subdomains) {
435 DCHECK(max_age);
436 DCHECK(include_subdomains);
437
438 int max_age_candidate = 0; 385 int max_age_candidate = 0;
439 386
440 enum ParserState { 387 enum ParserState {
441 START, 388 START,
442 AFTER_MAX_AGE_LABEL, 389 AFTER_MAX_AGE_LABEL,
443 AFTER_MAX_AGE_EQUALS, 390 AFTER_MAX_AGE_EQUALS,
444 AFTER_MAX_AGE, 391 AFTER_MAX_AGE,
445 AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER, 392 AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER,
446 AFTER_INCLUDE_SUBDOMAINS, 393 AFTER_INCLUDE_SUBDOMAINS,
447 } state = START; 394 } state = START;
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 } 451 }
505 } 452 }
506 453
507 // We've consumed all the input. Let's see what state we ended up in. 454 // We've consumed all the input. Let's see what state we ended up in.
508 switch (state) { 455 switch (state) {
509 case START: 456 case START:
510 case AFTER_MAX_AGE_LABEL: 457 case AFTER_MAX_AGE_LABEL:
511 case AFTER_MAX_AGE_EQUALS: 458 case AFTER_MAX_AGE_EQUALS:
512 return false; 459 return false;
513 case AFTER_MAX_AGE: 460 case AFTER_MAX_AGE:
514 *max_age = max_age_candidate; 461 upgrade_expiry =
515 *include_subdomains = false; 462 now + base::TimeDelta::FromSeconds(max_age_candidate);
463 include_subdomains = false;
464 upgrade_mode = MODE_FORCE_HTTPS;
516 return true; 465 return true;
517 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER: 466 case AFTER_MAX_AGE_INCLUDE_SUB_DOMAINS_DELIMITER:
518 return false; 467 return false;
519 case AFTER_INCLUDE_SUBDOMAINS: 468 case AFTER_INCLUDE_SUBDOMAINS:
520 *max_age = max_age_candidate; 469 upgrade_expiry =
521 *include_subdomains = true; 470 now + base::TimeDelta::FromSeconds(max_age_candidate);
471 include_subdomains = true;
472 upgrade_mode = MODE_FORCE_HTTPS;
522 return true; 473 return true;
523 default: 474 default:
524 NOTREACHED(); 475 NOTREACHED();
525 return false; 476 return false;
526 } 477 }
527 } 478 }
528 479
529 // Side pinning and superfluous certificates:
530 //
531 // In SSLClientSocketNSS::DoVerifyCertComplete we look for certificates with a
532 // Subject of CN=meta. When we find one we'll currently try and parse side
533 // pinned key from it.
534 //
535 // A side pin is a key which can be pinned to, but also can be kept offline and
536 // still held by the site owner. The CN=meta certificate is just a backwards
537 // compatiable method of carrying a lump of bytes to the client. (We could use
538 // a TLS extension just as well, but it's a lot easier for admins to add extra
539 // certificates to the chain.)
540
541 // A TagMap represents the simple key-value structure that we use. Keys are
542 // 32-bit ints. Values are byte strings.
543 typedef std::map<uint32, base::StringPiece> TagMap;
544
545 // ParseTags parses a list of key-value pairs from |in| to |out| and advances
546 // |in| past the data. The key-value pair data is:
547 // u16le num_tags
548 // u32le tag[num_tags]
549 // u16le lengths[num_tags]
550 // ...data...
551 static bool ParseTags(base::StringPiece* in, TagMap *out) {
552 // Many part of Chrome already assume little-endian. This is just to help
553 // anyone who should try to port it in the future.
554 #if defined(__BYTE_ORDER)
555 // Linux check
556 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian);
557 #elif defined(__BIG_ENDIAN__)
558 // Mac check
559 #error assumes little endian
560 #endif
561
562 uint16 num_tags_16;
563 if (in->size() < sizeof(num_tags_16))
564 return false;
565
566 memcpy(&num_tags_16, in->data(), sizeof(num_tags_16));
567 in->remove_prefix(sizeof(num_tags_16));
568 unsigned num_tags = num_tags_16;
569
570 if (in->size() < 6 * num_tags)
571 return false;
572
573 const uint32* tags = reinterpret_cast<const uint32*>(in->data());
574 const uint16* lens = reinterpret_cast<const uint16*>(
575 in->data() + 4*num_tags);
576 in->remove_prefix(6*num_tags);
577
578 uint32 prev_tag = 0;
579 for (unsigned i = 0; i < num_tags; i++) {
580 size_t len = lens[i];
581 uint32 tag = tags[i];
582
583 if (in->size() < len)
584 return false;
585 // tags must be in ascending order.
586 if (i > 0 && prev_tag >= tag)
587 return false;
588 (*out)[tag] = base::StringPiece(in->data(), len);
589 in->remove_prefix(len);
590 prev_tag = tag;
591 }
592
593 return true;
594 }
595
596 // GetTag extracts the data associated with |tag| in |tags|.
597 static bool GetTag(uint32 tag, const TagMap& tags, base::StringPiece* out) {
598 TagMap::const_iterator i = tags.find(tag);
599 if (i == tags.end())
600 return false;
601
602 *out = i->second;
603 return true;
604 }
605
606 // kP256SubjectPublicKeyInfoPrefix can be prepended onto a P256 elliptic curve
607 // point in X9.62 format in order to make a valid SubjectPublicKeyInfo. The
608 // ASN.1 interpretation of these bytes is:
609 //
610 // 0:d=0 hl=2 l= 89 cons: SEQUENCE
611 // 2:d=1 hl=2 l= 19 cons: SEQUENCE
612 // 4:d=2 hl=2 l= 7 prim: OBJECT :id-ecPublicKey
613 // 13:d=2 hl=2 l= 8 prim: OBJECT :prime256v1
614 // 23:d=1 hl=2 l= 66 prim: BIT STRING
615 static const uint8 kP256SubjectPublicKeyInfoPrefix[] = {
616 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
617 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
618 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
619 0x42, 0x00,
620 };
621
622 // VerifySignature returns true iff |sig| is a valid signature of
623 // |hash| by |pubkey|. The actual implementation is crypto library
624 // specific.
625 static bool VerifySignature(const base::StringPiece& pubkey,
626 const base::StringPiece& sig,
627 const base::StringPiece& hash);
628
629 #if defined(USE_OPENSSL)
630
631 static EVP_PKEY* DecodeX962P256PublicKey(
632 const base::StringPiece& pubkey_bytes) {
633 // The public key is an X9.62 encoded P256 point.
634 if (pubkey_bytes.size() != 1 + 2*32)
635 return NULL;
636
637 std::string pubkey_spki(
638 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
639 sizeof(kP256SubjectPublicKeyInfoPrefix));
640 pubkey_spki += pubkey_bytes.as_string();
641
642 EVP_PKEY* ret = NULL;
643 const unsigned char* der_pubkey =
644 reinterpret_cast<const unsigned char*>(pubkey_spki.data());
645 d2i_PUBKEY(&ret, &der_pubkey, pubkey_spki.size());
646 return ret;
647 }
648
649 static bool VerifySignature(const base::StringPiece& pubkey,
650 const base::StringPiece& sig,
651 const base::StringPiece& hash) {
652 crypto::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> secpubkey(
653 DecodeX962P256PublicKey(pubkey));
654 if (!secpubkey.get())
655 return false;
656
657
658 crypto::ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(
659 EVP_PKEY_get1_EC_KEY(secpubkey.get()));
660 if (!ec_key.get())
661 return false;
662
663 return ECDSA_verify(0, reinterpret_cast<const unsigned char*>(hash.data()),
664 hash.size(),
665 reinterpret_cast<const unsigned char*>(sig.data()),
666 sig.size(), ec_key.get()) == 1;
667 }
668
669 #else
670
671 // DecodeX962P256PublicKey parses an uncompressed, X9.62 format, P256 elliptic
672 // curve point from |pubkey_bytes| and returns it as a SECKEYPublicKey.
673 static SECKEYPublicKey* DecodeX962P256PublicKey(
674 const base::StringPiece& pubkey_bytes) {
675 // The public key is an X9.62 encoded P256 point.
676 if (pubkey_bytes.size() != 1 + 2*32)
677 return NULL;
678
679 std::string pubkey_spki(
680 reinterpret_cast<const char*>(kP256SubjectPublicKeyInfoPrefix),
681 sizeof(kP256SubjectPublicKeyInfoPrefix));
682 pubkey_spki += pubkey_bytes.as_string();
683
684 SECItem der;
685 memset(&der, 0, sizeof(der));
686 der.data = reinterpret_cast<uint8*>(const_cast<char*>(pubkey_spki.data()));
687 der.len = pubkey_spki.size();
688
689 CERTSubjectPublicKeyInfo* spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&der);
690 if (!spki)
691 return NULL;
692 SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
693 SECKEY_DestroySubjectPublicKeyInfo(spki);
694
695 return public_key;
696 }
697
698 static bool VerifySignature(const base::StringPiece& pubkey,
699 const base::StringPiece& sig,
700 const base::StringPiece& hash) {
701 SECKEYPublicKey* secpubkey = DecodeX962P256PublicKey(pubkey);
702 if (!secpubkey)
703 return false;
704
705 SECItem sigitem;
706 memset(&sigitem, 0, sizeof(sigitem));
707 sigitem.data = reinterpret_cast<uint8*>(const_cast<char*>(sig.data()));
708 sigitem.len = sig.size();
709
710 // |decoded_sigitem| is newly allocated, as is the data that it points to.
711 SECItem* decoded_sigitem = DSAU_DecodeDerSigToLen(
712 &sigitem, SECKEY_SignatureLen(secpubkey));
713
714 if (!decoded_sigitem) {
715 SECKEY_DestroyPublicKey(secpubkey);
716 return false;
717 }
718
719 SECItem hashitem;
720 memset(&hashitem, 0, sizeof(hashitem));
721 hashitem.data = reinterpret_cast<unsigned char*>(
722 const_cast<char*>(hash.data()));
723 hashitem.len = hash.size();
724
725 SECStatus rv = PK11_Verify(secpubkey, decoded_sigitem, &hashitem, NULL);
726 SECKEY_DestroyPublicKey(secpubkey);
727 SECITEM_FreeItem(decoded_sigitem, PR_TRUE);
728 return rv == SECSuccess;
729 }
730
731 #endif // !defined(USE_OPENSSL)
732
733 // These are the tag values that we use. Tags are little-endian on the wire and
734 // these values correspond to the ASCII of the name.
735 static const uint32 kTagALGO = 0x4f474c41;
736 static const uint32 kTagP256 = 0x36353250;
737 static const uint32 kTagPUBK = 0x4b425550;
738 static const uint32 kTagSIG = 0x474953;
739 static const uint32 kTagSPIN = 0x4e495053;
740
741 // static
742 bool TransportSecurityState::ParseSidePin(
743 const base::StringPiece& leaf_spki,
744 const base::StringPiece& in_side_info,
745 FingerprintVector* out_pub_key_hash) {
746 base::StringPiece side_info(in_side_info);
747
748 TagMap outer;
749 if (!ParseTags(&side_info, &outer))
750 return false;
751 // trailing data is not allowed
752 if (side_info.size())
753 return false;
754
755 base::StringPiece side_pin_bytes;
756 if (!GetTag(kTagSPIN, outer, &side_pin_bytes))
757 return false;
758
759 bool have_parsed_a_key = false;
760 uint8 leaf_spki_hash[crypto::kSHA256Length];
761 bool have_leaf_spki_hash = false;
762
763 while (side_pin_bytes.size() > 0) {
764 TagMap side_pin;
765 if (!ParseTags(&side_pin_bytes, &side_pin))
766 return false;
767
768 base::StringPiece algo, pubkey, sig;
769 if (!GetTag(kTagALGO, side_pin, &algo) ||
770 !GetTag(kTagPUBK, side_pin, &pubkey) ||
771 !GetTag(kTagSIG, side_pin, &sig)) {
772 return false;
773 }
774
775 if (algo.size() != sizeof(kTagP256) ||
776 0 != memcmp(algo.data(), &kTagP256, sizeof(kTagP256))) {
777 // We don't support anything but P256 at the moment.
778 continue;
779 }
780
781 if (!have_leaf_spki_hash) {
782 crypto::SHA256HashString(
783 leaf_spki.as_string(), leaf_spki_hash, sizeof(leaf_spki_hash));
784 have_leaf_spki_hash = true;
785 }
786
787 if (VerifySignature(pubkey, sig, base::StringPiece(
788 reinterpret_cast<const char*>(leaf_spki_hash),
789 sizeof(leaf_spki_hash)))) {
790 SHA1Fingerprint fpr;
791 base::SHA1HashBytes(
792 reinterpret_cast<const uint8*>(pubkey.data()),
793 pubkey.size(),
794 fpr.data);
795 out_pub_key_hash->push_back(fpr);
796 have_parsed_a_key = true;
797 }
798 }
799
800 return have_parsed_a_key;
801 }
802
803 // This function converts the binary hashes, which we store in
804 // |enabled_hosts_|, to a base64 string which we can include in a JSON file.
805 static std::string HashedDomainToExternalString(const std::string& hashed) {
806 std::string out;
807 CHECK(base::Base64Encode(hashed, &out));
808 return out;
809 }
810
811 // This inverts |HashedDomainToExternalString|, above. It turns an external
812 // string (from a JSON file) into an internal (binary) string.
813 static std::string ExternalStringToHashedDomain(const std::string& external) {
814 std::string out;
815 if (!base::Base64Decode(external, &out) ||
816 out.size() != crypto::kSHA256Length) {
817 return std::string();
818 }
819
820 return out;
821 }
822
823 static ListValue* SPKIHashesToListValue(const FingerprintVector& hashes) {
824 ListValue* pins = new ListValue;
825
826 for (FingerprintVector::const_iterator i = hashes.begin();
827 i != hashes.end(); ++i) {
828 std::string hash_str(reinterpret_cast<const char*>(i->data),
829 sizeof(i->data));
830 std::string b64;
831 base::Base64Encode(hash_str, &b64);
832 pins->Append(new StringValue("sha1/" + b64));
833 }
834
835 return pins;
836 }
837
838 bool TransportSecurityState::Serialise(std::string* output) {
839 DCHECK(CalledOnValidThread());
840
841 DictionaryValue toplevel;
842 base::Time now = base::Time::Now();
843 for (std::map<std::string, DomainState>::const_iterator
844 i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
845 DictionaryValue* state = new DictionaryValue;
846 state->SetBoolean("include_subdomains", i->second.include_subdomains);
847 state->SetDouble("created", i->second.created.ToDoubleT());
848 state->SetDouble("expiry", i->second.expiry.ToDoubleT());
849 state->SetDouble("dynamic_spki_hashes_expiry",
850 i->second.dynamic_spki_hashes_expiry.ToDoubleT());
851
852 switch (i->second.mode) {
853 case DomainState::MODE_STRICT:
854 state->SetString("mode", "strict");
855 break;
856 case DomainState::MODE_SPDY_ONLY:
857 state->SetString("mode", "spdy-only");
858 break;
859 case DomainState::MODE_PINNING_ONLY:
860 state->SetString("mode", "pinning-only");
861 break;
862 default:
863 NOTREACHED() << "DomainState with unknown mode";
864 delete state;
865 continue;
866 }
867
868 state->Set("preloaded_spki_hashes",
869 SPKIHashesToListValue(i->second.preloaded_spki_hashes));
870
871 if (now < i->second.dynamic_spki_hashes_expiry) {
872 state->Set("dynamic_spki_hashes",
873 SPKIHashesToListValue(i->second.dynamic_spki_hashes));
874 }
875
876 toplevel.Set(HashedDomainToExternalString(i->first), state);
877 }
878
879 base::JSONWriter::WriteWithOptions(&toplevel,
880 base::JSONWriter::OPTIONS_PRETTY_PRINT,
881 output);
882 return true;
883 }
884
885 bool TransportSecurityState::LoadEntries(const std::string& input,
886 bool* dirty) {
887 DCHECK(CalledOnValidThread());
888
889 enabled_hosts_.clear();
890 return Deserialise(input, dirty, &enabled_hosts_);
891 }
892
893 static bool AddHash(const std::string& type_and_base64, 480 static bool AddHash(const std::string& type_and_base64,
894 FingerprintVector* out) { 481 FingerprintVector* out) {
895 SHA1Fingerprint hash; 482 SHA1Fingerprint hash;
896 483
897 if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) 484 if (!TransportSecurityState::ParsePin(type_and_base64, &hash))
898 return false; 485 return false;
899 486
900 out->push_back(hash); 487 out->push_back(hash);
901 return true; 488 return true;
902 } 489 }
903 490
904 static void SPKIHashesFromListValue(FingerprintVector* hashes,
905 const ListValue& pins) {
906 size_t num_pins = pins.GetSize();
907 for (size_t i = 0; i < num_pins; ++i) {
908 std::string type_and_base64;
909 if (pins.GetString(i, &type_and_base64))
910 AddHash(type_and_base64, hashes);
911 }
912 }
913
914 // static
915 bool TransportSecurityState::Deserialise(
916 const std::string& input,
917 bool* dirty,
918 std::map<std::string, DomainState>* out) {
919 scoped_ptr<Value> value(base::JSONReader::Read(input));
920 if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY))
921 return false;
922
923 DictionaryValue* dict_value = reinterpret_cast<DictionaryValue*>(value.get());
924 const base::Time current_time(base::Time::Now());
925 bool dirtied = false;
926
927 for (DictionaryValue::key_iterator i = dict_value->begin_keys();
928 i != dict_value->end_keys(); ++i) {
929 DictionaryValue* state;
930 if (!dict_value->GetDictionaryWithoutPathExpansion(*i, &state))
931 continue;
932
933 bool include_subdomains;
934 std::string mode_string;
935 double created;
936 double expiry;
937 double dynamic_spki_hashes_expiry = 0.0;
938
939 if (!state->GetBoolean("include_subdomains", &include_subdomains) ||
940 !state->GetString("mode", &mode_string) ||
941 !state->GetDouble("expiry", &expiry)) {
942 continue;
943 }
944
945 // Don't fail if this key is not present.
946 (void) state->GetDouble("dynamic_spki_hashes_expiry",
947 &dynamic_spki_hashes_expiry);
948
949 ListValue* pins_list = NULL;
950 FingerprintVector preloaded_spki_hashes;
951 if (state->GetList("preloaded_spki_hashes", &pins_list))
952 SPKIHashesFromListValue(&preloaded_spki_hashes, *pins_list);
953
954 FingerprintVector dynamic_spki_hashes;
955 if (state->GetList("dynamic_spki_hashes", &pins_list))
956 SPKIHashesFromListValue(&dynamic_spki_hashes, *pins_list);
957
958 DomainState::Mode mode;
959 if (mode_string == "strict") {
960 mode = DomainState::MODE_STRICT;
961 } else if (mode_string == "spdy-only") {
962 mode = DomainState::MODE_SPDY_ONLY;
963 } else if (mode_string == "pinning-only") {
964 mode = DomainState::MODE_PINNING_ONLY;
965 } else {
966 LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
967 << mode_string;
968 continue;
969 }
970
971 base::Time expiry_time = base::Time::FromDoubleT(expiry);
972 base::Time dynamic_spki_hashes_expiry_time =
973 base::Time::FromDoubleT(dynamic_spki_hashes_expiry);
974 base::Time created_time;
975 if (state->GetDouble("created", &created)) {
976 created_time = base::Time::FromDoubleT(created);
977 } else {
978 // We're migrating an old entry with no creation date. Make sure we
979 // write the new date back in a reasonable time frame.
980 dirtied = true;
981 created_time = base::Time::Now();
982 }
983
984 if (expiry_time <= current_time &&
985 dynamic_spki_hashes_expiry_time <= current_time) {
986 // Make sure we dirty the state if we drop an entry.
987 dirtied = true;
988 continue;
989 }
990
991 std::string hashed = ExternalStringToHashedDomain(*i);
992 if (hashed.empty()) {
993 dirtied = true;
994 continue;
995 }
996
997 DomainState new_state;
998 new_state.mode = mode;
999 new_state.created = created_time;
1000 new_state.expiry = expiry_time;
1001 new_state.include_subdomains = include_subdomains;
1002 new_state.preloaded_spki_hashes = preloaded_spki_hashes;
1003 new_state.dynamic_spki_hashes = dynamic_spki_hashes;
1004 new_state.dynamic_spki_hashes_expiry = dynamic_spki_hashes_expiry_time;
1005 (*out)[hashed] = new_state;
1006 }
1007
1008 *dirty = dirtied;
1009 return true;
1010 }
1011
1012 TransportSecurityState::~TransportSecurityState() { 491 TransportSecurityState::~TransportSecurityState() {
1013 } 492 }
Ryan Sleevi 2012/04/26 19:21:12 nit: move } to line 491
palmer 2012/04/27 23:52:34 Done.
1014 493
1015 void TransportSecurityState::DirtyNotify() { 494 void TransportSecurityState::DirtyNotify() {
1016 DCHECK(CalledOnValidThread()); 495 DCHECK(CalledOnValidThread());
1017 496
1018 if (delegate_) 497 if (delegate_)
1019 delegate_->StateIsDirty(this); 498 delegate_->StateIsDirty(this);
1020 } 499 }
1021 500
1022 // static 501 // static
1023 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { 502 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
1115 for (size_t j = 0; j < num_entries; j++) { 594 for (size_t j = 0; j < num_entries; j++) {
1116 if (entries[j].length == canonicalized_host.size() - i && 595 if (entries[j].length == canonicalized_host.size() - i &&
1117 memcmp(entries[j].dns_name, &canonicalized_host[i], 596 memcmp(entries[j].dns_name, &canonicalized_host[i],
1118 entries[j].length) == 0) { 597 entries[j].length) == 0) {
1119 if (!entries[j].include_subdomains && i != 0) { 598 if (!entries[j].include_subdomains && i != 0) {
1120 *ret = false; 599 *ret = false;
1121 } else { 600 } else {
1122 out->include_subdomains = entries[j].include_subdomains; 601 out->include_subdomains = entries[j].include_subdomains;
1123 *ret = true; 602 *ret = true;
1124 if (!entries[j].https_required) 603 if (!entries[j].https_required)
1125 out->mode = TransportSecurityState::DomainState::MODE_PINNING_ONLY; 604 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT;
1126 if (entries[j].pins.required_hashes) { 605 if (entries[j].pins.required_hashes) {
1127 const char* const* hash = entries[j].pins.required_hashes; 606 const char* const* hash = entries[j].pins.required_hashes;
1128 while (*hash) { 607 while (*hash) {
1129 bool ok = AddHash(*hash, &out->preloaded_spki_hashes); 608 bool ok = AddHash(*hash, &out->static_spki_hashes);
1130 DCHECK(ok) << " failed to parse " << *hash; 609 DCHECK(ok) << " failed to parse " << *hash;
1131 hash++; 610 hash++;
1132 } 611 }
1133 } 612 }
1134 if (entries[j].pins.excluded_hashes) { 613 if (entries[j].pins.excluded_hashes) {
1135 const char* const* hash = entries[j].pins.excluded_hashes; 614 const char* const* hash = entries[j].pins.excluded_hashes;
1136 while (*hash) { 615 while (*hash) {
1137 bool ok = AddHash(*hash, &out->bad_preloaded_spki_hashes); 616 bool ok = AddHash(*hash, &out->bad_static_spki_hashes);
1138 DCHECK(ok) << " failed to parse " << *hash; 617 DCHECK(ok) << " failed to parse " << *hash;
1139 hash++; 618 hash++;
1140 } 619 }
1141 } 620 }
1142 } 621 }
1143 return true; 622 return true;
1144 } 623 }
1145 } 624 }
1146 return false; 625 return false;
1147 } 626 }
(...skipping 22 matching lines...) Expand all
1170 return entry; 649 return entry;
1171 } 650 }
1172 } 651 }
1173 } 652 }
1174 653
1175 return NULL; 654 return NULL;
1176 } 655 }
1177 656
1178 // static 657 // static
1179 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, 658 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host,
1180 bool sni_available) { 659 bool sni_enabled) {
1181 std::string canonicalized_host = CanonicalizeHost(host); 660 std::string canonicalized_host = CanonicalizeHost(host);
1182 const struct HSTSPreload* entry = 661 const struct HSTSPreload* entry =
1183 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 662 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
1184 663
1185 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 664 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
1186 return true; 665 return true;
1187 666
1188 if (sni_available) { 667 if (sni_enabled) {
1189 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 668 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
1190 kNumPreloadedSNISTS); 669 kNumPreloadedSNISTS);
1191 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 670 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
1192 return true; 671 return true;
1193 } 672 }
1194 673
1195 return false; 674 return false;
1196 } 675 }
1197 676
1198 // static 677 // static
1199 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { 678 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
1200 std::string canonicalized_host = CanonicalizeHost(host); 679 std::string canonicalized_host = CanonicalizeHost(host);
1201 680
1202 const struct HSTSPreload* entry = 681 const struct HSTSPreload* entry =
1203 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 682 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
1204 683
1205 if (!entry) { 684 if (!entry) {
1206 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 685 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
1207 kNumPreloadedSNISTS); 686 kNumPreloadedSNISTS);
1208 } 687 }
1209 688
1210 DCHECK(entry); 689 DCHECK(entry);
1211 DCHECK(entry->pins.required_hashes); 690 DCHECK(entry->pins.required_hashes);
1212 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); 691 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
1213 692
1214 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", 693 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
1215 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); 694 entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
1216 } 695 }
1217 696
1218 // IsPreloadedSTS returns true if the canonicalized hostname should always be 697 bool TransportSecurityState::GetStaticDomainState(
1219 // considered to have STS enabled.
1220 bool TransportSecurityState::IsPreloadedSTS(
1221 const std::string& canonicalized_host, 698 const std::string& canonicalized_host,
1222 bool sni_available, 699 bool sni_enabled,
1223 DomainState* out) { 700 DomainState* out) {
1224 DCHECK(CalledOnValidThread()); 701 DCHECK(CalledOnValidThread());
1225 702
1226 out->preloaded = true; 703 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS;
1227 out->mode = DomainState::MODE_STRICT;
1228 out->include_subdomains = false; 704 out->include_subdomains = false;
1229 705
1230 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 706 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
1231 std::string host_sub_chunk(&canonicalized_host[i], 707 std::string host_sub_chunk(&canonicalized_host[i],
1232 canonicalized_host.size() - i); 708 canonicalized_host.size() - i);
1233 out->domain = DNSDomainToString(host_sub_chunk); 709 out->domain = DNSDomainToString(host_sub_chunk);
1234 std::string hashed_host(HashHost(host_sub_chunk)); 710 std::string hashed_host(HashHost(host_sub_chunk));
1235 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) { 711 if (forced_hosts_.find(hashed_host) != forced_hosts_.end()) {
1236 *out = forced_hosts_[hashed_host]; 712 *out = forced_hosts_[hashed_host];
1237 out->domain = DNSDomainToString(host_sub_chunk); 713 out->domain = DNSDomainToString(host_sub_chunk);
1238 out->preloaded = true;
1239 return true; 714 return true;
1240 } 715 }
1241 bool ret; 716 bool ret;
1242 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, 717 if (HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
1243 &ret)) { 718 &ret)) {
1244 return ret; 719 return ret;
1245 } 720 }
1246 if (sni_available && 721 if (sni_enabled &&
1247 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, 722 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
1248 out, &ret)) { 723 out, &ret)) {
1249 return ret; 724 return ret;
1250 } 725 }
1251 } 726 }
1252 727
1253 return false; 728 return false;
1254 } 729 }
1255 730
1256 static std::string HashesToBase64String( 731 static std::string HashesToBase64String(
1257 const FingerprintVector& hashes) { 732 const FingerprintVector& hashes) {
1258 std::vector<std::string> hashes_strs; 733 std::vector<std::string> hashes_strs;
1259 for (FingerprintVector::const_iterator 734 for (FingerprintVector::const_iterator
1260 i = hashes.begin(); i != hashes.end(); i++) { 735 i = hashes.begin(); i != hashes.end(); i++) {
1261 std::string s; 736 std::string s;
1262 const std::string hash_str(reinterpret_cast<const char*>(i->data), 737 const std::string hash_str(reinterpret_cast<const char*>(i->data),
1263 sizeof(i->data)); 738 sizeof(i->data));
1264 base::Base64Encode(hash_str, &s); 739 base::Base64Encode(hash_str, &s);
1265 hashes_strs.push_back(s); 740 hashes_strs.push_back(s);
1266 } 741 }
1267 742
1268 return JoinString(hashes_strs, ','); 743 return JoinString(hashes_strs, ',');
1269 } 744 }
1270 745
1271 TransportSecurityState::DomainState::DomainState() 746 TransportSecurityState::DomainState::DomainState()
1272 : mode(MODE_STRICT), 747 : upgrade_mode(MODE_FORCE_HTTPS),
1273 created(base::Time::Now()), 748 created(base::Time::Now()),
1274 include_subdomains(false), 749 include_subdomains(false) {
1275 preloaded(false) {
1276 } 750 }
1277 751
1278 TransportSecurityState::DomainState::~DomainState() { 752 TransportSecurityState::DomainState::~DomainState() {
1279 } 753 }
1280 754
1281 bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted( 755 bool TransportSecurityState::DomainState::IsChainOfPublicKeysPermitted(
1282 const FingerprintVector& hashes) { 756 const FingerprintVector& hashes) const {
1283 757 if (HashesIntersect(bad_static_spki_hashes, hashes)) {
1284 if (HashesIntersect(bad_preloaded_spki_hashes, hashes)) {
1285 LOG(ERROR) << "Rejecting public key chain for domain " << domain 758 LOG(ERROR) << "Rejecting public key chain for domain " << domain
1286 << ". Validated chain: " << HashesToBase64String(hashes) 759 << ". Validated chain: " << HashesToBase64String(hashes)
1287 << ", matches one or more bad hashes: " 760 << ", matches one or more bad hashes: "
1288 << HashesToBase64String(bad_preloaded_spki_hashes); 761 << HashesToBase64String(bad_static_spki_hashes);
1289 return false; 762 return false;
1290 } 763 }
1291 764
1292 if (!(dynamic_spki_hashes.empty() && preloaded_spki_hashes.empty()) && 765 if (!(dynamic_spki_hashes.empty() && static_spki_hashes.empty()) &&
1293 !HashesIntersect(dynamic_spki_hashes, hashes) && 766 !HashesIntersect(dynamic_spki_hashes, hashes) &&
1294 !HashesIntersect(preloaded_spki_hashes, hashes)) { 767 !HashesIntersect(static_spki_hashes, hashes)) {
1295 LOG(ERROR) << "Rejecting public key chain for domain " << domain 768 LOG(ERROR) << "Rejecting public key chain for domain " << domain
1296 << ". Validated chain: " << HashesToBase64String(hashes) 769 << ". Validated chain: " << HashesToBase64String(hashes)
1297 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) 770 << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
1298 << " or: " << HashesToBase64String(preloaded_spki_hashes); 771 << " or: " << HashesToBase64String(static_spki_hashes);
1299 772
1300 return false; 773 return false;
1301 } 774 }
1302 775
1303 return true; 776 return true;
1304 } 777 }
1305 778
1306 bool TransportSecurityState::DomainState::IsMoreStrict( 779 bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() const {
1307 const TransportSecurityState::DomainState& other) { 780 return upgrade_mode == MODE_FORCE_HTTPS;
1308 if (this->dynamic_spki_hashes.empty() && !other.dynamic_spki_hashes.empty())
1309 return false;
1310
1311 if (!this->include_subdomains && other.include_subdomains)
1312 return false;
1313
1314 return true;
1315 } 781 }
1316 782
1317 bool TransportSecurityState::DomainState::ShouldRedirectHTTPToHTTPS() 783 bool TransportSecurityState::DomainState::HasPins() const {
1318 const { 784 return static_spki_hashes.size() > 0 ||
1319 return mode == MODE_STRICT; 785 bad_static_spki_hashes.size() > 0 ||
786 dynamic_spki_hashes.size() > 0;
1320 } 787 }
1321 788
1322 } // namespace 789 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698