OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/transport_security_state.h" | 5 #include "net/http/transport_security_state.h" |
6 | 6 |
7 #if defined(USE_OPENSSL) | 7 #if defined(USE_OPENSSL) |
8 #include <openssl/ecdsa.h> | 8 #include <openssl/ecdsa.h> |
9 #include <openssl/ssl.h> | 9 #include <openssl/ssl.h> |
10 #else // !defined(USE_OPENSSL) | 10 #else // !defined(USE_OPENSSL) |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 break; | 263 break; |
264 | 264 |
265 for (size_t j = 0; j < label_length; ++j) { | 265 for (size_t j = 0; j < label_length; ++j) { |
266 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); | 266 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); |
267 } | 267 } |
268 } | 268 } |
269 | 269 |
270 return new_host; | 270 return new_host; |
271 } | 271 } |
272 | 272 |
273 // |ReportUMAOnPinFailure| uses these to report which domain was associated | 273 // BitReader is a class that allows a bytestring to be read bit-by-bit. |
274 // with the public key pinning failure. | 274 class BitReader { |
275 // | 275 public: |
276 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new | 276 BitReader(const uint8 *bytes, size_t num_bits) |
palmer
2014/10/02 20:26:36
Style nit: "const uint8* bytes" (throughout).
agl
2014/10/03 00:01:20
Done.
| |
277 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS). | 277 : bytes_(bytes), |
278 enum SecondLevelDomainName { | 278 num_bits_(num_bits), |
279 DOMAIN_NOT_PINNED, | 279 num_bytes_((num_bits + 7) / 8), |
280 | 280 used_bytes_(0), |
281 DOMAIN_GOOGLE_COM, | 281 current_used_(8) {} |
282 DOMAIN_ANDROID_COM, | 282 |
283 DOMAIN_GOOGLE_ANALYTICS_COM, | 283 // Next sets |*out| to the next bit from the input. It returns false if no |
284 DOMAIN_GOOGLEPLEX_COM, | 284 // more bits are available or true otherwise. |
285 DOMAIN_YTIMG_COM, | 285 bool Next(bool *out) { |
286 DOMAIN_GOOGLEUSERCONTENT_COM, | 286 if (current_used_ == 8) { |
287 DOMAIN_YOUTUBE_COM, | 287 if (used_bytes_ >= num_bytes_) { |
288 DOMAIN_GOOGLEAPIS_COM, | 288 return false; |
289 DOMAIN_GOOGLEADSERVICES_COM, | 289 } |
290 DOMAIN_GOOGLECODE_COM, | 290 current_ = bytes_[used_bytes_++]; |
291 DOMAIN_APPSPOT_COM, | 291 current_used_ = 0; |
292 DOMAIN_GOOGLESYNDICATION_COM, | 292 } |
293 DOMAIN_DOUBLECLICK_NET, | 293 |
294 DOMAIN_GSTATIC_COM, | 294 *out = 1 & (current_ >> (7 - current_used_)); |
295 DOMAIN_GMAIL_COM, | 295 current_used_++; |
296 DOMAIN_GOOGLEMAIL_COM, | 296 return true; |
297 DOMAIN_GOOGLEGROUPS_COM, | 297 } |
298 | 298 |
299 DOMAIN_TORPROJECT_ORG, | 299 // Read sets the |num_bits| least-significant bits of |*out| to the value of |
300 | 300 // the next |num_bits| bits from the input. It returns false if there are |
301 DOMAIN_TWITTER_COM, | 301 // insufficient bits in the input or true otherwise. |
302 DOMAIN_TWIMG_COM, | 302 bool Read(unsigned num_bits, uint32 *out) { |
303 | 303 DCHECK_LE(num_bits, 32u); |
304 DOMAIN_AKAMAIHD_NET, | 304 |
305 | 305 uint32 ret = 0; |
306 DOMAIN_TOR2WEB_ORG, | 306 for (unsigned i = 0; i < num_bits; i++) { |
palmer
2014/10/02 20:26:36
Style nit: Chromium style is pre-increment (here a
agl
2014/10/03 00:01:20
Done.
| |
307 | 307 bool bit; |
308 DOMAIN_YOUTU_BE, | 308 if (!Next(&bit)) { |
309 DOMAIN_GOOGLECOMMERCE_COM, | 309 return false; |
310 DOMAIN_URCHIN_COM, | 310 } |
311 DOMAIN_GOO_GL, | 311 ret |= static_cast<uint32>(bit) << (num_bits - 1 - i); |
312 DOMAIN_G_CO, | 312 } |
313 DOMAIN_GOOGLE_AC, | 313 |
314 DOMAIN_GOOGLE_AD, | 314 *out = ret; |
315 DOMAIN_GOOGLE_AE, | 315 return true; |
316 DOMAIN_GOOGLE_AF, | 316 } |
317 DOMAIN_GOOGLE_AG, | 317 |
318 DOMAIN_GOOGLE_AM, | 318 // Unary sets |*out| to the result of decoding a unary value from the input. |
319 DOMAIN_GOOGLE_AS, | 319 // It returns false if there were insufficient bits in the input and true |
320 DOMAIN_GOOGLE_AT, | 320 // otherwise. |
321 DOMAIN_GOOGLE_AZ, | 321 bool Unary(size_t *out) { |
322 DOMAIN_GOOGLE_BA, | 322 size_t ret = 0; |
323 DOMAIN_GOOGLE_BE, | 323 |
324 DOMAIN_GOOGLE_BF, | 324 for (;;) { |
325 DOMAIN_GOOGLE_BG, | 325 bool bit; |
326 DOMAIN_GOOGLE_BI, | 326 if (!Next(&bit)) { |
327 DOMAIN_GOOGLE_BJ, | 327 return false; |
328 DOMAIN_GOOGLE_BS, | 328 } |
329 DOMAIN_GOOGLE_BY, | 329 if (!bit) { |
330 DOMAIN_GOOGLE_CA, | 330 break; |
331 DOMAIN_GOOGLE_CAT, | 331 } |
332 DOMAIN_GOOGLE_CC, | 332 ret++; |
333 DOMAIN_GOOGLE_CD, | 333 } |
334 DOMAIN_GOOGLE_CF, | 334 |
335 DOMAIN_GOOGLE_CG, | 335 *out = ret; |
336 DOMAIN_GOOGLE_CH, | 336 return true; |
337 DOMAIN_GOOGLE_CI, | 337 } |
338 DOMAIN_GOOGLE_CL, | 338 |
339 DOMAIN_GOOGLE_CM, | 339 // Seek sets the current offest in the input to bit number |offset|. It |
340 DOMAIN_GOOGLE_CN, | 340 // returns true if |offset| is within the range of the input and false |
341 DOMAIN_CO_AO, | 341 // otherwise. |
342 DOMAIN_CO_BW, | 342 bool Seek(size_t offset) { |
343 DOMAIN_CO_CK, | 343 if (offset >= num_bits_) { |
344 DOMAIN_CO_CR, | 344 return false; |
345 DOMAIN_CO_HU, | 345 } |
346 DOMAIN_CO_ID, | 346 used_bytes_ = offset / 8; |
347 DOMAIN_CO_IL, | 347 current_ = bytes_[used_bytes_++]; |
348 DOMAIN_CO_IM, | 348 current_used_ = offset % 8; |
349 DOMAIN_CO_IN, | 349 return true; |
350 DOMAIN_CO_JE, | 350 } |
351 DOMAIN_CO_JP, | 351 |
352 DOMAIN_CO_KE, | 352 private: |
353 DOMAIN_CO_KR, | 353 const uint8 *const bytes_; |
354 DOMAIN_CO_LS, | 354 const size_t num_bits_; |
355 DOMAIN_CO_MA, | 355 const size_t num_bytes_; |
356 DOMAIN_CO_MZ, | 356 // used_bytes_ contains the current byte offset in |bytes_|. |
357 DOMAIN_CO_NZ, | 357 size_t used_bytes_; |
358 DOMAIN_CO_TH, | 358 // current_ contains the current byte of the input. |
359 DOMAIN_CO_TZ, | 359 uint8 current_; |
palmer
2014/10/02 20:26:36
Nit: I might name this |current_byte_|, and name |
agl
2014/10/03 00:01:20
Done.
| |
360 DOMAIN_CO_UG, | 360 // current_used_ contains the number of bits of |current_| that have been |
361 DOMAIN_CO_UK, | 361 // read. |
362 DOMAIN_CO_UZ, | 362 unsigned current_used_; |
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 }; | 363 }; |
546 | 364 |
547 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. | 365 // HuffmanDecoder is a very simple Huffman reader. The input Huffman tree is |
548 // The validated certificate chain for the site must not include any of | 366 // simply encoded as a series of two-byte structures. The first byte determines |
549 // |excluded_hashes| and must include one or more of |required_hashes|. | 367 // the "0" pointer for that node and the second the "1" pointer. Each byte |
550 struct PublicKeyPins { | 368 // either has the MSB set, in which case the bottom 7 bits are the value for |
551 const char* const* required_hashes; | 369 // that position, or else the bottom seven bits contain the index of a node. |
552 const char* const* excluded_hashes; | 370 // |
371 // The tree is decoded by walking rather than a table-driven approach. | |
372 class HuffmanDecoder { | |
373 public: | |
374 HuffmanDecoder(const uint8 *tree, size_t tree_bytes) | |
375 : tree_(tree), | |
376 tree_bytes_(tree_bytes) {} | |
377 | |
378 bool Decode(BitReader *reader, char *out) { | |
379 const uint8 *current = &tree_[tree_bytes_-2]; | |
380 | |
381 for (;;) { | |
382 bool bit; | |
383 if (!reader->Next(&bit)) { | |
384 return false; | |
385 } | |
386 | |
387 uint8 b = current[bit]; | |
388 if (b & 0x80) { | |
389 *out = static_cast<char>(b & 0x7f); | |
390 return true; | |
391 } | |
392 | |
393 unsigned offset = static_cast<unsigned>(b) * 2; | |
394 DCHECK_LT(offset, tree_bytes_); | |
395 if (offset >= tree_bytes_) { | |
396 return false; | |
397 } | |
398 | |
399 current = &tree_[offset]; | |
400 } | |
401 } | |
402 | |
403 private: | |
404 const uint8 *const tree_; | |
405 const size_t tree_bytes_; | |
553 }; | 406 }; |
554 | 407 |
555 struct HSTSPreload { | 408 #include "net/http/transport_security_state_static.h" |
556 uint8 length; | 409 |
410 // PreloadResult is the result of resolving a specific name in the preloaded | |
411 // data. | |
412 struct PreloadResult { | |
557 bool include_subdomains; | 413 bool include_subdomains; |
558 char dns_name[38]; | 414 bool force_https; |
559 bool https_required; | 415 bool has_pins; |
560 PublicKeyPins pins; | 416 uint32 pinset_id; |
palmer
2014/10/02 20:26:35
Nit: Maybe we could pack this struct every-so-slig
agl
2014/10/03 00:01:20
I've moved the bools to the end but I don't think
| |
561 SecondLevelDomainName second_level_domain_name; | 417 uint32 domain_id; |
418 // hostname_offset contains the number of bytes from the start of the given | |
419 // hostname where the name of the matching entry starts. | |
420 size_t hostname_offset; | |
562 }; | 421 }; |
563 | 422 |
564 static bool HasPreload(const struct HSTSPreload* entries, | 423 // DecodeHSTSPreload resolves |hostname| in the preloaded data. It returns |
565 size_t num_entries, | 424 // false on internal error and true otherwise. After a successful return, |
palmer
2014/10/02 20:26:36
Would any internal errors be due to bugs? What are
agl
2014/10/03 00:01:20
Log the fact, essentially. However, you're correct
| |
566 const std::string& canonicalized_host, | 425 // |*out_found| is true iff a relevant entry has been found. If so, |*out| |
567 size_t i, | 426 // contains the details. |
568 bool enable_static_pins, | 427 // |
569 TransportSecurityState::DomainState* out, | 428 // Although this code should be robust, it never processes attacker-controlled |
570 bool* ret) { | 429 // data -- it only operates on the preloaded data built into the binary. |
571 for (size_t j = 0; j < num_entries; j++) { | 430 // |
572 if (entries[j].length == canonicalized_host.size() - i && | 431 // The preloaded data is represented as a trie and matches the hostname |
573 memcmp(entries[j].dns_name, &canonicalized_host[i], | 432 // backwards. Each node in the trie starts with a number of characters, which |
574 entries[j].length) == 0) { | 433 // must match exactly. After that is a dispatch table which maps the next |
575 if (!entries[j].include_subdomains && i != 0) { | 434 // character in the hostname to another node in the trie. |
576 *ret = false; | 435 // |
436 // In the disable table, the zero character represents the "end of string" | |
palmer
2014/10/02 20:26:35
Typo: "dispatch table"?
agl
2014/10/03 00:01:20
Done.
| |
437 // (which is the *beginning* of a hostname since we process it backwards). The | |
438 // value in that case is special -- rather than an offset to another trie node, | |
439 // it contains the HSTS information: whether subdomains are included, pinsets | |
440 // etc. If an "end of string" matches a period in the hostname then the | |
441 // information is remembered because, if no more specific node is found, then | |
442 // that information applies to the hostname. | |
443 // | |
444 // Dispatch tables are always given in order, but the "end of string" (zero) | |
445 // value always comes before an entry for '.'. | |
446 bool DecodeHSTSPreload(const std::string& hostname, | |
447 bool* out_found, | |
448 PreloadResult* out) { | |
449 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree)); | |
450 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits); | |
451 size_t bit_offset = kHSTSRootPosition; | |
452 static const char kEndOfString = 0; | |
453 static const char kEndOfTable = 127; | |
454 | |
455 *out_found = false; | |
456 | |
457 if (hostname.empty()) { | |
458 return true; | |
459 } | |
460 // hostname_offset contains one more than the index of the current character | |
461 // in the hostname that is being considered. It's one greater so that we can | |
462 // represent the position just before the beginning (with zero). | |
463 size_t hostname_offset = hostname.size(); | |
464 | |
465 for (;;) { | |
466 // Seek to the desired location. | |
467 if (!reader.Seek(bit_offset)) { | |
468 return false; | |
469 } | |
470 | |
471 // Decode the unary length of the common prefix. | |
472 size_t prefix_length; | |
473 if (!reader.Unary(&prefix_length)) { | |
474 return false; | |
475 } | |
476 | |
477 // Match each character in the prefix. | |
478 for (size_t i = 0; i < prefix_length; i++) { | |
479 if (hostname_offset == 0) { | |
480 // We can't match the terminator with a prefix string. | |
481 return true; | |
482 } | |
483 | |
484 char c; | |
485 if (!huffman.Decode(&reader, &c)) { | |
486 return false; | |
487 } | |
488 if (hostname[hostname_offset - 1] != c) { | |
489 return true; | |
490 } | |
491 hostname_offset--; | |
492 } | |
493 | |
494 bool is_first_offset = true; | |
495 size_t current_offset = 0; | |
496 | |
497 // Next is the dispatch table. | |
498 for (;;) { | |
499 char c; | |
500 if (!huffman.Decode(&reader, &c)) { | |
501 return false; | |
502 } | |
503 if (c == kEndOfTable) { | |
504 // No exact match. | |
505 return true; | |
506 } | |
507 | |
508 if (c == kEndOfString) { | |
509 PreloadResult tmp; | |
510 if (!reader.Next(&tmp.include_subdomains) || | |
511 !reader.Next(&tmp.force_https) || | |
512 !reader.Next(&tmp.has_pins)) { | |
513 return false; | |
514 } | |
515 | |
516 if (tmp.has_pins) { | |
517 if (!reader.Read(4, &tmp.pinset_id) || | |
518 !reader.Read(9, &tmp.domain_id)) { | |
519 return false; | |
520 } | |
521 } | |
522 | |
523 tmp.hostname_offset = hostname_offset; | |
524 | |
525 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') { | |
526 *out_found = tmp.include_subdomains; | |
527 *out = tmp; | |
528 } | |
529 | |
530 if (hostname_offset == 0) { | |
531 *out_found = true; | |
532 return true; | |
533 } | |
534 | |
535 continue; | |
536 } | |
537 | |
538 // The entries in a dispatch table are in order thus we can tell if there | |
539 // will be no match if the current character past the one that we want. | |
540 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) { | |
541 return true; | |
542 } | |
543 | |
544 if (is_first_offset) { | |
545 // The first offset is backwards from the current position. | |
546 uint32 jump_delta_bits; | |
547 uint32 jump_delta; | |
548 if (!reader.Read(5, &jump_delta_bits) || | |
549 !reader.Read(jump_delta_bits, &jump_delta)) { | |
550 return false; | |
551 } | |
552 | |
553 if (bit_offset <= jump_delta) { | |
554 return false; | |
555 } | |
556 | |
557 current_offset = bit_offset - jump_delta; | |
558 is_first_offset = false; | |
577 } else { | 559 } else { |
578 out->sts.include_subdomains = entries[j].include_subdomains; | 560 // Subsequent offsets are forward from the target of the first offset. |
579 out->sts.last_observed = base::GetBuildTime(); | 561 uint32 is_long_jump; |
580 *ret = true; | 562 if (!reader.Read(1, &is_long_jump)) { |
581 out->sts.upgrade_mode = | 563 return false; |
582 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | 564 } |
583 if (!entries[j].https_required) | 565 |
584 out->sts.upgrade_mode = | 566 uint32 jump_delta; |
585 TransportSecurityState::DomainState::MODE_DEFAULT; | 567 if (!is_long_jump) { |
586 | 568 if (!reader.Read(7, &jump_delta)) { |
587 if (enable_static_pins) { | 569 return false; |
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 } | 570 } |
597 if (entries[j].pins.excluded_hashes) { | 571 } else { |
598 const char* const* sha1_hash = entries[j].pins.excluded_hashes; | 572 uint32 jump_delta_bits; |
599 while (*sha1_hash) { | 573 if (!reader.Read(4, &jump_delta_bits) || |
600 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); | 574 !reader.Read(jump_delta_bits + 8, &jump_delta)) { |
601 sha1_hash++; | 575 return false; |
602 } | |
603 } | 576 } |
604 } | 577 } |
605 } | 578 |
606 return true; | 579 current_offset += jump_delta; |
607 } | 580 if (current_offset >= bit_offset) { |
608 } | 581 return false; |
609 return false; | 582 } |
583 } | |
584 | |
585 DCHECK_LT(0u, hostname_offset); | |
586 if (hostname[hostname_offset - 1] == c) { | |
587 bit_offset = current_offset; | |
588 hostname_offset--; | |
589 break; | |
590 } | |
591 } | |
592 } | |
610 } | 593 } |
611 | 594 |
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. | |
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 | |
641 bool TransportSecurityState::AddHSTSHeader(const std::string& host, | 595 bool TransportSecurityState::AddHSTSHeader(const std::string& host, |
642 const std::string& value) { | 596 const std::string& value) { |
643 DCHECK(CalledOnValidThread()); | 597 DCHECK(CalledOnValidThread()); |
644 | 598 |
645 base::Time now = base::Time::Now(); | 599 base::Time now = base::Time::Now(); |
646 base::TimeDelta max_age; | 600 base::TimeDelta max_age; |
647 TransportSecurityState::DomainState domain_state; | 601 TransportSecurityState::DomainState domain_state; |
648 GetDynamicDomainState(host, &domain_state); | 602 GetDynamicDomainState(host, &domain_state); |
649 if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) { | 603 if (ParseHSTSHeader(value, &max_age, &domain_state.sts.include_subdomains)) { |
650 // Handle max-age == 0. | 604 // Handle max-age == 0. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
725 domain_state.pkp.last_observed = base::Time::Now(); | 679 domain_state.pkp.last_observed = base::Time::Now(); |
726 domain_state.pkp.include_subdomains = include_subdomains; | 680 domain_state.pkp.include_subdomains = include_subdomains; |
727 domain_state.pkp.expiry = expiry; | 681 domain_state.pkp.expiry = expiry; |
728 domain_state.pkp.spki_hashes = hashes; | 682 domain_state.pkp.spki_hashes = hashes; |
729 EnableHost(host, domain_state); | 683 EnableHost(host, domain_state); |
730 return true; | 684 return true; |
731 } | 685 } |
732 | 686 |
733 // static | 687 // static |
734 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { | 688 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { |
735 std::string canonicalized_host = CanonicalizeHost(host); | 689 bool found; |
736 const struct HSTSPreload* entry = | 690 PreloadResult result; |
737 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); | 691 return DecodeHSTSPreload(host, &found, &result) && found && result.has_pins && |
738 | 692 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts; |
739 return entry && entry->pins.required_hashes == kGoogleAcceptableCerts; | |
740 } | 693 } |
741 | 694 |
742 // static | 695 // static |
743 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { | 696 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { |
744 std::string canonicalized_host = CanonicalizeHost(host); | 697 bool found; |
745 | 698 PreloadResult result; |
746 const struct HSTSPreload* entry = | 699 if (!DecodeHSTSPreload(host, &found, &result) || |
747 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); | 700 !found || |
748 | 701 !result.has_pins) { |
749 if (!entry) { | |
750 // We don't care to report pin failures for dynamic pins. | |
751 return; | 702 return; |
752 } | 703 } |
753 | 704 |
754 DCHECK(entry); | 705 DCHECK(result.domain_id != DOMAIN_NOT_PINNED); |
755 DCHECK(entry->pins.required_hashes); | |
756 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); | |
757 | 706 |
758 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", | 707 UMA_HISTOGRAM_ENUMERATION( |
759 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); | 708 "Net.PublicKeyPinFailureDomain", result.domain_id, DOMAIN_NUM_EVENTS); |
760 } | 709 } |
761 | 710 |
762 // static | 711 // static |
763 bool TransportSecurityState::IsBuildTimely() { | 712 bool TransportSecurityState::IsBuildTimely() { |
764 const base::Time build_time = base::GetBuildTime(); | 713 const base::Time build_time = base::GetBuildTime(); |
765 // We consider built-in information to be timely for 10 weeks. | 714 // We consider built-in information to be timely for 10 weeks. |
766 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; | 715 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; |
767 } | 716 } |
768 | 717 |
769 bool TransportSecurityState::CheckPublicKeyPinsImpl( | 718 bool TransportSecurityState::CheckPublicKeyPinsImpl( |
(...skipping 10 matching lines...) Expand all Loading... | |
780 | 729 |
781 // HasPublicKeyPins should have returned true in order for this method | 730 // 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. | 731 // to have been called, so if we fall through to here, it's an error. |
783 return false; | 732 return false; |
784 } | 733 } |
785 | 734 |
786 bool TransportSecurityState::GetStaticDomainState(const std::string& host, | 735 bool TransportSecurityState::GetStaticDomainState(const std::string& host, |
787 DomainState* out) const { | 736 DomainState* out) const { |
788 DCHECK(CalledOnValidThread()); | 737 DCHECK(CalledOnValidThread()); |
789 | 738 |
790 const std::string canonicalized_host = CanonicalizeHost(host); | |
791 | |
792 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; | 739 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; |
793 out->sts.include_subdomains = false; | 740 out->sts.include_subdomains = false; |
794 out->pkp.include_subdomains = false; | 741 out->pkp.include_subdomains = false; |
795 | 742 |
796 const bool is_build_timely = IsBuildTimely(); | 743 if (!IsBuildTimely()) |
744 return false; | |
797 | 745 |
798 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { | 746 bool found; |
799 std::string host_sub_chunk(&canonicalized_host[i], | 747 PreloadResult result; |
800 canonicalized_host.size() - i); | 748 if (!DecodeHSTSPreload(host, &found, &result)) { |
801 out->domain = DNSDomainToString(host_sub_chunk); | 749 LOG(ERROR) << "Internal error decoding HSTS data for " << host; |
802 bool ret; | 750 return false; |
803 if (is_build_timely && HasPreload(kPreloadedSTS, | 751 } |
804 kNumPreloadedSTS, | 752 |
805 canonicalized_host, | 753 if (!found) |
806 i, | 754 return false; |
807 enable_static_pins_, | 755 |
808 out, | 756 out->domain = host.substr(result.hostname_offset); |
809 &ret)) { | 757 out->sts.include_subdomains = result.include_subdomains; |
810 return ret; | 758 out->sts.last_observed = base::GetBuildTime(); |
759 out->sts.upgrade_mode = | |
760 TransportSecurityState::DomainState::MODE_DEFAULT; | |
761 if (result.force_https) { | |
762 out->sts.upgrade_mode = | |
763 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; | |
764 } | |
765 | |
766 if (enable_static_pins_ && result.has_pins) { | |
767 out->pkp.include_subdomains = result.include_subdomains; | |
768 out->pkp.last_observed = base::GetBuildTime(); | |
769 | |
770 if (result.pinset_id >= arraysize(kPinsets)) { | |
771 return false; | |
772 } | |
773 const Pinset *pinset = &kPinsets[result.pinset_id]; | |
774 | |
775 if (pinset->accepted_pins) { | |
776 const char* const* sha1_hash = pinset->accepted_pins; | |
777 while (*sha1_hash) { | |
778 AddHash(*sha1_hash, &out->pkp.spki_hashes); | |
779 sha1_hash++; | |
780 } | |
781 } | |
782 if (pinset->rejected_pins) { | |
783 const char* const* sha1_hash = pinset->rejected_pins; | |
784 while (*sha1_hash) { | |
785 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); | |
786 sha1_hash++; | |
787 } | |
811 } | 788 } |
812 } | 789 } |
813 | 790 |
814 return false; | 791 return true; |
815 } | 792 } |
816 | 793 |
817 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, | 794 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, |
818 DomainState* result) { | 795 DomainState* result) { |
819 DCHECK(CalledOnValidThread()); | 796 DCHECK(CalledOnValidThread()); |
820 | 797 |
821 DomainState state; | 798 DomainState state; |
822 const std::string canonicalized_host = CanonicalizeHost(host); | 799 const std::string canonicalized_host = CanonicalizeHost(host); |
823 if (canonicalized_host.empty()) | 800 if (canonicalized_host.empty()) |
824 return false; | 801 return false; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
918 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; | 895 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0; |
919 } | 896 } |
920 | 897 |
921 TransportSecurityState::DomainState::PKPState::PKPState() { | 898 TransportSecurityState::DomainState::PKPState::PKPState() { |
922 } | 899 } |
923 | 900 |
924 TransportSecurityState::DomainState::PKPState::~PKPState() { | 901 TransportSecurityState::DomainState::PKPState::~PKPState() { |
925 } | 902 } |
926 | 903 |
927 } // namespace | 904 } // namespace |
OLD | NEW |