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/crypto/cert_compressor.h" | 5 #include "net/quic/crypto/cert_compressor.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/memory/scoped_ptr.h" | 8 #include "base/memory/scoped_ptr.h" |
9 #include "net/quic/quic_utils.h" | 9 #include "net/quic/quic_utils.h" |
10 #include "third_party/zlib/zlib.h" | 10 #include "third_party/zlib/zlib.h" |
11 | 11 |
12 using base::StringPiece; | 12 using base::StringPiece; |
13 using std::string; | 13 using std::string; |
14 using std::vector; | 14 using std::vector; |
15 | 15 |
16 namespace net { | 16 namespace net { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings | 20 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings |
21 // in order to help zlib. This was generated via a fairly dumb algorithm from | 21 // 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. | 22 // the Alexa Top 5000 set - we could probably do better. |
23 static unsigned char kCommonCertSubstrings[] = { | 23 static const unsigned char kCommonCertSubstrings[] = { |
24 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, | 24 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, |
25 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, | 25 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, |
26 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, | 26 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, |
27 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, | 27 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01, |
28 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07, | 28 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07, |
29 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, | 29 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, |
30 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, | 30 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, |
31 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34, | 31 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34, |
32 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, | 32 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, |
33 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, | 33 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 uint32 index; | 169 uint32 index; |
170 }; | 170 }; |
171 | 171 |
172 // MatchCerts returns a vector of CertEntries describing how to most | 172 // MatchCerts returns a vector of CertEntries describing how to most |
173 // efficiently represent |certs| to a peer who has the common sets identified | 173 // efficiently represent |certs| to a peer who has the common sets identified |
174 // by |client_common_set_hashes| and who has cached the certificates with the | 174 // by |client_common_set_hashes| and who has cached the certificates with the |
175 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. | 175 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. |
176 vector<CertEntry> MatchCerts(const vector<string>& certs, | 176 vector<CertEntry> MatchCerts(const vector<string>& certs, |
177 StringPiece client_common_set_hashes, | 177 StringPiece client_common_set_hashes, |
178 StringPiece client_cached_cert_hashes, | 178 StringPiece client_cached_cert_hashes, |
179 const CommonCertSets* common_set) { | 179 const CommonCertSets* common_sets) { |
180 vector<CertEntry> entries; | 180 vector<CertEntry> entries; |
181 entries.reserve(certs.size()); | 181 entries.reserve(certs.size()); |
182 | 182 |
183 const bool cached_valid = | 183 const bool cached_valid = |
184 client_cached_cert_hashes.size() % sizeof(uint64) == 0 && | 184 client_cached_cert_hashes.size() % sizeof(uint64) == 0 && |
185 !client_cached_cert_hashes.empty(); | 185 !client_cached_cert_hashes.empty(); |
186 | 186 |
187 for (vector<string>::const_iterator i = certs.begin(); | 187 for (vector<string>::const_iterator i = certs.begin(); |
188 i != certs.end(); ++i) { | 188 i != certs.end(); ++i) { |
189 CertEntry entry; | 189 CertEntry entry; |
(...skipping 17 matching lines...) Expand all Loading... |
207 entries.push_back(entry); | 207 entries.push_back(entry); |
208 cached = true; | 208 cached = true; |
209 break; | 209 break; |
210 } | 210 } |
211 | 211 |
212 if (cached) { | 212 if (cached) { |
213 continue; | 213 continue; |
214 } | 214 } |
215 } | 215 } |
216 | 216 |
217 if (common_set && common_set->MatchCert(*i, client_common_set_hashes, | 217 if (common_sets && common_sets->MatchCert(*i, client_common_set_hashes, |
218 &entry.set_hash, &entry.index)) { | 218 &entry.set_hash, &entry.index)) { |
219 entry.type = CertEntry::COMMON; | 219 entry.type = CertEntry::COMMON; |
220 entries.push_back(entry); | 220 entries.push_back(entry); |
221 continue; | 221 continue; |
222 } | 222 } |
223 | 223 |
224 entry.type = CertEntry::COMPRESSED; | 224 entry.type = CertEntry::COMPRESSED; |
225 entries.push_back(entry); | 225 entries.push_back(entry); |
226 } | 226 } |
227 | 227 |
228 return entries; | 228 return entries; |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 for (vector<string>::const_iterator i = certs.begin(); | 321 for (vector<string>::const_iterator i = certs.begin(); |
322 i != certs.end(); ++i) { | 322 i != certs.end(); ++i) { |
323 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); | 323 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); |
324 } | 324 } |
325 | 325 |
326 return ret; | 326 return ret; |
327 } | 327 } |
328 | 328 |
329 // ParseEntries parses the serialised form of a vector of CertEntries from | 329 // ParseEntries parses the serialised form of a vector of CertEntries from |
330 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are | 330 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are |
331 // resolved using |cached_certs| and |common_set| and written to |out_certs|. | 331 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. |
332 // |in_out| is updated to contain the trailing data. | 332 // |in_out| is updated to contain the trailing data. |
333 bool ParseEntries(StringPiece* in_out, | 333 bool ParseEntries(StringPiece* in_out, |
334 const vector<string>& cached_certs, | 334 const vector<string>& cached_certs, |
335 const CommonCertSets* common_set, | 335 const CommonCertSets* common_sets, |
336 vector<CertEntry>* out_entries, | 336 vector<CertEntry>* out_entries, |
337 vector<string>* out_certs) { | 337 vector<string>* out_certs) { |
338 StringPiece in = *in_out; | 338 StringPiece in = *in_out; |
339 vector<uint64> cached_hashes; | 339 vector<uint64> cached_hashes; |
340 | 340 |
341 out_entries->clear(); | 341 out_entries->clear(); |
342 out_certs->clear(); | 342 out_certs->clear(); |
343 | 343 |
344 for (;;) { | 344 for (;;) { |
345 if (in.empty()) { | 345 if (in.empty()) { |
(...skipping 30 matching lines...) Expand all Loading... |
376 found = true; | 376 found = true; |
377 break; | 377 break; |
378 } | 378 } |
379 } | 379 } |
380 if (!found) { | 380 if (!found) { |
381 return false; | 381 return false; |
382 } | 382 } |
383 break; | 383 break; |
384 } | 384 } |
385 case CertEntry::COMMON: { | 385 case CertEntry::COMMON: { |
386 if (!common_set) { | 386 if (!common_sets) { |
387 return false; | 387 return false; |
388 } | 388 } |
389 if (in.size() < sizeof(uint64)) { | 389 if (in.size() < sizeof(uint64)) { |
390 return false; | 390 return false; |
391 } | 391 } |
392 memcpy(&entry.set_hash, in.data(), sizeof(uint64)); | 392 memcpy(&entry.set_hash, in.data(), sizeof(uint64)); |
393 in.remove_prefix(sizeof(uint64)); | 393 in.remove_prefix(sizeof(uint64)); |
394 | 394 |
395 if (in.size() < sizeof(uint32)) { | 395 if (in.size() < sizeof(uint32)) { |
396 return false; | 396 return false; |
397 } | 397 } |
398 memcpy(&entry.index, in.data(), sizeof(uint32)); | 398 memcpy(&entry.index, in.data(), sizeof(uint32)); |
399 in.remove_prefix(sizeof(uint32)); | 399 in.remove_prefix(sizeof(uint32)); |
400 | 400 |
401 StringPiece cert = common_set->GetCert(entry.set_hash, entry.index); | 401 StringPiece cert = 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 30 matching lines...) Expand all Loading... |
442 const Type type_; | 442 const Type type_; |
443 }; | 443 }; |
444 | 444 |
445 } // anonymous namespace | 445 } // anonymous namespace |
446 | 446 |
447 | 447 |
448 // static | 448 // static |
449 string CertCompressor::CompressChain(const vector<string>& certs, | 449 string CertCompressor::CompressChain(const vector<string>& certs, |
450 StringPiece client_common_set_hashes, | 450 StringPiece client_common_set_hashes, |
451 StringPiece client_cached_cert_hashes, | 451 StringPiece client_cached_cert_hashes, |
452 const CommonCertSets* common_set) { | 452 const CommonCertSets* common_sets) { |
453 const vector<CertEntry> entries = MatchCerts( | 453 const vector<CertEntry> entries = MatchCerts( |
454 certs, client_common_set_hashes, client_cached_cert_hashes, common_set); | 454 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets); |
455 DCHECK_EQ(entries.size(), certs.size()); | 455 DCHECK_EQ(entries.size(), certs.size()); |
456 | 456 |
457 size_t uncompressed_size = 0; | 457 size_t uncompressed_size = 0; |
458 for (size_t i = 0; i < entries.size(); i++) { | 458 for (size_t i = 0; i < entries.size(); i++) { |
459 if (entries[i].type == CertEntry::COMPRESSED) { | 459 if (entries[i].type == CertEntry::COMPRESSED) { |
460 uncompressed_size += 4 /* uint32 length */ + certs[i].size(); | 460 uncompressed_size += 4 /* uint32 length */ + certs[i].size(); |
461 } | 461 } |
462 } | 462 } |
463 | 463 |
464 size_t compressed_size = 0; | 464 size_t compressed_size = 0; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 return ""; | 542 return ""; |
543 } | 543 } |
544 | 544 |
545 result.resize(result.size() - z.avail_out); | 545 result.resize(result.size() - z.avail_out); |
546 return result; | 546 return result; |
547 } | 547 } |
548 | 548 |
549 // static | 549 // static |
550 bool CertCompressor::DecompressChain(StringPiece in, | 550 bool CertCompressor::DecompressChain(StringPiece in, |
551 const vector<string>& cached_certs, | 551 const vector<string>& cached_certs, |
552 const CommonCertSets* common_set, | 552 const CommonCertSets* common_sets, |
553 vector<string>* out_certs) { | 553 vector<string>* out_certs) { |
554 vector<CertEntry> entries; | 554 vector<CertEntry> entries; |
555 if (!ParseEntries(&in, cached_certs, common_set, &entries, out_certs)) { | 555 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) { |
556 return false; | 556 return false; |
557 } | 557 } |
558 DCHECK_EQ(entries.size(), out_certs->size()); | 558 DCHECK_EQ(entries.size(), out_certs->size()); |
559 | 559 |
560 scoped_ptr<uint8[]> uncompressed_data; | 560 scoped_ptr<uint8[]> uncompressed_data; |
561 StringPiece uncompressed; | 561 StringPiece uncompressed; |
562 | 562 |
563 if (!in.empty()) { | 563 if (!in.empty()) { |
564 if (in.size() < sizeof(uint32)) { | 564 if (in.size() < sizeof(uint32)) { |
565 return false; | 565 return false; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
628 } | 628 } |
629 | 629 |
630 if (!uncompressed.empty()) { | 630 if (!uncompressed.empty()) { |
631 return false; | 631 return false; |
632 } | 632 } |
633 | 633 |
634 return true; | 634 return true; |
635 } | 635 } |
636 | 636 |
637 } // namespace net | 637 } // namespace net |
OLD | NEW |