Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: net/http/transport_security_state.cc

Issue 619433002: Use a more compact HSTS representation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: g cl try Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | net/http/transport_security_state_static.h » ('j') | net/http/transport_security_state_static.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698