diff options
Diffstat (limited to 'security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp')
-rw-r--r-- | security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp b/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp new file mode 100644 index 000000000..f8f04804e --- /dev/null +++ b/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp @@ -0,0 +1,233 @@ +/* -*- 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 "mozilla/EnumSet.h" +#include "mozilla/Move.h" +#include "nss.h" + +namespace mozilla { namespace ct { + +using namespace mozilla::pkix; + +class MultiLogCTVerifierTest : public ::testing::Test +{ +public: + MultiLogCTVerifierTest() + : mNow(Time::uninitialized) + {} + + void SetUp() override + { + // Does nothing if NSS is already initialized. + MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess); + + ASSERT_EQ(Success, mVerifier.AddLog(InputForBuffer(GetTestPublicKey()))); + + 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 CheckForSingleVerifiedSCTInResult(const CTVerifyResult& result, + SignedCertificateTimestamp::Origin origin) + { + EXPECT_EQ(0U, result.decodingErrors); + ASSERT_EQ(1U, result.scts.length()); + EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::OK, + result.scts[0].verificationStatus); + EXPECT_EQ(origin, result.scts[0].origin); + } + + // Writes an SCTList containing a single |sct| into |output|. + void EncodeSCTListForTesting(Input sct, Buffer& output) + { + Vector<Input> list; + ASSERT_TRUE(list.append(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)); + CheckForSingleVerifiedSCTInResult(result, + SignedCertificateTimestamp::Origin::Embedded); + } + +protected: + MultiLogCTVerifier mVerifier; + Buffer mTestCert; + Buffer mEmbeddedCert; + Buffer mCaCert; + Buffer mCaCertSPKI; + Buffer mIntermediateCert; + Buffer mIntermediateCertSPKI; + Time mNow; +}; + +// 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)); + + CheckForSingleVerifiedSCTInResult(result, + SignedCertificateTimestamp::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)); + + CheckForSingleVerifiedSCTInResult(result, + SignedCertificateTimestamp::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. + EnumSet<SignedCertificateTimestamp::Origin> origins; + for (const SignedCertificateTimestamp& sct : result.scts) { + EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::OK, + sct.verificationStatus); + origins += sct.origin; + } + EXPECT_FALSE( + origins.contains(SignedCertificateTimestamp::Origin::Embedded)); + EXPECT_TRUE( + origins.contains(SignedCertificateTimestamp::Origin::OCSPResponse)); + EXPECT_TRUE( + origins.contains(SignedCertificateTimestamp::Origin::TLSExtension)); +} + +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.scts.length()); + EXPECT_EQ(SignedCertificateTimestamp::VerificationStatus::UnknownLog, + result.scts[0].verificationStatus); +} + +} } // namespace mozilla::ct |