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