diff options
Diffstat (limited to '')
-rw-r--r-- | security/ct/tests/gtest/MultiLogCTVerifierTest.cpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/security/ct/tests/gtest/MultiLogCTVerifierTest.cpp b/security/ct/tests/gtest/MultiLogCTVerifierTest.cpp new file mode 100644 index 0000000000..4ac3f42f28 --- /dev/null +++ b/security/ct/tests/gtest/MultiLogCTVerifierTest.cpp @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MultiLogCTVerifier.h" + +#include <stdint.h> + +#include "CTLogVerifier.h" +#include "CTObjectsExtractor.h" +#include "CTSerialization.h" +#include "CTTestUtils.h" +#include "gtest/gtest.h" +#include "nss.h" + +namespace mozilla { +namespace ct { + +using namespace mozilla::pkix; + +class MultiLogCTVerifierTest : public ::testing::Test { + public: + MultiLogCTVerifierTest() : mNow(Time::uninitialized), mLogOperatorID(123) {} + + void SetUp() override { + // Does nothing if NSS is already initialized. + if (NSS_NoDB_Init(nullptr) != SECSuccess) { + abort(); + } + + CTLogVerifier log; + ASSERT_EQ(Success, + log.Init(InputForBuffer(GetTestPublicKey()), mLogOperatorID, + CTLogStatus::Included, 0 /*disqualification time*/)); + mVerifier.AddLog(std::move(log)); + + mTestCert = GetDEREncodedX509Cert(); + mEmbeddedCert = GetDEREncodedTestEmbeddedCert(); + mCaCert = GetDEREncodedCACert(); + mCaCertSPKI = ExtractCertSPKI(mCaCert); + mIntermediateCert = GetDEREncodedIntermediateCert(); + mIntermediateCertSPKI = ExtractCertSPKI(mIntermediateCert); + + // Set the current time making sure all test timestamps are in the past. + mNow = + TimeFromEpochInSeconds(1451606400u); // Date.parse("2016-01-01")/1000 + } + + void CheckForSingleValidSCTInResult(const CTVerifyResult& result, + VerifiedSCT::Origin origin) { + EXPECT_EQ(0U, result.decodingErrors); + ASSERT_EQ(1U, result.verifiedScts.size()); + EXPECT_EQ(VerifiedSCT::Status::Valid, result.verifiedScts[0].status); + EXPECT_EQ(origin, result.verifiedScts[0].origin); + EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId); + } + + // Writes an SCTList containing a single |sct| into |output|. + void EncodeSCTListForTesting(Input sct, Buffer& output) { + std::vector<Input> list; + list.push_back(std::move(sct)); + ASSERT_EQ(Success, EncodeSCTList(list, output)); + } + + void GetSCTListWithInvalidLogID(Buffer& result) { + result.clear(); + Buffer sct(GetTestSignedCertificateTimestamp()); + // Change a byte inside the Log ID part of the SCT so it does + // not match the log used in the tests. + sct[15] ^= '\xFF'; + EncodeSCTListForTesting(InputForBuffer(sct), result); + } + + void CheckPrecertVerification(const Buffer& cert, const Buffer& issuerSPKI) { + Buffer sctList; + ExtractEmbeddedSCTList(cert, sctList); + ASSERT_FALSE(sctList.empty()); + + CTVerifyResult result; + ASSERT_EQ(Success, + mVerifier.Verify(InputForBuffer(cert), InputForBuffer(issuerSPKI), + InputForBuffer(sctList), Input(), Input(), mNow, + result)); + CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::Embedded); + } + + protected: + MultiLogCTVerifier mVerifier; + Buffer mTestCert; + Buffer mEmbeddedCert; + Buffer mCaCert; + Buffer mCaCertSPKI; + Buffer mIntermediateCert; + Buffer mIntermediateCertSPKI; + Time mNow; + CTLogOperatorId mLogOperatorID; +}; + +// Test that an embedded SCT can be extracted and the extracted SCT contains +// the expected data. This tests the ExtractEmbeddedSCTList function from +// CTTestUtils.h that other tests here rely upon. +TEST_F(MultiLogCTVerifierTest, ExtractEmbeddedSCT) { + SignedCertificateTimestamp sct; + + // Extract the embedded SCT. + + Buffer sctList; + ExtractEmbeddedSCTList(mEmbeddedCert, sctList); + ASSERT_FALSE(sctList.empty()); + + Reader sctReader; + ASSERT_EQ(Success, DecodeSCTList(InputForBuffer(sctList), sctReader)); + Input sctItemInput; + ASSERT_EQ(Success, ReadSCTListItem(sctReader, sctItemInput)); + EXPECT_TRUE(sctReader.AtEnd()); // we only expect one sct in the list + + Reader sctItemReader(sctItemInput); + ASSERT_EQ(Success, DecodeSignedCertificateTimestamp(sctItemReader, sct)); + + // Make sure the SCT contains the expected data. + + EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version); + EXPECT_EQ(GetTestPublicKeyId(), sct.logId); + + uint64_t expectedTimestamp = 1365181456275; + EXPECT_EQ(expectedTimestamp, sct.timestamp); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCT) { + CheckPrecertVerification(mEmbeddedCert, mCaCertSPKI); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithPreCA) { + CheckPrecertVerification(GetDEREncodedTestEmbeddedWithPreCACert(), + mCaCertSPKI); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediate) { + CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediateCert(), + mIntermediateCertSPKI); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediateAndPreCA) { + CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediatePreCACert(), + mIntermediateCertSPKI); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromOCSP) { + Buffer sct(GetTestSignedCertificateTimestamp()); + Buffer sctList; + EncodeSCTListForTesting(InputForBuffer(sct), sctList); + + CTVerifyResult result; + ASSERT_EQ(Success, + mVerifier.Verify(InputForBuffer(mTestCert), Input(), Input(), + InputForBuffer(sctList), Input(), mNow, result)); + + CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::OCSPResponse); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromTLS) { + Buffer sct(GetTestSignedCertificateTimestamp()); + Buffer sctList; + EncodeSCTListForTesting(InputForBuffer(sct), sctList); + + CTVerifyResult result; + ASSERT_EQ(Success, + mVerifier.Verify(InputForBuffer(mTestCert), Input(), Input(), + Input(), InputForBuffer(sctList), mNow, result)); + + CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::TLSExtension); +} + +TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromMultipleSources) { + Buffer sct(GetTestSignedCertificateTimestamp()); + Buffer sctList; + EncodeSCTListForTesting(InputForBuffer(sct), sctList); + + CTVerifyResult result; + ASSERT_EQ(Success, mVerifier.Verify(InputForBuffer(mTestCert), Input(), + Input(), InputForBuffer(sctList), + InputForBuffer(sctList), mNow, result)); + + // The result should contain verified SCTs from TLS and OCSP origins. + size_t embeddedCount = 0; + size_t tlsExtensionCount = 0; + size_t ocspResponseCount = 0; + for (const VerifiedSCT& verifiedSct : result.verifiedScts) { + EXPECT_EQ(VerifiedSCT::Status::Valid, verifiedSct.status); + switch (verifiedSct.origin) { + case VerifiedSCT::Origin::Embedded: + embeddedCount++; + break; + case VerifiedSCT::Origin::TLSExtension: + tlsExtensionCount++; + break; + case VerifiedSCT::Origin::OCSPResponse: + ocspResponseCount++; + break; + case VerifiedSCT::Origin::Unknown: + default: + ASSERT_TRUE(false); + } + } + EXPECT_EQ(embeddedCount, 0u); + EXPECT_TRUE(tlsExtensionCount > 0); + EXPECT_TRUE(ocspResponseCount > 0); +} + +TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) { + Buffer sctList; + GetSCTListWithInvalidLogID(sctList); + + CTVerifyResult result; + ASSERT_EQ(Success, + mVerifier.Verify(InputForBuffer(mTestCert), Input(), Input(), + Input(), InputForBuffer(sctList), mNow, result)); + + EXPECT_EQ(0U, result.decodingErrors); + ASSERT_EQ(1U, result.verifiedScts.size()); + EXPECT_EQ(VerifiedSCT::Status::UnknownLog, result.verifiedScts[0].status); +} + +TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromDisqualifiedLog) { + MultiLogCTVerifier verifier; + CTLogVerifier log; + const uint64_t disqualificationTime = 12345u; + ASSERT_EQ(Success, + log.Init(InputForBuffer(GetTestPublicKey()), mLogOperatorID, + CTLogStatus::Disqualified, disqualificationTime)); + verifier.AddLog(std::move(log)); + + Buffer sct(GetTestSignedCertificateTimestamp()); + Buffer sctList; + EncodeSCTListForTesting(InputForBuffer(sct), sctList); + + CTVerifyResult result; + ASSERT_EQ(Success, + verifier.Verify(InputForBuffer(mTestCert), Input(), Input(), + Input(), InputForBuffer(sctList), mNow, result)); + + EXPECT_EQ(0U, result.decodingErrors); + ASSERT_EQ(1U, result.verifiedScts.size()); + EXPECT_EQ(VerifiedSCT::Status::ValidFromDisqualifiedLog, + result.verifiedScts[0].status); + EXPECT_EQ(disqualificationTime, + result.verifiedScts[0].logDisqualificationTime); + EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId); +} + +} // namespace ct +} // namespace mozilla |