1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/base64.h" 6 #include "base/format_macros.h" 7 #include "base/json/json_reader.h" 8 #include "base/logging.h" 9 #include "base/stl_util.h" 10 #include "base/strings/string_util.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/time/time.h" 13 #include "base/values.h" 14 #include "crypto/sha2.h" 15 #include "net/cert/crl_set.h" 16 #include "third_party/zlib/zlib.h" 17 18 namespace net { 19 20 // Decompress zlib decompressed |in| into |out|. |out_len| is the number of 21 // bytes at |out| and must be exactly equal to the size of the decompressed 22 // data. 23 static bool DecompressZlib(uint8* out, int out_len, base::StringPiece in) { 24 z_stream z; 25 memset(&z, 0, sizeof(z)); 26 27 z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in.data())); 28 z.avail_in = in.size(); 29 z.next_out = reinterpret_cast<Bytef*>(out); 30 z.avail_out = out_len; 31 32 if (inflateInit(&z) != Z_OK) 33 return false; 34 bool ret = false; 35 int r = inflate(&z, Z_FINISH); 36 if (r != Z_STREAM_END) 37 goto err; 38 if (z.avail_in || z.avail_out) 39 goto err; 40 ret = true; 41 42 err: 43 inflateEnd(&z); 44 return ret; 45 } 46 47 CRLSet::CRLSet() 48 : sequence_(0), 49 not_after_(0) { 50 } 51 52 CRLSet::~CRLSet() { 53 } 54 55 // CRLSet format: 56 // 57 // uint16le header_len 58 // byte[header_len] header_bytes 59 // repeated { 60 // byte[32] parent_spki_sha256 61 // uint32le num_serials 62 // [num_serials] { 63 // uint8 serial_length; 64 // byte[serial_length] serial; 65 // } 66 // 67 // header_bytes consists of a JSON dictionary with the following keys: 68 // Version (int): currently 0 69 // ContentType (string): "CRLSet" or "CRLSetDelta" (magic value) 70 // DeltaFrom (int32): if this is a delta update (see below), then this 71 // contains the sequence number of the base CRLSet. 72 // Sequence (int32): the monotonic sequence number of this CRL set. 73 // 74 // A delta CRLSet is similar to a CRLSet: 75 // 76 // struct CompressedChanges { 77 // uint32le uncompressed_size 78 // uint32le compressed_size 79 // byte[compressed_size] zlib_data 80 // } 81 // 82 // uint16le header_len 83 // byte[header_len] header_bytes 84 // CompressedChanges crl_changes 85 // [crl_changes.uncompressed_size] { 86 // switch (crl_changes[i]) { 87 // case 0: 88 // // CRL is the same 89 // case 1: 90 // // New CRL inserted 91 // // See CRL structure from the non-delta format 92 // case 2: 93 // // CRL deleted 94 // case 3: 95 // // CRL changed 96 // CompressedChanges serials_changes 97 // [serials_changes.uncompressed_size] { 98 // switch (serials_changes[i]) { 99 // case 0: 100 // // the serial is the same 101 // case 1: 102 // // serial inserted 103 // uint8 serial_length 104 // byte[serial_length] serial 105 // case 2: 106 // // serial deleted 107 // } 108 // } 109 // } 110 // } 111 // 112 // A delta CRLSet applies to a specific CRL set as given in the 113 // header's "DeltaFrom" value. The delta describes the changes to each CRL 114 // in turn with a zlib compressed array of options: either the CRL is the same, 115 // a new CRL is inserted, the CRL is deleted or the CRL is updated. In the case 116 // of an update, the serials in the CRL are considered in the same fashion 117 // except there is no delta update of a serial number: they are either 118 // inserted, deleted or left the same. 119 120 // ReadHeader reads the header (including length prefix) from |data| and 121 // updates |data| to remove the header on return. Caller takes ownership of the 122 // returned pointer. 123 static base::DictionaryValue* ReadHeader(base::StringPiece* data) { 124 if (data->size() < 2) 125 return NULL; 126 uint16 header_len; 127 memcpy(&header_len, data->data(), 2); // assumes little-endian. 128 data->remove_prefix(2); 129 130 if (data->size() < header_len) 131 return NULL; 132 133 const base::StringPiece header_bytes(data->data(), header_len); 134 data->remove_prefix(header_len); 135 136 scoped_ptr<base::Value> header(base::JSONReader::Read( 137 header_bytes, base::JSON_ALLOW_TRAILING_COMMAS)); 138 if (header.get() == NULL) 139 return NULL; 140 141 if (!header->IsType(base::Value::TYPE_DICTIONARY)) 142 return NULL; 143 return reinterpret_cast<base::DictionaryValue*>(header.release()); 144 } 145 146 // kCurrentFileVersion is the version of the CRLSet file format that we 147 // currently implement. 148 static const int kCurrentFileVersion = 0; 149 150 static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash, 151 std::vector<std::string>* out_serials) { 152 if (data->size() < crypto::kSHA256Length) 153 return false; 154 *out_parent_spki_hash = std::string(data->data(), crypto::kSHA256Length); 155 data->remove_prefix(crypto::kSHA256Length); 156 157 if (data->size() < sizeof(uint32)) 158 return false; 159 uint32 num_serials; 160 memcpy(&num_serials, data->data(), sizeof(uint32)); // assumes little endian 161 data->remove_prefix(sizeof(uint32)); 162 163 for (uint32 i = 0; i < num_serials; ++i) { 164 uint8 serial_length; 165 if (data->size() < sizeof(uint8)) 166 return false; 167 memcpy(&serial_length, data->data(), sizeof(uint8)); 168 data->remove_prefix(sizeof(uint8)); 169 170 if (data->size() < serial_length) 171 return false; 172 std::string serial(data->data(), serial_length); 173 data->remove_prefix(serial_length); 174 out_serials->push_back(serial); 175 } 176 177 return true; 178 } 179 180 bool CRLSet::CopyBlockedSPKIsFromHeader(base::DictionaryValue* header_dict) { 181 base::ListValue* blocked_spkis_list = NULL; 182 if (!header_dict->GetList("BlockedSPKIs", &blocked_spkis_list)) { 183 // BlockedSPKIs is optional, so it's fine if we don't find it. 184 return true; 185 } 186 187 blocked_spkis_.clear(); 188 189 for (size_t i = 0; i < blocked_spkis_list->GetSize(); ++i) { 190 std::string spki_sha256_base64, spki_sha256; 191 if (!blocked_spkis_list->GetString(i, &spki_sha256_base64)) 192 return false; 193 if (!base::Base64Decode(spki_sha256_base64, &spki_sha256)) 194 return false; 195 blocked_spkis_.push_back(spki_sha256); 196 } 197 198 return true; 199 } 200 201 // static 202 bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) { 203 // Other parts of Chrome assume that we're little endian, so we don't lose 204 // anything by doing this. 205 #if defined(__BYTE_ORDER) 206 // Linux check 207 COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian); 208 #elif defined(__BIG_ENDIAN__) 209 // Mac check 210 #error assumes little endian 211 #endif 212 213 scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); 214 if (!header_dict.get()) 215 return false; 216 217 std::string contents; 218 if (!header_dict->GetString("ContentType", &contents)) 219 return false; 220 if (contents != "CRLSet") 221 return false; 222 223 int version; 224 if (!header_dict->GetInteger("Version", &version) || 225 version != kCurrentFileVersion) { 226 return false; 227 } 228 229 int sequence; 230 if (!header_dict->GetInteger("Sequence", &sequence)) 231 return false; 232 233 double not_after; 234 if (!header_dict->GetDouble("NotAfter", ¬_after)) { 235 // NotAfter is optional for now. 236 not_after = 0; 237 } 238 if (not_after < 0) 239 return false; 240 241 scoped_refptr<CRLSet> crl_set(new CRLSet); 242 crl_set->sequence_ = static_cast<uint32>(sequence); 243 crl_set->not_after_ = static_cast<uint64>(not_after); 244 245 for (size_t crl_index = 0; !data.empty(); crl_index++) { 246 std::string parent_spki_sha256; 247 std::vector<std::string> serials; 248 if (!ReadCRL(&data, &parent_spki_sha256, &serials)) 249 return false; 250 251 crl_set->crls_.push_back(std::make_pair(parent_spki_sha256, serials)); 252 crl_set->crls_index_by_issuer_[parent_spki_sha256] = crl_index; 253 } 254 255 if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get())) 256 return false; 257 258 *out_crl_set = crl_set; 259 return true; 260 } 261 262 // kMaxUncompressedChangesLength is the largest changes array that we'll 263 // accept. This bounds the number of CRLs in the CRLSet as well as the number 264 // of serial numbers in a given CRL. 265 static const unsigned kMaxUncompressedChangesLength = 1024 * 1024; 266 267 static bool ReadChanges(base::StringPiece* data, 268 std::vector<uint8>* out_changes) { 269 uint32 uncompressed_size, compressed_size; 270 if (data->size() < 2 * sizeof(uint32)) 271 return false; 272 // assumes little endian. 273 memcpy(&uncompressed_size, data->data(), sizeof(uint32)); 274 data->remove_prefix(4); 275 memcpy(&compressed_size, data->data(), sizeof(uint32)); 276 data->remove_prefix(4); 277 278 if (uncompressed_size > kMaxUncompressedChangesLength) 279 return false; 280 if (data->size() < compressed_size) 281 return false; 282 283 out_changes->clear(); 284 if (uncompressed_size == 0) 285 return true; 286 287 out_changes->resize(uncompressed_size); 288 base::StringPiece compressed(data->data(), compressed_size); 289 data->remove_prefix(compressed_size); 290 return DecompressZlib(&(*out_changes)[0], uncompressed_size, compressed); 291 } 292 293 // These are the range coder symbols used in delta updates. 294 enum { 295 SYMBOL_SAME = 0, 296 SYMBOL_INSERT = 1, 297 SYMBOL_DELETE = 2, 298 SYMBOL_CHANGED = 3, 299 }; 300 301 bool ReadDeltaCRL(base::StringPiece* data, 302 const std::vector<std::string>& old_serials, 303 std::vector<std::string>* out_serials) { 304 std::vector<uint8> changes; 305 if (!ReadChanges(data, &changes)) 306 return false; 307 308 size_t i = 0; 309 for (std::vector<uint8>::const_iterator k = changes.begin(); 310 k != changes.end(); ++k) { 311 if (*k == SYMBOL_SAME) { 312 if (i >= old_serials.size()) 313 return false; 314 out_serials->push_back(old_serials[i]); 315 i++; 316 } else if (*k == SYMBOL_INSERT) { 317 uint8 serial_length; 318 if (data->size() < sizeof(uint8)) 319 return false; 320 memcpy(&serial_length, data->data(), sizeof(uint8)); 321 data->remove_prefix(sizeof(uint8)); 322 323 if (data->size() < serial_length) 324 return false; 325 const std::string serial(data->data(), serial_length); 326 data->remove_prefix(serial_length); 327 328 out_serials->push_back(serial); 329 } else if (*k == SYMBOL_DELETE) { 330 if (i >= old_serials.size()) 331 return false; 332 i++; 333 } else { 334 NOTREACHED(); 335 return false; 336 } 337 } 338 339 if (i != old_serials.size()) 340 return false; 341 return true; 342 } 343 344 bool CRLSet::ApplyDelta(const base::StringPiece& in_data, 345 scoped_refptr<CRLSet>* out_crl_set) { 346 base::StringPiece data(in_data); 347 scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); 348 if (!header_dict.get()) 349 return false; 350 351 std::string contents; 352 if (!header_dict->GetString("ContentType", &contents)) 353 return false; 354 if (contents != "CRLSetDelta") 355 return false; 356 357 int version; 358 if (!header_dict->GetInteger("Version", &version) || 359 version != kCurrentFileVersion) { 360 return false; 361 } 362 363 int sequence, delta_from; 364 if (!header_dict->GetInteger("Sequence", &sequence) || 365 !header_dict->GetInteger("DeltaFrom", &delta_from) || 366 delta_from < 0 || 367 static_cast<uint32>(delta_from) != sequence_) { 368 return false; 369 } 370 371 double not_after; 372 if (!header_dict->GetDouble("NotAfter", ¬_after)) { 373 // NotAfter is optional for now. 374 not_after = 0; 375 } 376 if (not_after < 0) 377 return false; 378 379 scoped_refptr<CRLSet> crl_set(new CRLSet); 380 crl_set->sequence_ = static_cast<uint32>(sequence); 381 crl_set->not_after_ = static_cast<uint64>(not_after); 382 383 if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get())) 384 return false; 385 386 std::vector<uint8> crl_changes; 387 388 if (!ReadChanges(&data, &crl_changes)) 389 return false; 390 391 size_t i = 0, j = 0; 392 for (std::vector<uint8>::const_iterator k = crl_changes.begin(); 393 k != crl_changes.end(); ++k) { 394 if (*k == SYMBOL_SAME) { 395 if (i >= crls_.size()) 396 return false; 397 crl_set->crls_.push_back(crls_[i]); 398 crl_set->crls_index_by_issuer_[crls_[i].first] = j; 399 i++; 400 j++; 401 } else if (*k == SYMBOL_INSERT) { 402 std::string parent_spki_hash; 403 std::vector<std::string> serials; 404 if (!ReadCRL(&data, &parent_spki_hash, &serials)) 405 return false; 406 crl_set->crls_.push_back(std::make_pair(parent_spki_hash, serials)); 407 crl_set->crls_index_by_issuer_[parent_spki_hash] = j; 408 j++; 409 } else if (*k == SYMBOL_DELETE) { 410 if (i >= crls_.size()) 411 return false; 412 i++; 413 } else if (*k == SYMBOL_CHANGED) { 414 if (i >= crls_.size()) 415 return false; 416 std::vector<std::string> serials; 417 if (!ReadDeltaCRL(&data, crls_[i].second, &serials)) 418 return false; 419 crl_set->crls_.push_back(std::make_pair(crls_[i].first, serials)); 420 crl_set->crls_index_by_issuer_[crls_[i].first] = j; 421 i++; 422 j++; 423 } else { 424 NOTREACHED(); 425 return false; 426 } 427 } 428 429 if (!data.empty()) 430 return false; 431 if (i != crls_.size()) 432 return false; 433 434 *out_crl_set = crl_set; 435 return true; 436 } 437 438 // static 439 bool CRLSet::GetIsDeltaUpdate(const base::StringPiece& in_data, 440 bool* is_delta) { 441 base::StringPiece data(in_data); 442 scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); 443 if (!header_dict.get()) 444 return false; 445 446 std::string contents; 447 if (!header_dict->GetString("ContentType", &contents)) 448 return false; 449 450 if (contents == "CRLSet") { 451 *is_delta = false; 452 } else if (contents == "CRLSetDelta") { 453 *is_delta = true; 454 } else { 455 return false; 456 } 457 458 return true; 459 } 460 461 std::string CRLSet::Serialize() const { 462 std::string header = base::StringPrintf( 463 "{" 464 "\"Version\":0," 465 "\"ContentType\":\"CRLSet\"," 466 "\"Sequence\":%u," 467 "\"DeltaFrom\":0," 468 "\"NumParents\":%u," 469 "\"BlockedSPKIs\":[", 470 static_cast<unsigned>(sequence_), 471 static_cast<unsigned>(crls_.size())); 472 473 for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin(); 474 i != blocked_spkis_.end(); ++i) { 475 std::string spki_hash_base64; 476 base::Base64Encode(*i, &spki_hash_base64); 477 478 if (i != blocked_spkis_.begin()) 479 header += ","; 480 header += "\"" + spki_hash_base64 + "\""; 481 } 482 header += "]"; 483 if (not_after_ != 0) 484 header += base::StringPrintf(",\"NotAfter\":%" PRIu64, not_after_); 485 header += "}"; 486 487 size_t len = 2 /* header len */ + header.size(); 488 489 for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) { 490 len += i->first.size() + 4 /* num serials */; 491 for (std::vector<std::string>::const_iterator j = i->second.begin(); 492 j != i->second.end(); ++j) { 493 len += 1 /* serial length */ + j->size(); 494 } 495 } 496 497 std::string ret; 498 char* out = WriteInto(&ret, len + 1 /* to include final NUL */); 499 size_t off = 0; 500 out[off++] = header.size(); 501 out[off++] = header.size() >> 8; 502 memcpy(out + off, header.data(), header.size()); 503 off += header.size(); 504 505 for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) { 506 memcpy(out + off, i->first.data(), i->first.size()); 507 off += i->first.size(); 508 const uint32 num_serials = i->second.size(); 509 memcpy(out + off, &num_serials, sizeof(num_serials)); 510 off += sizeof(num_serials); 511 512 for (std::vector<std::string>::const_iterator j = i->second.begin(); 513 j != i->second.end(); ++j) { 514 out[off++] = j->size(); 515 memcpy(out + off, j->data(), j->size()); 516 off += j->size(); 517 } 518 } 519 520 CHECK_EQ(off, len); 521 return ret; 522 } 523 524 CRLSet::Result CRLSet::CheckSPKI(const base::StringPiece& spki_hash) const { 525 for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin(); 526 i != blocked_spkis_.end(); ++i) { 527 if (spki_hash.size() == i->size() && 528 memcmp(spki_hash.data(), i->data(), i->size()) == 0) { 529 return REVOKED; 530 } 531 } 532 533 return GOOD; 534 } 535 536 CRLSet::Result CRLSet::CheckSerial( 537 const base::StringPiece& serial_number, 538 const base::StringPiece& issuer_spki_hash) const { 539 base::StringPiece serial(serial_number); 540 541 if (!serial.empty() && (serial[0] & 0x80) != 0) { 542 // This serial number is negative but the process which generates CRL sets 543 // will reject any certificates with negative serial numbers as invalid. 544 return UNKNOWN; 545 } 546 547 // Remove any leading zero bytes. 548 while (serial.size() > 1 && serial[0] == 0x00) 549 serial.remove_prefix(1); 550 551 std::map<std::string, size_t>::const_iterator i = 552 crls_index_by_issuer_.find(issuer_spki_hash.as_string()); 553 if (i == crls_index_by_issuer_.end()) 554 return UNKNOWN; 555 const std::vector<std::string>& serials = crls_[i->second].second; 556 557 for (std::vector<std::string>::const_iterator i = serials.begin(); 558 i != serials.end(); ++i) { 559 if (base::StringPiece(*i) == serial) 560 return REVOKED; 561 } 562 563 return GOOD; 564 } 565 566 bool CRLSet::IsExpired() const { 567 if (not_after_ == 0) 568 return false; 569 570 uint64 now = base::Time::Now().ToTimeT(); 571 return now > not_after_; 572 } 573 574 uint32 CRLSet::sequence() const { 575 return sequence_; 576 } 577 578 const CRLSet::CRLList& CRLSet::crls() const { 579 return crls_; 580 } 581 582 // static 583 CRLSet* CRLSet::EmptyCRLSetForTesting() { 584 return ForTesting(false, NULL, ""); 585 } 586 587 CRLSet* CRLSet::ExpiredCRLSetForTesting() { 588 return ForTesting(true, NULL, ""); 589 } 590 591 // static 592 CRLSet* CRLSet::ForTesting(bool is_expired, 593 const SHA256HashValue* issuer_spki, 594 const std::string& serial_number) { 595 CRLSet* crl_set = new CRLSet; 596 if (is_expired) 597 crl_set->not_after_ = 1; 598 if (issuer_spki != NULL) { 599 const std::string spki(reinterpret_cast<const char*>(issuer_spki->data), 600 sizeof(issuer_spki->data)); 601 crl_set->crls_.push_back(make_pair(spki, std::vector<std::string>())); 602 crl_set->crls_index_by_issuer_[spki] = 0; 603 } 604 605 if (!serial_number.empty()) 606 crl_set->crls_[0].second.push_back(serial_number); 607 608 return crl_set; 609 } 610 611 } // namespace net 612