summaryrefslogtreecommitdiffstats
path: root/security/ct/tests/gtest/MultiLogCTVerifierTest.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /security/ct/tests/gtest/MultiLogCTVerifierTest.cpp
parentInitial commit. (diff)
downloadfirefox-esr-upstream/115.8.0esr.tar.xz
firefox-esr-upstream/115.8.0esr.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/ct/tests/gtest/MultiLogCTVerifierTest.cpp')
-rw-r--r--security/ct/tests/gtest/MultiLogCTVerifierTest.cpp254
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