1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "MultiLogCTVerifier.h"
11 #include "CTLogVerifier.h"
12 #include "CTObjectsExtractor.h"
13 #include "CTSerialization.h"
14 #include "CTTestUtils.h"
15 #include "gtest/gtest.h"
21 using namespace mozilla::pkix
;
23 class MultiLogCTVerifierTest
: public ::testing::Test
{
25 MultiLogCTVerifierTest() : mNow(Time::uninitialized
), mLogOperatorID(123) {}
27 void SetUp() override
{
28 // Does nothing if NSS is already initialized.
29 if (NSS_NoDB_Init(nullptr) != SECSuccess
) {
33 CTLogVerifier
log(mLogOperatorID
, CTLogState::Admissible
, 0);
35 ASSERT_EQ(Success
, log
.Init(InputForBuffer(GetTestPublicKey())));
36 mVerifier
.AddLog(std::move(log
));
38 mTestCert
= GetDEREncodedX509Cert();
39 mEmbeddedCert
= GetDEREncodedTestEmbeddedCert();
40 mCaCert
= GetDEREncodedCACert();
41 mCaCertSPKI
= ExtractCertSPKI(mCaCert
);
42 mIntermediateCert
= GetDEREncodedIntermediateCert();
43 mIntermediateCertSPKI
= ExtractCertSPKI(mIntermediateCert
);
45 // Set the current time making sure all test timestamps are in the past.
47 TimeFromEpochInSeconds(1451606400u); // Date.parse("2016-01-01")/1000
50 void CheckForSingleValidSCTInResult(const CTVerifyResult
& result
,
52 EXPECT_EQ(0U, result
.decodingErrors
);
53 ASSERT_EQ(1U, result
.verifiedScts
.size());
54 EXPECT_EQ(CTLogState::Admissible
, result
.verifiedScts
[0].logState
);
55 EXPECT_EQ(origin
, result
.verifiedScts
[0].origin
);
56 EXPECT_EQ(mLogOperatorID
, result
.verifiedScts
[0].logOperatorId
);
59 // Writes an SCTList containing a single |sct| into |output|.
60 void EncodeSCTListForTesting(Input sct
, Buffer
& output
) {
61 std::vector
<Input
> list
;
62 list
.push_back(std::move(sct
));
63 ASSERT_EQ(Success
, EncodeSCTList(list
, output
));
66 void GetSCTListWithInvalidLogID(Buffer
& result
) {
68 Buffer
sct(GetTestSignedCertificateTimestamp());
69 // Change a byte inside the Log ID part of the SCT so it does
70 // not match the log used in the tests.
72 EncodeSCTListForTesting(InputForBuffer(sct
), result
);
75 void CheckPrecertVerification(const Buffer
& cert
, const Buffer
& issuerSPKI
) {
77 ExtractEmbeddedSCTList(cert
, sctList
);
78 ASSERT_FALSE(sctList
.empty());
80 CTVerifyResult result
;
82 mVerifier
.Verify(InputForBuffer(cert
), InputForBuffer(issuerSPKI
),
83 InputForBuffer(sctList
), Input(), Input(), mNow
,
85 CheckForSingleValidSCTInResult(result
, SCTOrigin::Embedded
);
89 MultiLogCTVerifier mVerifier
;
94 Buffer mIntermediateCert
;
95 Buffer mIntermediateCertSPKI
;
97 CTLogOperatorId mLogOperatorID
;
100 // Test that an embedded SCT can be extracted and the extracted SCT contains
101 // the expected data. This tests the ExtractEmbeddedSCTList function from
102 // CTTestUtils.h that other tests here rely upon.
103 TEST_F(MultiLogCTVerifierTest
, ExtractEmbeddedSCT
) {
104 SignedCertificateTimestamp sct
;
106 // Extract the embedded SCT.
109 ExtractEmbeddedSCTList(mEmbeddedCert
, sctList
);
110 ASSERT_FALSE(sctList
.empty());
113 ASSERT_EQ(Success
, DecodeSCTList(InputForBuffer(sctList
), sctReader
));
115 ASSERT_EQ(Success
, ReadSCTListItem(sctReader
, sctItemInput
));
116 EXPECT_TRUE(sctReader
.AtEnd()); // we only expect one sct in the list
118 Reader
sctItemReader(sctItemInput
);
119 ASSERT_EQ(Success
, DecodeSignedCertificateTimestamp(sctItemReader
, sct
));
121 // Make sure the SCT contains the expected data.
123 EXPECT_EQ(SignedCertificateTimestamp::Version::V1
, sct
.version
);
124 EXPECT_EQ(GetTestPublicKeyId(), sct
.logId
);
126 uint64_t expectedTimestamp
= 1365181456275;
127 EXPECT_EQ(expectedTimestamp
, sct
.timestamp
);
130 TEST_F(MultiLogCTVerifierTest
, VerifiesEmbeddedSCT
) {
131 CheckPrecertVerification(mEmbeddedCert
, mCaCertSPKI
);
134 TEST_F(MultiLogCTVerifierTest
, VerifiesEmbeddedSCTWithPreCA
) {
135 CheckPrecertVerification(GetDEREncodedTestEmbeddedWithPreCACert(),
139 TEST_F(MultiLogCTVerifierTest
, VerifiesEmbeddedSCTWithIntermediate
) {
140 CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediateCert(),
141 mIntermediateCertSPKI
);
144 TEST_F(MultiLogCTVerifierTest
, VerifiesEmbeddedSCTWithIntermediateAndPreCA
) {
145 CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediatePreCACert(),
146 mIntermediateCertSPKI
);
149 TEST_F(MultiLogCTVerifierTest
, VerifiesSCTFromOCSP
) {
150 Buffer
sct(GetTestSignedCertificateTimestamp());
152 EncodeSCTListForTesting(InputForBuffer(sct
), sctList
);
154 CTVerifyResult result
;
156 mVerifier
.Verify(InputForBuffer(mTestCert
), Input(), Input(),
157 InputForBuffer(sctList
), Input(), mNow
, result
));
159 CheckForSingleValidSCTInResult(result
, SCTOrigin::OCSPResponse
);
162 TEST_F(MultiLogCTVerifierTest
, VerifiesSCTFromTLS
) {
163 Buffer
sct(GetTestSignedCertificateTimestamp());
165 EncodeSCTListForTesting(InputForBuffer(sct
), sctList
);
167 CTVerifyResult result
;
169 mVerifier
.Verify(InputForBuffer(mTestCert
), Input(), Input(),
170 Input(), InputForBuffer(sctList
), mNow
, result
));
172 CheckForSingleValidSCTInResult(result
, SCTOrigin::TLSExtension
);
175 TEST_F(MultiLogCTVerifierTest
, VerifiesSCTFromMultipleSources
) {
176 Buffer
sct(GetTestSignedCertificateTimestamp());
178 EncodeSCTListForTesting(InputForBuffer(sct
), sctList
);
180 CTVerifyResult result
;
181 ASSERT_EQ(Success
, mVerifier
.Verify(InputForBuffer(mTestCert
), Input(),
182 Input(), InputForBuffer(sctList
),
183 InputForBuffer(sctList
), mNow
, result
));
185 // The result should contain verified SCTs from TLS and OCSP origins.
186 size_t embeddedCount
= 0;
187 size_t tlsExtensionCount
= 0;
188 size_t ocspResponseCount
= 0;
189 for (const VerifiedSCT
& verifiedSct
: result
.verifiedScts
) {
190 EXPECT_EQ(CTLogState::Admissible
, verifiedSct
.logState
);
191 switch (verifiedSct
.origin
) {
192 case SCTOrigin::Embedded
:
195 case SCTOrigin::TLSExtension
:
198 case SCTOrigin::OCSPResponse
:
203 EXPECT_EQ(embeddedCount
, 0u);
204 EXPECT_TRUE(tlsExtensionCount
> 0);
205 EXPECT_TRUE(ocspResponseCount
> 0);
208 TEST_F(MultiLogCTVerifierTest
, IdentifiesSCTFromUnknownLog
) {
210 GetSCTListWithInvalidLogID(sctList
);
212 CTVerifyResult result
;
214 mVerifier
.Verify(InputForBuffer(mTestCert
), Input(), Input(),
215 Input(), InputForBuffer(sctList
), mNow
, result
));
217 EXPECT_EQ(0U, result
.decodingErrors
);
218 EXPECT_EQ(0U, result
.verifiedScts
.size());
219 EXPECT_EQ(1U, result
.sctsFromUnknownLogs
);
222 TEST_F(MultiLogCTVerifierTest
, IdentifiesSCTFromDisqualifiedLog
) {
223 MultiLogCTVerifier verifier
;
224 const uint64_t retiredTime
= 12345u;
225 CTLogVerifier
log(mLogOperatorID
, CTLogState::Retired
, retiredTime
);
226 ASSERT_EQ(Success
, log
.Init(InputForBuffer(GetTestPublicKey())));
227 verifier
.AddLog(std::move(log
));
229 Buffer
sct(GetTestSignedCertificateTimestamp());
231 EncodeSCTListForTesting(InputForBuffer(sct
), sctList
);
233 CTVerifyResult result
;
235 verifier
.Verify(InputForBuffer(mTestCert
), Input(), Input(),
236 Input(), InputForBuffer(sctList
), mNow
, result
));
238 EXPECT_EQ(0U, result
.decodingErrors
);
239 ASSERT_EQ(1U, result
.verifiedScts
.size());
240 EXPECT_EQ(CTLogState::Retired
, result
.verifiedScts
[0].logState
);
241 EXPECT_EQ(retiredTime
, result
.verifiedScts
[0].logTimestamp
);
242 EXPECT_EQ(mLogOperatorID
, result
.verifiedScts
[0].logOperatorId
);
246 } // namespace mozilla