diff options
-rw-r--r-- | crypto/sha2.cc | 6 | ||||
-rw-r--r-- | crypto/sha2.h | 7 | ||||
-rw-r--r-- | net/base/crl_set.cc | 76 | ||||
-rw-r--r-- | net/base/crl_set.h | 19 | ||||
-rw-r--r-- | net/base/crl_set_unittest.cc | 71 | ||||
-rw-r--r-- | net/base/x509_certificate_nss.cc | 27 |
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: |