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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
@@ -10,13 +10,13 @@
|
|||||||
|
|
||||||
namespace crypto {
|
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));
|
scoped_ptr<SecureHash> ctx(SecureHash::Create(SecureHash::SHA256));
|
||||||
ctx->Update(str.data(), str.length());
|
ctx->Update(str.data(), str.length());
|
||||||
ctx->Finish(output, len);
|
ctx->Finish(output, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SHA256HashString(const std::string& str) {
|
std::string SHA256HashString(const base::StringPiece& str) {
|
||||||
std::string output(kSHA256Length, 0);
|
std::string output(kSHA256Length, 0);
|
||||||
SHA256HashString(str, string_as_array(&output), output.size());
|
SHA256HashString(str, string_as_array(&output), output.size());
|
||||||
return output;
|
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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/string_piece.h"
|
||||||
#include "crypto/crypto_export.h"
|
#include "crypto/crypto_export.h"
|
||||||
|
|
||||||
namespace crypto {
|
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
|
// 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,
|
// '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.
|
// 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);
|
void* output, size_t len);
|
||||||
|
|
||||||
// Convenience version of the above that returns the result in a 32-byte
|
// Convenience version of the above that returns the result in a 32-byte
|
||||||
// string.
|
// string.
|
||||||
CRYPTO_EXPORT std::string SHA256HashString(const std::string& str);
|
CRYPTO_EXPORT std::string SHA256HashString(const base::StringPiece& str);
|
||||||
|
|
||||||
} // namespace crypto
|
} // namespace crypto
|
||||||
|
|
||||||
|
@@ -123,7 +123,7 @@ CRLSet::~CRLSet() {
|
|||||||
// ReadHeader reads the header (including length prefix) from |data| and
|
// ReadHeader reads the header (including length prefix) from |data| and
|
||||||
// updates |data| to remove the header on return. Caller takes ownership of the
|
// updates |data| to remove the header on return. Caller takes ownership of the
|
||||||
// returned pointer.
|
// returned pointer.
|
||||||
static DictionaryValue* ReadHeader(base::StringPiece* data) {
|
static base::DictionaryValue* ReadHeader(base::StringPiece* data) {
|
||||||
if (data->size() < 2)
|
if (data->size() < 2)
|
||||||
return NULL;
|
return NULL;
|
||||||
uint16 header_len;
|
uint16 header_len;
|
||||||
@@ -143,7 +143,7 @@ static DictionaryValue* ReadHeader(base::StringPiece* data) {
|
|||||||
|
|
||||||
if (!header->IsType(Value::TYPE_DICTIONARY))
|
if (!header->IsType(Value::TYPE_DICTIONARY))
|
||||||
return NULL;
|
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
|
// 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
|
memcpy(&num_serials, data->data(), sizeof(uint32)); // assumes little endian
|
||||||
data->remove_prefix(sizeof(uint32));
|
data->remove_prefix(sizeof(uint32));
|
||||||
|
|
||||||
for (uint32 i = 0; i < num_serials; i++) {
|
for (uint32 i = 0; i < num_serials; ++i) {
|
||||||
uint8 serial_length;
|
uint8 serial_length;
|
||||||
if (data->size() < sizeof(uint8))
|
if (data->size() < sizeof(uint8))
|
||||||
return false;
|
return false;
|
||||||
@@ -180,6 +180,27 @@ static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash,
|
|||||||
return true;
|
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
|
// static
|
||||||
bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) {
|
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
|
// 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
|
#error assumes little endian
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||||
if (!header_dict.get())
|
if (!header_dict.get())
|
||||||
return false;
|
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;
|
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;
|
*out_crl_set = crl_set;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -314,7 +338,7 @@ bool ReadDeltaCRL(base::StringPiece* data,
|
|||||||
bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
||||||
scoped_refptr<CRLSet>* out_crl_set) {
|
scoped_refptr<CRLSet>* out_crl_set) {
|
||||||
base::StringPiece data(in_data);
|
base::StringPiece data(in_data);
|
||||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||||
if (!header_dict.get())
|
if (!header_dict.get())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -341,6 +365,9 @@ bool CRLSet::ApplyDelta(const base::StringPiece& in_data,
|
|||||||
scoped_refptr<CRLSet> crl_set(new CRLSet);
|
scoped_refptr<CRLSet> crl_set(new CRLSet);
|
||||||
crl_set->sequence_ = static_cast<uint32>(sequence);
|
crl_set->sequence_ = static_cast<uint32>(sequence);
|
||||||
|
|
||||||
|
if (!crl_set->CopyBlockedSPKIsFromHeader(header_dict.get()))
|
||||||
|
return false;
|
||||||
|
|
||||||
std::vector<uint8> crl_changes;
|
std::vector<uint8> crl_changes;
|
||||||
|
|
||||||
if (!ReadChanges(&data, &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 CRLSet::GetIsDeltaUpdate(const base::StringPiece& in_data,
|
||||||
bool *is_delta) {
|
bool *is_delta) {
|
||||||
base::StringPiece data(in_data);
|
base::StringPiece data(in_data);
|
||||||
scoped_ptr<DictionaryValue> header_dict(ReadHeader(&data));
|
scoped_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
|
||||||
if (!header_dict.get())
|
if (!header_dict.get())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -423,17 +450,28 @@ std::string CRLSet::Serialize() const {
|
|||||||
"\"ContentType\":\"CRLSet\","
|
"\"ContentType\":\"CRLSet\","
|
||||||
"\"Sequence\":%u,"
|
"\"Sequence\":%u,"
|
||||||
"\"DeltaFrom\":0,"
|
"\"DeltaFrom\":0,"
|
||||||
"\"NumParents\":%u"
|
"\"NumParents\":%u,"
|
||||||
"}",
|
"\"BlockedSPKIs\":[",
|
||||||
static_cast<unsigned>(sequence_),
|
static_cast<unsigned>(sequence_),
|
||||||
static_cast<unsigned>(crls_.size()));
|
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();
|
size_t len = 2 /* header len */ + header.size();
|
||||||
|
|
||||||
for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) {
|
for (CRLList::const_iterator i = crls_.begin(); i != crls_.end(); ++i) {
|
||||||
len += i->first.size() + 4 /* num serials */;
|
len += i->first.size() + 4 /* num serials */;
|
||||||
for (std::vector<std::string>::const_iterator j = i->second.begin();
|
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();
|
len += 1 /* serial length */ + j->size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,7 +492,7 @@ std::string CRLSet::Serialize() const {
|
|||||||
off += sizeof(num_serials);
|
off += sizeof(num_serials);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator j = i->second.begin();
|
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();
|
out[off++] = j->size();
|
||||||
memcpy(out + off, j->data(), j->size());
|
memcpy(out + off, j->data(), j->size());
|
||||||
off += j->size();
|
off += j->size();
|
||||||
@@ -465,9 +503,21 @@ std::string CRLSet::Serialize() const {
|
|||||||
return ret;
|
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& serial_number,
|
||||||
const base::StringPiece& parent_spki) const {
|
const base::StringPiece& issuer_spki_hash) const {
|
||||||
base::StringPiece serial(serial_number);
|
base::StringPiece serial(serial_number);
|
||||||
|
|
||||||
if (!serial.empty() && (serial[0] & 0x80) != 0) {
|
if (!serial.empty() && (serial[0] & 0x80) != 0) {
|
||||||
@@ -481,7 +531,7 @@ CRLSet::Result CRLSet::CheckCertificate(
|
|||||||
serial.remove_prefix(1);
|
serial.remove_prefix(1);
|
||||||
|
|
||||||
std::map<std::string, size_t>::const_iterator i =
|
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())
|
if (i == crls_index_by_issuer_.end())
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
const std::vector<std::string>& serials = crls_[i->second].second;
|
const std::vector<std::string>& serials = crls_[i->second].second;
|
||||||
|
@@ -17,6 +17,10 @@
|
|||||||
#include "base/time.h"
|
#include "base/time.h"
|
||||||
#include "net/base/net_export.h"
|
#include "net/base/net_export.h"
|
||||||
|
|
||||||
|
namespace base {
|
||||||
|
class DictionaryValue;
|
||||||
|
}
|
||||||
|
|
||||||
namespace net {
|
namespace net {
|
||||||
|
|
||||||
// A CRLSet is a structure that lists the serial numbers of revoked
|
// 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,
|
static bool Parse(base::StringPiece data,
|
||||||
scoped_refptr<CRLSet>* out_crl_set);
|
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:
|
// certificate:
|
||||||
// serial_number: the serial number of the certificate
|
// serial_number: the serial number of the certificate
|
||||||
// issuer_spki_hash: the SHA256 of the SubjectPublicKeyInfo of the CRL
|
// issuer_spki_hash: the SHA256 of the SubjectPublicKeyInfo of the CRL
|
||||||
// signer
|
// signer
|
||||||
Result CheckCertificate(
|
Result CheckSerial(
|
||||||
const base::StringPiece& serial_number,
|
const base::StringPiece& serial_number,
|
||||||
const base::StringPiece& issuer_spki_hash) const;
|
const base::StringPiece& issuer_spki_hash) const;
|
||||||
|
|
||||||
@@ -78,7 +86,9 @@ class NET_EXPORT CRLSet : public base::RefCountedThreadSafe<CRLSet> {
|
|||||||
private:
|
private:
|
||||||
CRLSet();
|
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_;
|
uint32 sequence_;
|
||||||
CRLList crls_;
|
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
|
// and |crls_index_by_issuer_| because, when applying a delta update, we need
|
||||||
// to identify a CRL by index.
|
// to identify a CRL by index.
|
||||||
std::map<std::string, size_t> crls_index_by_issuer_;
|
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
|
} // 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
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
@@ -8,26 +8,28 @@
|
|||||||
// These data blocks were generated using a lot of code that is still in
|
// 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.
|
// development. For now, if you need to update them, you have to contact agl.
|
||||||
static const uint8 kGIACRLSet[] = {
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
0x31, 0x2c, 0x22, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x53, 0x50, 0x4b,
|
||||||
0xb7, 0x4f, 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7, 0x08, 0xaf, 0xc9, 0xe7, 0x32,
|
0x49, 0x73, 0x22, 0x3a, 0x5b, 0x5d, 0x7d, 0xb6, 0xb9, 0x54, 0x32, 0xab, 0xae,
|
||||||
0xac, 0xe2, 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05, 0x0d, 0x00, 0x00, 0x00, 0x0a,
|
0x57, 0xfe, 0x02, 0x0c, 0xb2, 0xb7, 0x4f, 0x4f, 0x9f, 0x91, 0x73, 0xc8, 0xc7,
|
||||||
0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0e,
|
0x08, 0xaf, 0xc9, 0xe7, 0x32, 0xac, 0xe2, 0x32, 0x79, 0x04, 0x7c, 0x6d, 0x05,
|
||||||
0x37, 0x06, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb1, 0x0a, 0x16, 0x25, 0x42, 0x54,
|
0x0d, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00,
|
||||||
0x00, 0x03, 0x00, 0x00, 0x14, 0x51, 0x0a, 0x16, 0x69, 0xd1, 0xd7, 0x00, 0x03,
|
0x23, 0xb0, 0x0a, 0x10, 0x0e, 0x37, 0x06, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb1,
|
||||||
0x00, 0x00, 0x14, 0x52, 0x0a, 0x16, 0x70, 0x8c, 0x22, 0x00, 0x03, 0x00, 0x00,
|
0x0a, 0x16, 0x25, 0x42, 0x54, 0x00, 0x03, 0x00, 0x00, 0x14, 0x51, 0x0a, 0x16,
|
||||||
0x14, 0x53, 0x0a, 0x16, 0x71, 0x31, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x14, 0x54,
|
0x69, 0xd1, 0xd7, 0x00, 0x03, 0x00, 0x00, 0x14, 0x52, 0x0a, 0x16, 0x70, 0x8c,
|
||||||
0x0a, 0x16, 0x7d, 0x75, 0x9d, 0x00, 0x03, 0x00, 0x00, 0x14, 0x55, 0x0a, 0x1f,
|
0x22, 0x00, 0x03, 0x00, 0x00, 0x14, 0x53, 0x0a, 0x16, 0x71, 0x31, 0x2c, 0x00,
|
||||||
0xee, 0xf9, 0x49, 0x00, 0x03, 0x00, 0x00, 0x23, 0xae, 0x0a, 0x1f, 0xfc, 0xd1,
|
0x03, 0x00, 0x00, 0x14, 0x54, 0x0a, 0x16, 0x7d, 0x75, 0x9d, 0x00, 0x03, 0x00,
|
||||||
0x89, 0x00, 0x03, 0x00, 0x00, 0x23, 0xaf, 0x0a, 0x61, 0xdd, 0xc7, 0x48, 0x00,
|
0x00, 0x14, 0x55, 0x0a, 0x1f, 0xee, 0xf9, 0x49, 0x00, 0x03, 0x00, 0x00, 0x23,
|
||||||
0x03, 0x00, 0x00, 0x18, 0x0e, 0x0a, 0x61, 0xe6, 0x12, 0x64, 0x00, 0x03, 0x00,
|
0xae, 0x0a, 0x1f, 0xfc, 0xd1, 0x89, 0x00, 0x03, 0x00, 0x00, 0x23, 0xaf, 0x0a,
|
||||||
0x00, 0x18, 0x0f, 0x0a, 0x61, 0xe9, 0x46, 0x56, 0x00, 0x03, 0x00, 0x00, 0x18,
|
0x61, 0xdd, 0xc7, 0x48, 0x00, 0x03, 0x00, 0x00, 0x18, 0x0e, 0x0a, 0x61, 0xe6,
|
||||||
0x10, 0x0a, 0x64, 0x63, 0x49, 0xd2, 0x00, 0x03, 0x00, 0x00, 0x1d, 0x77,
|
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[] = {
|
static const uint8 kNoopDeltaCRL[] = {
|
||||||
@@ -145,6 +147,21 @@ static const uint8 kUpdateSerialsDelta[] = {
|
|||||||
0xb0,
|
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
|
// kGIASPKISHA256 is the SHA256 digest the Google Internet Authority's
|
||||||
// SubjectPublicKeyInfo.
|
// SubjectPublicKeyInfo.
|
||||||
static const uint8 kGIASPKISHA256[32] = {
|
static const uint8 kGIASPKISHA256[32] = {
|
||||||
@@ -173,10 +190,10 @@ TEST(CRLSetTest, Parse) {
|
|||||||
const std::string gia_spki_hash(
|
const std::string gia_spki_hash(
|
||||||
reinterpret_cast<const char*>(kGIASPKISHA256),
|
reinterpret_cast<const char*>(kGIASPKISHA256),
|
||||||
sizeof(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),
|
std::string("\x16\x7D\x75\x9D\x00\x03\x00\x00\x14\x55", 10),
|
||||||
gia_spki_hash));
|
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),
|
std::string("\x47\x54\x3E\x79\x00\x03\x00\x00\x14\xF5", 10),
|
||||||
gia_spki_hash));
|
gia_spki_hash));
|
||||||
}
|
}
|
||||||
@@ -263,3 +280,21 @@ TEST(CRLSetTest, UpdateSerialsDelta) {
|
|||||||
const std::vector<std::string>& serials = crls[0].second;
|
const std::vector<std::string>& serials = crls[0].second;
|
||||||
EXPECT_EQ(45u, serials.size());
|
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/nss_util.h"
|
||||||
#include "crypto/rsa_private_key.h"
|
#include "crypto/rsa_private_key.h"
|
||||||
#include "crypto/scoped_nss_types.h"
|
#include "crypto/scoped_nss_types.h"
|
||||||
|
#include "crypto/sha2.h"
|
||||||
#include "net/base/asn1_util.h"
|
#include "net/base/asn1_util.h"
|
||||||
#include "net/base/cert_status_flags.h"
|
#include "net/base/cert_status_flags.h"
|
||||||
#include "net/base/cert_verify_result.h"
|
#include "net/base/cert_verify_result.h"
|
||||||
@@ -258,14 +259,12 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
|
|||||||
if (root)
|
if (root)
|
||||||
certs.push_back(root);
|
certs.push_back(root);
|
||||||
|
|
||||||
CERTCertificate* prev = NULL;
|
// We iterate from the root certificate down to the leaf, keeping track of
|
||||||
for (std::vector<CERTCertificate*>::iterator i = certs.begin();
|
// the issuer's SPKI at each step.
|
||||||
i != certs.end(); ++i) {
|
std::string issuer_spki_hash;
|
||||||
|
for (std::vector<CERTCertificate*>::reverse_iterator i = certs.rbegin();
|
||||||
|
i != certs.rend(); ++i) {
|
||||||
CERTCertificate* cert = *i;
|
CERTCertificate* cert = *i;
|
||||||
CERTCertificate* child = prev;
|
|
||||||
prev = cert;
|
|
||||||
if (child == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
|
base::StringPiece der(reinterpret_cast<char*>(cert->derCert.data),
|
||||||
cert->derCert.len);
|
cert->derCert.len);
|
||||||
@@ -275,12 +274,18 @@ CRLSetResult CheckRevocationWithCRLSet(CERTCertList* cert_list,
|
|||||||
NOTREACHED();
|
NOTREACHED();
|
||||||
return kCRLSetError;
|
return kCRLSetError;
|
||||||
}
|
}
|
||||||
|
const std::string spki_hash = crypto::SHA256HashString(spki);
|
||||||
|
|
||||||
std::string serial_number(
|
base::StringPiece serial_number = base::StringPiece(
|
||||||
reinterpret_cast<char*>(child->serialNumber.data),
|
reinterpret_cast<char*>(cert->serialNumber.data),
|
||||||
child->serialNumber.len);
|
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) {
|
switch (result) {
|
||||||
case CRLSet::REVOKED:
|
case CRLSet::REVOKED:
|
||||||
|
Reference in New Issue
Block a user