summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-10 19:10:33 +0000
committeragl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-10 19:10:33 +0000
commitda7582b7e45e5f0aac0a1b072580be65b1502334 (patch)
tree3f122cb56cdc23336f31d8847d1814c995c98135
parent0ca5bb5a118a4cee7a2976a2db286720e50537fe (diff)
downloadchromium_src-da7582b7e45e5f0aac0a1b072580be65b1502334.zip
chromium_src-da7582b7e45e5f0aac0a1b072580be65b1502334.tar.gz
chromium_src-da7582b7e45e5f0aac0a1b072580be65b1502334.tar.bz2
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
-rw-r--r--crypto/sha2.cc6
-rw-r--r--crypto/sha2.h7
-rw-r--r--net/base/crl_set.cc76
-rw-r--r--net/base/crl_set.h19
-rw-r--r--net/base/crl_set_unittest.cc71
-rw-r--r--net/base/x509_certificate_nss.cc27
6 files changed, 155 insertions, 51 deletions
diff --git a/crypto/sha2.cc b/crypto/sha2.cc
index da51cc5..6f36237 100644
--- a/crypto/sha2.cc
+++ b/crypto/sha2.cc
@@ -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;
diff --git a/crypto/sha2.h b/crypto/sha2.h
index 0ca1008..4aae6a0 100644
--- a/crypto/sha2.h
+++ b/crypto/sha2.h
@@ -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
diff --git a/net/base/crl_set.cc b/net/base/crl_set.cc
index 528d476..bf57d7f 100644
--- a/net/base/crl_set.cc
+++ b/net/base/crl_set.cc
@@ -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;
diff --git a/net/base/crl_set.h b/net/base/crl_set.h
index a41cf0c..e20e28d 100644
--- a/net/base/crl_set.h
+++ b/net/base/crl_set.h
@@ -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
diff --git a/net/base/crl_set_unittest.cc b/net/base/crl_set_unittest.cc
index 160c020..43fab02 100644
--- a/net/base/crl_set_unittest.cc
+++ b/net/base/crl_set_unittest.cc
@@ -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)));
+}
diff --git a/net/base/x509_certificate_nss.cc b/net/base/x509_certificate_nss.cc
index a338e74..fdd65fd 100644
--- a/net/base/x509_certificate_nss.cc
+++ b/net/base/x509_certificate_nss.cc
@@ -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);
+
+ base::StringPiece serial_number = base::StringPiece(
+ reinterpret_cast<char*>(cert->serialNumber.data),
+ cert->serialNumber.len);
+
+ CRLSet::Result result = crl_set->CheckSPKI(spki_hash);
- std::string serial_number(
- reinterpret_cast<char*>(child->serialNumber.data),
- child->serialNumber.len);
+ if (result != CRLSet::REVOKED && !issuer_spki_hash.empty())
+ result = crl_set->CheckSerial(serial_number, issuer_spki_hash);
- CRLSet::Result result = crl_set->CheckCertificate(serial_number, spki);
+ issuer_spki_hash = spki_hash;
switch (result) {
case CRLSet::REVOKED: