tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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