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