// 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/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 "net/test/test_data_directory.h" #include "testing/gtest/include/gtest/gtest.h" namespace net::ct { class CTObjectsExtractorTest : public ::testing::Test { public: 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( base::as_bytes(base::make_span(der_test_cert))); ASSERT_TRUE(test_cert_); log_ = CTLogVerifier::Create(ct::GetTestPublicKey(), "testlog"); ASSERT_TRUE(log_); } void ExtractEmbeddedSCT(scoped_refptr cert, scoped_refptr* sct) { std::string sct_list; ASSERT_TRUE(ExtractEmbeddedSCTList(cert->cert_buffer(), &sct_list)); std::vector parsed_scts; // Make sure the SCT list can be decoded properly ASSERT_TRUE(DecodeSCTList(sct_list, &parsed_scts)); ASSERT_EQ(1u, parsed_scts.size()); EXPECT_TRUE(DecodeSignedCertificateTimestamp(&parsed_scts[0], sct)); } protected: CertificateList precert_chain_; scoped_refptr test_cert_; scoped_refptr log_; }; // Test that an SCT can be extracted and the extracted SCT contains the // expected data. TEST_F(CTObjectsExtractorTest, ExtractEmbeddedSCT) { auto sct = base::MakeRefCounted(); ExtractEmbeddedSCT(precert_chain_[0], &sct); EXPECT_EQ(sct->version, SignedCertificateTimestamp::V1); EXPECT_EQ(ct::GetTestPublicKeyId(), sct->log_id); base::Time expected_timestamp = base::Time::UnixEpoch() + base::Milliseconds(1365181456275); EXPECT_EQ(expected_timestamp, sct->timestamp); } // Test that the extractor correctly skips over issuerUniqueID and // subjectUniqueID fields. See https://crbug.com/1199744. TEST_F(CTObjectsExtractorTest, ExtractEmbeddedSCTListWithUIDs) { CertificateList certs = CreateCertificateListFromFile( GetTestCertsDirectory(), "ct-test-embedded-with-uids.pem", X509Certificate::FORMAT_PEM_CERT_SEQUENCE); ASSERT_EQ(1u, certs.size()); auto sct = base::MakeRefCounted(); ExtractEmbeddedSCT(certs[0], &sct); EXPECT_EQ(sct->version, SignedCertificateTimestamp::V1); EXPECT_EQ(ct::GetTestPublicKeyId(), sct->log_id); base::Time expected_timestamp = base::Time::UnixEpoch() + base::Milliseconds(1365181456275); EXPECT_EQ(expected_timestamp, sct->timestamp); } TEST_F(CTObjectsExtractorTest, ExtractPrecert) { SignedEntryData entry; ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(), precert_chain_[1]->cert_buffer(), &entry)); ASSERT_EQ(ct::SignedEntryData::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_EQ(expected_issuer_key_hash, entry.issuer_key_hash); } TEST_F(CTObjectsExtractorTest, ExtractOrdinaryX509Cert) { SignedEntryData entry; ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry)); ASSERT_EQ(ct::SignedEntryData::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) { auto sct = base::MakeRefCounted(); ExtractEmbeddedSCT(precert_chain_[0], &sct); SignedEntryData entry; ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(), precert_chain_[1]->cert_buffer(), &entry)); EXPECT_TRUE(log_->Verify(entry, *sct.get())); } // Test that an externally-provided SCT verifies over the SignedEntryData // of a regular X.509 Certificate TEST_F(CTObjectsExtractorTest, ComplementarySCTVerifies) { auto sct = base::MakeRefCounted(); GetX509CertSCT(&sct); SignedEntryData entry; ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry)); EXPECT_TRUE(log_->Verify(entry, *sct.get())); } // Test that the extractor can parse OCSP responses. TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponse) { std::string der_subject_cert(ct::GetDerEncodedFakeOCSPResponseCert()); scoped_refptr subject_cert = X509Certificate::CreateFromBytes( base::as_bytes(base::make_span(der_subject_cert))); ASSERT_TRUE(subject_cert); std::string der_issuer_cert(ct::GetDerEncodedFakeOCSPResponseIssuerCert()); scoped_refptr issuer_cert = X509Certificate::CreateFromBytes( base::as_bytes(base::make_span(der_issuer_cert))); ASSERT_TRUE(issuer_cert); std::string fake_sct_list = ct::GetFakeOCSPExtensionValue(); ASSERT_FALSE(fake_sct_list.empty()); std::string ocsp_response = ct::GetDerEncodedFakeOCSPResponse(); std::string extracted_sct_list; EXPECT_TRUE(ct::ExtractSCTListFromOCSPResponse( issuer_cert->cert_buffer(), subject_cert->serial_number(), ocsp_response, &extracted_sct_list)); EXPECT_EQ(extracted_sct_list, fake_sct_list); } // Test that the extractor honours serial number. TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponseMatchesSerial) { std::string der_issuer_cert(ct::GetDerEncodedFakeOCSPResponseIssuerCert()); scoped_refptr issuer_cert = X509Certificate::CreateFromBytes( base::as_bytes(base::make_span(der_issuer_cert))); ASSERT_TRUE(issuer_cert); std::string ocsp_response = ct::GetDerEncodedFakeOCSPResponse(); std::string extracted_sct_list; EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse( issuer_cert->cert_buffer(), test_cert_->serial_number(), ocsp_response, &extracted_sct_list)); } // Test that the extractor honours issuer ID. TEST_F(CTObjectsExtractorTest, ExtractSCTListFromOCSPResponseMatchesIssuer) { std::string der_subject_cert(ct::GetDerEncodedFakeOCSPResponseCert()); scoped_refptr subject_cert = X509Certificate::CreateFromBytes( base::as_bytes(base::make_span(der_subject_cert))); ASSERT_TRUE(subject_cert); std::string ocsp_response = ct::GetDerEncodedFakeOCSPResponse(); std::string extracted_sct_list; // Use test_cert_ for issuer - it is not the correct issuer of |subject_cert|. EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse( test_cert_->cert_buffer(), subject_cert->serial_number(), ocsp_response, &extracted_sct_list)); } } // namespace net::ct