/src/mozilla-central/security/certverifier/tests/gtest/MultiLogCTVerifierTest.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #include "MultiLogCTVerifier.h" |
8 | | |
9 | | #include <stdint.h> |
10 | | |
11 | | #include "CTLogVerifier.h" |
12 | | #include "CTObjectsExtractor.h" |
13 | | #include "CTSerialization.h" |
14 | | #include "CTTestUtils.h" |
15 | | #include "gtest/gtest.h" |
16 | | #include "mozilla/EnumSet.h" |
17 | | #include "mozilla/Move.h" |
18 | | #include "nss.h" |
19 | | |
20 | | namespace mozilla { namespace ct { |
21 | | |
22 | | using namespace mozilla::pkix; |
23 | | |
24 | | class MultiLogCTVerifierTest : public ::testing::Test |
25 | | { |
26 | | public: |
27 | | MultiLogCTVerifierTest() |
28 | | : mNow(Time::uninitialized) |
29 | | , mLogOperatorID(123) |
30 | 0 | {} |
31 | | |
32 | | void SetUp() override |
33 | 0 | { |
34 | 0 | // Does nothing if NSS is already initialized. |
35 | 0 | MOZ_RELEASE_ASSERT(NSS_NoDB_Init(nullptr) == SECSuccess); |
36 | 0 |
|
37 | 0 | CTLogVerifier log; |
38 | 0 | ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey()), |
39 | 0 | mLogOperatorID, |
40 | 0 | CTLogStatus::Included, |
41 | 0 | 0 /*disqualification time*/)); |
42 | 0 | ASSERT_EQ(Success, mVerifier.AddLog(std::move(log))); |
43 | 0 |
|
44 | 0 | mTestCert = GetDEREncodedX509Cert(); |
45 | 0 | mEmbeddedCert = GetDEREncodedTestEmbeddedCert(); |
46 | 0 | mCaCert = GetDEREncodedCACert(); |
47 | 0 | mCaCertSPKI = ExtractCertSPKI(mCaCert); |
48 | 0 | mIntermediateCert = GetDEREncodedIntermediateCert(); |
49 | 0 | mIntermediateCertSPKI = ExtractCertSPKI(mIntermediateCert); |
50 | 0 |
|
51 | 0 | // Set the current time making sure all test timestamps are in the past. |
52 | 0 | mNow = TimeFromEpochInSeconds(1451606400u); // Date.parse("2016-01-01")/1000 |
53 | 0 | } |
54 | | |
55 | | void CheckForSingleValidSCTInResult(const CTVerifyResult& result, |
56 | | VerifiedSCT::Origin origin) |
57 | 0 | { |
58 | 0 | EXPECT_EQ(0U, result.decodingErrors); |
59 | 0 | ASSERT_EQ(1U, result.verifiedScts.length()); |
60 | 0 | EXPECT_EQ(VerifiedSCT::Status::Valid, result.verifiedScts[0].status); |
61 | 0 | EXPECT_EQ(origin, result.verifiedScts[0].origin); |
62 | 0 | EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId); |
63 | 0 | } |
64 | | |
65 | | // Writes an SCTList containing a single |sct| into |output|. |
66 | | void EncodeSCTListForTesting(Input sct, Buffer& output) |
67 | 0 | { |
68 | 0 | Vector<Input> list; |
69 | 0 | ASSERT_TRUE(list.append(std::move(sct))); |
70 | 0 | ASSERT_EQ(Success, EncodeSCTList(list, output)); |
71 | 0 | } |
72 | | |
73 | | void GetSCTListWithInvalidLogID(Buffer& result) |
74 | 0 | { |
75 | 0 | result.clear(); |
76 | 0 | Buffer sct(GetTestSignedCertificateTimestamp()); |
77 | 0 | // Change a byte inside the Log ID part of the SCT so it does |
78 | 0 | // not match the log used in the tests. |
79 | 0 | sct[15] ^= '\xFF'; |
80 | 0 | EncodeSCTListForTesting(InputForBuffer(sct), result); |
81 | 0 | } |
82 | | |
83 | | void CheckPrecertVerification(const Buffer& cert, const Buffer& issuerSPKI) |
84 | 0 | { |
85 | 0 | Buffer sctList; |
86 | 0 | ExtractEmbeddedSCTList(cert, sctList); |
87 | 0 | ASSERT_FALSE(sctList.empty()); |
88 | 0 |
|
89 | 0 | CTVerifyResult result; |
90 | 0 | ASSERT_EQ(Success, |
91 | 0 | mVerifier.Verify(InputForBuffer(cert), InputForBuffer(issuerSPKI), |
92 | 0 | InputForBuffer(sctList), Input(), Input(), |
93 | 0 | mNow, result)); |
94 | 0 | CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::Embedded); |
95 | 0 | } |
96 | | |
97 | | protected: |
98 | | MultiLogCTVerifier mVerifier; |
99 | | Buffer mTestCert; |
100 | | Buffer mEmbeddedCert; |
101 | | Buffer mCaCert; |
102 | | Buffer mCaCertSPKI; |
103 | | Buffer mIntermediateCert; |
104 | | Buffer mIntermediateCertSPKI; |
105 | | Time mNow; |
106 | | CTLogOperatorId mLogOperatorID; |
107 | | }; |
108 | | |
109 | | // Test that an embedded SCT can be extracted and the extracted SCT contains |
110 | | // the expected data. This tests the ExtractEmbeddedSCTList function from |
111 | | // CTTestUtils.h that other tests here rely upon. |
112 | | TEST_F(MultiLogCTVerifierTest, ExtractEmbeddedSCT) |
113 | 0 | { |
114 | 0 | SignedCertificateTimestamp sct; |
115 | 0 |
|
116 | 0 | // Extract the embedded SCT. |
117 | 0 |
|
118 | 0 | Buffer sctList; |
119 | 0 | ExtractEmbeddedSCTList(mEmbeddedCert, sctList); |
120 | 0 | ASSERT_FALSE(sctList.empty()); |
121 | 0 |
|
122 | 0 | Reader sctReader; |
123 | 0 | ASSERT_EQ(Success, DecodeSCTList(InputForBuffer(sctList), sctReader)); |
124 | 0 | Input sctItemInput; |
125 | 0 | ASSERT_EQ(Success, ReadSCTListItem(sctReader, sctItemInput)); |
126 | 0 | EXPECT_TRUE(sctReader.AtEnd()); // we only expect one sct in the list |
127 | 0 |
|
128 | 0 | Reader sctItemReader(sctItemInput); |
129 | 0 | ASSERT_EQ(Success, DecodeSignedCertificateTimestamp(sctItemReader, sct)); |
130 | 0 |
|
131 | 0 | // Make sure the SCT contains the expected data. |
132 | 0 |
|
133 | 0 | EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version); |
134 | 0 | EXPECT_EQ(GetTestPublicKeyId(), sct.logId); |
135 | 0 |
|
136 | 0 | uint64_t expectedTimestamp = 1365181456275; |
137 | 0 | EXPECT_EQ(expectedTimestamp, sct.timestamp); |
138 | 0 | } |
139 | | |
140 | | TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCT) |
141 | 0 | { |
142 | 0 | CheckPrecertVerification(mEmbeddedCert, mCaCertSPKI); |
143 | 0 | } |
144 | | |
145 | | TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithPreCA) |
146 | 0 | { |
147 | 0 | CheckPrecertVerification(GetDEREncodedTestEmbeddedWithPreCACert(), |
148 | 0 | mCaCertSPKI); |
149 | 0 | } |
150 | | |
151 | | TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediate) |
152 | 0 | { |
153 | 0 | CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediateCert(), |
154 | 0 | mIntermediateCertSPKI); |
155 | 0 | } |
156 | | |
157 | | TEST_F(MultiLogCTVerifierTest, VerifiesEmbeddedSCTWithIntermediateAndPreCA) |
158 | 0 | { |
159 | 0 | CheckPrecertVerification(GetDEREncodedTestEmbeddedWithIntermediatePreCACert(), |
160 | 0 | mIntermediateCertSPKI); |
161 | 0 | } |
162 | | |
163 | | TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromOCSP) |
164 | 0 | { |
165 | 0 | Buffer sct(GetTestSignedCertificateTimestamp()); |
166 | 0 | Buffer sctList; |
167 | 0 | EncodeSCTListForTesting(InputForBuffer(sct), sctList); |
168 | 0 |
|
169 | 0 | CTVerifyResult result; |
170 | 0 | ASSERT_EQ(Success, |
171 | 0 | mVerifier.Verify(InputForBuffer(mTestCert), Input(), |
172 | 0 | Input(), InputForBuffer(sctList), Input(), |
173 | 0 | mNow, result)); |
174 | 0 |
|
175 | 0 | CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::OCSPResponse); |
176 | 0 | } |
177 | | |
178 | | TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromTLS) |
179 | 0 | { |
180 | 0 | Buffer sct(GetTestSignedCertificateTimestamp()); |
181 | 0 | Buffer sctList; |
182 | 0 | EncodeSCTListForTesting(InputForBuffer(sct), sctList); |
183 | 0 |
|
184 | 0 | CTVerifyResult result; |
185 | 0 | ASSERT_EQ(Success, |
186 | 0 | mVerifier.Verify(InputForBuffer(mTestCert), Input(), |
187 | 0 | Input(), Input(), InputForBuffer(sctList), |
188 | 0 | mNow, result)); |
189 | 0 |
|
190 | 0 | CheckForSingleValidSCTInResult(result, VerifiedSCT::Origin::TLSExtension); |
191 | 0 | } |
192 | | |
193 | | TEST_F(MultiLogCTVerifierTest, VerifiesSCTFromMultipleSources) |
194 | 0 | { |
195 | 0 | Buffer sct(GetTestSignedCertificateTimestamp()); |
196 | 0 | Buffer sctList; |
197 | 0 | EncodeSCTListForTesting(InputForBuffer(sct), sctList); |
198 | 0 |
|
199 | 0 | CTVerifyResult result; |
200 | 0 | ASSERT_EQ(Success, |
201 | 0 | mVerifier.Verify(InputForBuffer(mTestCert), Input(), Input(), |
202 | 0 | InputForBuffer(sctList), InputForBuffer(sctList), |
203 | 0 | mNow, result)); |
204 | 0 |
|
205 | 0 | // The result should contain verified SCTs from TLS and OCSP origins. |
206 | 0 | EnumSet<VerifiedSCT::Origin> origins; |
207 | 0 | for (const VerifiedSCT& verifiedSct : result.verifiedScts) { |
208 | 0 | EXPECT_EQ(VerifiedSCT::Status::Valid, verifiedSct.status); |
209 | 0 | origins += verifiedSct.origin; |
210 | 0 | } |
211 | 0 | EXPECT_FALSE(origins.contains(VerifiedSCT::Origin::Embedded)); |
212 | 0 | EXPECT_TRUE(origins.contains(VerifiedSCT::Origin::OCSPResponse)); |
213 | 0 | EXPECT_TRUE(origins.contains(VerifiedSCT::Origin::TLSExtension)); |
214 | 0 | } |
215 | | |
216 | | TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromUnknownLog) |
217 | 0 | { |
218 | 0 | Buffer sctList; |
219 | 0 | GetSCTListWithInvalidLogID(sctList); |
220 | 0 |
|
221 | 0 | CTVerifyResult result; |
222 | 0 | ASSERT_EQ(Success, |
223 | 0 | mVerifier.Verify(InputForBuffer(mTestCert), Input(), |
224 | 0 | Input(), Input(), InputForBuffer(sctList), |
225 | 0 | mNow, result)); |
226 | 0 |
|
227 | 0 | EXPECT_EQ(0U, result.decodingErrors); |
228 | 0 | ASSERT_EQ(1U, result.verifiedScts.length()); |
229 | 0 | EXPECT_EQ(VerifiedSCT::Status::UnknownLog, result.verifiedScts[0].status); |
230 | 0 | } |
231 | | |
232 | | TEST_F(MultiLogCTVerifierTest, IdentifiesSCTFromDisqualifiedLog) |
233 | 0 | { |
234 | 0 | MultiLogCTVerifier verifier; |
235 | 0 | CTLogVerifier log; |
236 | 0 | const uint64_t disqualificationTime = 12345u; |
237 | 0 | ASSERT_EQ(Success, log.Init(InputForBuffer(GetTestPublicKey()), |
238 | 0 | mLogOperatorID, CTLogStatus::Disqualified, disqualificationTime)); |
239 | 0 | ASSERT_EQ(Success, verifier.AddLog(std::move(log))); |
240 | 0 |
|
241 | 0 | Buffer sct(GetTestSignedCertificateTimestamp()); |
242 | 0 | Buffer sctList; |
243 | 0 | EncodeSCTListForTesting(InputForBuffer(sct), sctList); |
244 | 0 |
|
245 | 0 | CTVerifyResult result; |
246 | 0 | ASSERT_EQ(Success, |
247 | 0 | verifier.Verify(InputForBuffer(mTestCert), Input(), |
248 | 0 | Input(), Input(), InputForBuffer(sctList), |
249 | 0 | mNow, result)); |
250 | 0 |
|
251 | 0 | EXPECT_EQ(0U, result.decodingErrors); |
252 | 0 | ASSERT_EQ(1U, result.verifiedScts.length()); |
253 | 0 | EXPECT_EQ(VerifiedSCT::Status::ValidFromDisqualifiedLog, |
254 | 0 | result.verifiedScts[0].status); |
255 | 0 | EXPECT_EQ(disqualificationTime, |
256 | 0 | result.verifiedScts[0].logDisqualificationTime); |
257 | 0 | EXPECT_EQ(mLogOperatorID, result.verifiedScts[0].logOperatorId); |
258 | 0 | } |
259 | | |
260 | | } } // namespace mozilla::ct |