| 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" |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 159 COMPRESSED = 1, | 159 COMPRESSED = 1, |
| 160 // CACHED means that the certificate is already known to the peer and will | 160 // CACHED means that the certificate is already known to the peer and will |
| 161 // be replaced by its 64-bit hash (in |hash|). | 161 // be replaced by its 64-bit hash (in |hash|). |
| 162 CACHED = 2, | 162 CACHED = 2, |
| 163 // COMMON means that the certificate is in a common certificate set known | 163 // COMMON means that the certificate is in a common certificate set known |
| 164 // to the peer with hash |set_hash| and certificate index |index|. | 164 // to the peer with hash |set_hash| and certificate index |index|. |
| 165 COMMON = 3, | 165 COMMON = 3, |
| 166 }; | 166 }; |
| 167 | 167 |
| 168 Type type; | 168 Type type; |
| 169 uint64 hash; | 169 uint64_t hash; |
| 170 uint64 set_hash; | 170 uint64_t set_hash; |
| 171 uint32 index; | 171 uint32_t index; |
| 172 }; | 172 }; |
| 173 | 173 |
| 174 // MatchCerts returns a vector of CertEntries describing how to most | 174 // MatchCerts returns a vector of CertEntries describing how to most |
| 175 // efficiently represent |certs| to a peer who has the common sets identified | 175 // 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 | 176 // by |client_common_set_hashes| and who has cached the certificates with the |
| 177 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. | 177 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|. |
| 178 vector<CertEntry> MatchCerts(const vector<string>& certs, | 178 vector<CertEntry> MatchCerts(const vector<string>& certs, |
| 179 StringPiece client_common_set_hashes, | 179 StringPiece client_common_set_hashes, |
| 180 StringPiece client_cached_cert_hashes, | 180 StringPiece client_cached_cert_hashes, |
| 181 const CommonCertSets* common_sets) { | 181 const CommonCertSets* common_sets) { |
| 182 vector<CertEntry> entries; | 182 vector<CertEntry> entries; |
| 183 entries.reserve(certs.size()); | 183 entries.reserve(certs.size()); |
| 184 | 184 |
| 185 const bool cached_valid = | 185 const bool cached_valid = |
| 186 client_cached_cert_hashes.size() % sizeof(uint64) == 0 && | 186 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 && |
| 187 !client_cached_cert_hashes.empty(); | 187 !client_cached_cert_hashes.empty(); |
| 188 | 188 |
| 189 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); | 189 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); |
| 190 ++i) { | 190 ++i) { |
| 191 CertEntry entry; | 191 CertEntry entry; |
| 192 | 192 |
| 193 if (cached_valid) { | 193 if (cached_valid) { |
| 194 bool cached = false; | 194 bool cached = false; |
| 195 | 195 |
| 196 uint64 hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size()); | 196 uint64_t hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size()); |
| 197 // This assumes that the machine is little-endian. | 197 // This assumes that the machine is little-endian. |
| 198 for (size_t j = 0; j < client_cached_cert_hashes.size(); | 198 for (size_t j = 0; j < client_cached_cert_hashes.size(); |
| 199 j += sizeof(uint64)) { | 199 j += sizeof(uint64_t)) { |
| 200 uint64 cached_hash; | 200 uint64_t cached_hash; |
| 201 memcpy(&cached_hash, client_cached_cert_hashes.data() + j, | 201 memcpy(&cached_hash, client_cached_cert_hashes.data() + j, |
| 202 sizeof(uint64)); | 202 sizeof(uint64_t)); |
| 203 if (hash != cached_hash) { | 203 if (hash != cached_hash) { |
| 204 continue; | 204 continue; |
| 205 } | 205 } |
| 206 | 206 |
| 207 entry.type = CertEntry::CACHED; | 207 entry.type = CertEntry::CACHED; |
| 208 entry.hash = hash; | 208 entry.hash = hash; |
| 209 entries.push_back(entry); | 209 entries.push_back(entry); |
| 210 cached = true; | 210 cached = true; |
| 211 break; | 211 break; |
| 212 } | 212 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 236 size_t CertEntriesSize(const vector<CertEntry>& entries) { | 236 size_t CertEntriesSize(const vector<CertEntry>& entries) { |
| 237 size_t entries_size = 0; | 237 size_t entries_size = 0; |
| 238 | 238 |
| 239 for (vector<CertEntry>::const_iterator i = entries.begin(); | 239 for (vector<CertEntry>::const_iterator i = entries.begin(); |
| 240 i != entries.end(); ++i) { | 240 i != entries.end(); ++i) { |
| 241 entries_size++; | 241 entries_size++; |
| 242 switch (i->type) { | 242 switch (i->type) { |
| 243 case CertEntry::COMPRESSED: | 243 case CertEntry::COMPRESSED: |
| 244 break; | 244 break; |
| 245 case CertEntry::CACHED: | 245 case CertEntry::CACHED: |
| 246 entries_size += sizeof(uint64); | 246 entries_size += sizeof(uint64_t); |
| 247 break; | 247 break; |
| 248 case CertEntry::COMMON: | 248 case CertEntry::COMMON: |
| 249 entries_size += sizeof(uint64) + sizeof(uint32); | 249 entries_size += sizeof(uint64_t) + sizeof(uint32_t); |
| 250 break; | 250 break; |
| 251 } | 251 } |
| 252 } | 252 } |
| 253 | 253 |
| 254 entries_size++; // for end marker | 254 entries_size++; // for end marker |
| 255 | 255 |
| 256 return entries_size; | 256 return entries_size; |
| 257 } | 257 } |
| 258 | 258 |
| 259 // SerializeCertEntries serialises |entries| to |out|, which must have enough | 259 // SerializeCertEntries serialises |entries| to |out|, which must have enough |
| 260 // space to contain them. | 260 // space to contain them. |
| 261 void SerializeCertEntries(uint8* out, const vector<CertEntry>& entries) { | 261 void SerializeCertEntries(uint8_t* out, const vector<CertEntry>& entries) { |
| 262 for (vector<CertEntry>::const_iterator i = entries.begin(); | 262 for (vector<CertEntry>::const_iterator i = entries.begin(); |
| 263 i != entries.end(); ++i) { | 263 i != entries.end(); ++i) { |
| 264 *out++ = static_cast<uint8>(i->type); | 264 *out++ = static_cast<uint8_t>(i->type); |
| 265 switch (i->type) { | 265 switch (i->type) { |
| 266 case CertEntry::COMPRESSED: | 266 case CertEntry::COMPRESSED: |
| 267 break; | 267 break; |
| 268 case CertEntry::CACHED: | 268 case CertEntry::CACHED: |
| 269 memcpy(out, &i->hash, sizeof(i->hash)); | 269 memcpy(out, &i->hash, sizeof(i->hash)); |
| 270 out += sizeof(uint64); | 270 out += sizeof(uint64_t); |
| 271 break; | 271 break; |
| 272 case CertEntry::COMMON: | 272 case CertEntry::COMMON: |
| 273 // Assumes a little-endian machine. | 273 // Assumes a little-endian machine. |
| 274 memcpy(out, &i->set_hash, sizeof(i->set_hash)); | 274 memcpy(out, &i->set_hash, sizeof(i->set_hash)); |
| 275 out += sizeof(i->set_hash); | 275 out += sizeof(i->set_hash); |
| 276 memcpy(out, &i->index, sizeof(uint32)); | 276 memcpy(out, &i->index, sizeof(uint32_t)); |
| 277 out += sizeof(uint32); | 277 out += sizeof(uint32_t); |
| 278 break; | 278 break; |
| 279 } | 279 } |
| 280 } | 280 } |
| 281 | 281 |
| 282 *out++ = 0; // end marker | 282 *out++ = 0; // end marker |
| 283 } | 283 } |
| 284 | 284 |
| 285 // ZlibDictForEntries returns a string that contains the zlib pre-shared | 285 // ZlibDictForEntries returns a string that contains the zlib pre-shared |
| 286 // dictionary to use in order to decompress a zlib block following |entries|. | 286 // dictionary to use in order to decompress a zlib block following |entries|. |
| 287 // |certs| is one-to-one with |entries| and contains the certificates for those | 287 // |certs| is one-to-one with |entries| and contains the certificates for those |
| (...skipping 23 matching lines...) Expand all Loading... |
| 311 | 311 |
| 312 zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings), | 312 zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings), |
| 313 sizeof(kCommonCertSubstrings)); | 313 sizeof(kCommonCertSubstrings)); |
| 314 | 314 |
| 315 DCHECK_EQ(zlib_dict.size(), zlib_dict_size); | 315 DCHECK_EQ(zlib_dict.size(), zlib_dict_size); |
| 316 | 316 |
| 317 return zlib_dict; | 317 return zlib_dict; |
| 318 } | 318 } |
| 319 | 319 |
| 320 // HashCerts returns the FNV-1a hashes of |certs|. | 320 // HashCerts returns the FNV-1a hashes of |certs|. |
| 321 vector<uint64> HashCerts(const vector<string>& certs) { | 321 vector<uint64_t> HashCerts(const vector<string>& certs) { |
| 322 vector<uint64> ret; | 322 vector<uint64_t> ret; |
| 323 ret.reserve(certs.size()); | 323 ret.reserve(certs.size()); |
| 324 | 324 |
| 325 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); | 325 for (vector<string>::const_iterator i = certs.begin(); i != certs.end(); |
| 326 ++i) { | 326 ++i) { |
| 327 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); | 327 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size())); |
| 328 } | 328 } |
| 329 | 329 |
| 330 return ret; | 330 return ret; |
| 331 } | 331 } |
| 332 | 332 |
| 333 // ParseEntries parses the serialised form of a vector of CertEntries from | 333 // 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 | 334 // |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|. | 335 // resolved using |cached_certs| and |common_sets| and written to |out_certs|. |
| 336 // |in_out| is updated to contain the trailing data. | 336 // |in_out| is updated to contain the trailing data. |
| 337 bool ParseEntries(StringPiece* in_out, | 337 bool ParseEntries(StringPiece* in_out, |
| 338 const vector<string>& cached_certs, | 338 const vector<string>& cached_certs, |
| 339 const CommonCertSets* common_sets, | 339 const CommonCertSets* common_sets, |
| 340 vector<CertEntry>* out_entries, | 340 vector<CertEntry>* out_entries, |
| 341 vector<string>* out_certs) { | 341 vector<string>* out_certs) { |
| 342 StringPiece in = *in_out; | 342 StringPiece in = *in_out; |
| 343 vector<uint64> cached_hashes; | 343 vector<uint64_t> cached_hashes; |
| 344 | 344 |
| 345 out_entries->clear(); | 345 out_entries->clear(); |
| 346 out_certs->clear(); | 346 out_certs->clear(); |
| 347 | 347 |
| 348 for (;;) { | 348 for (;;) { |
| 349 if (in.empty()) { | 349 if (in.empty()) { |
| 350 return false; | 350 return false; |
| 351 } | 351 } |
| 352 CertEntry entry; | 352 CertEntry entry; |
| 353 const uint8 type_byte = in[0]; | 353 const uint8_t type_byte = in[0]; |
| 354 in.remove_prefix(1); | 354 in.remove_prefix(1); |
| 355 | 355 |
| 356 if (type_byte == 0) { | 356 if (type_byte == 0) { |
| 357 break; | 357 break; |
| 358 } | 358 } |
| 359 | 359 |
| 360 entry.type = static_cast<CertEntry::Type>(type_byte); | 360 entry.type = static_cast<CertEntry::Type>(type_byte); |
| 361 | 361 |
| 362 switch (entry.type) { | 362 switch (entry.type) { |
| 363 case CertEntry::COMPRESSED: | 363 case CertEntry::COMPRESSED: |
| 364 out_certs->push_back(string()); | 364 out_certs->push_back(string()); |
| 365 break; | 365 break; |
| 366 case CertEntry::CACHED: { | 366 case CertEntry::CACHED: { |
| 367 if (in.size() < sizeof(uint64)) { | 367 if (in.size() < sizeof(uint64_t)) { |
| 368 return false; | 368 return false; |
| 369 } | 369 } |
| 370 memcpy(&entry.hash, in.data(), sizeof(uint64)); | 370 memcpy(&entry.hash, in.data(), sizeof(uint64_t)); |
| 371 in.remove_prefix(sizeof(uint64)); | 371 in.remove_prefix(sizeof(uint64_t)); |
| 372 | 372 |
| 373 if (cached_hashes.size() != cached_certs.size()) { | 373 if (cached_hashes.size() != cached_certs.size()) { |
| 374 cached_hashes = HashCerts(cached_certs); | 374 cached_hashes = HashCerts(cached_certs); |
| 375 } | 375 } |
| 376 bool found = false; | 376 bool found = false; |
| 377 for (size_t i = 0; i < cached_hashes.size(); i++) { | 377 for (size_t i = 0; i < cached_hashes.size(); i++) { |
| 378 if (cached_hashes[i] == entry.hash) { | 378 if (cached_hashes[i] == entry.hash) { |
| 379 out_certs->push_back(cached_certs[i]); | 379 out_certs->push_back(cached_certs[i]); |
| 380 found = true; | 380 found = true; |
| 381 break; | 381 break; |
| 382 } | 382 } |
| 383 } | 383 } |
| 384 if (!found) { | 384 if (!found) { |
| 385 return false; | 385 return false; |
| 386 } | 386 } |
| 387 break; | 387 break; |
| 388 } | 388 } |
| 389 case CertEntry::COMMON: { | 389 case CertEntry::COMMON: { |
| 390 if (!common_sets) { | 390 if (!common_sets) { |
| 391 return false; | 391 return false; |
| 392 } | 392 } |
| 393 if (in.size() < sizeof(uint64) + sizeof(uint32)) { | 393 if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) { |
| 394 return false; | 394 return false; |
| 395 } | 395 } |
| 396 memcpy(&entry.set_hash, in.data(), sizeof(uint64)); | 396 memcpy(&entry.set_hash, in.data(), sizeof(uint64_t)); |
| 397 in.remove_prefix(sizeof(uint64)); | 397 in.remove_prefix(sizeof(uint64_t)); |
| 398 memcpy(&entry.index, in.data(), sizeof(uint32)); | 398 memcpy(&entry.index, in.data(), sizeof(uint32_t)); |
| 399 in.remove_prefix(sizeof(uint32)); | 399 in.remove_prefix(sizeof(uint32_t)); |
| 400 | 400 |
| 401 StringPiece cert = common_sets->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; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 StringPiece client_common_set_hashes, | 457 StringPiece client_common_set_hashes, |
| 458 StringPiece client_cached_cert_hashes, | 458 StringPiece client_cached_cert_hashes, |
| 459 const CommonCertSets* common_sets) { | 459 const CommonCertSets* common_sets) { |
| 460 const vector<CertEntry> entries = MatchCerts( | 460 const 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 length */ + certs[i].size(); | 467 uncompressed_size += 4 /* uint32_t length */ + certs[i].size(); |
| 468 } | 468 } |
| 469 } | 469 } |
| 470 | 470 |
| 471 size_t compressed_size = 0; | 471 size_t compressed_size = 0; |
| 472 z_stream z; | 472 z_stream z; |
| 473 ScopedZLib scoped_z(ScopedZLib::DEFLATE); | 473 ScopedZLib scoped_z(ScopedZLib::DEFLATE); |
| 474 | 474 |
| 475 if (uncompressed_size > 0) { | 475 if (uncompressed_size > 0) { |
| 476 memset(&z, 0, sizeof(z)); | 476 memset(&z, 0, sizeof(z)); |
| 477 int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION); | 477 int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION); |
| 478 DCHECK_EQ(Z_OK, rv); | 478 DCHECK_EQ(Z_OK, rv); |
| 479 if (rv != Z_OK) { | 479 if (rv != Z_OK) { |
| 480 return ""; | 480 return ""; |
| 481 } | 481 } |
| 482 scoped_z.reset(&z); | 482 scoped_z.reset(&z); |
| 483 | 483 |
| 484 string zlib_dict = ZlibDictForEntries(entries, certs); | 484 string zlib_dict = ZlibDictForEntries(entries, certs); |
| 485 | 485 |
| 486 rv = deflateSetDictionary(&z, reinterpret_cast<const uint8*>(&zlib_dict[0]), | 486 rv = deflateSetDictionary( |
| 487 zlib_dict.size()); | 487 &z, reinterpret_cast<const uint8_t*>(&zlib_dict[0]), zlib_dict.size()); |
| 488 DCHECK_EQ(Z_OK, rv); | 488 DCHECK_EQ(Z_OK, rv); |
| 489 if (rv != Z_OK) { | 489 if (rv != Z_OK) { |
| 490 return ""; | 490 return ""; |
| 491 } | 491 } |
| 492 | 492 |
| 493 compressed_size = deflateBound(&z, uncompressed_size); | 493 compressed_size = deflateBound(&z, uncompressed_size); |
| 494 } | 494 } |
| 495 | 495 |
| 496 const size_t entries_size = CertEntriesSize(entries); | 496 const size_t entries_size = CertEntriesSize(entries); |
| 497 | 497 |
| 498 string result; | 498 string result; |
| 499 result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) + | 499 result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) + |
| 500 compressed_size); | 500 compressed_size); |
| 501 | 501 |
| 502 uint8* j = reinterpret_cast<uint8*>(&result[0]); | 502 uint8_t* j = reinterpret_cast<uint8_t*>(&result[0]); |
| 503 SerializeCertEntries(j, entries); | 503 SerializeCertEntries(j, entries); |
| 504 j += entries_size; | 504 j += entries_size; |
| 505 | 505 |
| 506 if (uncompressed_size == 0) { | 506 if (uncompressed_size == 0) { |
| 507 return result; | 507 return result; |
| 508 } | 508 } |
| 509 | 509 |
| 510 uint32 uncompressed_size_32 = uncompressed_size; | 510 uint32_t uncompressed_size_32 = uncompressed_size; |
| 511 memcpy(j, &uncompressed_size_32, sizeof(uint32)); | 511 memcpy(j, &uncompressed_size_32, sizeof(uint32_t)); |
| 512 j += sizeof(uint32); | 512 j += sizeof(uint32_t); |
| 513 | 513 |
| 514 int rv; | 514 int rv; |
| 515 | 515 |
| 516 z.next_out = j; | 516 z.next_out = j; |
| 517 z.avail_out = compressed_size; | 517 z.avail_out = compressed_size; |
| 518 | 518 |
| 519 for (size_t i = 0; i < certs.size(); i++) { | 519 for (size_t i = 0; i < certs.size(); i++) { |
| 520 if (entries[i].type != CertEntry::COMPRESSED) { | 520 if (entries[i].type != CertEntry::COMPRESSED) { |
| 521 continue; | 521 continue; |
| 522 } | 522 } |
| 523 | 523 |
| 524 uint32 length32 = certs[i].size(); | 524 uint32_t length32 = certs[i].size(); |
| 525 z.next_in = reinterpret_cast<uint8*>(&length32); | 525 z.next_in = reinterpret_cast<uint8_t*>(&length32); |
| 526 z.avail_in = sizeof(length32); | 526 z.avail_in = sizeof(length32); |
| 527 rv = deflate(&z, Z_NO_FLUSH); | 527 rv = deflate(&z, Z_NO_FLUSH); |
| 528 DCHECK_EQ(Z_OK, rv); | 528 DCHECK_EQ(Z_OK, rv); |
| 529 DCHECK_EQ(0u, z.avail_in); | 529 DCHECK_EQ(0u, z.avail_in); |
| 530 if (rv != Z_OK || z.avail_in) { | 530 if (rv != Z_OK || z.avail_in) { |
| 531 return ""; | 531 return ""; |
| 532 } | 532 } |
| 533 | 533 |
| 534 z.next_in = | 534 z.next_in = |
| 535 const_cast<uint8*>(reinterpret_cast<const uint8*>(certs[i].data())); | 535 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(certs[i].data())); |
| 536 z.avail_in = certs[i].size(); | 536 z.avail_in = certs[i].size(); |
| 537 rv = deflate(&z, Z_NO_FLUSH); | 537 rv = deflate(&z, Z_NO_FLUSH); |
| 538 DCHECK_EQ(Z_OK, rv); | 538 DCHECK_EQ(Z_OK, rv); |
| 539 DCHECK_EQ(0u, z.avail_in); | 539 DCHECK_EQ(0u, z.avail_in); |
| 540 if (rv != Z_OK || z.avail_in) { | 540 if (rv != Z_OK || z.avail_in) { |
| 541 return ""; | 541 return ""; |
| 542 } | 542 } |
| 543 } | 543 } |
| 544 | 544 |
| 545 z.avail_in = 0; | 545 z.avail_in = 0; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 557 bool CertCompressor::DecompressChain(StringPiece in, | 557 bool CertCompressor::DecompressChain(StringPiece in, |
| 558 const vector<string>& cached_certs, | 558 const vector<string>& cached_certs, |
| 559 const CommonCertSets* common_sets, | 559 const CommonCertSets* common_sets, |
| 560 vector<string>* out_certs) { | 560 vector<string>* out_certs) { |
| 561 vector<CertEntry> entries; | 561 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 scoped_ptr<uint8[]> uncompressed_data; | 567 scoped_ptr<uint8_t[]> uncompressed_data; |
| 568 StringPiece uncompressed; | 568 StringPiece uncompressed; |
| 569 | 569 |
| 570 if (!in.empty()) { | 570 if (!in.empty()) { |
| 571 if (in.size() < sizeof(uint32)) { | 571 if (in.size() < sizeof(uint32_t)) { |
| 572 return false; | 572 return false; |
| 573 } | 573 } |
| 574 | 574 |
| 575 uint32 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)); | 577 in.remove_prefix(sizeof(uint32_t)); |
| 578 | 578 |
| 579 if (uncompressed_size > 128 * 1024) { | 579 if (uncompressed_size > 128 * 1024) { |
| 580 return false; | 580 return false; |
| 581 } | 581 } |
| 582 | 582 |
| 583 uncompressed_data.reset(new uint8[uncompressed_size]); | 583 uncompressed_data.reset(new uint8_t[uncompressed_size]); |
| 584 z_stream z; | 584 z_stream z; |
| 585 ScopedZLib scoped_z(ScopedZLib::INFLATE); | 585 ScopedZLib scoped_z(ScopedZLib::INFLATE); |
| 586 | 586 |
| 587 memset(&z, 0, sizeof(z)); | 587 memset(&z, 0, sizeof(z)); |
| 588 z.next_out = uncompressed_data.get(); | 588 z.next_out = uncompressed_data.get(); |
| 589 z.avail_out = uncompressed_size; | 589 z.avail_out = uncompressed_size; |
| 590 z.next_in = const_cast<uint8*>(reinterpret_cast<const uint8*>(in.data())); | 590 z.next_in = |
| 591 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(in.data())); |
| 591 z.avail_in = in.size(); | 592 z.avail_in = in.size(); |
| 592 | 593 |
| 593 if (Z_OK != inflateInit(&z)) { | 594 if (Z_OK != inflateInit(&z)) { |
| 594 return false; | 595 return false; |
| 595 } | 596 } |
| 596 scoped_z.reset(&z); | 597 scoped_z.reset(&z); |
| 597 | 598 |
| 598 int rv = inflate(&z, Z_FINISH); | 599 int rv = inflate(&z, Z_FINISH); |
| 599 if (rv == Z_NEED_DICT) { | 600 if (rv == Z_NEED_DICT) { |
| 600 string zlib_dict = ZlibDictForEntries(entries, *out_certs); | 601 string zlib_dict = ZlibDictForEntries(entries, *out_certs); |
| 601 const uint8* dict = reinterpret_cast<const uint8*>(zlib_dict.data()); | 602 const uint8_t* dict = reinterpret_cast<const uint8_t*>(zlib_dict.data()); |
| 602 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) { | 603 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) { |
| 603 return false; | 604 return false; |
| 604 } | 605 } |
| 605 rv = inflate(&z, Z_FINISH); | 606 rv = inflate(&z, Z_FINISH); |
| 606 } | 607 } |
| 607 | 608 |
| 608 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) { |
| 609 return false; | 610 return false; |
| 610 } | 611 } |
| 611 | 612 |
| 612 uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()), | 613 uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()), |
| 613 uncompressed_size); | 614 uncompressed_size); |
| 614 } | 615 } |
| 615 | 616 |
| 616 for (size_t i = 0; i < entries.size(); i++) { | 617 for (size_t i = 0; i < entries.size(); i++) { |
| 617 switch (entries[i].type) { | 618 switch (entries[i].type) { |
| 618 case CertEntry::COMPRESSED: | 619 case CertEntry::COMPRESSED: |
| 619 if (uncompressed.size() < sizeof(uint32)) { | 620 if (uncompressed.size() < sizeof(uint32_t)) { |
| 620 return false; | 621 return false; |
| 621 } | 622 } |
| 622 uint32 cert_len; | 623 uint32_t cert_len; |
| 623 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len)); | 624 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len)); |
| 624 uncompressed.remove_prefix(sizeof(uint32)); | 625 uncompressed.remove_prefix(sizeof(uint32_t)); |
| 625 if (uncompressed.size() < cert_len) { | 626 if (uncompressed.size() < cert_len) { |
| 626 return false; | 627 return false; |
| 627 } | 628 } |
| 628 (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string(); | 629 (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string(); |
| 629 uncompressed.remove_prefix(cert_len); | 630 uncompressed.remove_prefix(cert_len); |
| 630 break; | 631 break; |
| 631 case CertEntry::CACHED: | 632 case CertEntry::CACHED: |
| 632 case CertEntry::COMMON: | 633 case CertEntry::COMMON: |
| 633 break; | 634 break; |
| 634 } | 635 } |
| 635 } | 636 } |
| 636 | 637 |
| 637 if (!uncompressed.empty()) { | 638 if (!uncompressed.empty()) { |
| 638 return false; | 639 return false; |
| 639 } | 640 } |
| 640 | 641 |
| 641 return true; | 642 return true; |
| 642 } | 643 } |
| 643 | 644 |
| 644 } // namespace net | 645 } // namespace net |
| OLD | NEW |