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

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: ... 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)
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 current_byte_index_(0),
281 DOMAIN_GOOGLE_COM, 281 num_bits_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 (num_bits_used_ == 8) {
287 DOMAIN_YOUTUBE_COM, 287 if (current_byte_index_ >= num_bytes_) {
288 DOMAIN_GOOGLEAPIS_COM, 288 return false;
289 DOMAIN_GOOGLEADSERVICES_COM, 289 }
290 DOMAIN_GOOGLECODE_COM, 290 current_byte_ = bytes_[current_byte_index_++];
291 DOMAIN_APPSPOT_COM, 291 num_bits_used_ = 0;
292 DOMAIN_GOOGLESYNDICATION_COM, 292 }
293 DOMAIN_DOUBLECLICK_NET, 293
294 DOMAIN_GSTATIC_COM, 294 *out = 1 & (current_byte_ >> (7 - num_bits_used_));
295 DOMAIN_GMAIL_COM, 295 num_bits_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) {
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 current_byte_index_ = offset / 8;
347 DOMAIN_CO_IL, 347 current_byte_ = bytes_[current_byte_index_++];
348 DOMAIN_CO_IM, 348 num_bits_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 // current_byte_index_ contains the current byte offset in |bytes_|.
357 DOMAIN_CO_NZ, 357 size_t current_byte_index_;
358 DOMAIN_CO_TH, 358 // current_byte_ contains the current byte of the input.
359 DOMAIN_CO_TZ, 359 uint8 current_byte_;
360 DOMAIN_CO_UG, 360 // num_bits_used_ contains the number of bits of |current_byte_| that have
361 DOMAIN_CO_UK, 361 // been read.
362 DOMAIN_CO_UZ, 362 unsigned num_bits_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 {
413 uint32 pinset_id;
414 uint32 domain_id;
415 // hostname_offset contains the number of bytes from the start of the given
416 // hostname where the name of the matching entry starts.
417 size_t hostname_offset;
557 bool include_subdomains; 418 bool include_subdomains;
558 char dns_name[38]; 419 bool force_https;
559 bool https_required; 420 bool has_pins;
560 PublicKeyPins pins;
561 SecondLevelDomainName second_level_domain_name;
562 }; 421 };
563 422
564 static bool HasPreload(const struct HSTSPreload* entries, 423 // DecodeHSTSPreloadRaw 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,
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 // Don't call this function, call DecodeHSTSPreload, below.
570 bool* ret) { 429 //
571 for (size_t j = 0; j < num_entries; j++) { 430 // Although this code should be robust, it never processes attacker-controlled
572 if (entries[j].length == canonicalized_host.size() - i && 431 // data -- it only operates on the preloaded data built into the binary.
573 memcmp(entries[j].dns_name, &canonicalized_host[i], 432 //
574 entries[j].length) == 0) { 433 // The preloaded data is represented as a trie and matches the hostname
575 if (!entries[j].include_subdomains && i != 0) { 434 // backwards. Each node in the trie starts with a number of characters, which
576 *ret = false; 435 // must match exactly. After that is a dispatch table which maps the next
436 // character in the hostname to another node in the trie.
437 //
438 // In the dispatch table, the zero character represents the "end of string"
439 // (which is the *beginning* of a hostname since we process it backwards). The
440 // value in that case is special -- rather than an offset to another trie node,
441 // it contains the HSTS information: whether subdomains are included, pinsets
442 // etc. If an "end of string" matches a period in the hostname then the
443 // information is remembered because, if no more specific node is found, then
444 // that information applies to the hostname.
445 //
446 // Dispatch tables are always given in order, but the "end of string" (zero)
447 // value always comes before an entry for '.'.
448 bool DecodeHSTSPreloadRaw(const std::string& hostname,
449 bool* out_found,
450 PreloadResult* out) {
451 HuffmanDecoder huffman(kHSTSHuffmanTree, sizeof(kHSTSHuffmanTree));
452 BitReader reader(kPreloadedHSTSData, kPreloadedHSTSBits);
453 size_t bit_offset = kHSTSRootPosition;
454 static const char kEndOfString = 0;
455 static const char kEndOfTable = 127;
456
457 *out_found = false;
458
459 if (hostname.empty()) {
460 return true;
461 }
462 // hostname_offset contains one more than the index of the current character
463 // in the hostname that is being considered. It's one greater so that we can
464 // represent the position just before the beginning (with zero).
465 size_t hostname_offset = hostname.size();
466
467 for (;;) {
468 // Seek to the desired location.
469 if (!reader.Seek(bit_offset)) {
470 return false;
471 }
472
473 // Decode the unary length of the common prefix.
474 size_t prefix_length;
475 if (!reader.Unary(&prefix_length)) {
476 return false;
477 }
478
479 // Match each character in the prefix.
480 for (size_t i = 0; i < prefix_length; ++i) {
481 if (hostname_offset == 0) {
482 // We can't match the terminator with a prefix string.
483 return true;
484 }
485
486 char c;
487 if (!huffman.Decode(&reader, &c)) {
488 return false;
489 }
490 if (hostname[hostname_offset - 1] != c) {
491 return true;
492 }
493 hostname_offset--;
494 }
495
496 bool is_first_offset = true;
497 size_t current_offset = 0;
498
499 // Next is the dispatch table.
500 for (;;) {
501 char c;
502 if (!huffman.Decode(&reader, &c)) {
503 return false;
504 }
505 if (c == kEndOfTable) {
506 // No exact match.
507 return true;
508 }
509
510 if (c == kEndOfString) {
511 PreloadResult tmp;
512 if (!reader.Next(&tmp.include_subdomains) ||
513 !reader.Next(&tmp.force_https) ||
514 !reader.Next(&tmp.has_pins)) {
515 return false;
516 }
517
518 if (tmp.has_pins) {
519 if (!reader.Read(4, &tmp.pinset_id) ||
520 !reader.Read(9, &tmp.domain_id)) {
521 return false;
522 }
523 }
524
525 tmp.hostname_offset = hostname_offset;
526
527 if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
528 *out_found = tmp.include_subdomains;
529 *out = tmp;
530 }
531
532 if (hostname_offset == 0) {
533 *out_found = true;
534 return true;
535 }
536
537 continue;
538 }
539
540 // The entries in a dispatch table are in order thus we can tell if there
541 // will be no match if the current character past the one that we want.
542 if (hostname_offset == 0 || hostname[hostname_offset-1] < c) {
543 return true;
544 }
545
546 if (is_first_offset) {
547 // The first offset is backwards from the current position.
548 uint32 jump_delta_bits;
549 uint32 jump_delta;
550 if (!reader.Read(5, &jump_delta_bits) ||
551 !reader.Read(jump_delta_bits, &jump_delta)) {
552 return false;
553 }
554
555 if (bit_offset <= jump_delta) {
556 return false;
557 }
558
559 current_offset = bit_offset - jump_delta;
560 is_first_offset = false;
577 } else { 561 } else {
578 out->sts.include_subdomains = entries[j].include_subdomains; 562 // Subsequent offsets are forward from the target of the first offset.
579 out->sts.last_observed = base::GetBuildTime(); 563 uint32 is_long_jump;
580 *ret = true; 564 if (!reader.Read(1, &is_long_jump)) {
581 out->sts.upgrade_mode = 565 return false;
582 TransportSecurityState::DomainState::MODE_FORCE_HTTPS; 566 }
583 if (!entries[j].https_required) 567
584 out->sts.upgrade_mode = 568 uint32 jump_delta;
585 TransportSecurityState::DomainState::MODE_DEFAULT; 569 if (!is_long_jump) {
586 570 if (!reader.Read(7, &jump_delta)) {
587 if (enable_static_pins) { 571 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 } 572 }
597 if (entries[j].pins.excluded_hashes) { 573 } else {
598 const char* const* sha1_hash = entries[j].pins.excluded_hashes; 574 uint32 jump_delta_bits;
599 while (*sha1_hash) { 575 if (!reader.Read(4, &jump_delta_bits) ||
600 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes); 576 !reader.Read(jump_delta_bits + 8, &jump_delta)) {
601 sha1_hash++; 577 return false;
602 }
603 } 578 }
604 } 579 }
605 } 580
606 return true; 581 current_offset += jump_delta;
607 } 582 if (current_offset >= bit_offset) {
608 } 583 return false;
609 return false; 584 }
585 }
586
587 DCHECK_LT(0u, hostname_offset);
588 if (hostname[hostname_offset - 1] == c) {
589 bit_offset = current_offset;
590 hostname_offset--;
591 break;
592 }
593 }
594 }
610 } 595 }
611 596
612 #include "net/http/transport_security_state_static.h" 597 bool DecodeHSTSPreload(const std::string& hostname,
613 598 PreloadResult* out) {
614 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|, 599 bool found;
615 // or NULL if there is none. Prefers exact hostname matches to those that 600 if (!DecodeHSTSPreloadRaw(hostname, &found, out)) {
616 // match only because HSTSPreload.include_subdomains is true. 601 LOG(ERROR) << "Internal error in DecodeHSTSPreloadRaw for hostname "
617 // 602 << hostname;
618 // |canonicalized_host| should be the hostname as canonicalized by 603 return false;
619 // CanonicalizeHost. 604 }
620 static const struct HSTSPreload* GetHSTSPreload( 605
621 const std::string& canonicalized_host, 606 return found;
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 } 607 }
640 608
641 bool TransportSecurityState::AddHSTSHeader(const std::string& host, 609 bool TransportSecurityState::AddHSTSHeader(const std::string& host,
642 const std::string& value) { 610 const std::string& value) {
643 DCHECK(CalledOnValidThread()); 611 DCHECK(CalledOnValidThread());
644 612
645 base::Time now = base::Time::Now(); 613 base::Time now = base::Time::Now();
646 base::TimeDelta max_age; 614 base::TimeDelta max_age;
647 TransportSecurityState::DomainState domain_state; 615 TransportSecurityState::DomainState domain_state;
648 GetDynamicDomainState(host, &domain_state); 616 GetDynamicDomainState(host, &domain_state);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 domain_state.pkp.last_observed = base::Time::Now(); 693 domain_state.pkp.last_observed = base::Time::Now();
726 domain_state.pkp.include_subdomains = include_subdomains; 694 domain_state.pkp.include_subdomains = include_subdomains;
727 domain_state.pkp.expiry = expiry; 695 domain_state.pkp.expiry = expiry;
728 domain_state.pkp.spki_hashes = hashes; 696 domain_state.pkp.spki_hashes = hashes;
729 EnableHost(host, domain_state); 697 EnableHost(host, domain_state);
730 return true; 698 return true;
731 } 699 }
732 700
733 // static 701 // static
734 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { 702 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) {
735 std::string canonicalized_host = CanonicalizeHost(host); 703 PreloadResult result;
736 const struct HSTSPreload* entry = 704 return DecodeHSTSPreload(host, &result) && result.has_pins &&
737 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 705 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts;
738
739 return entry && entry->pins.required_hashes == kGoogleAcceptableCerts;
740 } 706 }
741 707
742 // static 708 // static
743 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { 709 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) {
744 std::string canonicalized_host = CanonicalizeHost(host); 710 PreloadResult result;
745 711 if (!DecodeHSTSPreload(host, &result) ||
746 const struct HSTSPreload* entry = 712 !result.has_pins) {
747 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS);
748
749 if (!entry) {
750 // We don't care to report pin failures for dynamic pins.
751 return; 713 return;
752 } 714 }
753 715
754 DCHECK(entry); 716 DCHECK(result.domain_id != DOMAIN_NOT_PINNED);
755 DCHECK(entry->pins.required_hashes);
756 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED);
757 717
758 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", 718 UMA_HISTOGRAM_ENUMERATION(
759 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); 719 "Net.PublicKeyPinFailureDomain", result.domain_id, DOMAIN_NUM_EVENTS);
760 } 720 }
761 721
762 // static 722 // static
763 bool TransportSecurityState::IsBuildTimely() { 723 bool TransportSecurityState::IsBuildTimely() {
764 const base::Time build_time = base::GetBuildTime(); 724 const base::Time build_time = base::GetBuildTime();
765 // We consider built-in information to be timely for 10 weeks. 725 // We consider built-in information to be timely for 10 weeks.
766 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; 726 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
767 } 727 }
768 728
769 bool TransportSecurityState::CheckPublicKeyPinsImpl( 729 bool TransportSecurityState::CheckPublicKeyPinsImpl(
(...skipping 10 matching lines...) Expand all
780 740
781 // HasPublicKeyPins should have returned true in order for this method 741 // 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. 742 // to have been called, so if we fall through to here, it's an error.
783 return false; 743 return false;
784 } 744 }
785 745
786 bool TransportSecurityState::GetStaticDomainState(const std::string& host, 746 bool TransportSecurityState::GetStaticDomainState(const std::string& host,
787 DomainState* out) const { 747 DomainState* out) const {
788 DCHECK(CalledOnValidThread()); 748 DCHECK(CalledOnValidThread());
789 749
790 const std::string canonicalized_host = CanonicalizeHost(host);
791
792 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS; 750 out->sts.upgrade_mode = DomainState::MODE_FORCE_HTTPS;
793 out->sts.include_subdomains = false; 751 out->sts.include_subdomains = false;
794 out->pkp.include_subdomains = false; 752 out->pkp.include_subdomains = false;
795 753
796 const bool is_build_timely = IsBuildTimely(); 754 if (!IsBuildTimely())
755 return false;
797 756
798 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 757 PreloadResult result;
799 std::string host_sub_chunk(&canonicalized_host[i], 758 if (!DecodeHSTSPreload(host, &result))
800 canonicalized_host.size() - i); 759 return false;
801 out->domain = DNSDomainToString(host_sub_chunk); 760
802 bool ret; 761 out->domain = host.substr(result.hostname_offset);
803 if (is_build_timely && HasPreload(kPreloadedSTS, 762 out->sts.include_subdomains = result.include_subdomains;
804 kNumPreloadedSTS, 763 out->sts.last_observed = base::GetBuildTime();
805 canonicalized_host, 764 out->sts.upgrade_mode =
806 i, 765 TransportSecurityState::DomainState::MODE_DEFAULT;
807 enable_static_pins_, 766 if (result.force_https) {
808 out, 767 out->sts.upgrade_mode =
809 &ret)) { 768 TransportSecurityState::DomainState::MODE_FORCE_HTTPS;
810 return ret; 769 }
770
771 if (enable_static_pins_ && result.has_pins) {
772 out->pkp.include_subdomains = result.include_subdomains;
773 out->pkp.last_observed = base::GetBuildTime();
774
775 if (result.pinset_id >= arraysize(kPinsets))
776 return false;
777 const Pinset *pinset = &kPinsets[result.pinset_id];
778
779 if (pinset->accepted_pins) {
780 const char* const* sha1_hash = pinset->accepted_pins;
781 while (*sha1_hash) {
782 AddHash(*sha1_hash, &out->pkp.spki_hashes);
783 sha1_hash++;
784 }
785 }
786 if (pinset->rejected_pins) {
787 const char* const* sha1_hash = pinset->rejected_pins;
788 while (*sha1_hash) {
789 AddHash(*sha1_hash, &out->pkp.bad_spki_hashes);
790 sha1_hash++;
791 }
811 } 792 }
812 } 793 }
813 794
814 return false; 795 return true;
815 } 796 }
816 797
817 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, 798 bool TransportSecurityState::GetDynamicDomainState(const std::string& host,
818 DomainState* result) { 799 DomainState* result) {
819 DCHECK(CalledOnValidThread()); 800 DCHECK(CalledOnValidThread());
820 801
821 DomainState state; 802 DomainState state;
822 const std::string canonicalized_host = CanonicalizeHost(host); 803 const std::string canonicalized_host = CanonicalizeHost(host);
823 if (canonicalized_host.empty()) 804 if (canonicalized_host.empty())
824 return false; 805 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; 899 return pkp.spki_hashes.size() > 0 || pkp.bad_spki_hashes.size() > 0;
919 } 900 }
920 901
921 TransportSecurityState::DomainState::PKPState::PKPState() { 902 TransportSecurityState::DomainState::PKPState::PKPState() {
922 } 903 }
923 904
924 TransportSecurityState::DomainState::PKPState::~PKPState() { 905 TransportSecurityState::DomainState::PKPState::~PKPState() {
925 } 906 }
926 907
927 } // namespace 908 } // 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