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