tor-browser

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

BTSignedTreeHeadTest.cpp (11388B)


      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 "BTVerifier.h"
      8 #include "CTTestUtils.h"
      9 #include "gtest/gtest.h"
     10 
     11 #include "nss.h"
     12 
     13 namespace mozilla {
     14 namespace ct {
     15 
     16 using namespace pkix;
     17 
     18 struct BTSignedTreeHeadTestParams {
     19  const char* mSubjectPublicKeyInfoHex;
     20  pkix::DigestAlgorithm mDigestAlgorithm;
     21  pkix::der::PublicKeyAlgorithm mPublicKeyAlgorithm;
     22  const char* mSignedTreeHeadHex;
     23 
     24  pkix::Result mExpectedSignedTreeHeadResult;
     25  uint64_t mExpectedTimestamp;
     26  uint64_t mExpectedTreeSize;
     27  const char* mExpectedRootHashHex;
     28 };
     29 
     30 class BTSignedTreeHeadTest
     31    : public ::testing::Test,
     32      public ::testing::WithParamInterface<BTSignedTreeHeadTestParams> {
     33  void SetUp() override {
     34    if (!NSS_IsInitialized()) {
     35      if (NSS_NoDB_Init(nullptr) != SECSuccess) {
     36        abort();
     37      }
     38    }
     39  }
     40 };
     41 
     42 namespace ValidSTH {
     43 #include "valid-sth.inc"
     44 }
     45 namespace ValidWithExtensionSTH {
     46 #include "valid-with-extension-sth.inc"
     47 }
     48 namespace ValidSecp521r1SHA512STH {
     49 #include "valid-secp521r1-sha512-sth.inc"
     50 }
     51 namespace SignatureCoversLogIDSTH {
     52 #include "signature-covers-log-id-sth.inc"
     53 }
     54 namespace WrongSPKISTH {
     55 #include "wrong-spki-sth.inc"
     56 }
     57 namespace WrongSigningKeySTH {
     58 #include "wrong-signing-key-sth.inc"
     59 }
     60 namespace MissingLogIDSTH {
     61 #include "missing-log-id-sth.inc"
     62 }
     63 namespace MissingTimestampSTH {
     64 #include "missing-timestamp-sth.inc"
     65 }
     66 namespace MissingTreeSizeSTH {
     67 #include "missing-tree-size-sth.inc"
     68 }
     69 namespace MissingRootHashSTH {
     70 #include "missing-root-hash-sth.inc"
     71 }
     72 namespace MissingExtensionsSTH {
     73 #include "missing-extensions-sth.inc"
     74 }
     75 namespace TruncatedLogIDSTH {
     76 #include "truncated-log-id-sth.inc"
     77 }
     78 namespace TruncatedTimestampSTH {
     79 #include "truncated-timestamp-sth.inc"
     80 }
     81 namespace TruncatedTreeSizeSTH {
     82 #include "truncated-tree-size-sth.inc"
     83 }
     84 namespace TruncatedRootHashSTH {
     85 #include "truncated-root-hash-sth.inc"
     86 }
     87 namespace TruncatedExtensionSTH {
     88 #include "truncated-extension-sth.inc"
     89 }
     90 namespace RSASignerRSASPKISTH {
     91 #include "rsa-signer-rsa-spki-sth.inc"
     92 }
     93 namespace RSASignerECSPKISTH {
     94 #include "rsa-signer-ec-spki-sth.inc"
     95 }
     96 namespace ECSignerRSASPKISTH {
     97 #include "ec-signer-rsa-spki-sth.inc"
     98 }
     99 
    100 static const char* kValidRootHashHex =
    101    "d1a0d3947db4ae8305f2ac32985957e02659b2ea3c10da52a48d2526e9af3bbc";
    102 
    103 static const char* kValidRootHashSHA512Hex =
    104    "374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6c"
    105    "c69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387";
    106 
    107 MOZ_RUNINIT static const BTSignedTreeHeadTestParams
    108    BT_SIGNED_TREE_HEAD_TEST_PARAMS[] = {
    109        {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    110         pkix::der::PublicKeyAlgorithm::ECDSA, ValidSTH::kSTHHex, Success,
    111         1541189938000, 7, kValidRootHashHex},
    112        {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha512,
    113         pkix::der::PublicKeyAlgorithm::ECDSA, ValidSTH::kSTHHex,
    114         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    115        {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    116         pkix::der::PublicKeyAlgorithm::RSA_PKCS1, ValidSTH::kSTHHex,
    117         Result::FATAL_ERROR_INVALID_ARGS, 0, 0, nullptr},
    118        {ValidWithExtensionSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    119         pkix::der::PublicKeyAlgorithm::ECDSA, ValidWithExtensionSTH::kSTHHex,
    120         Success, 1541189938000, 7, kValidRootHashHex},
    121        {ValidSecp521r1SHA512STH::kSPKIHex, pkix::DigestAlgorithm::sha512,
    122         pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
    123         Success, 1542136309473, 731393445, kValidRootHashSHA512Hex},
    124        {ValidSecp521r1SHA512STH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    125         pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
    126         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    127        {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha512,
    128         pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
    129         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    130        {SignatureCoversLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    131         pkix::der::PublicKeyAlgorithm::ECDSA, SignatureCoversLogIDSTH::kSTHHex,
    132         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    133        {WrongSPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    134         pkix::der::PublicKeyAlgorithm::ECDSA, WrongSPKISTH::kSTHHex,
    135         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    136        {WrongSigningKeySTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    137         pkix::der::PublicKeyAlgorithm::ECDSA, WrongSigningKeySTH::kSTHHex,
    138         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    139        {MissingLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    140         pkix::der::PublicKeyAlgorithm::ECDSA, MissingLogIDSTH::kSTHHex,
    141         Result::ERROR_BAD_DER, 0, 0, nullptr},
    142        {MissingTimestampSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    143         pkix::der::PublicKeyAlgorithm::ECDSA, MissingTimestampSTH::kSTHHex,
    144         Result::ERROR_BAD_DER, 0, 0, nullptr},
    145        {MissingTreeSizeSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    146         pkix::der::PublicKeyAlgorithm::ECDSA, MissingTreeSizeSTH::kSTHHex,
    147         Result::ERROR_BAD_DER, 0, 0, nullptr},
    148        {MissingRootHashSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    149         pkix::der::PublicKeyAlgorithm::ECDSA, MissingRootHashSTH::kSTHHex,
    150         Result::ERROR_BAD_DER, 0, 0, nullptr},
    151        {MissingExtensionsSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    152         pkix::der::PublicKeyAlgorithm::ECDSA, MissingExtensionsSTH::kSTHHex,
    153         Result::ERROR_BAD_DER, 0, 0, nullptr},
    154        {TruncatedLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    155         pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedLogIDSTH::kSTHHex,
    156         Result::ERROR_BAD_DER, 0, 0, nullptr},
    157        {TruncatedTimestampSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    158         pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedTimestampSTH::kSTHHex,
    159         Result::ERROR_BAD_DER, 0, 0, nullptr},
    160        {TruncatedTreeSizeSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    161         pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedTreeSizeSTH::kSTHHex,
    162         Result::ERROR_BAD_DER, 0, 0, nullptr},
    163        {TruncatedRootHashSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    164         pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedRootHashSTH::kSTHHex,
    165         Result::ERROR_BAD_DER, 0, 0, nullptr},
    166        {TruncatedExtensionSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    167         pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedExtensionSTH::kSTHHex,
    168         Result::ERROR_BAD_DER, 0, 0, nullptr},
    169        {RSASignerRSASPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    170         pkix::der::PublicKeyAlgorithm::ECDSA, RSASignerRSASPKISTH::kSTHHex,
    171         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    172        {RSASignerECSPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    173         pkix::der::PublicKeyAlgorithm::ECDSA, RSASignerECSPKISTH::kSTHHex,
    174         Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
    175        {ECSignerRSASPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
    176         pkix::der::PublicKeyAlgorithm::ECDSA, ECSignerRSASPKISTH::kSTHHex,
    177         Result::ERROR_INVALID_KEY, 0, 0, nullptr},
    178 };
    179 
    180 TEST_P(BTSignedTreeHeadTest, BTSignedTreeHeadSimpleTest) {
    181  const BTSignedTreeHeadTestParams& params(GetParam());
    182 
    183  Buffer subjectPublicKeyInfoBuffer(
    184      HexToBytes(params.mSubjectPublicKeyInfoHex));
    185  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
    186 
    187  Buffer signedTreeHeadBuffer(HexToBytes(params.mSignedTreeHeadHex));
    188  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
    189 
    190  SignedTreeHeadDataV2 sth;
    191  EXPECT_EQ(params.mExpectedSignedTreeHeadResult,
    192            DecodeAndVerifySignedTreeHead(
    193                subjectPublicKeyInfoInput, params.mDigestAlgorithm,
    194                params.mPublicKeyAlgorithm, signedTreeHeadInput, sth));
    195 
    196  if (params.mExpectedSignedTreeHeadResult == Success) {
    197    EXPECT_EQ(params.mExpectedTimestamp, sth.timestamp);
    198    EXPECT_EQ(params.mExpectedTreeSize, sth.treeSize);
    199    EXPECT_EQ(HexToBytes(params.mExpectedRootHashHex), sth.rootHash);
    200  }
    201 }
    202 
    203 INSTANTIATE_TEST_SUITE_P(BTSignedTreeHeadTest, BTSignedTreeHeadTest,
    204                         testing::ValuesIn(BT_SIGNED_TREE_HEAD_TEST_PARAMS));
    205 
    206 TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadTamperedSignatureTest) {
    207  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
    208  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
    209 
    210  Buffer signedTreeHeadBuffer(HexToBytes(ValidSTH::kSTHHex));
    211  ASSERT_TRUE(signedTreeHeadBuffer.size() > 15);
    212  signedTreeHeadBuffer[signedTreeHeadBuffer.size() - 15] ^= 0xff;
    213  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
    214 
    215  SignedTreeHeadDataV2 sth;
    216  EXPECT_EQ(Result::ERROR_BAD_SIGNATURE,
    217            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
    218                                          pkix::DigestAlgorithm::sha256,
    219                                          pkix::der::PublicKeyAlgorithm::ECDSA,
    220                                          signedTreeHeadInput, sth));
    221 }
    222 
    223 TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadTruncatedSignatureTest) {
    224  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
    225  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
    226 
    227  Buffer signedTreeHeadBuffer(HexToBytes(ValidSTH::kSTHHex));
    228  ASSERT_TRUE(signedTreeHeadBuffer.size() > 17);
    229  signedTreeHeadBuffer.resize(signedTreeHeadBuffer.size() - 17);
    230  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
    231 
    232  SignedTreeHeadDataV2 sth;
    233  EXPECT_EQ(Result::ERROR_BAD_DER,
    234            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
    235                                          pkix::DigestAlgorithm::sha256,
    236                                          pkix::der::PublicKeyAlgorithm::ECDSA,
    237                                          signedTreeHeadInput, sth));
    238 }
    239 
    240 TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadMissingSignatureTest) {
    241  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
    242  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
    243 
    244  Buffer signedTreeHeadBuffer = {
    245      0x02, 0x00, 0x00,
    246      // 1541189938000 milliseconds since the epoch
    247      0x00, 0x00, 0x01, 0x66, 0xd6, 0x14, 0x2b, 0x50, 0x00, 0x00, 0x00, 0x00,
    248      0x00, 0x00, 0x00, 0x07,  // 7 total nodes
    249      0x20,                    // 32 byte hash
    250      0xd1, 0xa0, 0xd3, 0x94, 0x7d, 0xb4, 0xae, 0x83, 0x05, 0xf2, 0xac, 0x32,
    251      0x98, 0x59, 0x57, 0xe0, 0x26, 0x59, 0xb2, 0xea, 0x3c, 0x10, 0xda, 0x52,
    252      0xa4, 0x8d, 0x25, 0x26, 0xe9, 0xaf, 0x3b, 0xbc, 0x00,
    253      0x00,  // no extensions
    254             // missing signature
    255  };
    256  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
    257 
    258  SignedTreeHeadDataV2 sth;
    259  EXPECT_EQ(Result::ERROR_BAD_DER,
    260            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
    261                                          pkix::DigestAlgorithm::sha256,
    262                                          pkix::der::PublicKeyAlgorithm::ECDSA,
    263                                          signedTreeHeadInput, sth));
    264 }
    265 
    266 }  // namespace ct
    267 }  // namespace mozilla