diff options
Diffstat (limited to 'net/base/crl_set.cc')
-rw-r--r-- | net/base/crl_set.cc | 593 |
1 files changed, 0 insertions, 593 deletions
diff --git a/net/base/crl_set.cc b/net/base/crl_set.cc deleted file mode 100644 index 735bb5e..0000000 --- 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 |