| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/quic/core/crypto/cert_compressor.h" | 5 #include "net/quic/core/crypto/cert_compressor.h" |
| 6 | 6 |
| 7 #include <cstdint> | 7 #include <cstdint> |
| 8 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "net/quic/core/quic_utils.h" | 10 #include "net/quic/core/quic_utils.h" |
| 11 #include "third_party/zlib/zlib.h" | 11 #include "third_party/zlib/zlib.h" |
| 12 | 12 |
| 13 using base::StringPiece; | |
| 14 using std::string; | 13 using std::string; |
| 15 | 14 |
| 16 namespace net { | 15 namespace net { |
| 17 | 16 |
| 18 namespace { | 17 namespace { |
| 19 | 18 |
| 20 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings | 19 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings |
| 21 // in order to help zlib. This was generated via a fairly dumb algorithm from | 20 // in order to help zlib. This was generated via a fairly dumb algorithm from |
| 22 // the Alexa Top 5000 set - we could probably do better. | 21 // the Alexa Top 5000 set - we could probably do better. |
| 23 static const unsigned char kCommonCertSubstrings[] = { | 22 static const unsigned char kCommonCertSubstrings[] = { |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 uint64_t hash; | 168 uint64_t hash; |
| 170 uint64_t set_hash; | 169 uint64_t set_hash; |
| 171 uint32_t index; | 170 uint32_t index; |
| 172 }; | 171 }; |
| 173 | 172 |
| 174 // MatchCerts returns a vector of CertEntries describing how to most | 173 // MatchCerts returns a vector of CertEntries describing how to most |
| 175 // efficiently represent |certs| to a peer who has the common sets identified | 174 // efficiently represent |certs| to a peer who has the common sets identified |
| 176 // by |client_common_set_hashes| and who has cached the certificates with the | 175 // by |client_common_set_hashes| and who has cached the certificates with the |
| 177 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. | 176 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. |
| 178 std::vector<CertEntry> MatchCerts(const std::vector<string>& certs, | 177 std::vector<CertEntry> MatchCerts(const std::vector<string>& certs, |
| 179 StringPiece client_common_set_hashes, | 178 QuicStringPiece client_common_set_hashes, |
| 180 StringPiece client_cached_cert_hashes, | 179 QuicStringPiece client_cached_cert_hashes, |
| 181 const CommonCertSets* common_sets) { | 180 const CommonCertSets* common_sets) { |
| 182 std::vector<CertEntry> entries; | 181 std::vector<CertEntry> entries; |
| 183 entries.reserve(certs.size()); | 182 entries.reserve(certs.size()); |
| 184 | 183 |
| 185 const bool cached_valid = | 184 const bool cached_valid = |
| 186 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && | 185 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && |
| 187 !client_cached_cert_hashes.empty(); | 186 !client_cached_cert_hashes.empty(); |
| 188 | 187 |
| 189 for (std::vector<string>::const_iterator i = certs.begin(); i != certs.end(); | 188 for (std::vector<string>::const_iterator i = certs.begin(); i != certs.end(); |
| 190 ++i) { | 189 ++i) { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 ret.push_back(QuicUtils::FNV1a_64_Hash(*i)); | 326 ret.push_back(QuicUtils::FNV1a_64_Hash(*i)); |
| 328 } | 327 } |
| 329 | 328 |
| 330 return ret; | 329 return ret; |
| 331 } | 330 } |
| 332 | 331 |
| 333 // ParseEntries parses the serialised form of a vector of CertEntries from | 332 // ParseEntries parses the serialised form of a vector of CertEntries from |
| 334 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are | 333 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are |
| 335 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. | 334 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. |
| 336 // |in_out| is updated to contain the trailing data. | 335 // |in_out| is updated to contain the trailing data. |
| 337 bool ParseEntries(StringPiece* in_out, | 336 bool ParseEntries(QuicStringPiece* in_out, |
| 338 const std::vector<string>& cached_certs, | 337 const std::vector<string>& cached_certs, |
| 339 const CommonCertSets* common_sets, | 338 const CommonCertSets* common_sets, |
| 340 std::vector<CertEntry>* out_entries, | 339 std::vector<CertEntry>* out_entries, |
| 341 std::vector<string>* out_certs) { | 340 std::vector<string>* out_certs) { |
| 342 StringPiece in = *in_out; | 341 QuicStringPiece in = *in_out; |
| 343 std::vector<uint64_t> cached_hashes; | 342 std::vector<uint64_t> cached_hashes; |
| 344 | 343 |
| 345 out_entries->clear(); | 344 out_entries->clear(); |
| 346 out_certs->clear(); | 345 out_certs->clear(); |
| 347 | 346 |
| 348 for (;;) { | 347 for (;;) { |
| 349 if (in.empty()) { | 348 if (in.empty()) { |
| 350 return false; | 349 return false; |
| 351 } | 350 } |
| 352 CertEntry entry; | 351 CertEntry entry; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 return false; | 390 return false; |
| 392 } | 391 } |
| 393 if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) { | 392 if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) { |
| 394 return false; | 393 return false; |
| 395 } | 394 } |
| 396 memcpy(&entry.set_hash, in.data(), sizeof(uint64_t)); | 395 memcpy(&entry.set_hash, in.data(), sizeof(uint64_t)); |
| 397 in.remove_prefix(sizeof(uint64_t)); | 396 in.remove_prefix(sizeof(uint64_t)); |
| 398 memcpy(&entry.index, in.data(), sizeof(uint32_t)); | 397 memcpy(&entry.index, in.data(), sizeof(uint32_t)); |
| 399 in.remove_prefix(sizeof(uint32_t)); | 398 in.remove_prefix(sizeof(uint32_t)); |
| 400 | 399 |
| 401 StringPiece cert = common_sets->GetCert(entry.set_hash, entry.index); | 400 QuicStringPiece cert = |
| 401 common_sets->GetCert(entry.set_hash, entry.index); |
| 402 if (cert.empty()) { | 402 if (cert.empty()) { |
| 403 return false; | 403 return false; |
| 404 } | 404 } |
| 405 out_certs->push_back(cert.as_string()); | 405 out_certs->push_back(cert.as_string()); |
| 406 break; | 406 break; |
| 407 } | 407 } |
| 408 default: | 408 default: |
| 409 return false; | 409 return false; |
| 410 } | 410 } |
| 411 out_entries->push_back(entry); | 411 out_entries->push_back(entry); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 } | 447 } |
| 448 | 448 |
| 449 z_stream* z_; | 449 z_stream* z_; |
| 450 const Type type_; | 450 const Type type_; |
| 451 }; | 451 }; |
| 452 | 452 |
| 453 } // anonymous namespace | 453 } // anonymous namespace |
| 454 | 454 |
| 455 // static | 455 // static |
| 456 string CertCompressor::CompressChain(const std::vector<string>& certs, | 456 string CertCompressor::CompressChain(const std::vector<string>& certs, |
| 457 StringPiece client_common_set_hashes, | 457 QuicStringPiece client_common_set_hashes, |
| 458 StringPiece client_cached_cert_hashes, | 458 QuicStringPiece client_cached_cert_hashes, |
| 459 const CommonCertSets* common_sets) { | 459 const CommonCertSets* common_sets) { |
| 460 const std::vector<CertEntry> entries = MatchCerts( | 460 const std::vector<CertEntry> entries = MatchCerts( |
| 461 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); | 461 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); |
| 462 DCHECK_EQ(entries.size(), certs.size()); | 462 DCHECK_EQ(entries.size(), certs.size()); |
| 463 | 463 |
| 464 size_t uncompressed_size = 0; | 464 size_t uncompressed_size = 0; |
| 465 for (size_t i = 0; i < entries.size(); i++) { | 465 for (size_t i = 0; i < entries.size(); i++) { |
| 466 if (entries[i].type == CertEntry::COMPRESSED) { | 466 if (entries[i].type == CertEntry::COMPRESSED) { |
| 467 uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); | 467 uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); |
| 468 } | 468 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 DCHECK_EQ(Z_STREAM_END, rv); | 547 DCHECK_EQ(Z_STREAM_END, rv); |
| 548 if (rv != Z_STREAM_END) { | 548 if (rv != Z_STREAM_END) { |
| 549 return ""; | 549 return ""; |
| 550 } | 550 } |
| 551 | 551 |
| 552 result.resize(result.size() - z.avail_out); | 552 result.resize(result.size() - z.avail_out); |
| 553 return result; | 553 return result; |
| 554 } | 554 } |
| 555 | 555 |
| 556 // static | 556 // static |
| 557 bool CertCompressor::DecompressChain(StringPiece in, | 557 bool CertCompressor::DecompressChain(QuicStringPiece in, |
| 558 const std::vector<string>& cached_certs, | 558 const std::vector<string>& cached_certs, |
| 559 const CommonCertSets* common_sets, | 559 const CommonCertSets* common_sets, |
| 560 std::vector<string>* out_certs) { | 560 std::vector<string>* out_certs) { |
| 561 std::vector<CertEntry> entries; | 561 std::vector<CertEntry> entries; |
| 562 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { | 562 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { |
| 563 return false; | 563 return false; |
| 564 } | 564 } |
| 565 DCHECK_EQ(entries.size(), out_certs->size()); | 565 DCHECK_EQ(entries.size(), out_certs->size()); |
| 566 | 566 |
| 567 std::unique_ptr<uint8_t[]> uncompressed_data; | 567 std::unique_ptr<uint8_t[]> uncompressed_data; |
| 568 StringPiece uncompressed; | 568 QuicStringPiece uncompressed; |
| 569 | 569 |
| 570 if (!in.empty()) { | 570 if (!in.empty()) { |
| 571 if (in.size() < sizeof(uint32_t)) { | 571 if (in.size() < sizeof(uint32_t)) { |
| 572 return false; | 572 return false; |
| 573 } | 573 } |
| 574 | 574 |
| 575 uint32_t uncompressed_size; | 575 uint32_t uncompressed_size; |
| 576 memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size)); | 576 memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size)); |
| 577 in.remove_prefix(sizeof(uint32_t)); | 577 in.remove_prefix(sizeof(uint32_t)); |
| 578 | 578 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 603 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) { | 603 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) { |
| 604 return false; | 604 return false; |
| 605 } | 605 } |
| 606 rv = inflate(&z, Z_FINISH); | 606 rv = inflate(&z, Z_FINISH); |
| 607 } | 607 } |
| 608 | 608 |
| 609 if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) { | 609 if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) { |
| 610 return false; | 610 return false; |
| 611 } | 611 } |
| 612 | 612 |
| 613 uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()), | 613 uncompressed = QuicStringPiece( |
| 614 uncompressed_size); | 614 reinterpret_cast<char*>(uncompressed_data.get()), uncompressed_size); |
| 615 } | 615 } |
| 616 | 616 |
| 617 for (size_t i = 0; i < entries.size(); i++) { | 617 for (size_t i = 0; i < entries.size(); i++) { |
| 618 switch (entries[i].type) { | 618 switch (entries[i].type) { |
| 619 case CertEntry::COMPRESSED: | 619 case CertEntry::COMPRESSED: |
| 620 if (uncompressed.size() < sizeof(uint32_t)) { | 620 if (uncompressed.size() < sizeof(uint32_t)) { |
| 621 return false; | 621 return false; |
| 622 } | 622 } |
| 623 uint32_t cert_len; | 623 uint32_t cert_len; |
| 624 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len)); | 624 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 636 } | 636 } |
| 637 | 637 |
| 638 if (!uncompressed.empty()) { | 638 if (!uncompressed.empty()) { |
| 639 return false; | 639 return false; |
| 640 } | 640 } |
| 641 | 641 |
| 642 return true; | 642 return true; |
| 643 } | 643 } |
| 644 | 644 |
| 645 } // namespace net | 645 } // namespace net |
| OLD | NEW |