diff options
author | eranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-19 04:23:10 +0000 |
---|---|---|
committer | eranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-19 04:23:10 +0000 |
commit | f5c82e82d06b5ecb640e78b549460479f59ea8e7 (patch) | |
tree | 47f8b5cbbb2ca33e80d14cbc10f877253e382b95 | |
parent | 3d6a8298c13dc5062898762839daad2e957f0c99 (diff) | |
download | chromium_src-f5c82e82d06b5ecb640e78b549460479f59ea8e7.zip chromium_src-f5c82e82d06b5ecb640e78b549460479f59ea8e7.tar.gz chromium_src-f5c82e82d06b5ecb640e78b549460479f59ea8e7.tar.bz2 |
CT: Adding SCT and PreCertificates extractor. This code creates the
LogEntry structure over which Signed Certificate Timestamps can be
verified (and the unit tests demonstrate this).
BUG=309578
Review URL: https://codereview.chromium.org/65863002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@235915 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/cert/ct_objects_extractor.h | 52 | ||||
-rw-r--r-- | net/cert/ct_objects_extractor_nss.cc | 284 | ||||
-rw-r--r-- | net/cert/ct_objects_extractor_openssl.cc | 33 | ||||
-rw-r--r-- | net/cert/ct_objects_extractor_unittest.cc | 125 | ||||
-rw-r--r-- | net/cert/ct_serialization_unittest.cc | 6 | ||||
-rw-r--r-- | net/data/ssl/certificates/README | 3 | ||||
-rw-r--r-- | net/data/ssl/certificates/ct-test-embedded-cert.pem | 126 | ||||
-rw-r--r-- | net/net.gyp | 10 | ||||
-rw-r--r-- | net/test/ct_test_util.cc | 6 | ||||
-rw-r--r-- | net/test/ct_test_util.h | 7 |
10 files changed, 646 insertions, 6 deletions
diff --git a/net/cert/ct_objects_extractor.h b/net/cert/ct_objects_extractor.h new file mode 100644 index 0000000..de47c852 --- /dev/null +++ b/net/cert/ct_objects_extractor.h @@ -0,0 +1,52 @@ +// Copyright 2013 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. + +#ifndef NET_CERT_CT_OBJECTS_EXTRACTOR_H_ +#define NET_CERT_CT_OBJECTS_EXTRACTOR_H_ + +#include <string> + +#include "net/base/net_export.h" +#include "net/cert/x509_certificate.h" + +namespace net { + +namespace ct { + +struct LogEntry; + +// Extracts a SignedCertificateTimestampList that has been embedded within a +// leaf cert as an X.509v3 extension with the OID 1.3.6.1.4.1.11129.2.4.2. +// If the extension is present, returns true, updating |*sct_list| to contain +// the encoded list, minus the DER encoding necessary for the extension. +// |*sct_list| can then be further decoded with ct::DecodeSCTList +NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList( + X509Certificate::OSCertHandle cert, + std::string* sct_list); + +// Obtains a PrecertChain log entry for |leaf|, an X.509v3 certificate that +// contains an X.509v3 extension with the OID 1.3.6.1.4.1.11129.2.4.2. On +// success, fills |*result| with the data for a PrecertChain log entry and +// returns true. +// The filled |*result| should be verified using ct::CTLogVerifier::Verify +// Note: If |leaf| does not contain the required extension, it is treated as +// a failure. +NET_EXPORT_PRIVATE bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, + X509Certificate::OSCertHandle issuer, + LogEntry* result); + +// Obtains an X509Chain log entry for |leaf|, an X.509v3 certificate that +// is not expected to contain an X.509v3 extension with the OID +// 1.3.6.1.4.1.11129.2.4.2 (meaning a certificate without an embedded SCT). +// On success, fills |result| with the data for an X509Chain log entry and +// returns true. +// The filled |*result| should be verified using ct::CTLogVerifier::Verify +NET_EXPORT_PRIVATE bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, + LogEntry* result); + +} // namespace ct + +} // namespace net + +#endif // NET_CERT_CT_OBJECTS_EXTRACTOR_H_ diff --git a/net/cert/ct_objects_extractor_nss.cc b/net/cert/ct_objects_extractor_nss.cc new file mode 100644 index 0000000..97b8590 --- /dev/null +++ b/net/cert/ct_objects_extractor_nss.cc @@ -0,0 +1,284 @@ +// Copyright 2013 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 "net/cert/ct_objects_extractor.h" + +#include <cert.h> +#include <secasn1.h> +#include <secitem.h> +#include <secoid.h> + +#include "base/lazy_instance.h" +#include "crypto/scoped_nss_types.h" +#include "crypto/sha2.h" +#include "net/cert/asn1_util.h" +#include "net/cert/signed_certificate_timestamp.h" + +namespace net { + +namespace ct { + +namespace { + +struct FreeCERTCertificate { + public: + inline void operator()(CERTCertificate* x) const { + CERT_DestroyCertificate(x); + } +}; + +typedef scoped_ptr_malloc<CERTCertificate, FreeCERTCertificate> + ScopedCERTCertificate; + +// Wrapper class to convert a X509Certificate::OSCertHandle directly +// into a CERTCertificate* usable with other NSS functions. This is used for +// platforms where X509Certificate::OSCertHandle refers to a different type +// than a CERTCertificate*. +struct NSSCertWrapper { + explicit NSSCertWrapper(X509Certificate::OSCertHandle cert_handle); + ~NSSCertWrapper() {} + + ScopedCERTCertificate cert; +}; + +NSSCertWrapper::NSSCertWrapper(X509Certificate::OSCertHandle cert_handle) { +#if defined(USE_NSS) + cert.reset(CERT_DupCertificate(cert_handle)); +#else + SECItem der_cert; + std::string der_data; + if (!X509Certificate::GetDEREncoded(cert_handle, &der_data)) + return; + der_cert.data = + reinterpret_cast<unsigned char*>(const_cast<char*>(der_data.data())); + der_cert.len = der_data.size(); + + // Note: CERT_NewTempCertificate may return NULL if the certificate + // shares a serial number with another cert issued by the same CA, + // which is not supposed to happen. + cert.reset(CERT_NewTempCertificate( + CERT_GetDefaultCertDB(), &der_cert, NULL, PR_FALSE, PR_TRUE)); +#endif + DCHECK(cert.get() != NULL); +} + +// The wire form of the OID 1.3.6.1.4.1.11129.2.4.2. See Section 3.3 of +// RFC6962. +static const unsigned char kEmbeddedSCTOid[] = {0x2B, 0x06, 0x01, 0x04, 0x01, + 0xD6, 0x79, 0x02, 0x04, 0x02}; +static const char kEmbeddedSCTDescription[] = + "X.509v3 Certificate Transparency Embedded Signed Certificate Timestamp " + "List"; + +// Initializes the necessary NSS internals for use with Certificate +// Transparency. +class CTInitSingleton { + public: + SECOidTag embedded_oid() const { return embedded_oid_; } + + private: + friend struct base::DefaultLazyInstanceTraits<CTInitSingleton>; + + CTInitSingleton() : embedded_oid_(SEC_OID_UNKNOWN) { + embedded_oid_ = RegisterOid( + kEmbeddedSCTOid, sizeof(kEmbeddedSCTOid), kEmbeddedSCTDescription); + } + + ~CTInitSingleton() {} + + SECOidTag RegisterOid(const unsigned char* oid, + unsigned int oid_len, + const char* description) { + SECOidData oid_data; + oid_data.oid.len = oid_len; + oid_data.oid.data = const_cast<unsigned char*>(oid); + oid_data.offset = SEC_OID_UNKNOWN; + oid_data.desc = description; + oid_data.mechanism = CKM_INVALID_MECHANISM; + // Setting this to SUPPORTED_CERT_EXTENSION ensures that if a certificate + // contains this extension with the critical bit set, NSS will not reject + // it. However, because verification of this extension happens after NSS, + // it is currently left as INVALID_CERT_EXTENSION. + oid_data.supportedExtension = INVALID_CERT_EXTENSION; + + SECOidTag result = SECOID_AddEntry(&oid_data); + CHECK_NE(SEC_OID_UNKNOWN, result); + + return result; + } + + SECOidTag embedded_oid_; + + DISALLOW_COPY_AND_ASSIGN(CTInitSingleton); +}; + +base::LazyInstance<CTInitSingleton>::Leaky g_ct_singleton = + LAZY_INSTANCE_INITIALIZER; + +// Obtains the data for an X.509v3 certificate extension identified by |oid| +// and encoded as an OCTET STRING. Returns true if the extension was found, +// updating |ext_data| to be the extension data after removing the DER +// encoding of OCTET STRING. +bool GetOctetStringExtension(CERTCertificate* cert, + SECOidTag oid, + std::string* extension_data) { + SECItem extension; + SECStatus rv = CERT_FindCertExtension(cert, oid, &extension); + if (rv != SECSuccess) + return false; + + base::StringPiece raw_data(reinterpret_cast<char*>(extension.data), + extension.len); + base::StringPiece parsed_data; + if (!asn1::GetElement(&raw_data, asn1::kOCTETSTRING, &parsed_data)) { + rv = SECFailure; + } else { + if (raw_data.size() > 0) + return false; // leftover data + parsed_data.CopyToString(extension_data); + } + + SECITEM_FreeItem(&extension, PR_FALSE); + return rv == SECSuccess; +} + +// Given a |cert|, extract the TBSCertificate from this certificate, also +// removing X.509 extensions with OID 1.3.6.1.4.1.11129.2.4.2 (that is, +// the embedded SCT) +bool ExtractTBSCertWithoutSCTs(CERTCertificate* cert, + std::string* to_be_signed) { + SECOidData* oid = SECOID_FindOIDByTag(g_ct_singleton.Get().embedded_oid()); + if (!oid) + return false; + + // This is a giant hack, due to the fact that NSS does not expose a good API + // for simply removing certificate fields from existing certificates. + CERTCertificate temp_cert; + temp_cert = *cert; + temp_cert.extensions = NULL; + + // Strip out the embedded SCT OID from the new certificate by directly + // mutating the extensions in place. + std::vector<CERTCertExtension*> new_extensions; + if (cert->extensions) { + for (CERTCertExtension** exts = cert->extensions; *exts; ++exts) { + CERTCertExtension* ext = *exts; + SECComparison result = SECITEM_CompareItem(&oid->oid, &ext->id); + if (result != SECEqual) + new_extensions.push_back(ext); + } + } + if (!new_extensions.empty()) { + new_extensions.push_back(NULL); + temp_cert.extensions = &new_extensions[0]; + } + + crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); + + SECItem tbs_data; + tbs_data.len = 0; + tbs_data.data = NULL; + void* result = SEC_ASN1EncodeItem(arena.get(), + &tbs_data, + &temp_cert, + SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!result) + return false; + + to_be_signed->assign(reinterpret_cast<char*>(tbs_data.data), tbs_data.len); + return true; +} + +} // namespace + +bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, + std::string* sct_list) { + DCHECK(cert); + + NSSCertWrapper leaf_cert(cert); + if (!leaf_cert.cert) + return false; + + return GetOctetStringExtension( + leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), sct_list); +} + +bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, + X509Certificate::OSCertHandle issuer, + LogEntry* result) { + DCHECK(leaf); + DCHECK(issuer); + + NSSCertWrapper leaf_cert(leaf); + NSSCertWrapper issuer_cert(issuer); + + result->Reset(); + // XXX(rsleevi): This check may be overkill, since we should be able to + // generate precerts for certs without the extension. For now, just a sanity + // check to match the reference implementation. + SECItem extension; + SECStatus rv = CERT_FindCertExtension( + leaf_cert.cert.get(), g_ct_singleton.Get().embedded_oid(), &extension); + if (rv != SECSuccess) + return false; + SECITEM_FreeItem(&extension, PR_FALSE); + + std::string to_be_signed; + if (!ExtractTBSCertWithoutSCTs(leaf_cert.cert.get(), &to_be_signed)) + return false; + + if (!issuer_cert.cert) { + // This can happen when the issuer and leaf certs share the same serial + // number and are from the same CA, which should never be the case + // (but happened with bad test certs). + VLOG(1) << "Issuer cert is null, cannot generate Precert entry."; + return false; + } + + SECKEYPublicKey* issuer_pub_key = + SECKEY_ExtractPublicKey(&(issuer_cert.cert->subjectPublicKeyInfo)); + if (!issuer_pub_key) { + VLOG(1) << "Could not extract issuer public key, " + << "cannot generate Precert entry."; + return false; + } + + SECItem* encoded_issuer_pubKey = + SECKEY_EncodeDERSubjectPublicKeyInfo(issuer_pub_key); + if (!encoded_issuer_pubKey) { + SECKEY_DestroyPublicKey(issuer_pub_key); + return false; + } + + result->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT; + result->tbs_certificate.swap(to_be_signed); + + crypto::SHA256HashString( + base::StringPiece(reinterpret_cast<char*>(encoded_issuer_pubKey->data), + encoded_issuer_pubKey->len), + result->issuer_key_hash.data, + sizeof(result->issuer_key_hash.data)); + + SECITEM_FreeItem(encoded_issuer_pubKey, PR_TRUE); + SECKEY_DestroyPublicKey(issuer_pub_key); + + return true; +} + +bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { + DCHECK(leaf); + + std::string encoded; + if (!X509Certificate::GetDEREncoded(leaf, &encoded)) + return false; + + result->Reset(); + result->type = ct::LogEntry::LOG_ENTRY_TYPE_X509; + result->leaf_certificate.swap(encoded); + return true; +} + +} // namespace ct + +} // namespace net diff --git a/net/cert/ct_objects_extractor_openssl.cc b/net/cert/ct_objects_extractor_openssl.cc new file mode 100644 index 0000000..3fb5f2c --- /dev/null +++ b/net/cert/ct_objects_extractor_openssl.cc @@ -0,0 +1,33 @@ +// Copyright 2013 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 "net/cert/ct_objects_extractor.h" + +#include "base/logging.h" + +namespace net { + +namespace ct { + +bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert, + std::string* sct_list) { + NOTIMPLEMENTED(); + return false; +} + +bool GetPrecertLogEntry(X509Certificate::OSCertHandle leaf, + X509Certificate::OSCertHandle issuer, + LogEntry* result) { + NOTIMPLEMENTED(); + return false; +} + +bool GetX509LogEntry(X509Certificate::OSCertHandle leaf, LogEntry* result) { + NOTIMPLEMENTED(); + return false; +} + +} // namespace ct + +} // namespace net diff --git a/net/cert/ct_objects_extractor_unittest.cc b/net/cert/ct_objects_extractor_unittest.cc new file mode 100644 index 0000000..30ababd --- /dev/null +++ b/net/cert/ct_objects_extractor_unittest.cc @@ -0,0 +1,125 @@ +// Copyright 2013 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 "net/cert/ct_objects_extractor.h" + +#include "base/files/file_path.h" +#include "net/base/test_data_directory.h" +#include "net/cert/ct_log_verifier.h" +#include "net/cert/ct_serialization.h" +#include "net/cert/signed_certificate_timestamp.h" +#include "net/cert/x509_certificate.h" +#include "net/test/cert_test_util.h" +#include "net/test/ct_test_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +namespace ct { + +class CTObjectsExtractorTest : public ::testing::Test { + public: + virtual void SetUp() OVERRIDE { + precert_chain_ = + CreateCertificateListFromFile(GetTestCertsDirectory(), + "ct-test-embedded-cert.pem", + X509Certificate::FORMAT_AUTO); + ASSERT_EQ(2u, precert_chain_.size()); + + std::string der_test_cert(ct::GetDerEncodedX509Cert()); + test_cert_ = X509Certificate::CreateFromBytes(der_test_cert.data(), + der_test_cert.length()); + + log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog").Pass(); + ASSERT_TRUE(log_); + } + + void ExtractEmbeddedSCT(scoped_refptr<X509Certificate> cert, + SignedCertificateTimestamp* sct) { + std::string sct_list; + EXPECT_TRUE(ExtractEmbeddedSCTList(cert->os_cert_handle(), &sct_list)); + + std::vector<base::StringPiece> parsed_scts; + base::StringPiece sct_list_sp(sct_list); + // Make sure the SCT list can be decoded properly + EXPECT_TRUE(DecodeSCTList(&sct_list_sp, &parsed_scts)); + + EXPECT_TRUE(DecodeSignedCertificateTimestamp(&parsed_scts[0], sct)); + } + + protected: + CertificateList precert_chain_; + scoped_refptr<X509Certificate> test_cert_; + scoped_ptr<CTLogVerifier> log_; +}; + +// Test that an SCT can be extracted and the extracted SCT contains the +// expected data. +TEST_F(CTObjectsExtractorTest, ExtractEmbeddedSCT) { + ct::SignedCertificateTimestamp sct; + ExtractEmbeddedSCT(precert_chain_[0], &sct); + + EXPECT_EQ(sct.version, SignedCertificateTimestamp::SCT_VERSION_1); + EXPECT_EQ(ct::GetTestPublicKeyId(), sct.log_id); + + base::Time expected_timestamp = + base::Time::UnixEpoch() + + base::TimeDelta::FromMilliseconds(1365181456275); + EXPECT_EQ(expected_timestamp, sct.timestamp); +} + +TEST_F(CTObjectsExtractorTest, ExtractPrecert) { + LogEntry entry; + ASSERT_TRUE(GetPrecertLogEntry(precert_chain_[0]->os_cert_handle(), + precert_chain_[1]->os_cert_handle(), + &entry)); + + ASSERT_EQ(ct::LogEntry::LOG_ENTRY_TYPE_PRECERT, entry.type); + // Should have empty leaf cert for this log entry type. + ASSERT_TRUE(entry.leaf_certificate.empty()); + // Compare hash values of issuer spki. + SHA256HashValue expected_issuer_key_hash; + memcpy(expected_issuer_key_hash.data, GetDefaultIssuerKeyHash().data(), 32); + ASSERT_TRUE(expected_issuer_key_hash.Equals(entry.issuer_key_hash)); +} + +TEST_F(CTObjectsExtractorTest, ExtractOrdinaryX509Cert) { + LogEntry entry; + ASSERT_TRUE(GetX509LogEntry(test_cert_->os_cert_handle(), &entry)); + + ASSERT_EQ(ct::LogEntry::LOG_ENTRY_TYPE_X509, entry.type); + // Should have empty tbs_certificate for this log entry type. + ASSERT_TRUE(entry.tbs_certificate.empty()); + // Length of leaf_certificate should be 718, see the CT Serialization tests. + ASSERT_EQ(718U, entry.leaf_certificate.size()); +} + +// Test that the embedded SCT verifies +TEST_F(CTObjectsExtractorTest, ExtractedSCTVerifies) { + ct::SignedCertificateTimestamp sct; + ExtractEmbeddedSCT(precert_chain_[0], &sct); + + LogEntry entry; + ASSERT_TRUE(GetPrecertLogEntry(precert_chain_[0]->os_cert_handle(), + precert_chain_[1]->os_cert_handle(), + &entry)); + + EXPECT_TRUE(log_->Verify(entry, sct)); +} + +// Test that an externally-provided SCT verifies over the LogEntry +// of a regular X.509 Certificate +TEST_F(CTObjectsExtractorTest, ComplementarySCTVerifies) { + ct::SignedCertificateTimestamp sct; + GetX509CertSCT(&sct); + + LogEntry entry; + ASSERT_TRUE(GetX509LogEntry(test_cert_->os_cert_handle(), &entry)); + + EXPECT_TRUE(log_->Verify(entry, sct)); +} + +} // namespace ct + +} // namespace net diff --git a/net/cert/ct_serialization_unittest.cc b/net/cert/ct_serialization_unittest.cc index 9692fb9..03fc034 100644 --- a/net/cert/ct_serialization_unittest.cc +++ b/net/cert/ct_serialization_unittest.cc @@ -138,11 +138,7 @@ TEST_F(CtSerializationTest, DecodesSignedCertificateTimestamp) { ct::SignedCertificateTimestamp sct; ASSERT_TRUE(ct::DecodeSignedCertificateTimestamp(&encoded_sct, &sct)); EXPECT_EQ(0, sct.version); - std::string expected_log_key( - "\xdf\x1c\x2e\xc1\x15\x00\x94\x52\x47\xa9\x61\x68\x32\x5d\xdc\x5c\x79\x59" - "\xe8\xf7\xc6\xd3\x88\xfc\x00\x2e\x0b\xbd\x3f\x74\xd7\x64", - 32); - EXPECT_EQ(expected_log_key, sct.log_id); + EXPECT_EQ(ct::GetTestPublicKeyId(), sct.log_id); base::Time expected_time = base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(1365181456089); EXPECT_EQ(expected_time, sct.timestamp); diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README index 01f6dfd..86f10a6 100644 --- a/net/data/ssl/certificates/README +++ b/net/data/ssl/certificates/README @@ -226,3 +226,6 @@ unit tests. http://crbug.com/31497. It is generated by running the script net/data/ssl/scripts/generate-policy-certs.sh +- ct-test-embedded-cert.pem + Test certificate chain for Certificate Transparency: The leaf certificate + in this file contains embedded SCTs, followed by the issuer certificate. diff --git a/net/data/ssl/certificates/ct-test-embedded-cert.pem b/net/data/ssl/certificates/ct-test-embedded-cert.pem new file mode 100644 index 0000000..ff4875d --- /dev/null +++ b/net/data/ssl/certificates/ct-test-embedded-cert.pem @@ -0,0 +1,126 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 7 (0x7) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen + Validity + Not Before: Jun 1 00:00:00 2012 GMT + Not After : Jun 1 00:00:00 2022 GMT + Subject: C=GB, O=Certificate Transparency, ST=Wales, L=Erw Wen + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:be:ef:98:e7:c2:68:77:ae:38:5f:75:32:5a:0c: + 1d:32:9b:ed:f1:8f:aa:f4:d7:96:bf:04:7e:b7:e1: + ce:15:c9:5b:a2:f8:0e:e4:58:bd:7d:b8:6f:8a:4b: + 25:21:91:a7:9b:d7:00:c3:8e:9c:03:89:b4:5c:d4: + dc:9a:12:0a:b2:1e:0c:b4:1c:d0:e7:28:05:a4:10: + cd:9c:5b:db:5d:49:27:72:6d:af:17:10:f6:01:87: + 37:7e:a2:5b:1a:1e:39:ee:d0:b8:81:19:dc:15:4d: + c6:8f:7d:a8:e3:0c:af:15:8a:33:e6:c9:50:9f:4a: + 05:b0:14:09:ff:5d:d8:7e:b5 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 20:31:54:1A:F2:5C:05:FF:D8:65:8B:68:43:79:4F:5E:90:36:F7:B4 + X509v3 Authority Key Identifier: + keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55 + DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen + serial:00 + + X509v3 Basic Constraints: + CA:FALSE + 1.3.6.1.4.1.11129.2.4.2: + .z.x.v........RG.ah2].\yY..........?t.d...=.'.......G0E. H/gQ.5..T6...d.=..AB...E0(....>..!.....:.r.....jh.S.}.A.}....Q..... + Signature Algorithm: sha1WithRSAEncryption + 8a:0c:4b:ef:09:9d:47:92:79:af:a0:a2:8e:68:9f:91:e1:c4: + 42:1b:e2:d2:69:a2:ea:6c:a4:e8:21:5d:de:dd:ca:15:04:a1: + 1e:7c:87:c4:b7:7e:80:f0:e9:79:03:52:68:f2:7c:a2:0e:16: + 68:04:ae:55:6f:31:69:81:f9:6a:39:4a:b7:ab:fd:3e:25:5a: + c0:04:45:13:fe:76:57:0c:67:95:ab:e4:70:31:33:d3:03:f8: + 9f:3a:fa:6b:bc:fc:51:73:19:df:d9:5b:93:42:41:21:1f:63: + 40:35:c3:d0:78:30:7a:68:c6:07:5a:2e:20:c8:9f:36:b8:91: + 0c:a0 +-----BEGIN CERTIFICATE----- +MIIDWTCCAsKgAwIBAgIBBzANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk +MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX +YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw +MDAwMDBaMFIxCzAJBgNVBAYTAkdCMSEwHwYDVQQKExhDZXJ0aWZpY2F0ZSBUcmFu +c3BhcmVuY3kxDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGfMA0G +CSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+75jnwmh3rjhfdTJaDB0ym+3xj6r015a/ +BH634c4VyVui+A7kWL19uG+KSyUhkaeb1wDDjpwDibRc1NyaEgqyHgy0HNDnKAWk +EM2cW9tdSSdyba8XEPYBhzd+olsaHjnu0LiBGdwVTcaPfajjDK8VijPmyVCfSgWw +FAn/Xdh+tQIDAQABo4IBOjCCATYwHQYDVR0OBBYEFCAxVBryXAX/2GWLaEN5T16Q +Nve0MH0GA1UdIwR2MHSAFF+diA3Ic+ZU1PgN2OawwSS0R8NVoVmkVzBVMQswCQYD +VQQGEwJHQjEkMCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4w +DAYDVQQIEwVXYWxlczEQMA4GA1UEBxMHRXJ3IFdlboIBADAJBgNVHRMEAjAAMIGK +BgorBgEEAdZ5AgQCBHwEegB4AHYA3xwuwRUAlFJHqWFoMl3cXHlZ6PfG04j8AC4L +vT9012QAAAE92yffkwAABAMARzBFAiBIL2dRrzXbplQ2vh/WZA89v5pBQpSVkkUw +KI+j5eI+BgIhAOTtwNs6xXKx4vXoq2poBlOYfc9BAn3+/6EFUZ2J7b8IMA0GCSqG +SIb3DQEBBQUAA4GBAIoMS+8JnUeSea+goo5on5HhxEIb4tJpoupspOghXd7dyhUE +oR58h8S3foDw6XkDUmjyfKIOFmgErlVvMWmB+Wo5Srer/T4lWsAERRP+dlcMZ5Wr +5HAxM9MD+J86+mu8/FFzGd/ZW5NCQSEfY0A1w9B4MHpoxgdaLiDInza4kQyg +-----END CERTIFICATE----- +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 0 (0x0) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen + Validity + Not Before: Jun 1 00:00:00 2012 GMT + Not After : Jun 1 00:00:00 2022 GMT + Subject: C=GB, O=Certificate Transparency CA, ST=Wales, L=Erw Wen + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (1024 bit) + Modulus: + 00:d5:8a:68:53:62:10:a2:71:19:93:6e:77:83:21: + 18:1c:2a:40:13:c6:d0:7b:8c:76:eb:91:57:d3:d0: + fb:4b:3b:51:6e:ce:cb:d1:c9:8d:91:c5:2f:74:3f: + ab:63:5d:55:09:9c:d1:3a:ba:f3:1a:e5:41:44:24: + 51:a7:4c:78:16:f2:24:3c:f8:48:cf:28:31:cc:e6: + 7b:a0:4a:5a:23:81:9f:3c:ba:37:e6:24:d9:c3:bd: + b2:99:b8:39:dd:fe:26:31:d2:cb:3a:84:fc:7b:b2: + b5:c5:2f:cf:c1:4f:ff:40:6f:5c:d4:46:69:cb:b2: + f7:cf:df:86:fb:6a:b9:d1:b1 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55 + X509v3 Authority Key Identifier: + keyid:5F:9D:88:0D:C8:73:E6:54:D4:F8:0D:D8:E6:B0:C1:24:B4:47:C3:55 + DirName:/C=GB/O=Certificate Transparency CA/ST=Wales/L=Erw Wen + serial:00 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: sha1WithRSAEncryption + 06:08:cc:4a:6d:64:f2:20:5e:14:6c:04:b2:76:f9:2b:0e:fa: + 94:a5:da:f2:3a:fc:38:06:60:6d:39:90:d0:a1:ea:23:3d:40: + 29:57:69:46:3b:04:66:61:e7:fa:1d:17:99:15:20:9a:ea:2e: + 0a:77:51:76:41:12:27:d7:c0:03:07:c7:47:0e:61:58:4f:d7: + 33:42:24:72:7f:51:d6:90:bc:47:a9:df:35:4d:b0:f6:eb:25: + 95:5d:e1:89:3c:4d:d5:20:2b:24:a2:f3:e4:40:d2:74:b5:4e: + 1b:d3:76:26:9c:a9:62:89:b7:6e:ca:a4:10:90:e1:4f:3b:0a: + 94:2e +-----BEGIN CERTIFICATE----- +MIIC0DCCAjmgAwIBAgIBADANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJHQjEk +MCIGA1UEChMbQ2VydGlmaWNhdGUgVHJhbnNwYXJlbmN5IENBMQ4wDAYDVQQIEwVX +YWxlczEQMA4GA1UEBxMHRXJ3IFdlbjAeFw0xMjA2MDEwMDAwMDBaFw0yMjA2MDEw +MDAwMDBaMFUxCzAJBgNVBAYTAkdCMSQwIgYDVQQKExtDZXJ0aWZpY2F0ZSBUcmFu +c3BhcmVuY3kgQ0ExDjAMBgNVBAgTBVdhbGVzMRAwDgYDVQQHEwdFcncgV2VuMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVimhTYhCicRmTbneDIRgcKkATxtB7 +jHbrkVfT0PtLO1FuzsvRyY2RxS90P6tjXVUJnNE6uvMa5UFEJFGnTHgW8iQ8+EjP +KDHM5nugSlojgZ88ujfmJNnDvbKZuDnd/iYx0ss6hPx7srXFL8/BT/9Ab1zURmnL +svfP34b7arnRsQIDAQABo4GvMIGsMB0GA1UdDgQWBBRfnYgNyHPmVNT4DdjmsMEk +tEfDVTB9BgNVHSMEdjB0gBRfnYgNyHPmVNT4DdjmsMEktEfDVaFZpFcwVTELMAkG +A1UEBhMCR0IxJDAiBgNVBAoTG0NlcnRpZmljYXRlIFRyYW5zcGFyZW5jeSBDQTEO +MAwGA1UECBMFV2FsZXMxEDAOBgNVBAcTB0VydyBXZW6CAQAwDAYDVR0TBAUwAwEB +/zANBgkqhkiG9w0BAQUFAAOBgQAGCMxKbWTyIF4UbASydvkrDvqUpdryOvw4BmBt +OZDQoeojPUApV2lGOwRmYef6HReZFSCa6i4Kd1F2QRIn18ADB8dHDmFYT9czQiRy +f1HWkLxHqd81TbD26yWVXeGJPE3VICskovPkQNJ0tU4b03YmnKliibduyqQQkOFP +OwqULg== +-----END CERTIFICATE----- diff --git a/net/net.gyp b/net/net.gyp index 3e5b04b..771fbc8 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -274,6 +274,9 @@ 'cert/ct_log_verifier.h', 'cert/ct_log_verifier_nss.cc', 'cert/ct_log_verifier_openssl.cc', + 'cert/ct_objects_extractor.h', + 'cert/ct_objects_extractor_nss.cc', + 'cert/ct_objects_extractor_openssl.cc', 'cert/ct_serialization.cc', 'cert/ct_serialization.h', 'cert/ev_root_ca_metadata.cc', @@ -1264,6 +1267,7 @@ 'cert/cert_verify_proc_nss.cc', 'cert/cert_verify_proc_nss.h', 'cert/ct_log_verifier_nss.cc', + 'cert/ct_objects_extractor_nss.cc', 'cert/jwk_serializer_nss.cc', 'cert/nss_cert_database.cc', 'cert/nss_cert_database.h', @@ -1303,6 +1307,7 @@ 'cert/cert_verify_proc_openssl.cc', 'cert/cert_verify_proc_openssl.h', 'cert/ct_log_verifier_openssl.cc', + 'cert/ct_objects_extractor_openssl.cc', 'cert/jwk_serializer_openssl.cc', 'cert/test_root_certs_openssl.cc', 'cert/x509_certificate_openssl.cc', @@ -1592,6 +1597,7 @@ 'cert/cert_verify_proc_unittest.cc', 'cert/crl_set_unittest.cc', 'cert/ct_log_verifier_unittest.cc', + 'cert/ct_objects_extractor_unittest.cc', 'cert/ct_serialization_unittest.cc', 'cert/ev_root_ca_metadata_unittest.cc', 'cert/jwk_serializer_unittest.cc', @@ -2053,10 +2059,12 @@ ], }], [ 'use_openssl==1', { - # When building for OpenSSL, we need to exclude NSS specific tests. + # When building for OpenSSL, we need to exclude NSS specific tests + # or functionality not supported by OpenSSL yet. # TODO(bulach): Add equivalent tests when the underlying # functionality is ported to OpenSSL. 'sources!': [ + 'cert/ct_objects_extractor_unittest.cc', 'cert/nss_cert_database_unittest.cc', 'cert/x509_util_nss_unittest.cc', 'quic/test_tools/crypto_test_utils_nss.cc', diff --git a/net/test/ct_test_util.cc b/net/test/ct_test_util.cc index b588b13..db690e3 100644 --- a/net/test/ct_test_util.cc +++ b/net/test/ct_test_util.cc @@ -108,6 +108,8 @@ void GetX509CertLogEntry(LogEntry* entry) { entry->leaf_certificate = HexToBytes(kDefaultDerCert); } +std::string GetDerEncodedX509Cert() { return HexToBytes(kDefaultDerCert); } + void GetPrecertLogEntry(LogEntry* entry) { entry->type = ct::LogEntry::LOG_ENTRY_TYPE_PRECERT; std::string issuer_hash(HexToBytes(kDefaultIssuerKeyHash)); @@ -153,6 +155,10 @@ void GetPrecertSCT(SignedCertificateTimestamp* sct) { sct->signature.signature_data = HexToBytes(kTestSCTPrecertSignatureData); } +std::string GetDefaultIssuerKeyHash() { + return HexToBytes(kDefaultIssuerKeyHash); +} + } // namespace ct } // namespace net diff --git a/net/test/ct_test_util.h b/net/test/ct_test_util.h index f12e144..8343cb8 100644 --- a/net/test/ct_test_util.h +++ b/net/test/ct_test_util.h @@ -22,6 +22,10 @@ struct SignedCertificateTimestamp; // Fills |entry| with test data for an X.509 entry. void GetX509CertLogEntry(LogEntry* entry); +// Returns a DER-encoded X509 cert. The SCT provided by +// GetX509CertSCT is signed over this certificate. +std::string GetDerEncodedX509Cert(); + // Fills |entry| with test data for a Precertificate entry. void GetPrecertLogEntry(LogEntry* entry); @@ -43,6 +47,9 @@ void GetX509CertSCT(SignedCertificateTimestamp* sct); // SCT for the Precertificate log entry provided above. void GetPrecertSCT(SignedCertificateTimestamp* sct); +// Issuer key hash +std::string GetDefaultIssuerKeyHash(); + } // namespace ct } // namespace net |