OLD | NEW |
| (Empty) |
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/metrics/sparse_histogram.h" | |
26 #include "base/sha1.h" | |
27 #include "base/strings/string_number_conversions.h" | |
28 #include "base/strings/string_util.h" | |
29 #include "base/strings/utf_string_conversions.h" | |
30 #include "base/time/time.h" | |
31 #include "base/values.h" | |
32 #include "crypto/sha2.h" | |
33 #include "net/base/dns_util.h" | |
34 #include "net/cert/x509_cert_types.h" | |
35 #include "net/cert/x509_certificate.h" | |
36 #include "net/http/http_security_headers.h" | |
37 #include "net/ssl/ssl_info.h" | |
38 #include "url/gurl.h" | |
39 | |
40 #if defined(USE_OPENSSL) | |
41 #include "crypto/openssl_util.h" | |
42 #endif | |
43 | |
44 namespace net { | |
45 | |
46 namespace { | |
47 | |
48 std::string HashesToBase64String(const HashValueVector& hashes) { | |
49 std::string str; | |
50 for (size_t i = 0; i != hashes.size(); ++i) { | |
51 if (i != 0) | |
52 str += ","; | |
53 str += hashes[i].ToString(); | |
54 } | |
55 return str; | |
56 } | |
57 | |
58 std::string HashHost(const std::string& canonicalized_host) { | |
59 char hashed[crypto::kSHA256Length]; | |
60 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); | |
61 return std::string(hashed, sizeof(hashed)); | |
62 } | |
63 | |
64 // Returns true if the intersection of |a| and |b| is not empty. If either | |
65 // |a| or |b| is empty, returns false. | |
66 bool HashesIntersect(const HashValueVector& a, | |
67 const HashValueVector& b) { | |
68 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { | |
69 HashValueVector::const_iterator j = | |
70 std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); | |
71 if (j != b.end()) | |
72 return true; | |
73 } | |
74 return false; | |
75 } | |
76 | |
77 bool AddHash(const char* sha1_hash, | |
78 HashValueVector* out) { | |
79 HashValue hash(HASH_VALUE_SHA1); | |
80 memcpy(hash.data(), sha1_hash, hash.size()); | |
81 out->push_back(hash); | |
82 return true; | |
83 } | |
84 | |
85 } // namespace | |
86 | |
87 TransportSecurityState::TransportSecurityState() | |
88 : delegate_(NULL), enable_static_pins_(true) { | |
89 // Static pinning is only enabled for official builds to make sure that | |
90 // others don't end up with pins that cannot be easily updated. | |
91 #if !defined(OFFICIAL_BUILD) || defined(OS_ANDROID) || defined(OS_IOS) | |
92 enable_static_pins_ = false; | |
93 #endif | |
94 DCHECK(CalledOnValidThread()); | |
95 } | |
96 | |
97 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) | |
98 : iterator_(state.enabled_hosts_.begin()), | |
99 end_(state.enabled_hosts_.end()) { | |
100 } | |
101 | |
102 TransportSecurityState::Iterator::~Iterator() {} | |
103 | |
104 bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) { | |
105 DomainState state; | |
106 if (GetStaticDomainState(host, &state)) | |
107 return true; | |
108 return GetDynamicDomainState(host, &state); | |
109 } | |
110 | |
111 bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) { | |
112 DomainState dynamic_state; | |
113 if (GetDynamicDomainState(host, &dynamic_state)) | |
114 return dynamic_state.ShouldUpgradeToSSL(); | |
115 | |
116 DomainState static_state; | |
117 if (GetStaticDomainState(host, &static_state) && | |
118 static_state.ShouldUpgradeToSSL()) { | |
119 return true; | |
120 } | |
121 | |
122 return false; | |
123 } | |
124 | |
125 bool TransportSecurityState::CheckPublicKeyPins( | |
126 const std::string& host, | |
127 bool is_issued_by_known_root, | |
128 const HashValueVector& public_key_hashes, | |
129 std::string* pinning_failure_log) { | |
130 // Perform pin validation if, and only if, all these conditions obtain: | |
131 // | |
132 // * the server's certificate chain chains up to a known root (i.e. not a | |
133 // user-installed trust anchor); and | |
134 // * the server actually has public key pins. | |
135 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) { | |
136 return true; | |
137 } | |
138 | |
139 bool pins_are_valid = CheckPublicKeyPinsImpl( | |
140 host, public_key_hashes, pinning_failure_log); | |
141 if (!pins_are_valid) { | |
142 LOG(ERROR) << *pinning_failure_log; | |
143 ReportUMAOnPinFailure(host); | |
144 } | |
145 | |
146 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); | |
147 return pins_are_valid; | |
148 } | |
149 | |
150 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) { | |
151 DomainState dynamic_state; | |
152 if (GetDynamicDomainState(host, &dynamic_state)) | |
153 return dynamic_state.HasPublicKeyPins(); | |
154 | |
155 DomainState static_state; | |
156 if (GetStaticDomainState(host, &static_state)) { | |
157 if (static_state.HasPublicKeyPins()) | |
158 return true; | |
159 } | |
160 | |
161 return false; | |
162 } | |
163 | |
164 void TransportSecurityState::SetDelegate( | |
165 TransportSecurityState::Delegate* delegate) { | |
166 DCHECK(CalledOnValidThread()); | |
167 delegate_ = delegate; | |
168 } | |
169 | |
170 void TransportSecurityState::AddHSTSInternal( | |
171 const std::string& host, | |
172 TransportSecurityState::DomainState::UpgradeMode upgrade_mode, | |
173 const base::Time& expiry, | |
174 bool include_subdomains) { | |
175 DCHECK(CalledOnValidThread()); | |
176 | |
177 // Copy-and-modify the existing DomainState for this host (if any). | |
178 DomainState domain_state; | |
179 const std::string canonicalized_host = CanonicalizeHost(host); | |
180 const std::string hashed_host = HashHost(canonicalized_host); | |
181 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | |
182 if (i != enabled_hosts_.end()) | |
183 domain_state = i->second; | |
184 | |
185 domain_state.sts.last_observed = base::Time::Now(); | |
186 domain_state.sts.include_subdomains = include_subdomains; | |
187 domain_state.sts.expiry = expiry; | |
188 domain_state.sts.upgrade_mode = upgrade_mode; | |
189 EnableHost(host, domain_state); | |
190 } | |
191 | |
192 void TransportSecurityState::AddHPKPInternal(const std::string& host, | |
193 const base::Time& last_observed, | |
194 const base::Time& expiry, | |
195 bool include_subdomains, | |
196 const HashValueVector& hashes) { | |
197 DCHECK(CalledOnValidThread()); | |
198 | |
199 // Copy-and-modify the existing DomainState for this host (if any). | |
200 DomainState domain_state; | |
201 const std::string canonicalized_host = CanonicalizeHost(host); | |
202 const std::string hashed_host = HashHost(canonicalized_host); | |
203 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | |
204 if (i != enabled_hosts_.end()) | |
205 domain_state = i->second; | |
206 | |
207 domain_state.pkp.last_observed = last_observed; | |
208 domain_state.pkp.expiry = expiry; | |
209 domain_state.pkp.include_subdomains = include_subdomains; | |
210 domain_state.pkp.spki_hashes = hashes; | |
211 EnableHost(host, domain_state); | |
212 } | |
213 | |
214 void TransportSecurityState::EnableHost(const std::string& host, | |
215 const DomainState& state) { | |
216 DCHECK(CalledOnValidThread()); | |
217 | |
218 const std::string canonicalized_host = CanonicalizeHost(host); | |
219 if (canonicalized_host.empty()) | |
220 return; | |
221 | |
222 DomainState state_copy(state); | |
223 // No need to store this value since it is redundant. (|canonicalized_host| | |
224 // is the map key.) | |
225 state_copy.sts.domain.clear(); | |
226 state_copy.pkp.domain.clear(); | |
227 | |
228 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; | |
229 DirtyNotify(); | |
230 } | |
231 | |
232 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { | |
233 DCHECK(CalledOnValidThread()); | |
234 | |
235 const std::string canonicalized_host = CanonicalizeHost(host); | |
236 if (canonicalized_host.empty()) | |
237 return false; | |
238 | |
239 DomainStateMap::iterator i = enabled_hosts_.find( | |
240 HashHost(canonicalized_host)); | |
241 if (i != enabled_hosts_.end()) { | |
242 enabled_hosts_.erase(i); | |
243 DirtyNotify(); | |
244 return true; | |
245 } | |
246 return false; | |
247 } | |
248 | |
249 void TransportSecurityState::ClearDynamicData() { | |
250 DCHECK(CalledOnValidThread()); | |
251 enabled_hosts_.clear(); | |
252 } | |
253 | |
254 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { | |
255 DCHECK(CalledOnValidThread()); | |
256 | |
257 bool dirtied = false; | |
258 DomainStateMap::iterator i = enabled_hosts_.begin(); | |
259 while (i != enabled_hosts_.end()) { | |
260 // Clear STS and PKP state independently. | |
261 if (i->second.sts.last_observed >= time) { | |
262 dirtied = true; | |
263 i->second.sts.upgrade_mode = DomainState::MODE_DEFAULT; | |
264 } | |
265 if (i->second.pkp.last_observed >= time) { | |
266 dirtied = true; | |
267 i->second.pkp.spki_hashes.clear(); | |
268 i->second.pkp.expiry = base::Time(); | |
269 } | |
270 | |
271 // If both are now invalid, drop the entry altogether. | |
272 if (!i->second.ShouldUpgradeToSSL() && !i->second.HasPublicKeyPins()) { | |
273 dirtied = true; | |
274 enabled_hosts_.erase(i++); | |
275 continue; | |
276 } | |
277 | |
278 ++i; | |
279 } | |
280 | |
281 if (dirtied) | |
282 DirtyNotify(); | |
283 } | |
284 | |
285 TransportSecurityState::~TransportSecurityState() { | |
286 DCHECK(CalledOnValidThread()); | |
287 } | |
288 | |
289 void TransportSecurityState::DirtyNotify() { | |
290 DCHECK(CalledOnValidThread()); | |
291 | |
292 if (delegate_) | |
293 delegate_->StateIsDirty(this); | |
294 } | |
295 | |
296 // static | |
297 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { | |
298 // We cannot perform the operations as detailed in the spec here as |host| | |
299 // has already undergone IDN processing before it reached us. Thus, we check | |
300 // that there are no invalid characters in the host and lowercase the result. | |
301 | |
302 std::string new_host; | |
303 if (!DNSDomainFromDot(host, &new_host)) { | |
304 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole | |
305 // name is >255 bytes. However, search terms can have those properties. | |
306 return std::string(); | |
307 } | |
308 | |
309 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { | |
310 const unsigned label_length = static_cast<unsigned>(new_host[i]); | |
311 if (!label_length) | |
312 break; | |
313 | |
314 for (size_t j = 0; j < label_length; ++j) { | |
315 new_host[i + 1 + j] = static_cast<char>(tolower(new_host[i + 1 + j])); | |
316 } | |
317 } | |
318 | |
319 return new_host; | |
320 } | |
321 | |
322 // BitReader is a class that allows a bytestring to be read bit-by-bit. | |
323 class BitReader { | |
324 public: | |
325 BitReader(const uint8* bytes, size_t num_bits) | |
326 : bytes_(bytes), | |
327 num_bits_(num_bits), | |
328 num_bytes_((num_bits + 7) / 8), | |
329 current_byte_index_(0), | |
330 num_bits_used_(8) {} | |
331 | |
332 // Next sets |*out| to the next bit from the input. It returns false if no | |
333 // more bits are available or true otherwise. | |
334 bool Next(bool* out) { | |
335 if (num_bits_used_ == 8) { | |
336 if (current_byte_index_ >= num_bytes_) { | |
337 return false; | |
338 } | |
339 current_byte_ = bytes_[current_byte_index_++]; | |
340 num_bits_used_ = 0; | |
341 } | |
342 | |
343 *out = 1 & (current_byte_ >> (7 - num_bits_used_)); | |
344 num_bits_used_++; | |
345 return true; | |
346 } | |
347 | |
348 // Read sets the |num_bits| least-significant bits of |*out| to the value of | |
349 // the next |num_bits| bits from the input. It returns false if there are | |
350 // insufficient bits in the input or true otherwise. | |
351 bool Read(unsigned num_bits, uint32* out) { | |
352 DCHECK_LE(num_bits, 32u); | |
353 | |
354 uint32 ret = 0; | |
355 for (unsigned i = 0; i < num_bits; ++i) { | |
356 bool bit; | |
357 if (!Next(&bit)) { | |
358 return false; | |
359 } | |
360 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i); | |
361 } | |
362 | |
363 *out = ret; | |
364 return true; | |
365 } | |
366 | |
367 // Unary sets |*out| to the result of decoding a unary value from the input. | |
368 // It returns false if there were insufficient bits in the input and true | |
369 // otherwise. | |
370 bool Unary(size_t* out) { | |
371 size_t ret = 0; | |
372 | |
373 for (;;) { | |
374 bool bit; | |
375 if (!Next(&bit)) { | |
376 return false; | |
377 } | |
378 if (!bit) { | |
379 break; | |
380 } | |
381 ret++; | |
382 } | |
383 | |
384 *out = ret; | |
385 return true; | |
386 } | |
387 | |
388 // Seek sets the current offest in the input to bit number |offset|. It | |
389 // returns true if |offset| is within the range of the input and false | |
390 // otherwise. | |
391 bool Seek(size_t offset) { | |
392 if (offset >= num_bits_) { | |
393 return false; | |
394 } | |
395 current_byte_index_ = offset / 8; | |
396 current_byte_ = bytes_[current_byte_index_++]; | |
397 num_bits_used_ = offset % 8; | |
398 return true; | |
399 } | |
400 | |
401 private: | |
402 const uint8* const bytes_; | |
403 const size_t num_bits_; | |
404 const size_t num_bytes_; | |
405 // current_byte_index_ contains the current byte offset in |bytes_|. | |
406 size_t current_byte_index_; | |
407 // current_byte_ contains the current byte of the input. | |
408 uint8 current_byte_; | |
409 // num_bits_used_ contains the number of bits of |current_byte_| that have | |
410 // been read. | |
411 unsigned num_bits_used_; | |
412 }; | |
413 | |
414 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is | |
415 // simply encoded as a series of two-byte structures. The first byte determines | |
416 // the "0" pointer for that node and the second the "1" pointer. Each byte | |
417 // either has the MSB set, in which case the bottom 7 bits are the value for | |
418 // that position, or else the bottom seven bits contain the index of a node. | |
419 // | |
420 // The tree is decoded by walking rather than a table-driven approach. | |
421 class HuffmanDecoder { | |
422 public: | |
423 HuffmanDecoder(const uint8* tree, size_t tree_bytes) | |
424 : tree_(tree), | |
425 tree_bytes_(tree_bytes) {} | |
426 | |
427 bool Decode(BitReader* reader, char* out) { | |
428 const uint8* current = &tree_[tree_bytes_-2]; | |
429 | |
430 for (;;) { | |
431 bool bit; | |
432 if (!reader->Next(&bit)) { | |
433 return false; | |
434 } | |
435 | |
436 uint8 b = current[bit]; | |
437 if (b & 0x80) { | |
438 *out = static_cast<char>(b & 0x7f); | |
439 return true; | |
440 } | |
441 | |
442 unsigned offset = static_cast<unsigned>(b) * 2; | |
443 DCHECK_LT(offset, tree_bytes_); | |
444 if (offset >= tree_bytes_) { | |
445 return false; | |
446 } | |
447 | |
448 current = &tree_[offset]; | |
449 } | |
450 } | |
451 | |
452 private: | |
453 const uint8* const tree_; | |
454 const size_t tree_bytes_; | |
455 }; | |
456 | |
457 #include "net/http/transport_security_state_static.h" | |
458 | |
459 // PreloadResult is the result of resolving a specific name in the preloaded | |
460 // data. | |
461 struct PreloadResult { | |
462 uint32 pinset_id; | |
463 uint32 domain_id; | |
464 // hostname_offset contains the number of bytes from the start of the given | |
465 // hostname where the name of the matching entry starts. | |
466 size_t hostname_offset; | |
467 bool sts_include_subdomains; | |
468 bool pkp_include_subdomains; | |
469 bool force_https; | |
470 bool has_pins; | |
471 }; | |
472 | |
473 // DecodeHSTSPreloadRaw resolves |hostname| in the preloaded data. It returns | |
474 // false on internal error and true otherwise. After a successful return, | |
475 // |*out_found| is true iff a relevant entry has been found. If so, |*out| | |
476 // contains the details. | |
477 // | |
478 // Don't call this function, call DecodeHSTSPreload, below. | |
479 // | |
480 // Although this code should be robust, it never processes attacker-controlled | |
481 // data -- it only operates on the preloaded data built into the binary. | |
482 // | |
483 // The preloaded data is represented as a trie and matches the hostname | |
484 // backwards. Each node in the trie starts with a number of characters, which | |
485 // must match exactly. After that is a dispatch table which maps the next | |
486 // character in the hostname to another node in the trie. | |
487 // | |
488 // In the dispatch table, the zero character represents the "end of string" | |
489 // (which is the *beginning* of a hostname since we process it backwards). The | |
490 // value in that case is special -- rather than an offset to another trie node, | |
491 // it contains the HSTS information: whether subdomains are included, pinsets | |
492 // etc. If an "end of string" matches a period in the hostname then the | |
493 // information is remembered because, if no more specific node is found, then | |
494 // that information applies to the hostname. | |
495 // | |
496 // Dispatch tables are always given in order, but the "end of string" (zero) | |
497 // value always comes before an entry for '.'. | |
498 bool DecodeHSTSPreloadRaw(const std::string& hostname, | |
499 bool* out_found, | |
500 PreloadResult* out) { | |
501 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree)); | |
502 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits); | |
503 size_t bit_offset = kHSTSRootPosition; | |
504 static const char kEndOfString = 0; | |
505 static const char kEndOfTable = 127; | |
506 | |
507 *out_found = false; | |
508 | |
509 if (hostname.empty()) { | |
510 return true; | |
511 } | |
512 // hostname_offset contains one more than the index of the current character | |
513 // in the hostname that is being considered. It's one greater so that we can | |
514 // represent the position just before the beginning (with zero). | |
515 size_t hostname_offset = hostname.size(); | |
516 | |
517 for (;;) { | |
518 // Seek to the desired location. | |
519 if (!reader.Seek(bit_offset)) { | |
520 return false; | |
521 } | |
522 | |
523 // Decode the unary length of the common prefix. | |
524 size_t prefix_length; | |
525 if (!reader.Unary(&prefix_length)) { | |
526 return false; | |
527 } | |
528 | |
529 // Match each character in the prefix. | |
530 for (size_t i = 0; i < prefix_length; ++i) { | |
531 if (hostname_offset == 0) { | |
532 // We can't match the terminator with a prefix string. | |
533 return true; | |
534 } | |
535 | |
536 char c; | |
537 if (!huffman.Decode(&reader, &c)) { | |
538 return false; | |
539 } | |
540 if (hostname[hostname_offset - 1] != c) { | |
541 return true; | |
542 } | |
543 hostname_offset--; | |
544 } | |
545 | |
546 bool is_first_offset = true; | |
547 size_t current_offset = 0; | |
548 | |
549 // Next is the dispatch table. | |
550 for (;;) { | |
551 char c; | |
552 if (!huffman.Decode(&reader, &c)) { | |
553 return false; | |
554 } | |
555 if (c == kEndOfTable) { | |
556 // No exact match. | |
557 return true; | |
558 } | |
559 | |
560 if (c == kEndOfString) { | |
561 PreloadResult tmp; | |
562 if (!reader.Next(&tmp.sts_include_subdomains) || | |
563 !reader.Next(&tmp.force_https) || | |
564 !reader.Next(&tmp.has_pins)) { | |
565 return false; | |
566 } | |
567 | |
568 tmp.pkp_include_subdomains = tmp.sts_include_subdomains; | |
569 | |
570 if (tmp.has_pins) { | |
571 if (!reader.Read(4, &tmp.pinset_id) || | |
572 !reader.Read(9, &tmp.domain_id) || | |
573 (!tmp.sts_include_subdomains && | |
574 !reader.Next(&tmp.pkp_include_subdomains))) { | |
575 return false; | |
576 } | |
577 } | |
578 | |
579 tmp.hostname_offset = hostname_offset; | |
580 | |
581 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') { | |
582 *out_found = | |
583 tmp.sts_include_subdomains || tmp.pkp_include_subdomains; | |
584 *out = tmp; | |
585 | |
586 if (hostname_offset > 0) { | |
587 out->force_https &= tmp.sts_include_subdomains; | |
588 } else { | |
589 *out_found = true; | |
590 return true; | |
591 } | |
592 } | |
593 | |
594 continue; | |
595 } | |
596 | |
597 // The entries in a dispatch table are in order thus we can tell if there | |
598 // will be no match if the current character past the one that we want. | |
599 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) { | |
600 return true; | |
601 } | |
602 | |
603 if (is_first_offset) { | |
604 // The first offset is backwards from the current position. | |
605 uint32 jump_delta_bits; | |
606 uint32 jump_delta; | |
607 if (!reader.Read(5, &jump_delta_bits) || | |
608 !reader.Read(jump_delta_bits, &jump_delta)) { | |
609 return false; | |
610 } | |
611 | |
612 if (bit_offset < jump_delta) { | |
613 return false; | |
614 } | |
615 | |
616 current_offset = bit_offset - jump_delta; | |
617 is_first_offset = false; | |
618 } else { | |
619 // Subsequent offsets are forward from the target of the first offset. | |
620 uint32 is_long_jump; | |
621 if (!reader.Read(1, &is_long_jump)) { | |
622 return false; | |
623 } | |
624 | |
625 uint32 jump_delta; | |
626 if (!is_long_jump) { | |
627 if (!reader.Read(7, &jump_delta)) { | |
628 return false; | |
629 } | |
630 } else { | |
631 uint32 jump_delta_bits; | |
632 if (!reader.Read(4, &jump_delta_bits) || | |
633 !reader.Read(jump_delta_bits + 8, &jump_delta)) { | |
634 return false; | |
635 } | |
636 } | |
637 | |
638 current_offset += jump_delta; | |
639 if (current_offset >= bit_offset) { | |
640 return false; | |
641 } | |
642 } | |
643 | |
644 DCHECK_LT(0u, hostname_offset); | |
645 if (hostname[hostname_offset - 1] == c) { | |
646 bit_offset = current_offset; | |
647 hostname_offset--; | |
648 break; | |
649 } | |
650 } | |
651 } | |
652 } | |
653 | |
654 bool DecodeHSTSPreload(const std::string& hostname, | |
655 PreloadResult* out) { | |
656 bool found; | |
657 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) { | |
658 DCHECK(false) << "Internal error in DecodeHSTSPreloadRaw for hostname " | |
659 << hostname; | |
660 return false; | |
661 } | |
662 | |
663 return found; | |
664 } | |
665 | |
666 bool TransportSecurityState::AddHSTSHeader(const std::string& host, | |
667 const std::string& value) { | |
668 DCHECK(CalledOnValidThread()); | |
669 | |
670 base::Time now = base::Time::Now(); | |
671 base::TimeDelta max_age; | |
672 bool include_subdomains; | |
673 if (!ParseHSTSHeader(value, &max_age, &include_subdomains)) { | |
674 return false; | |
675 } | |
676 | |
677 // Handle max-age == 0. | |
678 DomainState::UpgradeMode upgrade_mode; | |
679 if (max_age.InSeconds() == 0) { | |
680 upgrade_mode = DomainState::MODE_DEFAULT; | |
681 } else { | |
682 upgrade_mode = DomainState::MODE_FORCE_HTTPS; | |
683 } | |
684 | |
685 AddHSTSInternal(host, upgrade_mode, now + max_age, include_subdomains); | |
686 return true; | |
687 } | |
688 | |
689 bool TransportSecurityState::AddHPKPHeader(const std::string& host, | |
690 const std::string& value, | |
691 const SSLInfo& ssl_info) { | |
692 DCHECK(CalledOnValidThread()); | |
693 | |
694 base::Time now = base::Time::Now(); | |
695 base::TimeDelta max_age; | |
696 bool include_subdomains; | |
697 HashValueVector spki_hashes; | |
698 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age, | |
699 &include_subdomains, &spki_hashes)) { | |
700 return false; | |
701 } | |
702 // Handle max-age == 0. | |
703 if (max_age.InSeconds() == 0) | |
704 spki_hashes.clear(); | |
705 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes); | |
706 return true; | |
707 } | |
708 | |
709 void TransportSecurityState::AddHSTS(const std::string& host, | |
710 const base::Time& expiry, | |
711 bool include_subdomains) { | |
712 DCHECK(CalledOnValidThread()); | |
713 AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry, | |
714 include_subdomains); | |
715 } | |
716 | |
717 void TransportSecurityState::AddHPKP(const std::string& host, | |
718 const base::Time& expiry, | |
719 bool include_subdomains, | |
720 const HashValueVector& hashes) { | |
721 DCHECK(CalledOnValidThread()); | |
722 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes); | |
723 } | |
724 | |
725 // static | |
726 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { | |
727 PreloadResult result; | |
728 return DecodeHSTSPreload(host, &result) && result.has_pins && | |
729 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts; | |
730 } | |
731 | |
732 // static | |
733 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { | |
734 PreloadResult result; | |
735 if (!DecodeHSTSPreload(host, &result) || | |
736 !result.has_pins) { | |
737 return; | |
738 } | |
739 | |
740 DCHECK(result.domain_id != DOMAIN_NOT_PINNED); | |
741 | |
742 UMA_HISTOGRAM_SPARSE_SLOWLY( | |
743 "Net.PublicKeyPinFailureDomain", result.domain_id); | |
744 } | |
745 | |
746 // static | |
747 bool TransportSecurityState::IsBuildTimely() { | |
748 // If the build metadata aren't embedded in the binary then we can't use the | |
749 // build time to determine if the build is timely, return true by default. If | |
750 // we're building an official build then keep using the build time, even if | |
751 // it's invalid it'd be a date in the past and this function will return | |
752 // false. | |
753 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD) | |
754 return true; | |
755 #else | |
756 const base::Time build_time = base::GetBuildTime(); | |
757 // We consider built-in information to be timely for 10 weeks. | |
758 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; | |
759 #endif | |
760 } | |
761 | |
762 bool TransportSecurityState::CheckPublicKeyPinsImpl( | |
763 const std::string& host, | |
764 const HashValueVector& hashes, | |
765 std::string* failure_log) { | |
766 DomainState dynamic_state; | |
767 if (GetDynamicDomainState(host, &dynamic_state)) | |
768 return dynamic_state.CheckPublicKeyPins(hashes, failure_log); | |
769 | |
770 DomainState static_state; | |
771 if (GetStaticDomainState(host, &static_state)) | |
772 return static_state.CheckPublicKeyPins(hashes, failure_log); | |
773 | |
774 // HasPublicKeyPins should have returned true in order for this method | |
775 // to have been called, so if we fall through to here, it's an error. | |
776 return false; | |
777 } | |
778 | |
779 bool TransportSecurityState::GetStaticDomainState(const std::string& host, | |
780 DomainState* out) const { | |
781 DCHECK(CalledOnValidThread()); | |
782 | |
783 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; | |
784 out->sts.include_subdomains = false; | |
785 out->pkp.include_subdomains = false; | |
786 | |
787 if (!IsBuildTimely()) | |
788 return false; | |
789 | |
790 PreloadResult result; | |
791 if (!DecodeHSTSPreload(host, &result)) | |
792 return false; | |
793 | |
794 out->sts.domain = host.substr(result.hostname_offset); | |
795 out->pkp.domain = out->sts.domain; | |
796 out->sts.include_subdomains = result.sts_include_subdomains; | |
797 out->sts.last_observed = base::GetBuildTime(); | |
798 out->sts.upgrade_mode = | |
799 TransportSecurityState::DomainState::MODE_DEFAULT; | |
800 if (result.force_https) { | |
801 out->sts.upgrade_mode = | |
802 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | |
803 } | |
804 | |
805 if (enable_static_pins_ && result.has_pins) { | |
806 out->pkp.include_subdomains = result.pkp_include_subdomains; | |
807 out->pkp.last_observed = base::GetBuildTime(); | |
808 | |
809 if (result.pinset_id >= arraysize(kPinsets)) | |
810 return false; | |
811 const Pinset *pinset = &kPinsets[result.pinset_id]; | |
812 | |
813 if (pinset->accepted_pins) { | |
814 const char* const* sha1_hash = pinset->accepted_pins; | |
815 while (*sha1_hash) { | |
816 AddHash(*sha1_hash, &out->pkp.spki_hashes); | |
817 sha1_hash++; | |
818 } | |
819 } | |
820 if (pinset->rejected_pins) { | |
821 const char* const* sha1_hash = pinset->rejected_pins; | |
822 while (*sha1_hash) { | |
823 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); | |
824 sha1_hash++; | |
825 } | |
826 } | |
827 } | |
828 | |
829 return true; | |
830 } | |
831 | |
832 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, | |
833 DomainState* result) { | |
834 DCHECK(CalledOnValidThread()); | |
835 | |
836 DomainState state; | |
837 const std::string canonicalized_host = CanonicalizeHost(host); | |
838 if (canonicalized_host.empty()) | |
839 return false; | |
840 | |
841 base::Time current_time(base::Time::Now()); | |
842 | |
843 bool found_sts = false; | |
844 bool found_pkp = false; | |
845 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | |
846 std::string host_sub_chunk(&canonicalized_host[i], | |
847 canonicalized_host.size() - i); | |
848 DomainStateMap::iterator j = | |
849 enabled_hosts_.find(HashHost(host_sub_chunk)); | |
850 if (j == enabled_hosts_.end()) | |
851 continue; | |
852 | |
853 // If both halves of the entry are invalid, drop it. | |
854 if (current_time > j->second.sts.expiry && | |
855 current_time > j->second.pkp.expiry) { | |
856 enabled_hosts_.erase(j); | |
857 DirtyNotify(); | |
858 continue; | |
859 } | |
860 | |
861 // If this is the most specific STS match, add it to the result. | |
862 if (!found_sts && (i == 0 || j->second.sts.include_subdomains) && | |
863 current_time <= j->second.sts.expiry && | |
864 j->second.ShouldUpgradeToSSL()) { | |
865 found_sts = true; | |
866 state.sts = j->second.sts; | |
867 state.sts.domain = DNSDomainToString(host_sub_chunk); | |
868 } | |
869 | |
870 // If this is the most specific PKP match, add it to the result. | |
871 if (!found_pkp && (i == 0 || j->second.pkp.include_subdomains) && | |
872 current_time <= j->second.pkp.expiry && j->second.HasPublicKeyPins()) { | |
873 found_pkp = true; | |
874 state.pkp = j->second.pkp; | |
875 state.pkp.domain = DNSDomainToString(host_sub_chunk); | |
876 } | |
877 | |
878 if (found_sts && found_pkp) | |
879 break; | |
880 } | |
881 | |
882 if (!found_sts && !found_pkp) | |
883 return false; | |
884 | |
885 *result = state; | |
886 return true; | |
887 } | |
888 | |
889 void TransportSecurityState::AddOrUpdateEnabledHosts( | |
890 const std::string& hashed_host, const DomainState& state) { | |
891 DCHECK(CalledOnValidThread()); | |
892 enabled_hosts_[hashed_host] = state; | |
893 } | |
894 | |
895 TransportSecurityState::DomainState::DomainState() { | |
896 sts.upgrade_mode = MODE_DEFAULT; | |
897 sts.include_subdomains = false; | |
898 pkp.include_subdomains = false; | |
899 } | |
900 | |
901 TransportSecurityState::DomainState::~DomainState() { | |
902 } | |
903 | |
904 bool TransportSecurityState::DomainState::CheckPublicKeyPins( | |
905 const HashValueVector& hashes, std::string* failure_log) const { | |
906 // Validate that hashes is not empty. By the time this code is called (in | |
907 // production), that should never happen, but it's good to be defensive. | |
908 // And, hashes *can* be empty in some test scenarios. | |
909 if (hashes.empty()) { | |
910 failure_log->append( | |
911 "Rejecting empty public key chain for public-key-pinned domains: " + | |
912 pkp.domain); | |
913 return false; | |
914 } | |
915 | |
916 if (HashesIntersect(pkp.bad_spki_hashes, hashes)) { | |
917 failure_log->append("Rejecting public key chain for domain " + pkp.domain + | |
918 ". Validated chain: " + HashesToBase64String(hashes) + | |
919 ", matches one or more bad hashes: " + | |
920 HashesToBase64String(pkp.bad_spki_hashes)); | |
921 return false; | |
922 } | |
923 | |
924 // If there are no pins, then any valid chain is acceptable. | |
925 if (pkp.spki_hashes.empty()) | |
926 return true; | |
927 | |
928 if (HashesIntersect(pkp.spki_hashes, hashes)) { | |
929 return true; | |
930 } | |
931 | |
932 failure_log->append("Rejecting public key chain for domain " + pkp.domain + | |
933 ". Validated chain: " + HashesToBase64String(hashes) + | |
934 ", expected: " + HashesToBase64String(pkp.spki_hashes)); | |
935 return false; | |
936 } | |
937 | |
938 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { | |
939 return sts.upgrade_mode == MODE_FORCE_HTTPS; | |
940 } | |
941 | |
942 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { | |
943 // Both HSTS and HPKP cause fatal SSL errors, so enable this on the presense | |
944 // of either. (If neither is active, no DomainState will be returned.) | |
945 return true; | |
946 } | |
947 | |
948 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { | |
949 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; | |
950 } | |
951 | |
952 TransportSecurityState::DomainState::STSState::STSState() { | |
953 } | |
954 | |
955 TransportSecurityState::DomainState::STSState::~STSState() { | |
956 } | |
957 | |
958 TransportSecurityState::DomainState::PKPState::PKPState() { | |
959 } | |
960 | |
961 TransportSecurityState::DomainState::PKPState::~PKPState() { | |
962 } | |
963 | |
964 } // namespace | |
OLD | NEW |