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