net: allow CRLSets to block specific SPKIs.
This change allows CRLSets to include a list of blocked SPKI fingerprints, which may save us doing emergency binary pushes in the future. It also corrects a bug where the NSS code was passing in the full SPKI rather than the SHA256 hash. BUG=none TEST=net_unittests Review URL: http://codereview.chromium.org/9149010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117069 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -10,13 +10,13 @@
|
||||
|
||||
namespace crypto {
|
||||
|
||||
void SHA256HashString(const std::string& str, void* output, size_t len) {
|
||||
void SHA256HashString(const base::StringPiece& str, void* output, size_t len) {
|
||||
scoped_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256));
|
||||
ctx->Update(str.data(), str.length());
|
||||
ctx->Finish(output, len);
|
||||
}
|
||||
|
||||
std::string SHA256HashString(const std::string& str) {
|
||||
std::string SHA256HashString(const base::StringPiece& str) {
|
||||
std::string output(kSHA256Length, 0);
|
||||
SHA256HashString(str, string_as_array(&output), output.size());
|
||||
return output;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/string_piece.h"
|
||||
#include "crypto/crypto_export.h"
|
||||
|
||||
namespace crypto {
|
||||
@ -21,12 +22,12 @@ static const size_t kSHA256Length = 32; // Length in bytes of a SHA-256 hash.
|
||||
// Computes the SHA-256 hash of the input string 'str' and stores the first
|
||||
// 'len' bytes of the hash in the output buffer 'output'. If 'len' > 32,
|
||||
// only 32 bytes (the full hash) are stored in the 'output' buffer.
|
||||
CRYPTO_EXPORT void SHA256HashString(const std::string& str,
|
||||
CRYPTO_EXPORT void SHA256HashString(const base::StringPiece& str,
|
||||
void* output, size_t len);
|
||||
|
||||
// Convenience version of the above that returns the result in a 32-byte
|
||||
// string.
|
||||
CRYPTO_EXPORT std::string SHA256HashString(const std::string& str);
|
||||
CRYPTO_EXPORT std::string SHA256HashString(const base::StringPiece& str);
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
|
@ -123,7 +123,7 @@ CRLSet::~CRLSet() {
|
||||
// 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 DictionaryValue* ReadHeader(base::StringPiece* data) {
|
||||
static base::DictionaryValue* ReadHeader(base::StringPiece* data) {
|
||||
if (data->size() < 2)
|
||||
return NULL;
|
||||
uint16 header_len;
|
||||
@ -143,7 +143,7 @@ static DictionaryValue* ReadHeader(base::StringPiece* data) {
|
||||
|
||||
if (!header->IsType(Value::TYPE_DICTIONARY))
|
||||
return NULL;
|
||||
return reinterpret_cast<DictionaryValue*>(header.release());
|
||||
return reinterpret_cast<base::DictionaryValue*>(header.release());
|
||||
}
|
||||
|
||||
// kCurrentFileVersion is the version of the CRLSet file format that we
|
||||
@ -163,7 +163,7 @@ static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash,
|
||||
memcpy(&num_serials, data->data(), sizeof(uint32)); // assumes little endian
|
||||
data->remove_prefix(sizeof(uint32));
|
||||
|
||||
for (uint32 i = 0; i < num_serials; i++) {
|
||||
for (uint32 i = 0; i < num_serials; ++i) {
|
||||
uint8 serial_length;
|
||||
if (data->size() < sizeof(uint8))
|
||||
return false;
|
||||
@ -180,6 +180,27 @@ static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash,
|
||||
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
|
||||
@ -192,7 +213,7 @@ bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) {
|
||||
#error assumes little endian
|
||||
#endif
|
||||
|
||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
||||
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||
if (!header_dict.get())
|
||||
return false;
|
||||
|
||||
@ -225,6 +246,9 @@ bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) {
|
||||
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;
|
||||
}
|
||||
@ -314,7 +338,7 @@ bool ReadDeltaCRL(base::StringPiece* data,
|
||||
bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
||||
scoped_refptr<CRLSet>* out_crl_set) {
|
||||
base::StringPiece data(in_data);
|
||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
||||
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||
if (!header_dict.get())
|
||||
return false;
|
||||
|
||||
@ -341,6 +365,9 @@ bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
||||
scoped_refptr<CRLSet> crl_set(new CRLSet);
|
||||
crl_set->sequence_ = static_cast<uint32>(sequence);
|
||||
|
||||
if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get()))
|
||||
return false;
|
||||
|
||||
std::vector<uint8> crl_changes;
|
||||
|
||||
if (!ReadChanges(&data, &crl_changes))
|
||||
@ -397,7 +424,7 @@ bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
||||
bool CRLSet::GetIsDeltaUpdate(const base::StringPiece& in_data,
|
||||
bool *is_delta) {
|
||||
base::StringPiece data(in_data);
|
||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
||||
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||
if (!header_dict.get())
|
||||
return false;
|
||||
|
||||
@ -423,17 +450,28 @@ std::string CRLSet::Serialize() const {
|
||||
"\"ContentType\":\"CRLSet\","
|
||||
"\"Sequence\":%u,"
|
||||
"\"DeltaFrom\":0,"
|
||||
"\"NumParents\":%u"
|
||||
"}",
|
||||
"\"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 += "]}";
|
||||
|
||||
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++) {
|
||||
j != i->second.end(); ++j) {
|
||||
len += 1 /* serial length */ + j->size();
|
||||
}
|
||||
}
|
||||
@ -454,7 +492,7 @@ std::string CRLSet::Serialize() const {
|
||||
off += sizeof(num_serials);
|
||||
|
||||
for (std::vector<std::string>::const_iterator j = i->second.begin();
|
||||
j != i->second.end(); j++) {
|
||||
j != i->second.end(); ++j) {
|
||||
out[off++] = j->size();
|
||||
memcpy(out + off, j->data(), j->size());
|
||||
off += j->size();
|
||||
@ -465,9 +503,21 @@ std::string CRLSet::Serialize() const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
CRLSet::Result CRLSet::CheckCertificate(
|
||||
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& parent_spki) const {
|
||||
const base::StringPiece& issuer_spki_hash) const {
|
||||
base::StringPiece serial(serial_number);
|
||||
|
||||
if (!serial.empty() && (serial[0] & 0x80) != 0) {
|
||||
@ -481,7 +531,7 @@ CRLSet::Result CRLSet::CheckCertificate(
|
||||
serial.remove_prefix(1);
|
||||
|
||||
std::map<std::string, size_t>::const_iterator i =
|
||||
crls_index_by_issuer_.find(parent_spki.as_string());
|
||||
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;
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include "base/time.h"
|
||||
#include "net/base/net_export.h"
|
||||
|
||||
namespace base {
|
||||
class DictionaryValue;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
|
||||
// A CRLSet is a structure that lists the serial numbers of revoked
|
||||
@ -37,12 +41,16 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> {
|
||||
static bool Parse(base::StringPiece data,
|
||||
scoped_refptr<CRLSet>* out_crl_set);
|
||||
|
||||
// CheckCertificate returns the information contained in the set for a given
|
||||
// CheckSPKI checks whether the given SPKI has been listed as blocked.
|
||||
// spki_hash: the SHA256 of the SubjectPublicKeyInfo of the certificate.
|
||||
Result CheckSPKI(const base::StringPiece& spki_hash) const;
|
||||
|
||||
// CheckSerial returns the information contained in the set for a given
|
||||
// certificate:
|
||||
// serial_number: the serial number of the certificate
|
||||
// issuer_spki_hash: the SHA256 of the SubjectPublicKeyInfo of the CRL
|
||||
// signer
|
||||
Result CheckCertificate(
|
||||
Result CheckSerial(
|
||||
const base::StringPiece& serial_number,
|
||||
const base::StringPiece& issuer_spki_hash) const;
|
||||
|
||||
@ -78,7 +86,9 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> {
|
||||
private:
|
||||
CRLSet();
|
||||
|
||||
static CRLSet* CRLSetFromHeader(base::StringPiece header);
|
||||
// CopyBlockedSPKIsFromHeader sets |blocked_spkis_| to the list of values
|
||||
// from "BlockedSPKIs" in |header_dict|.
|
||||
bool CopyBlockedSPKIsFromHeader(base::DictionaryValue* header_dict);
|
||||
|
||||
uint32 sequence_;
|
||||
CRLList crls_;
|
||||
@ -87,6 +97,9 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> {
|
||||
// and |crls_index_by_issuer_| because, when applying a delta update, we need
|
||||
// to identify a CRL by index.
|
||||
std::map<std::string, size_t> crls_index_by_issuer_;
|
||||
// blocked_spkis_ contains the SHA256 hashes of SPKIs which are to be blocked
|
||||
// no matter where in a certificate chain they might appear.
|
||||
std::vector<std::string> blocked_spkis_;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@ -8,26 +8,28 @@
|
||||
// These data blocks were generated using a lot of code that is still in
|
||||
// development. For now, if you need to update them, you have to contact agl.
|
||||
static const uint8 kGIACRLSet[] = {
|
||||
0x4e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
|
||||
0x60, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
|
||||
0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
|
||||
0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
|
||||
0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
|
||||
0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
|
||||
0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
|
||||
0x31, 0x7d, 0xb6, 0xb9, 0x54, 0x32, 0xab, 0xae, 0x57, 0xfe, 0x02, 0x0c, 0xb2,
|
||||
0xb7, 0x4f, 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7, 0x08, 0xaf, 0xc9, 0xe7, 0x32,
|
||||
0xac, 0xe2, 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x0a,
|
||||
0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0e,
|
||||
0x37, 0x06, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb1, 0x0a, 0x16, 0x25, 0x42, 0x54,
|
||||
0x00, 0x03, 0x00, 0x00, 0x14, 0x51, 0x0a, 0x16, 0x69, 0xd1, 0xd7, 0x00, 0x03,
|
||||
0x00, 0x00, 0x14, 0x52, 0x0a, 0x16, 0x70, 0x8c, 0x22, 0x00, 0x03, 0x00, 0x00,
|
||||
0x14, 0x53, 0x0a, 0x16, 0x71, 0x31, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x14, 0x54,
|
||||
0x0a, 0x16, 0x7d, 0x75, 0x9d, 0x00, 0x03, 0x00, 0x00, 0x14, 0x55, 0x0a, 0x1f,
|
||||
0xee, 0xf9, 0x49, 0x00, 0x03, 0x00, 0x00, 0x23, 0xae, 0x0a, 0x1f, 0xfc, 0xd1,
|
||||
0x89, 0x00, 0x03, 0x00, 0x00, 0x23, 0xaf, 0x0a, 0x61, 0xdd, 0xc7, 0x48, 0x00,
|
||||
0x03, 0x00, 0x00, 0x18, 0x0e, 0x0a, 0x61, 0xe6, 0x12, 0x64, 0x00, 0x03, 0x00,
|
||||
0x00, 0x18, 0x0f, 0x0a, 0x61, 0xe9, 0x46, 0x56, 0x00, 0x03, 0x00, 0x00, 0x18,
|
||||
0x10, 0x0a, 0x64, 0x63, 0x49, 0xd2, 0x00, 0x03, 0x00, 0x00, 0x1d, 0x77,
|
||||
0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
|
||||
0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xb6, 0xb9, 0x54, 0x32, 0xab, 0xae,
|
||||
0x57, 0xfe, 0x02, 0x0c, 0xb2, 0xb7, 0x4f, 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7,
|
||||
0x08, 0xaf, 0xc9, 0xe7, 0x32, 0xac, 0xe2, 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05,
|
||||
0x0d, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00,
|
||||
0x23, 0xb0, 0x0a, 0x10, 0x0e, 0x37, 0x06, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb1,
|
||||
0x0a, 0x16, 0x25, 0x42, 0x54, 0x00, 0x03, 0x00, 0x00, 0x14, 0x51, 0x0a, 0x16,
|
||||
0x69, 0xd1, 0xd7, 0x00, 0x03, 0x00, 0x00, 0x14, 0x52, 0x0a, 0x16, 0x70, 0x8c,
|
||||
0x22, 0x00, 0x03, 0x00, 0x00, 0x14, 0x53, 0x0a, 0x16, 0x71, 0x31, 0x2c, 0x00,
|
||||
0x03, 0x00, 0x00, 0x14, 0x54, 0x0a, 0x16, 0x7d, 0x75, 0x9d, 0x00, 0x03, 0x00,
|
||||
0x00, 0x14, 0x55, 0x0a, 0x1f, 0xee, 0xf9, 0x49, 0x00, 0x03, 0x00, 0x00, 0x23,
|
||||
0xae, 0x0a, 0x1f, 0xfc, 0xd1, 0x89, 0x00, 0x03, 0x00, 0x00, 0x23, 0xaf, 0x0a,
|
||||
0x61, 0xdd, 0xc7, 0x48, 0x00, 0x03, 0x00, 0x00, 0x18, 0x0e, 0x0a, 0x61, 0xe6,
|
||||
0x12, 0x64, 0x00, 0x03, 0x00, 0x00, 0x18, 0x0f, 0x0a, 0x61, 0xe9, 0x46, 0x56,
|
||||
0x00, 0x03, 0x00, 0x00, 0x18, 0x10, 0x0a, 0x64, 0x63, 0x49, 0xd2, 0x00, 0x03,
|
||||
0x00, 0x00, 0x1d, 0x77,
|
||||
};
|
||||
|
||||
static const uint8 kNoopDeltaCRL[] = {
|
||||
@ -145,6 +147,21 @@ static const uint8 kUpdateSerialsDelta[] = {
|
||||
0xb0,
|
||||
};
|
||||
|
||||
static const uint8 kBlockedSPKICRLSet[] = {
|
||||
0x8e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
|
||||
0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
|
||||
0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x22, 0x2c, 0x22,
|
||||
0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x30, 0x2c, 0x22,
|
||||
0x44, 0x65, 0x6c, 0x74, 0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c,
|
||||
0x22, 0x4e, 0x75, 0x6d, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a,
|
||||
0x30, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
|
||||
0x49, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x34, 0x37, 0x44, 0x45, 0x51, 0x70, 0x6a,
|
||||
0x38, 0x48, 0x42, 0x53, 0x61, 0x2b, 0x2f, 0x54, 0x49, 0x6d, 0x57, 0x2b, 0x35,
|
||||
0x4a, 0x43, 0x65, 0x75, 0x51, 0x65, 0x52, 0x6b, 0x6d, 0x35, 0x4e, 0x4d, 0x70,
|
||||
0x4a, 0x57, 0x5a, 0x47, 0x33, 0x68, 0x53, 0x75, 0x46, 0x55, 0x3d, 0x22, 0x5d,
|
||||
0x7d,
|
||||
};
|
||||
|
||||
// kGIASPKISHA256 is the SHA256 digest the Google Internet Authority's
|
||||
// SubjectPublicKeyInfo.
|
||||
static const uint8 kGIASPKISHA256[32] = {
|
||||
@ -173,10 +190,10 @@ TEST(CRLSetTest, Parse) {
|
||||
const std::string gia_spki_hash(
|
||||
reinterpret_cast<const char*>(kGIASPKISHA256),
|
||||
sizeof(kGIASPKISHA256));
|
||||
EXPECT_EQ(net::CRLSet::REVOKED, set->CheckCertificate(
|
||||
EXPECT_EQ(net::CRLSet::REVOKED, set->CheckSerial(
|
||||
std::string("\x16\x7D\x75\x9D\x00\x03\x00\x00\x14\x55", 10),
|
||||
gia_spki_hash));
|
||||
EXPECT_EQ(net::CRLSet::GOOD, set->CheckCertificate(
|
||||
EXPECT_EQ(net::CRLSet::GOOD, set->CheckSerial(
|
||||
std::string("\x47\x54\x3E\x79\x00\x03\x00\x00\x14\xF5", 10),
|
||||
gia_spki_hash));
|
||||
}
|
||||
@ -263,3 +280,21 @@ TEST(CRLSetTest, UpdateSerialsDelta) {
|
||||
const std::vector<std::string>& serials = crls[0].second;
|
||||
EXPECT_EQ(45u, serials.size());
|
||||
}
|
||||
|
||||
TEST(CRLSetTest, BlockedSPKIs) {
|
||||
base::StringPiece s(reinterpret_cast<const char*>(kBlockedSPKICRLSet),
|
||||
sizeof(kBlockedSPKICRLSet));
|
||||
scoped_refptr<net::CRLSet> set;
|
||||
EXPECT_TRUE(net::CRLSet::Parse(s, &set));
|
||||
ASSERT_TRUE(set.get() != NULL);
|
||||
|
||||
const uint8 spki_hash[] = {
|
||||
227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185, 36,
|
||||
39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82, 184, 85,
|
||||
0,
|
||||
};
|
||||
|
||||
EXPECT_EQ(net::CRLSet::GOOD, set->CheckSPKI(""));
|
||||
EXPECT_EQ(net::CRLSet::REVOKED, set->CheckSPKI(
|
||||
reinterpret_cast<const char*>(spki_hash)));
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "crypto/nss_util.h"
|
||||
#include "crypto/rsa_private_key.h"
|
||||
#include "crypto/scoped_nss_types.h"
|
||||
#include "crypto/sha2.h"
|
||||
#include "net/base/asn1_util.h"
|
||||
#include "net/base/cert_status_flags.h"
|
||||
#include "net/base/cert_verify_result.h"
|
||||
@ -258,14 +259,12 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
|
||||
if (root)
|
||||
certs.push_back(root);
|
||||
|
||||
CERTCertificate* prev = NULL;
|
||||
for (std::vector<CERTCertificate*>::iterator i = certs.begin();
|
||||
i != certs.end(); ++i) {
|
||||
// We iterate from the root certificate down to the leaf, keeping track of
|
||||
// the issuer's SPKI at each step.
|
||||
std::string issuer_spki_hash;
|
||||
for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin();
|
||||
i != certs.rend(); ++i) {
|
||||
CERTCertificate* cert = *i;
|
||||
CERTCertificate* child = prev;
|
||||
prev = cert;
|
||||
if (child == NULL)
|
||||
continue;
|
||||
|
||||
base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
|
||||
cert->derCert.len);
|
||||
@ -275,12 +274,18 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
|
||||
NOTREACHED();
|
||||
return kCRLSetError;
|
||||
}
|
||||
const std::string spki_hash = crypto::SHA256HashString(spki);
|
||||
|
||||
std::string serial_number(
|
||||
reinterpret_cast<char*>(child->serialNumber.data),
|
||||
child->serialNumber.len);
|
||||
base::StringPiece serial_number = base::StringPiece(
|
||||
reinterpret_cast<char*>(cert->serialNumber.data),
|
||||
cert->serialNumber.len);
|
||||
|
||||
CRLSet::Result result = crl_set->CheckCertificate(serial_number, spki);
|
||||
CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
|
||||
|
||||
if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
|
||||
result = crl_set->CheckSerial(serial_number, issuer_spki_hash);
|
||||
|
||||
issuer_spki_hash = spki_hash;
|
||||
|
||||
switch (result) {
|
||||
case CRLSet::REVOKED:
|
||||
|
Reference in New Issue
Block a user