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
3 // found in the LICENSE file.
4
5 #include "net/http/transport_security_state.h"
6
7 #if defined(USE_OPENSSL)
8 #include <openssl/ecdsa.h>
9 #include <openssl/ssl.h>
10 #else // !defined(USE_OPENSSL)
11 #include <cryptohi.h>
12 #include <hasht.h>
13 #include <keyhi.h>
14 #include <nspr.h>
15 #include <pk11pub.h>
16 #endif
17
18 #include <algorithm>
19
20 #include "base/base64.h"
21 #include "base/build_time.h"
22 #include "base/logging.h"
23 #include "base/memory/scoped_ptr.h"
24 #include "base/metrics/histogram.h"
25 #include "base/sha1.h"
26 #include "base/strings/string_number_conversions.h"
27 #include "base/strings/string_util.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/time/time.h"
30 #include "base/values.h"
31 #include "crypto/sha2.h"
32 #include "net/base/dns_util.h"
33 #include "net/cert/x509_cert_types.h"
34 #include "net/cert/x509_certificate.h"
35 #include "net/http/http_security_headers.h"
36 #include "net/ssl/ssl_info.h"
37 #include "url/gurl.h"
38
39 #if defined(USE_OPENSSL)
40 #include "crypto/openssl_util.h"
41 #endif
42
43 namespace net {
44
45 namespace {
46
HashesToBase64String(const HashValueVector & hashes)47 std::string HashesToBase64String(const HashValueVector& hashes) {
48 std::string str;
49 for (size_t i = 0; i != hashes.size(); ++i) {
50 if (i != 0)
51 str += ",";
52 str += hashes[i].ToString();
53 }
54 return str;
55 }
56
HashHost(const std::string & canonicalized_host)57 std::string HashHost(const std::string& canonicalized_host) {
58 char hashed[crypto::kSHA256Length];
59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed));
60 return std::string(hashed, sizeof(hashed));
61 }
62
63 // Returns true if the intersection of |a| and |b| is not empty. If either
64 // |a| or |b| is empty, returns false.
HashesIntersect(const HashValueVector & a,const HashValueVector & b)65 bool HashesIntersect(const HashValueVector& a,
66 const HashValueVector& b) {
67 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) {
68 HashValueVector::const_iterator j =
69 std::find_if(b.begin(), b.end(), HashValuesEqual(*i));
70 if (j != b.end())
71 return true;
72 }
73 return false;
74 }
75
AddHash(const char * sha1_hash,HashValueVector * out)76 bool AddHash(const char* sha1_hash,
77 HashValueVector* out) {
78 HashValue hash(HASH_VALUE_SHA1);
79 memcpy(hash.data(), sha1_hash, hash.size());
80 out->push_back(hash);
81 return true;
82 }
83
84 } // namespace
85
TransportSecurityState()86 TransportSecurityState::TransportSecurityState()
87 : delegate_(NULL) {
88 DCHECK(CalledOnValidThread());
89 }
90
Iterator(const TransportSecurityState & state)91 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state)
92 : iterator_(state.enabled_hosts_.begin()),
93 end_(state.enabled_hosts_.end()) {
94 }
95
~Iterator()96 TransportSecurityState::Iterator::~Iterator() {}
97
SetDelegate(TransportSecurityState::Delegate * delegate)98 void TransportSecurityState::SetDelegate(
99 TransportSecurityState::Delegate* delegate) {
100 DCHECK(CalledOnValidThread());
101 delegate_ = delegate;
102 }
103
EnableHost(const std::string & host,const DomainState & state)104 void TransportSecurityState::EnableHost(const std::string& host,
105 const DomainState& state) {
106 DCHECK(CalledOnValidThread());
107
108 const std::string canonicalized_host = CanonicalizeHost(host);
109 if (canonicalized_host.empty())
110 return;
111
112 DomainState state_copy(state);
113 // No need to store this value since it is redundant. (|canonicalized_host|
114 // is the map key.)
115 state_copy.domain.clear();
116
117 enabled_hosts_[HashHost(canonicalized_host)] = state_copy;
118 DirtyNotify();
119 }
120
DeleteDynamicDataForHost(const std::string & host)121 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
122 DCHECK(CalledOnValidThread());
123
124 const std::string canonicalized_host = CanonicalizeHost(host);
125 if (canonicalized_host.empty())
126 return false;
127
128 DomainStateMap::iterator i = enabled_hosts_.find(
129 HashHost(canonicalized_host));
130 if (i != enabled_hosts_.end()) {
131 enabled_hosts_.erase(i);
132 DirtyNotify();
133 return true;
134 }
135 return false;
136 }
137
GetDomainState(const std::string & host,bool sni_enabled,DomainState * result)138 bool TransportSecurityState::GetDomainState(const std::string& host,
139 bool sni_enabled,
140 DomainState* result) {
141 DCHECK(CalledOnValidThread());
142
143 DomainState state;
144 const std::string canonicalized_host = CanonicalizeHost(host);
145 if (canonicalized_host.empty())
146 return false;
147
148 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled,
149 &state);
150 std::string canonicalized_preload = CanonicalizeHost(state.domain);
151 GetDynamicDomainState(host, &state);
152
153 base::Time current_time(base::Time::Now());
154
155 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
156 std::string host_sub_chunk(&canonicalized_host[i],
157 canonicalized_host.size() - i);
158 // Exact match of a preload always wins.
159 if (has_preload && host_sub_chunk == canonicalized_preload) {
160 *result = state;
161 return true;
162 }
163
164 DomainStateMap::iterator j =
165 enabled_hosts_.find(HashHost(host_sub_chunk));
166 if (j == enabled_hosts_.end())
167 continue;
168
169 if (current_time > j->second.upgrade_expiry &&
170 current_time > j->second.dynamic_spki_hashes_expiry) {
171 enabled_hosts_.erase(j);
172 DirtyNotify();
173 continue;
174 }
175
176 state = j->second;
177 state.domain = DNSDomainToString(host_sub_chunk);
178
179 // Succeed if we matched the domain exactly or if subdomain matches are
180 // allowed.
181 if (i == 0 || j->second.sts_include_subdomains ||
182 j->second.pkp_include_subdomains) {
183 *result = state;
184 return true;
185 }
186
187 return false;
188 }
189
190 return false;
191 }
192
ClearDynamicData()193 void TransportSecurityState::ClearDynamicData() {
194 DCHECK(CalledOnValidThread());
195 enabled_hosts_.clear();
196 }
197
DeleteAllDynamicDataSince(const base::Time & time)198 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) {
199 DCHECK(CalledOnValidThread());
200
201 bool dirtied = false;
202
203 DomainStateMap::iterator i = enabled_hosts_.begin();
204 while (i != enabled_hosts_.end()) {
205 if (i->second.created >= time) {
206 dirtied = true;
207 enabled_hosts_.erase(i++);
208 } else {
209 i++;
210 }
211 }
212
213 if (dirtied)
214 DirtyNotify();
215 }
216
~TransportSecurityState()217 TransportSecurityState::~TransportSecurityState() {
218 DCHECK(CalledOnValidThread());
219 }
220
DirtyNotify()221 void TransportSecurityState::DirtyNotify() {
222 DCHECK(CalledOnValidThread());
223
224 if (delegate_)
225 delegate_->StateIsDirty(this);
226 }
227
228 // static
CanonicalizeHost(const std::string & host)229 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) {
230 // We cannot perform the operations as detailed in the spec here as |host|
231 // has already undergone IDN processing before it reached us. Thus, we check
232 // that there are no invalid characters in the host and lowercase the result.
233
234 std::string new_host;
235 if (!DNSDomainFromDot(host, &new_host)) {
236 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole
237 // name is >255 bytes. However, search terms can have those properties.
238 return std::string();
239 }
240
241 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) {
242 const unsigned label_length = static_cast<unsigned>(new_host[i]);
243 if (!label_length)
244 break;
245
246 for (size_t j = 0; j < label_length; ++j) {
247 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]);
248 }
249 }
250
251 return new_host;
252 }
253
254 // |ReportUMAOnPinFailure| uses these to report which domain was associated
255 // with the public key pinning failure.
256 //
257 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new
258 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS).
259 enum SecondLevelDomainName {
260 DOMAIN_NOT_PINNED,
261
262 DOMAIN_GOOGLE_COM,
263 DOMAIN_ANDROID_COM,
264 DOMAIN_GOOGLE_ANALYTICS_COM,
265 DOMAIN_GOOGLEPLEX_COM,
266 DOMAIN_YTIMG_COM,
267 DOMAIN_GOOGLEUSERCONTENT_COM,
268 DOMAIN_YOUTUBE_COM,
269 DOMAIN_GOOGLEAPIS_COM,
270 DOMAIN_GOOGLEADSERVICES_COM,
271 DOMAIN_GOOGLECODE_COM,
272 DOMAIN_APPSPOT_COM,
273 DOMAIN_GOOGLESYNDICATION_COM,
274 DOMAIN_DOUBLECLICK_NET,
275 DOMAIN_GSTATIC_COM,
276 DOMAIN_GMAIL_COM,
277 DOMAIN_GOOGLEMAIL_COM,
278 DOMAIN_GOOGLEGROUPS_COM,
279
280 DOMAIN_TORPROJECT_ORG,
281
282 DOMAIN_TWITTER_COM,
283 DOMAIN_TWIMG_COM,
284
285 DOMAIN_AKAMAIHD_NET,
286
287 DOMAIN_TOR2WEB_ORG,
288
289 DOMAIN_YOUTU_BE,
290 DOMAIN_GOOGLECOMMERCE_COM,
291 DOMAIN_URCHIN_COM,
292 DOMAIN_GOO_GL,
293 DOMAIN_G_CO,
294 DOMAIN_GOOGLE_AC,
295 DOMAIN_GOOGLE_AD,
296 DOMAIN_GOOGLE_AE,
297 DOMAIN_GOOGLE_AF,
298 DOMAIN_GOOGLE_AG,
299 DOMAIN_GOOGLE_AM,
300 DOMAIN_GOOGLE_AS,
301 DOMAIN_GOOGLE_AT,
302 DOMAIN_GOOGLE_AZ,
303 DOMAIN_GOOGLE_BA,
304 DOMAIN_GOOGLE_BE,
305 DOMAIN_GOOGLE_BF,
306 DOMAIN_GOOGLE_BG,
307 DOMAIN_GOOGLE_BI,
308 DOMAIN_GOOGLE_BJ,
309 DOMAIN_GOOGLE_BS,
310 DOMAIN_GOOGLE_BY,
311 DOMAIN_GOOGLE_CA,
312 DOMAIN_GOOGLE_CAT,
313 DOMAIN_GOOGLE_CC,
314 DOMAIN_GOOGLE_CD,
315 DOMAIN_GOOGLE_CF,
316 DOMAIN_GOOGLE_CG,
317 DOMAIN_GOOGLE_CH,
318 DOMAIN_GOOGLE_CI,
319 DOMAIN_GOOGLE_CL,
320 DOMAIN_GOOGLE_CM,
321 DOMAIN_GOOGLE_CN,
322 DOMAIN_CO_AO,
323 DOMAIN_CO_BW,
324 DOMAIN_CO_CK,
325 DOMAIN_CO_CR,
326 DOMAIN_CO_HU,
327 DOMAIN_CO_ID,
328 DOMAIN_CO_IL,
329 DOMAIN_CO_IM,
330 DOMAIN_CO_IN,
331 DOMAIN_CO_JE,
332 DOMAIN_CO_JP,
333 DOMAIN_CO_KE,
334 DOMAIN_CO_KR,
335 DOMAIN_CO_LS,
336 DOMAIN_CO_MA,
337 DOMAIN_CO_MZ,
338 DOMAIN_CO_NZ,
339 DOMAIN_CO_TH,
340 DOMAIN_CO_TZ,
341 DOMAIN_CO_UG,
342 DOMAIN_CO_UK,
343 DOMAIN_CO_UZ,
344 DOMAIN_CO_VE,
345 DOMAIN_CO_VI,
346 DOMAIN_CO_ZA,
347 DOMAIN_CO_ZM,
348 DOMAIN_CO_ZW,
349 DOMAIN_COM_AF,
350 DOMAIN_COM_AG,
351 DOMAIN_COM_AI,
352 DOMAIN_COM_AR,
353 DOMAIN_COM_AU,
354 DOMAIN_COM_BD,
355 DOMAIN_COM_BH,
356 DOMAIN_COM_BN,
357 DOMAIN_COM_BO,
358 DOMAIN_COM_BR,
359 DOMAIN_COM_BY,
360 DOMAIN_COM_BZ,
361 DOMAIN_COM_CN,
362 DOMAIN_COM_CO,
363 DOMAIN_COM_CU,
364 DOMAIN_COM_CY,
365 DOMAIN_COM_DO,
366 DOMAIN_COM_EC,
367 DOMAIN_COM_EG,
368 DOMAIN_COM_ET,
369 DOMAIN_COM_FJ,
370 DOMAIN_COM_GE,
371 DOMAIN_COM_GH,
372 DOMAIN_COM_GI,
373 DOMAIN_COM_GR,
374 DOMAIN_COM_GT,
375 DOMAIN_COM_HK,
376 DOMAIN_COM_IQ,
377 DOMAIN_COM_JM,
378 DOMAIN_COM_JO,
379 DOMAIN_COM_KH,
380 DOMAIN_COM_KW,
381 DOMAIN_COM_LB,
382 DOMAIN_COM_LY,
383 DOMAIN_COM_MT,
384 DOMAIN_COM_MX,
385 DOMAIN_COM_MY,
386 DOMAIN_COM_NA,
387 DOMAIN_COM_NF,
388 DOMAIN_COM_NG,
389 DOMAIN_COM_NI,
390 DOMAIN_COM_NP,
391 DOMAIN_COM_NR,
392 DOMAIN_COM_OM,
393 DOMAIN_COM_PA,
394 DOMAIN_COM_PE,
395 DOMAIN_COM_PH,
396 DOMAIN_COM_PK,
397 DOMAIN_COM_PL,
398 DOMAIN_COM_PR,
399 DOMAIN_COM_PY,
400 DOMAIN_COM_QA,
401 DOMAIN_COM_RU,
402 DOMAIN_COM_SA,
403 DOMAIN_COM_SB,
404 DOMAIN_COM_SG,
405 DOMAIN_COM_SL,
406 DOMAIN_COM_SV,
407 DOMAIN_COM_TJ,
408 DOMAIN_COM_TN,
409 DOMAIN_COM_TR,
410 DOMAIN_COM_TW,
411 DOMAIN_COM_UA,
412 DOMAIN_COM_UY,
413 DOMAIN_COM_VC,
414 DOMAIN_COM_VE,
415 DOMAIN_COM_VN,
416 DOMAIN_GOOGLE_CV,
417 DOMAIN_GOOGLE_CZ,
418 DOMAIN_GOOGLE_DE,
419 DOMAIN_GOOGLE_DJ,
420 DOMAIN_GOOGLE_DK,
421 DOMAIN_GOOGLE_DM,
422 DOMAIN_GOOGLE_DZ,
423 DOMAIN_GOOGLE_EE,
424 DOMAIN_GOOGLE_ES,
425 DOMAIN_GOOGLE_FI,
426 DOMAIN_GOOGLE_FM,
427 DOMAIN_GOOGLE_FR,
428 DOMAIN_GOOGLE_GA,
429 DOMAIN_GOOGLE_GE,
430 DOMAIN_GOOGLE_GG,
431 DOMAIN_GOOGLE_GL,
432 DOMAIN_GOOGLE_GM,
433 DOMAIN_GOOGLE_GP,
434 DOMAIN_GOOGLE_GR,
435 DOMAIN_GOOGLE_GY,
436 DOMAIN_GOOGLE_HK,
437 DOMAIN_GOOGLE_HN,
438 DOMAIN_GOOGLE_HR,
439 DOMAIN_GOOGLE_HT,
440 DOMAIN_GOOGLE_HU,
441 DOMAIN_GOOGLE_IE,
442 DOMAIN_GOOGLE_IM,
443 DOMAIN_GOOGLE_INFO,
444 DOMAIN_GOOGLE_IQ,
445 DOMAIN_GOOGLE_IS,
446 DOMAIN_GOOGLE_IT,
447 DOMAIN_IT_AO,
448 DOMAIN_GOOGLE_JE,
449 DOMAIN_GOOGLE_JO,
450 DOMAIN_GOOGLE_JOBS,
451 DOMAIN_GOOGLE_JP,
452 DOMAIN_GOOGLE_KG,
453 DOMAIN_GOOGLE_KI,
454 DOMAIN_GOOGLE_KZ,
455 DOMAIN_GOOGLE_LA,
456 DOMAIN_GOOGLE_LI,
457 DOMAIN_GOOGLE_LK,
458 DOMAIN_GOOGLE_LT,
459 DOMAIN_GOOGLE_LU,
460 DOMAIN_GOOGLE_LV,
461 DOMAIN_GOOGLE_MD,
462 DOMAIN_GOOGLE_ME,
463 DOMAIN_GOOGLE_MG,
464 DOMAIN_GOOGLE_MK,
465 DOMAIN_GOOGLE_ML,
466 DOMAIN_GOOGLE_MN,
467 DOMAIN_GOOGLE_MS,
468 DOMAIN_GOOGLE_MU,
469 DOMAIN_GOOGLE_MV,
470 DOMAIN_GOOGLE_MW,
471 DOMAIN_GOOGLE_NE,
472 DOMAIN_NE_JP,
473 DOMAIN_GOOGLE_NET,
474 DOMAIN_GOOGLE_NL,
475 DOMAIN_GOOGLE_NO,
476 DOMAIN_GOOGLE_NR,
477 DOMAIN_GOOGLE_NU,
478 DOMAIN_OFF_AI,
479 DOMAIN_GOOGLE_PK,
480 DOMAIN_GOOGLE_PL,
481 DOMAIN_GOOGLE_PN,
482 DOMAIN_GOOGLE_PS,
483 DOMAIN_GOOGLE_PT,
484 DOMAIN_GOOGLE_RO,
485 DOMAIN_GOOGLE_RS,
486 DOMAIN_GOOGLE_RU,
487 DOMAIN_GOOGLE_RW,
488 DOMAIN_GOOGLE_SC,
489 DOMAIN_GOOGLE_SE,
490 DOMAIN_GOOGLE_SH,
491 DOMAIN_GOOGLE_SI,
492 DOMAIN_GOOGLE_SK,
493 DOMAIN_GOOGLE_SM,
494 DOMAIN_GOOGLE_SN,
495 DOMAIN_GOOGLE_SO,
496 DOMAIN_GOOGLE_ST,
497 DOMAIN_GOOGLE_TD,
498 DOMAIN_GOOGLE_TG,
499 DOMAIN_GOOGLE_TK,
500 DOMAIN_GOOGLE_TL,
501 DOMAIN_GOOGLE_TM,
502 DOMAIN_GOOGLE_TN,
503 DOMAIN_GOOGLE_TO,
504 DOMAIN_GOOGLE_TP,
505 DOMAIN_GOOGLE_TT,
506 DOMAIN_GOOGLE_US,
507 DOMAIN_GOOGLE_UZ,
508 DOMAIN_GOOGLE_VG,
509 DOMAIN_GOOGLE_VU,
510 DOMAIN_GOOGLE_WS,
511
512 DOMAIN_CHROMIUM_ORG,
513
514 DOMAIN_CRYPTO_CAT,
515 DOMAIN_LAVABIT_COM,
516
517 DOMAIN_GOOGLETAGMANAGER_COM,
518
519 // Boundary value for UMA_HISTOGRAM_ENUMERATION:
520 DOMAIN_NUM_EVENTS
521 };
522
523 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site.
524 // The validated certificate chain for the site must not include any of
525 // |excluded_hashes| and must include one or more of |required_hashes|.
526 struct PublicKeyPins {
527 const char* const* required_hashes;
528 const char* const* excluded_hashes;
529 };
530
531 struct HSTSPreload {
532 uint8 length;
533 bool include_subdomains;
534 char dns_name[38];
535 bool https_required;
536 PublicKeyPins pins;
537 SecondLevelDomainName second_level_domain_name;
538 };
539
HasPreload(const struct HSTSPreload * entries,size_t num_entries,const std::string & canonicalized_host,size_t i,TransportSecurityState::DomainState * out,bool * ret)540 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries,
541 const std::string& canonicalized_host, size_t i,
542 TransportSecurityState::DomainState* out, bool* ret) {
543 for (size_t j = 0; j < num_entries; j++) {
544 if (entries[j].length == canonicalized_host.size() - i &&
545 memcmp(entries[j].dns_name, &canonicalized_host[i],
546 entries[j].length) == 0) {
547 if (!entries[j].include_subdomains && i != 0) {
548 *ret = false;
549 } else {
550 out->sts_include_subdomains = entries[j].include_subdomains;
551 out->pkp_include_subdomains = entries[j].include_subdomains;
552 *ret = true;
553 if (!entries[j].https_required)
554 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT;
555 if (entries[j].pins.required_hashes) {
556 const char* const* sha1_hash = entries[j].pins.required_hashes;
557 while (*sha1_hash) {
558 AddHash(*sha1_hash, &out->static_spki_hashes);
559 sha1_hash++;
560 }
561 }
562 if (entries[j].pins.excluded_hashes) {
563 const char* const* sha1_hash = entries[j].pins.excluded_hashes;
564 while (*sha1_hash) {
565 AddHash(*sha1_hash, &out->bad_static_spki_hashes);
566 sha1_hash++;
567 }
568 }
569 }
570 return true;
571 }
572 }
573 return false;
574 }
575
576 #include "net/http/transport_security_state_static.h"
577
578 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|,
579 // or NULL if there is none. Prefers exact hostname matches to those that
580 // match only because HSTSPreload.include_subdomains is true.
581 //
582 // |canonicalized_host| should be the hostname as canonicalized by
583 // CanonicalizeHost.
GetHSTSPreload(const std::string & canonicalized_host,const struct HSTSPreload * entries,size_t num_entries)584 static const struct HSTSPreload* GetHSTSPreload(
585 const std::string& canonicalized_host,
586 const struct HSTSPreload* entries,
587 size_t num_entries) {
588 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
589 for (size_t j = 0; j < num_entries; j++) {
590 const struct HSTSPreload* entry = entries + j;
591
592 if (i != 0 && !entry->include_subdomains)
593 continue;
594
595 if (entry->length == canonicalized_host.size() - i &&
596 memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) {
597 return entry;
598 }
599 }
600 }
601
602 return NULL;
603 }
604
AddHSTSHeader(const std::string & host,const std::string & value)605 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
606 const std::string& value) {
607 DCHECK(CalledOnValidThread());
608
609 base::Time now = base::Time::Now();
610 base::TimeDelta max_age;
611 TransportSecurityState::DomainState domain_state;
612 GetDynamicDomainState(host, &domain_state);
613 if (ParseHSTSHeader(value, &max_age, &domain_state.sts_include_subdomains)) {
614 // Handle max-age == 0
615 if (max_age.InSeconds() == 0)
616 domain_state.upgrade_mode = DomainState::MODE_DEFAULT;
617 else
618 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
619 domain_state.created = now;
620 domain_state.upgrade_expiry = now + max_age;
621 EnableHost(host, domain_state);
622 return true;
623 }
624 return false;
625 }
626
AddHPKPHeader(const std::string & host,const std::string & value,const SSLInfo & ssl_info)627 bool TransportSecurityState::AddHPKPHeader(const std::string& host,
628 const std::string& value,
629 const SSLInfo& ssl_info) {
630 DCHECK(CalledOnValidThread());
631
632 base::Time now = base::Time::Now();
633 base::TimeDelta max_age;
634 TransportSecurityState::DomainState domain_state;
635 GetDynamicDomainState(host, &domain_state);
636 if (ParseHPKPHeader(value, ssl_info.public_key_hashes,
637 &max_age, &domain_state.pkp_include_subdomains,
638 &domain_state.dynamic_spki_hashes)) {
639 // TODO(palmer): http://crbug.com/243865 handle max-age == 0.
640 domain_state.created = now;
641 domain_state.dynamic_spki_hashes_expiry = now + max_age;
642 EnableHost(host, domain_state);
643 return true;
644 }
645 return false;
646 }
647
AddHSTS(const std::string & host,const base::Time & expiry,bool include_subdomains)648 bool TransportSecurityState::AddHSTS(const std::string& host,
649 const base::Time& expiry,
650 bool include_subdomains) {
651 DCHECK(CalledOnValidThread());
652
653 // Copy-and-modify the existing DomainState for this host (if any).
654 TransportSecurityState::DomainState domain_state;
655 const std::string canonicalized_host = CanonicalizeHost(host);
656 const std::string hashed_host = HashHost(canonicalized_host);
657 DomainStateMap::const_iterator i = enabled_hosts_.find(
658 hashed_host);
659 if (i != enabled_hosts_.end())
660 domain_state = i->second;
661
662 domain_state.created = base::Time::Now();
663 domain_state.sts_include_subdomains = include_subdomains;
664 domain_state.upgrade_expiry = expiry;
665 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
666 EnableHost(host, domain_state);
667 return true;
668 }
669
AddHPKP(const std::string & host,const base::Time & expiry,bool include_subdomains,const HashValueVector & hashes)670 bool TransportSecurityState::AddHPKP(const std::string& host,
671 const base::Time& expiry,
672 bool include_subdomains,
673 const HashValueVector& hashes) {
674 DCHECK(CalledOnValidThread());
675
676 // Copy-and-modify the existing DomainState for this host (if any).
677 TransportSecurityState::DomainState domain_state;
678 const std::string canonicalized_host = CanonicalizeHost(host);
679 const std::string hashed_host = HashHost(canonicalized_host);
680 DomainStateMap::const_iterator i = enabled_hosts_.find(
681 hashed_host);
682 if (i != enabled_hosts_.end())
683 domain_state = i->second;
684
685 domain_state.created = base::Time::Now();
686 domain_state.pkp_include_subdomains = include_subdomains;
687 domain_state.dynamic_spki_hashes_expiry = expiry;
688 domain_state.dynamic_spki_hashes = hashes;
689 EnableHost(host, domain_state);
690 return true;
691 }
692
693 // static
IsGooglePinnedProperty(const std::string & host,bool sni_enabled)694 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host,
695 bool sni_enabled) {
696 std::string canonicalized_host = CanonicalizeHost(host);
697 const struct HSTSPreload* entry =
698 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
699
700 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
701 return true;
702
703 if (sni_enabled) {
704 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
705 kNumPreloadedSNISTS);
706 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts)
707 return true;
708 }
709
710 return false;
711 }
712
713 // static
ReportUMAOnPinFailure(const std::string & host)714 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
715 std::string canonicalized_host = CanonicalizeHost(host);
716
717 const struct HSTSPreload* entry =
718 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
719
720 if (!entry) {
721 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS,
722 kNumPreloadedSNISTS);
723 }
724
725 if (!entry) {
726 // We don't care to report pin failures for dynamic pins.
727 return;
728 }
729
730 DCHECK(entry);
731 DCHECK(entry->pins.required_hashes);
732 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
733
734 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain",
735 entry->second_level_domain_name, DOMAIN_NUM_EVENTS);
736 }
737
738 // static
IsBuildTimely()739 bool TransportSecurityState::IsBuildTimely() {
740 const base::Time build_time = base::GetBuildTime();
741 // We consider built-in information to be timely for 10 weeks.
742 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
743 }
744
GetStaticDomainState(const std::string & canonicalized_host,bool sni_enabled,DomainState * out)745 bool TransportSecurityState::GetStaticDomainState(
746 const std::string& canonicalized_host,
747 bool sni_enabled,
748 DomainState* out) {
749 DCHECK(CalledOnValidThread());
750
751 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS;
752 out->sts_include_subdomains = false;
753 out->pkp_include_subdomains = false;
754
755 const bool is_build_timely = IsBuildTimely();
756
757 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
758 std::string host_sub_chunk(&canonicalized_host[i],
759 canonicalized_host.size() - i);
760 out->domain = DNSDomainToString(host_sub_chunk);
761 bool ret;
762 if (is_build_timely &&
763 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out,
764 &ret)) {
765 return ret;
766 }
767 if (sni_enabled &&
768 is_build_timely &&
769 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i,
770 out, &ret)) {
771 return ret;
772 }
773 }
774
775 return false;
776 }
777
GetDynamicDomainState(const std::string & host,DomainState * result)778 bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
779 DomainState* result) {
780 DCHECK(CalledOnValidThread());
781
782 DomainState state;
783 const std::string canonicalized_host = CanonicalizeHost(host);
784 if (canonicalized_host.empty())
785 return false;
786
787 base::Time current_time(base::Time::Now());
788
789 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) {
790 std::string host_sub_chunk(&canonicalized_host[i],
791 canonicalized_host.size() - i);
792 DomainStateMap::iterator j =
793 enabled_hosts_.find(HashHost(host_sub_chunk));
794 if (j == enabled_hosts_.end())
795 continue;
796
797 if (current_time > j->second.upgrade_expiry &&
798 current_time > j->second.dynamic_spki_hashes_expiry) {
799 enabled_hosts_.erase(j);
800 DirtyNotify();
801 continue;
802 }
803
804 state = j->second;
805 state.domain = DNSDomainToString(host_sub_chunk);
806
807 // Succeed if we matched the domain exactly or if subdomain matches are
808 // allowed.
809 if (i == 0 || j->second.sts_include_subdomains ||
810 j->second.pkp_include_subdomains) {
811 *result = state;
812 return true;
813 }
814
815 return false;
816 }
817
818 return false;
819 }
820
821
AddOrUpdateEnabledHosts(const std::string & hashed_host,const DomainState & state)822 void TransportSecurityState::AddOrUpdateEnabledHosts(
823 const std::string& hashed_host, const DomainState& state) {
824 DCHECK(CalledOnValidThread());
825 enabled_hosts_[hashed_host] = state;
826 }
827
DomainState()828 TransportSecurityState::DomainState::DomainState()
829 : upgrade_mode(MODE_DEFAULT),
830 created(base::Time::Now()),
831 sts_include_subdomains(false),
832 pkp_include_subdomains(false) {
833 }
834
~DomainState()835 TransportSecurityState::DomainState::~DomainState() {
836 }
837
CheckPublicKeyPins(const HashValueVector & hashes) const838 bool TransportSecurityState::DomainState::CheckPublicKeyPins(
839 const HashValueVector& hashes) const {
840 // Validate that hashes is not empty. By the time this code is called (in
841 // production), that should never happen, but it's good to be defensive.
842 // And, hashes *can* be empty in some test scenarios.
843 if (hashes.empty()) {
844 LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned "
845 "domain " << domain;
846 return false;
847 }
848
849 if (HashesIntersect(bad_static_spki_hashes, hashes)) {
850 LOG(ERROR) << "Rejecting public key chain for domain " << domain
851 << ". Validated chain: " << HashesToBase64String(hashes)
852 << ", matches one or more bad hashes: "
853 << HashesToBase64String(bad_static_spki_hashes);
854 return false;
855 }
856
857 // If there are no pins, then any valid chain is acceptable.
858 if (dynamic_spki_hashes.empty() && static_spki_hashes.empty())
859 return true;
860
861 if (HashesIntersect(dynamic_spki_hashes, hashes) ||
862 HashesIntersect(static_spki_hashes, hashes)) {
863 return true;
864 }
865
866 LOG(ERROR) << "Rejecting public key chain for domain " << domain
867 << ". Validated chain: " << HashesToBase64String(hashes)
868 << ", expected: " << HashesToBase64String(dynamic_spki_hashes)
869 << " or: " << HashesToBase64String(static_spki_hashes);
870 return false;
871 }
872
ShouldUpgradeToSSL() const873 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const {
874 return upgrade_mode == MODE_FORCE_HTTPS;
875 }
876
ShouldSSLErrorsBeFatal() const877 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const {
878 return true;
879 }
880
HasPublicKeyPins() const881 bool TransportSecurityState::DomainState::HasPublicKeyPins() const {
882 return static_spki_hashes.size() > 0 ||
883 bad_static_spki_hashes.size() > 0 ||
884 dynamic_spki_hashes.size() > 0;
885 }
886
887 } // namespace
888