Index: net/base/crl_set.cc |
diff --git a/net/base/crl_set.cc b/net/base/crl_set.cc |
deleted file mode 100644 |
index 735bb5e96e89c32da12ce9f326fe3e223de68729..0000000000000000000000000000000000000000 |
--- a/net/base/crl_set.cc |
+++ /dev/null |
@@ -1,593 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "base/base64.h" |
-#include "base/format_macros.h" |
-#include "base/json/json_reader.h" |
-#include "base/logging.h" |
-#include "base/stl_util.h" |
-#include "base/string_util.h" |
-#include "base/stringprintf.h" |
-#include "base/time.h" |
-#include "base/values.h" |
-#include "crypto/sha2.h" |
-#include "net/base/crl_set.h" |
-#include "third_party/zlib/zlib.h" |
- |
-namespace net { |
- |
-// Decompress zlib decompressed |in| into |out|. |out_len| is the number of |
-// bytes at |out| and must be exactly equal to the size of the decompressed |
-// data. |
-static bool DecompressZlib(uint8* out, int out_len, base::StringPiece in) { |
- z_stream z; |
- memset(&z, 0, sizeof(z)); |
- |
- z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in.data())); |
- z.avail_in = in.size(); |
- z.next_out = reinterpret_cast<Bytef*>(out); |
- z.avail_out = out_len; |
- |
- if (inflateInit(&z) != Z_OK) |
- return false; |
- bool ret = false; |
- int r = inflate(&z, Z_FINISH); |
- if (r != Z_STREAM_END) |
- goto err; |
- if (z.avail_in || z.avail_out) |
- goto err; |
- ret = true; |
- |
- err: |
- inflateEnd(&z); |
- return ret; |
-} |
- |
-CRLSet::CRLSet() |
- : sequence_(0), |
- not_after_(0) { |
-} |
- |
-CRLSet::~CRLSet() { |
-} |
- |
-// CRLSet format: |
-// |
-// uint16le header_len |
-// byte[header_len] header_bytes |
-// repeated { |
-// byte[32] parent_spki_sha256 |
-// uint32le num_serials |
-// [num_serials] { |
-// uint8 serial_length; |
-// byte[serial_length] serial; |
-// } |
-// |
-// header_bytes consists of a JSON dictionary with the following keys: |
-// Version (int): currently 0 |
-// ContentType (string): "CRLSet" or "CRLSetDelta" (magic value) |
-// DeltaFrom (int32): if this is a delta update (see below), then this |
-// contains the sequence number of the base CRLSet. |
-// Sequence (int32): the monotonic sequence number of this CRL set. |
-// |
-// A delta CRLSet is similar to a CRLSet: |
-// |
-// struct CompressedChanges { |
-// uint32le uncompressed_size |
-// uint32le compressed_size |
-// byte[compressed_size] zlib_data |
-// } |
-// |
-// uint16le header_len |
-// byte[header_len] header_bytes |
-// CompressedChanges crl_changes |
-// [crl_changes.uncompressed_size] { |
-// switch (crl_changes[i]) { |
-// case 0: |
-// // CRL is the same |
-// case 1: |
-// // New CRL inserted |
-// // See CRL structure from the non-delta format |
-// case 2: |
-// // CRL deleted |
-// case 3: |
-// // CRL changed |
-// CompressedChanges serials_changes |
-// [serials_changes.uncompressed_size] { |
-// switch (serials_changes[i]) { |
-// case 0: |
-// // the serial is the same |
-// case 1: |
-// // serial inserted |
-// uint8 serial_length |
-// byte[serial_length] serial |
-// case 2: |
-// // serial deleted |
-// } |
-// } |
-// } |
-// } |
-// |
-// A delta CRLSet applies to a specific CRL set as given in the |
-// header's "DeltaFrom" value. The delta describes the changes to each CRL |
-// in turn with a zlib compressed array of options: either the CRL is the same, |
-// a new CRL is inserted, the CRL is deleted or the CRL is updated. In the case |
-// of an update, the serials in the CRL are considered in the same fashion |
-// except there is no delta update of a serial number: they are either |
-// inserted, deleted or left the same. |
- |
-// ReadHeader reads the header (including length prefix) from |data| and |
-// updates |data| to remove the header on return. Caller takes ownership of the |
-// returned pointer. |
-static base::DictionaryValue* ReadHeader(base::StringPiece* data) { |
- if (data->size() < 2) |
- return NULL; |
- uint16 header_len; |
- memcpy(&header_len, data->data(), 2); // assumes little-endian. |
- data->remove_prefix(2); |
- |
- if (data->size() < header_len) |
- return NULL; |
- |
- const base::StringPiece header_bytes(data->data(), header_len); |
- data->remove_prefix(header_len); |
- |
- scoped_ptr<Value> header(base::JSONReader::Read( |
- header_bytes, base::JSON_ALLOW_TRAILING_COMMAS)); |
- if (header.get() == NULL) |
- return NULL; |
- |
- if (!header->IsType(Value::TYPE_DICTIONARY)) |
- return NULL; |
- return reinterpret_cast<base::DictionaryValue*>(header.release()); |
-} |
- |
-// kCurrentFileVersion is the version of the CRLSet file format that we |
-// currently implement. |
-static const int kCurrentFileVersion = 0; |
- |
-static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash, |
- std::vector<std::string>* out_serials) { |
- if (data->size() < crypto::kSHA256Length) |
- return false; |
- *out_parent_spki_hash = std::string(data->data(), crypto::kSHA256Length); |
- data->remove_prefix(crypto::kSHA256Length); |
- |
- if (data->size() < sizeof(uint32)) |
- return false; |
- uint32 num_serials; |
- memcpy(&num_serials, data->data(), sizeof(uint32)); // assumes little endian |
- data->remove_prefix(sizeof(uint32)); |
- |
- for (uint32 i = 0; i < num_serials; ++i) { |
- uint8 serial_length; |
- if (data->size() < sizeof(uint8)) |
- return false; |
- memcpy(&serial_length, data->data(), sizeof(uint8)); |
- data->remove_prefix(sizeof(uint8)); |
- |
- if (data->size() < serial_length) |
- return false; |
- std::string serial(data->data(), serial_length); |
- data->remove_prefix(serial_length); |
- out_serials->push_back(serial); |
- } |
- |
- return true; |
-} |
- |
-bool CRLSet::CopyBlockedSPKIsFromHeader(base::DictionaryValue* header_dict) { |
- ListValue* blocked_spkis_list = NULL; |
- if (!header_dict->GetList("BlockedSPKIs", &blocked_spkis_list)) { |
- // BlockedSPKIs is optional, so it's fine if we don't find it. |
- return true; |
- } |
- |
- blocked_spkis_.clear(); |
- |
- for (size_t i = 0; i < blocked_spkis_list->GetSize(); ++i) { |
- std::string spki_sha256_base64, spki_sha256; |
- if (!blocked_spkis_list->GetString(i, &spki_sha256_base64)) |
- return false; |
- if (!base::Base64Decode(spki_sha256_base64, &spki_sha256)) |
- return false; |
- blocked_spkis_.push_back(spki_sha256); |
- } |
- |
- return true; |
-} |
- |
-// static |
-bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) { |
- // Other parts of Chrome assume that we're little endian, so we don't lose |
- // anything by doing this. |
-#if defined(__BYTE_ORDER) |
- // Linux check |
- COMPILE_ASSERT(__BYTE_ORDER == __LITTLE_ENDIAN, assumes_little_endian); |
-#elif defined(__BIG_ENDIAN__) |
- // Mac check |
- #error assumes little endian |
-#endif |
- |
- scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); |
- if (!header_dict.get()) |
- return false; |
- |
- std::string contents; |
- if (!header_dict->GetString("ContentType", &contents)) |
- return false; |
- if (contents != "CRLSet") |
- return false; |
- |
- int version; |
- if (!header_dict->GetInteger("Version", &version) || |
- version != kCurrentFileVersion) { |
- return false; |
- } |
- |
- int sequence; |
- if (!header_dict->GetInteger("Sequence", &sequence)) |
- return false; |
- |
- double not_after; |
- if (!header_dict->GetDouble("NotAfter", ¬_after)) { |
- // NotAfter is optional for now. |
- not_after = 0; |
- } |
- if (not_after < 0) |
- return false; |
- |
- scoped_refptr<CRLSet> crl_set(new CRLSet); |
- crl_set->sequence_ = static_cast<uint32>(sequence); |
- crl_set->not_after_ = static_cast<uint64>(not_after); |
- |
- for (size_t crl_index = 0; !data.empty(); crl_index++) { |
- std::string parent_spki_sha256; |
- std::vector<std::string> serials; |
- if (!ReadCRL(&data, &parent_spki_sha256, &serials)) |
- return false; |
- |
- crl_set->crls_.push_back(std::make_pair(parent_spki_sha256, serials)); |
- crl_set->crls_index_by_issuer_[parent_spki_sha256] = crl_index; |
- } |
- |
- if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get())) |
- return false; |
- |
- *out_crl_set = crl_set; |
- return true; |
-} |
- |
-// kMaxUncompressedChangesLength is the largest changes array that we'll |
-// accept. This bounds the number of CRLs in the CRLSet as well as the number |
-// of serial numbers in a given CRL. |
-static const unsigned kMaxUncompressedChangesLength = 1024 * 1024; |
- |
-static bool ReadChanges(base::StringPiece* data, |
- std::vector<uint8>* out_changes) { |
- uint32 uncompressed_size, compressed_size; |
- if (data->size() < 2 * sizeof(uint32)) |
- return false; |
- // assumes little endian. |
- memcpy(&uncompressed_size, data->data(), sizeof(uint32)); |
- data->remove_prefix(4); |
- memcpy(&compressed_size, data->data(), sizeof(uint32)); |
- data->remove_prefix(4); |
- |
- if (uncompressed_size > kMaxUncompressedChangesLength) |
- return false; |
- if (data->size() < compressed_size) |
- return false; |
- |
- out_changes->clear(); |
- if (uncompressed_size == 0) |
- return true; |
- |
- out_changes->resize(uncompressed_size); |
- base::StringPiece compressed(data->data(), compressed_size); |
- data->remove_prefix(compressed_size); |
- return DecompressZlib(&(*out_changes)[0], uncompressed_size, compressed); |
-} |
- |
-// These are the range coder symbols used in delta updates. |
-enum { |
- SYMBOL_SAME = 0, |
- SYMBOL_INSERT = 1, |
- SYMBOL_DELETE = 2, |
- SYMBOL_CHANGED = 3, |
-}; |
- |
-bool ReadDeltaCRL(base::StringPiece* data, |
- const std::vector<std::string>& old_serials, |
- std::vector<std::string>* out_serials) { |
- std::vector<uint8> changes; |
- if (!ReadChanges(data, &changes)) |
- return false; |
- |
- size_t i = 0; |
- for (std::vector<uint8>::const_iterator k = changes.begin(); |
- k != changes.end(); ++k) { |
- if (*k == SYMBOL_SAME) { |
- if (i >= old_serials.size()) |
- return false; |
- out_serials->push_back(old_serials[i]); |
- i++; |
- } else if (*k == SYMBOL_INSERT) { |
- uint8 serial_length; |
- if (data->size() < sizeof(uint8)) |
- return false; |
- memcpy(&serial_length, data->data(), sizeof(uint8)); |
- data->remove_prefix(sizeof(uint8)); |
- |
- if (data->size() < serial_length) |
- return false; |
- const std::string serial(data->data(), serial_length); |
- data->remove_prefix(serial_length); |
- |
- out_serials->push_back(serial); |
- } else if (*k == SYMBOL_DELETE) { |
- if (i >= old_serials.size()) |
- return false; |
- i++; |
- } else { |
- NOTREACHED(); |
- return false; |
- } |
- } |
- |
- if (i != old_serials.size()) |
- return false; |
- return true; |
-} |
- |
-bool CRLSet::ApplyDelta(const base::StringPiece& in_data, |
- scoped_refptr<CRLSet>* out_crl_set) { |
- base::StringPiece data(in_data); |
- scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); |
- if (!header_dict.get()) |
- return false; |
- |
- std::string contents; |
- if (!header_dict->GetString("ContentType", &contents)) |
- return false; |
- if (contents != "CRLSetDelta") |
- return false; |
- |
- int version; |
- if (!header_dict->GetInteger("Version", &version) || |
- version != kCurrentFileVersion) { |
- return false; |
- } |
- |
- int sequence, delta_from; |
- if (!header_dict->GetInteger("Sequence", &sequence) || |
- !header_dict->GetInteger("DeltaFrom", &delta_from) || |
- delta_from < 0 || |
- static_cast<uint32>(delta_from) != sequence_) { |
- return false; |
- } |
- |
- double not_after; |
- if (!header_dict->GetDouble("NotAfter", ¬_after)) { |
- // NotAfter is optional for now. |
- not_after = 0; |
- } |
- if (not_after < 0) |
- return false; |
- |
- scoped_refptr<CRLSet> crl_set(new CRLSet); |
- crl_set->sequence_ = static_cast<uint32>(sequence); |
- crl_set->not_after_ = static_cast<uint64>(not_after); |
- |
- if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get())) |
- return false; |
- |
- std::vector<uint8> crl_changes; |
- |
- if (!ReadChanges(&data, &crl_changes)) |
- return false; |
- |
- size_t i = 0, j = 0; |
- for (std::vector<uint8>::const_iterator k = crl_changes.begin(); |
- k != crl_changes.end(); ++k) { |
- if (*k == SYMBOL_SAME) { |
- if (i >= crls_.size()) |
- return false; |
- crl_set->crls_.push_back(crls_[i]); |
- crl_set->crls_index_by_issuer_[crls_[i].first] = j; |
- i++; |
- j++; |
- } else if (*k == SYMBOL_INSERT) { |
- std::string parent_spki_hash; |
- std::vector<std::string> serials; |
- if (!ReadCRL(&data, &parent_spki_hash, &serials)) |
- return false; |
- crl_set->crls_.push_back(std::make_pair(parent_spki_hash, serials)); |
- crl_set->crls_index_by_issuer_[parent_spki_hash] = j; |
- j++; |
- } else if (*k == SYMBOL_DELETE) { |
- if (i >= crls_.size()) |
- return false; |
- i++; |
- } else if (*k == SYMBOL_CHANGED) { |
- if (i >= crls_.size()) |
- return false; |
- std::vector<std::string> serials; |
- if (!ReadDeltaCRL(&data, crls_[i].second, &serials)) |
- return false; |
- crl_set->crls_.push_back(std::make_pair(crls_[i].first, serials)); |
- crl_set->crls_index_by_issuer_[crls_[i].first] = j; |
- i++; |
- j++; |
- } else { |
- NOTREACHED(); |
- return false; |
- } |
- } |
- |
- if (!data.empty()) |
- return false; |
- if (i != crls_.size()) |
- return false; |
- |
- *out_crl_set = crl_set; |
- return true; |
-} |
- |
-// static |
-bool CRLSet::GetIsDeltaUpdate(const base::StringPiece& in_data, |
- bool* is_delta) { |
- base::StringPiece data(in_data); |
- scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data)); |
- if (!header_dict.get()) |
- return false; |
- |
- std::string contents; |
- if (!header_dict->GetString("ContentType", &contents)) |
- return false; |
- |
- if (contents == "CRLSet") { |
- *is_delta = false; |
- } else if (contents == "CRLSetDelta") { |
- *is_delta = true; |
- } else { |
- return false; |
- } |
- |
- return true; |
-} |
- |
-std::string CRLSet::Serialize() const { |
- std::string header = base::StringPrintf( |
- "{" |
- "\"Version\":0," |
- "\"ContentType\":\"CRLSet\"," |
- "\"Sequence\":%u," |
- "\"DeltaFrom\":0," |
- "\"NumParents\":%u," |
- "\"BlockedSPKIs\":[", |
- static_cast<unsigned>(sequence_), |
- static_cast<unsigned>(crls_.size())); |
- |
- for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin(); |
- i != blocked_spkis_.end(); ++i) { |
- std::string spki_hash_base64; |
- base::Base64Encode(*i, &spki_hash_base64); |
- |
- if (i != blocked_spkis_.begin()) |
- header += ","; |
- header += "\"" + spki_hash_base64 + "\""; |
- } |
- header += "]"; |
- if (not_after_ != 0) |
- header += base::StringPrintf(",\"NotAfter\":%" PRIu64, not_after_); |
- header += "}"; |
- |
- size_t len = 2 /* header len */ + header.size(); |
- |
- for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) { |
- len += i->first.size() + 4 /* num serials */; |
- for (std::vector<std::string>::const_iterator j = i->second.begin(); |
- j != i->second.end(); ++j) { |
- len += 1 /* serial length */ + j->size(); |
- } |
- } |
- |
- std::string ret; |
- char* out = WriteInto(&ret, len + 1 /* to include final NUL */); |
- size_t off = 0; |
- out[off++] = header.size(); |
- out[off++] = header.size() >> 8; |
- memcpy(out + off, header.data(), header.size()); |
- off += header.size(); |
- |
- for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) { |
- memcpy(out + off, i->first.data(), i->first.size()); |
- off += i->first.size(); |
- const uint32 num_serials = i->second.size(); |
- memcpy(out + off, &num_serials, sizeof(num_serials)); |
- off += sizeof(num_serials); |
- |
- for (std::vector<std::string>::const_iterator j = i->second.begin(); |
- j != i->second.end(); ++j) { |
- out[off++] = j->size(); |
- memcpy(out + off, j->data(), j->size()); |
- off += j->size(); |
- } |
- } |
- |
- CHECK_EQ(off, len); |
- return ret; |
-} |
- |
-CRLSet::Result CRLSet::CheckSPKI(const base::StringPiece& spki_hash) const { |
- for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin(); |
- i != blocked_spkis_.end(); ++i) { |
- if (spki_hash.size() == i->size() && |
- memcmp(spki_hash.data(), i->data(), i->size()) == 0) { |
- return REVOKED; |
- } |
- } |
- |
- return GOOD; |
-} |
- |
-CRLSet::Result CRLSet::CheckSerial( |
- const base::StringPiece& serial_number, |
- const base::StringPiece& issuer_spki_hash) const { |
- base::StringPiece serial(serial_number); |
- |
- if (!serial.empty() && (serial[0] & 0x80) != 0) { |
- // This serial number is negative but the process which generates CRL sets |
- // will reject any certificates with negative serial numbers as invalid. |
- return UNKNOWN; |
- } |
- |
- // Remove any leading zero bytes. |
- while (serial.size() > 1 && serial[0] == 0x00) |
- serial.remove_prefix(1); |
- |
- std::map<std::string, size_t>::const_iterator i = |
- crls_index_by_issuer_.find(issuer_spki_hash.as_string()); |
- if (i == crls_index_by_issuer_.end()) |
- return UNKNOWN; |
- const std::vector<std::string>& serials = crls_[i->second].second; |
- |
- for (std::vector<std::string>::const_iterator i = serials.begin(); |
- i != serials.end(); ++i) { |
- if (base::StringPiece(*i) == serial) |
- return REVOKED; |
- } |
- |
- return GOOD; |
-} |
- |
-bool CRLSet::IsExpired() const { |
- if (not_after_ == 0) |
- return false; |
- |
- uint64 now = base::Time::Now().ToTimeT(); |
- return now > not_after_; |
-} |
- |
-uint32 CRLSet::sequence() const { |
- return sequence_; |
-} |
- |
-const CRLSet::CRLList& CRLSet::crls() const { |
- return crls_; |
-} |
- |
-// static |
-CRLSet* CRLSet::EmptyCRLSetForTesting() { |
- return new CRLSet; |
-} |
- |
-CRLSet* CRLSet::ExpiredCRLSetForTesting() { |
- CRLSet* crl_set = new CRLSet; |
- crl_set->not_after_ = 1; |
- return crl_set; |
-} |
- |
-} // namespace net |