Chromium Code Reviews| 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 "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "net/quic/core/quic_utils.h" | 11 #include "net/quic/core/quic_utils.h" |
| 12 #include "third_party/zlib/zlib.h" | 12 #include "third_party/zlib/zlib.h" |
| 13 | 13 |
| 14 using base::StringPiece; | 14 using base::StringPiece; |
| 15 using std::string; | 15 using std::string; |
| 16 using std::vector; | 16 using std::vector; |
|
Ryan Hamilton
2016/10/30 20:22:30
ditto.
| |
| 17 | 17 |
| 18 namespace net { | 18 namespace net { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 | 21 |
| 22 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings | 22 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings |
| 23 // in order to help zlib. This was generated via a fairly dumb algorithm from | 23 // in order to help zlib. This was generated via a fairly dumb algorithm from |
| 24 // the Alexa Top 5000 set - we could probably do better. | 24 // the Alexa Top 5000 set - we could probably do better. |
| 25 static const unsigned char kCommonCertSubstrings[] = { | 25 static const unsigned char kCommonCertSubstrings[] = { |
| 26 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, | 26 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 Type type; | 170 Type type; |
| 171 uint64_t hash; | 171 uint64_t hash; |
| 172 uint64_t set_hash; | 172 uint64_t set_hash; |
| 173 uint32_t index; | 173 uint32_t index; |
| 174 }; | 174 }; |
| 175 | 175 |
| 176 // MatchCerts returns a vector of CertEntries describing how to most | 176 // MatchCerts returns a vector of CertEntries describing how to most |
| 177 // efficiently represent |certs| to a peer who has the common sets identified | 177 // efficiently represent |certs| to a peer who has the common sets identified |
| 178 // by |client_common_set_hashes| and who has cached the certificates with the | 178 // by |client_common_set_hashes| and who has cached the certificates with the |
| 179 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. | 179 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. |
| 180 vector<CertEntry> MatchCerts(const vector<string>& certs, | 180 std::vector<CertEntry> MatchCerts(const std::vector<string>& certs, |
| 181 StringPiece client_common_set_hashes, | 181 StringPiece client_common_set_hashes, |
| 182 StringPiece client_cached_cert_hashes, | 182 StringPiece client_cached_cert_hashes, |
| 183 const CommonCertSets* common_sets) { | 183 const CommonCertSets* common_sets) { |
| 184 vector<CertEntry> entries; | 184 std::vector<CertEntry> entries; |
| 185 entries.reserve(certs.size()); | 185 entries.reserve(certs.size()); |
| 186 | 186 |
| 187 const bool cached_valid = | 187 const bool cached_valid = |
| 188 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && | 188 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && |
| 189 !client_cached_cert_hashes.empty(); | 189 !client_cached_cert_hashes.empty(); |
| 190 | 190 |
| 191 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); | 191 for (std::vector<string>::const_iterator i = certs.begin(); i != certs.end(); |
| 192 ++i) { | 192 ++i) { |
| 193 CertEntry entry; | 193 CertEntry entry; |
| 194 | 194 |
| 195 if (cached_valid) { | 195 if (cached_valid) { |
| 196 bool cached = false; | 196 bool cached = false; |
| 197 | 197 |
| 198 uint64_t hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size()); | 198 uint64_t hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size()); |
| 199 // This assumes that the machine is little-endian. | 199 // This assumes that the machine is little-endian. |
| 200 for (size_t j = 0; j < client_cached_cert_hashes.size(); | 200 for (size_t j = 0; j < client_cached_cert_hashes.size(); |
| 201 j += sizeof(uint64_t)) { | 201 j += sizeof(uint64_t)) { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 228 | 228 |
| 229 entry.type = CertEntry::COMPRESSED; | 229 entry.type = CertEntry::COMPRESSED; |
| 230 entries.push_back(entry); | 230 entries.push_back(entry); |
| 231 } | 231 } |
| 232 | 232 |
| 233 return entries; | 233 return entries; |
| 234 } | 234 } |
| 235 | 235 |
| 236 // CertEntriesSize returns the size, in bytes, of the serialised form of | 236 // CertEntriesSize returns the size, in bytes, of the serialised form of |
| 237 // |entries|. | 237 // |entries|. |
| 238 size_t CertEntriesSize(const vector<CertEntry>& entries) { | 238 size_t CertEntriesSize(const std::vector<CertEntry>& entries) { |
| 239 size_t entries_size = 0; | 239 size_t entries_size = 0; |
| 240 | 240 |
| 241 for (vector<CertEntry>::const_iterator i = entries.begin(); | 241 for (std::vector<CertEntry>::const_iterator i = entries.begin(); |
| 242 i != entries.end(); ++i) { | 242 i != entries.end(); ++i) { |
| 243 entries_size++; | 243 entries_size++; |
| 244 switch (i->type) { | 244 switch (i->type) { |
| 245 case CertEntry::COMPRESSED: | 245 case CertEntry::COMPRESSED: |
| 246 break; | 246 break; |
| 247 case CertEntry::CACHED: | 247 case CertEntry::CACHED: |
| 248 entries_size += sizeof(uint64_t); | 248 entries_size += sizeof(uint64_t); |
| 249 break; | 249 break; |
| 250 case CertEntry::COMMON: | 250 case CertEntry::COMMON: |
| 251 entries_size += sizeof(uint64_t) + sizeof(uint32_t); | 251 entries_size += sizeof(uint64_t) + sizeof(uint32_t); |
| 252 break; | 252 break; |
| 253 } | 253 } |
| 254 } | 254 } |
| 255 | 255 |
| 256 entries_size++; // for end marker | 256 entries_size++; // for end marker |
| 257 | 257 |
| 258 return entries_size; | 258 return entries_size; |
| 259 } | 259 } |
| 260 | 260 |
| 261 // SerializeCertEntries serialises |entries| to |out|, which must have enough | 261 // SerializeCertEntries serialises |entries| to |out|, which must have enough |
| 262 // space to contain them. | 262 // space to contain them. |
| 263 void SerializeCertEntries(uint8_t* out, const vector<CertEntry>& entries) { | 263 void SerializeCertEntries(uint8_t* out, const std::vector<CertEntry>& entries) { |
| 264 for (vector<CertEntry>::const_iterator i = entries.begin(); | 264 for (std::vector<CertEntry>::const_iterator i = entries.begin(); |
| 265 i != entries.end(); ++i) { | 265 i != entries.end(); ++i) { |
| 266 *out++ = static_cast<uint8_t>(i->type); | 266 *out++ = static_cast<uint8_t>(i->type); |
| 267 switch (i->type) { | 267 switch (i->type) { |
| 268 case CertEntry::COMPRESSED: | 268 case CertEntry::COMPRESSED: |
| 269 break; | 269 break; |
| 270 case CertEntry::CACHED: | 270 case CertEntry::CACHED: |
| 271 memcpy(out, &i->hash, sizeof(i->hash)); | 271 memcpy(out, &i->hash, sizeof(i->hash)); |
| 272 out += sizeof(uint64_t); | 272 out += sizeof(uint64_t); |
| 273 break; | 273 break; |
| 274 case CertEntry::COMMON: | 274 case CertEntry::COMMON: |
| 275 // Assumes a little-endian machine. | 275 // Assumes a little-endian machine. |
| 276 memcpy(out, &i->set_hash, sizeof(i->set_hash)); | 276 memcpy(out, &i->set_hash, sizeof(i->set_hash)); |
| 277 out += sizeof(i->set_hash); | 277 out += sizeof(i->set_hash); |
| 278 memcpy(out, &i->index, sizeof(uint32_t)); | 278 memcpy(out, &i->index, sizeof(uint32_t)); |
| 279 out += sizeof(uint32_t); | 279 out += sizeof(uint32_t); |
| 280 break; | 280 break; |
| 281 } | 281 } |
| 282 } | 282 } |
| 283 | 283 |
| 284 *out++ = 0; // end marker | 284 *out++ = 0; // end marker |
| 285 } | 285 } |
| 286 | 286 |
| 287 // ZlibDictForEntries returns a string that contains the zlib pre-shared | 287 // ZlibDictForEntries returns a string that contains the zlib pre-shared |
| 288 // dictionary to use in order to decompress a zlib block following |entries|. | 288 // dictionary to use in order to decompress a zlib block following |entries|. |
| 289 // |certs| is one-to-one with |entries| and contains the certificates for those | 289 // |certs| is one-to-one with |entries| and contains the certificates for those |
| 290 // entries that are CACHED or COMMON. | 290 // entries that are CACHED or COMMON. |
| 291 string ZlibDictForEntries(const vector<CertEntry>& entries, | 291 string ZlibDictForEntries(const std::vector<CertEntry>& entries, |
| 292 const vector<string>& certs) { | 292 const std::vector<string>& certs) { |
| 293 string zlib_dict; | 293 string zlib_dict; |
| 294 | 294 |
| 295 // The dictionary starts with the common and cached certs in reverse order. | 295 // The dictionary starts with the common and cached certs in reverse order. |
| 296 size_t zlib_dict_size = 0; | 296 size_t zlib_dict_size = 0; |
| 297 for (size_t i = certs.size() - 1; i < certs.size(); i--) { | 297 for (size_t i = certs.size() - 1; i < certs.size(); i--) { |
| 298 if (entries[i].type != CertEntry::COMPRESSED) { | 298 if (entries[i].type != CertEntry::COMPRESSED) { |
| 299 zlib_dict_size += certs[i].size(); | 299 zlib_dict_size += certs[i].size(); |
| 300 } | 300 } |
| 301 } | 301 } |
| 302 | 302 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 313 | 313 |
| 314 zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings), | 314 zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings), |
| 315 sizeof(kCommonCertSubstrings)); | 315 sizeof(kCommonCertSubstrings)); |
| 316 | 316 |
| 317 DCHECK_EQ(zlib_dict.size(), zlib_dict_size); | 317 DCHECK_EQ(zlib_dict.size(), zlib_dict_size); |
| 318 | 318 |
| 319 return zlib_dict; | 319 return zlib_dict; |
| 320 } | 320 } |
| 321 | 321 |
| 322 // HashCerts returns the FNV-1a hashes of |certs|. | 322 // HashCerts returns the FNV-1a hashes of |certs|. |
| 323 vector<uint64_t> HashCerts(const vector<string>& certs) { | 323 std::vector<uint64_t> HashCerts(const std::vector<string>& certs) { |
| 324 vector<uint64_t> ret; | 324 std::vector<uint64_t> ret; |
| 325 ret.reserve(certs.size()); | 325 ret.reserve(certs.size()); |
| 326 | 326 |
| 327 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); | 327 for (std::vector<string>::const_iterator i = certs.begin(); i != certs.end(); |
| 328 ++i) { | 328 ++i) { |
| 329 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); | 329 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); |
| 330 } | 330 } |
| 331 | 331 |
| 332 return ret; | 332 return ret; |
| 333 } | 333 } |
| 334 | 334 |
| 335 // ParseEntries parses the serialised form of a vector of CertEntries from | 335 // ParseEntries parses the serialised form of a vector of CertEntries from |
| 336 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are | 336 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are |
| 337 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. | 337 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. |
| 338 // |in_out| is updated to contain the trailing data. | 338 // |in_out| is updated to contain the trailing data. |
| 339 bool ParseEntries(StringPiece* in_out, | 339 bool ParseEntries(StringPiece* in_out, |
| 340 const vector<string>& cached_certs, | 340 const std::vector<string>& cached_certs, |
| 341 const CommonCertSets* common_sets, | 341 const CommonCertSets* common_sets, |
| 342 vector<CertEntry>* out_entries, | 342 std::vector<CertEntry>* out_entries, |
| 343 vector<string>* out_certs) { | 343 std::vector<string>* out_certs) { |
| 344 StringPiece in = *in_out; | 344 StringPiece in = *in_out; |
| 345 vector<uint64_t> cached_hashes; | 345 std::vector<uint64_t> cached_hashes; |
| 346 | 346 |
| 347 out_entries->clear(); | 347 out_entries->clear(); |
| 348 out_certs->clear(); | 348 out_certs->clear(); |
| 349 | 349 |
| 350 for (;;) { | 350 for (;;) { |
| 351 if (in.empty()) { | 351 if (in.empty()) { |
| 352 return false; | 352 return false; |
| 353 } | 353 } |
| 354 CertEntry entry; | 354 CertEntry entry; |
| 355 const uint8_t type_byte = in[0]; | 355 const uint8_t type_byte = in[0]; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 448 z_ = nullptr; | 448 z_ = nullptr; |
| 449 } | 449 } |
| 450 | 450 |
| 451 z_stream* z_; | 451 z_stream* z_; |
| 452 const Type type_; | 452 const Type type_; |
| 453 }; | 453 }; |
| 454 | 454 |
| 455 } // anonymous namespace | 455 } // anonymous namespace |
| 456 | 456 |
| 457 // static | 457 // static |
| 458 string CertCompressor::CompressChain(const vector<string>& certs, | 458 string CertCompressor::CompressChain(const std::vector<string>& certs, |
| 459 StringPiece client_common_set_hashes, | 459 StringPiece client_common_set_hashes, |
| 460 StringPiece client_cached_cert_hashes, | 460 StringPiece client_cached_cert_hashes, |
| 461 const CommonCertSets* common_sets) { | 461 const CommonCertSets* common_sets) { |
| 462 const vector<CertEntry> entries = MatchCerts( | 462 const std::vector<CertEntry> entries = MatchCerts( |
| 463 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); | 463 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); |
| 464 DCHECK_EQ(entries.size(), certs.size()); | 464 DCHECK_EQ(entries.size(), certs.size()); |
| 465 | 465 |
| 466 size_t uncompressed_size = 0; | 466 size_t uncompressed_size = 0; |
| 467 for (size_t i = 0; i < entries.size(); i++) { | 467 for (size_t i = 0; i < entries.size(); i++) { |
| 468 if (entries[i].type == CertEntry::COMPRESSED) { | 468 if (entries[i].type == CertEntry::COMPRESSED) { |
| 469 uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); | 469 uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); |
| 470 } | 470 } |
| 471 } | 471 } |
| 472 | 472 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 550 if (rv != Z_STREAM_END) { | 550 if (rv != Z_STREAM_END) { |
| 551 return ""; | 551 return ""; |
| 552 } | 552 } |
| 553 | 553 |
| 554 result.resize(result.size() - z.avail_out); | 554 result.resize(result.size() - z.avail_out); |
| 555 return result; | 555 return result; |
| 556 } | 556 } |
| 557 | 557 |
| 558 // static | 558 // static |
| 559 bool CertCompressor::DecompressChain(StringPiece in, | 559 bool CertCompressor::DecompressChain(StringPiece in, |
| 560 const vector<string>& cached_certs, | 560 const std::vector<string>& cached_certs, |
| 561 const CommonCertSets* common_sets, | 561 const CommonCertSets* common_sets, |
| 562 vector<string>* out_certs) { | 562 std::vector<string>* out_certs) { |
| 563 vector<CertEntry> entries; | 563 std::vector<CertEntry> entries; |
| 564 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { | 564 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { |
| 565 return false; | 565 return false; |
| 566 } | 566 } |
| 567 DCHECK_EQ(entries.size(), out_certs->size()); | 567 DCHECK_EQ(entries.size(), out_certs->size()); |
| 568 | 568 |
| 569 std::unique_ptr<uint8_t[]> uncompressed_data; | 569 std::unique_ptr<uint8_t[]> uncompressed_data; |
| 570 StringPiece uncompressed; | 570 StringPiece uncompressed; |
| 571 | 571 |
| 572 if (!in.empty()) { | 572 if (!in.empty()) { |
| 573 if (in.size() < sizeof(uint32_t)) { | 573 if (in.size() < sizeof(uint32_t)) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 638 } | 638 } |
| 639 | 639 |
| 640 if (!uncompressed.empty()) { | 640 if (!uncompressed.empty()) { |
| 641 return false; | 641 return false; |
| 642 } | 642 } |
| 643 | 643 |
| 644 return true; | 644 return true; |
| 645 } | 645 } |
| 646 | 646 |
| 647 } // namespace net | 647 } // namespace net |
| OLD | NEW |