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