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 |