From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Sun, 7 Apr 2024 19:32:43 +0200
Subject: Adding upstream version 1:115.7.0.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 security/ct/tests/gtest/BTSignedTreeHeadTest.cpp | 266 +++++++++++++++++++++++
 1 file changed, 266 insertions(+)
 create mode 100644 security/ct/tests/gtest/BTSignedTreeHeadTest.cpp

(limited to 'security/ct/tests/gtest/BTSignedTreeHeadTest.cpp')

diff --git a/security/ct/tests/gtest/BTSignedTreeHeadTest.cpp b/security/ct/tests/gtest/BTSignedTreeHeadTest.cpp
new file mode 100644
index 0000000000..580d6a84f3
--- /dev/null
+++ b/security/ct/tests/gtest/BTSignedTreeHeadTest.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BTVerifier.h"
+#include "CTTestUtils.h"
+#include "gtest/gtest.h"
+
+#include "nss.h"
+
+namespace mozilla {
+namespace ct {
+
+using namespace pkix;
+
+struct BTSignedTreeHeadTestParams {
+  const char* mSubjectPublicKeyInfoHex;
+  pkix::DigestAlgorithm mDigestAlgorithm;
+  pkix::der::PublicKeyAlgorithm mPublicKeyAlgorithm;
+  const char* mSignedTreeHeadHex;
+
+  pkix::Result mExpectedSignedTreeHeadResult;
+  uint64_t mExpectedTimestamp;
+  uint64_t mExpectedTreeSize;
+  const char* mExpectedRootHashHex;
+};
+
+class BTSignedTreeHeadTest
+    : public ::testing::Test,
+      public ::testing::WithParamInterface<BTSignedTreeHeadTestParams> {
+  void SetUp() override {
+    if (!NSS_IsInitialized()) {
+      if (NSS_NoDB_Init(nullptr) != SECSuccess) {
+        abort();
+      }
+    }
+  }
+};
+
+namespace ValidSTH {
+#include "valid-sth.inc"
+}
+namespace ValidWithExtensionSTH {
+#include "valid-with-extension-sth.inc"
+}
+namespace ValidSecp521r1SHA512STH {
+#include "valid-secp521r1-sha512-sth.inc"
+}
+namespace SignatureCoversLogIDSTH {
+#include "signature-covers-log-id-sth.inc"
+}
+namespace WrongSPKISTH {
+#include "wrong-spki-sth.inc"
+}
+namespace WrongSigningKeySTH {
+#include "wrong-signing-key-sth.inc"
+}
+namespace MissingLogIDSTH {
+#include "missing-log-id-sth.inc"
+}
+namespace MissingTimestampSTH {
+#include "missing-timestamp-sth.inc"
+}
+namespace MissingTreeSizeSTH {
+#include "missing-tree-size-sth.inc"
+}
+namespace MissingRootHashSTH {
+#include "missing-root-hash-sth.inc"
+}
+namespace MissingExtensionsSTH {
+#include "missing-extensions-sth.inc"
+}
+namespace TruncatedLogIDSTH {
+#include "truncated-log-id-sth.inc"
+}
+namespace TruncatedTimestampSTH {
+#include "truncated-timestamp-sth.inc"
+}
+namespace TruncatedTreeSizeSTH {
+#include "truncated-tree-size-sth.inc"
+}
+namespace TruncatedRootHashSTH {
+#include "truncated-root-hash-sth.inc"
+}
+namespace TruncatedExtensionSTH {
+#include "truncated-extension-sth.inc"
+}
+namespace RSASignerRSASPKISTH {
+#include "rsa-signer-rsa-spki-sth.inc"
+}
+namespace RSASignerECSPKISTH {
+#include "rsa-signer-ec-spki-sth.inc"
+}
+namespace ECSignerRSASPKISTH {
+#include "ec-signer-rsa-spki-sth.inc"
+}
+
+static const char* kValidRootHashHex =
+    "d1a0d3947db4ae8305f2ac32985957e02659b2ea3c10da52a48d2526e9af3bbc";
+
+static const char* kValidRootHashSHA512Hex =
+    "374d794a95cdcfd8b35993185fef9ba368f160d8daf432d08ba9f1ed1e5abe6c"
+    "c69291e0fa2fe0006a52570ef18c19def4e617c33ce52ef0a6e5fbe318cb0387";
+
+static const BTSignedTreeHeadTestParams BT_SIGNED_TREE_HEAD_TEST_PARAMS[] = {
+    {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidSTH::kSTHHex, Success,
+     1541189938000, 7, kValidRootHashHex},
+    {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha512,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidSTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::RSA_PKCS1, ValidSTH::kSTHHex,
+     Result::FATAL_ERROR_INVALID_ARGS, 0, 0, nullptr},
+    {ValidWithExtensionSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidWithExtensionSTH::kSTHHex,
+     Success, 1541189938000, 7, kValidRootHashHex},
+    {ValidSecp521r1SHA512STH::kSPKIHex, pkix::DigestAlgorithm::sha512,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
+     Success, 1542136309473, 731393445, kValidRootHashSHA512Hex},
+    {ValidSecp521r1SHA512STH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {ValidSTH::kSPKIHex, pkix::DigestAlgorithm::sha512,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ValidSecp521r1SHA512STH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {SignatureCoversLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, SignatureCoversLogIDSTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {WrongSPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, WrongSPKISTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {WrongSigningKeySTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, WrongSigningKeySTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {MissingLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, MissingLogIDSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {MissingTimestampSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, MissingTimestampSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {MissingTreeSizeSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, MissingTreeSizeSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {MissingRootHashSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, MissingRootHashSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {MissingExtensionsSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, MissingExtensionsSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {TruncatedLogIDSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedLogIDSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {TruncatedTimestampSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedTimestampSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {TruncatedTreeSizeSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedTreeSizeSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {TruncatedRootHashSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedRootHashSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {TruncatedExtensionSTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, TruncatedExtensionSTH::kSTHHex,
+     Result::ERROR_BAD_DER, 0, 0, nullptr},
+    {RSASignerRSASPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, RSASignerRSASPKISTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {RSASignerECSPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, RSASignerECSPKISTH::kSTHHex,
+     Result::ERROR_BAD_SIGNATURE, 0, 0, nullptr},
+    {ECSignerRSASPKISTH::kSPKIHex, pkix::DigestAlgorithm::sha256,
+     pkix::der::PublicKeyAlgorithm::ECDSA, ECSignerRSASPKISTH::kSTHHex,
+     Result::ERROR_INVALID_KEY, 0, 0, nullptr},
+};
+
+TEST_P(BTSignedTreeHeadTest, BTSignedTreeHeadSimpleTest) {
+  const BTSignedTreeHeadTestParams& params(GetParam());
+
+  Buffer subjectPublicKeyInfoBuffer(
+      HexToBytes(params.mSubjectPublicKeyInfoHex));
+  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
+
+  Buffer signedTreeHeadBuffer(HexToBytes(params.mSignedTreeHeadHex));
+  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
+
+  SignedTreeHeadDataV2 sth;
+  EXPECT_EQ(params.mExpectedSignedTreeHeadResult,
+            DecodeAndVerifySignedTreeHead(
+                subjectPublicKeyInfoInput, params.mDigestAlgorithm,
+                params.mPublicKeyAlgorithm, signedTreeHeadInput, sth));
+
+  if (params.mExpectedSignedTreeHeadResult == Success) {
+    EXPECT_EQ(params.mExpectedTimestamp, sth.timestamp);
+    EXPECT_EQ(params.mExpectedTreeSize, sth.treeSize);
+    EXPECT_EQ(HexToBytes(params.mExpectedRootHashHex), sth.rootHash);
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(BTSignedTreeHeadTest, BTSignedTreeHeadTest,
+                         testing::ValuesIn(BT_SIGNED_TREE_HEAD_TEST_PARAMS));
+
+TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadTamperedSignatureTest) {
+  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
+  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
+
+  Buffer signedTreeHeadBuffer(HexToBytes(ValidSTH::kSTHHex));
+  ASSERT_TRUE(signedTreeHeadBuffer.size() > 15);
+  signedTreeHeadBuffer[signedTreeHeadBuffer.size() - 15] ^= 0xff;
+  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
+
+  SignedTreeHeadDataV2 sth;
+  EXPECT_EQ(Result::ERROR_BAD_SIGNATURE,
+            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
+                                          pkix::DigestAlgorithm::sha256,
+                                          pkix::der::PublicKeyAlgorithm::ECDSA,
+                                          signedTreeHeadInput, sth));
+}
+
+TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadTruncatedSignatureTest) {
+  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
+  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
+
+  Buffer signedTreeHeadBuffer(HexToBytes(ValidSTH::kSTHHex));
+  ASSERT_TRUE(signedTreeHeadBuffer.size() > 17);
+  signedTreeHeadBuffer.resize(signedTreeHeadBuffer.size() - 17);
+  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
+
+  SignedTreeHeadDataV2 sth;
+  EXPECT_EQ(Result::ERROR_BAD_DER,
+            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
+                                          pkix::DigestAlgorithm::sha256,
+                                          pkix::der::PublicKeyAlgorithm::ECDSA,
+                                          signedTreeHeadInput, sth));
+}
+
+TEST_F(BTSignedTreeHeadTest, BTSignedTreeHeadMissingSignatureTest) {
+  Buffer subjectPublicKeyInfoBuffer(HexToBytes(ValidSTH::kSPKIHex));
+  Input subjectPublicKeyInfoInput = InputForBuffer(subjectPublicKeyInfoBuffer);
+
+  Buffer signedTreeHeadBuffer = {
+      0x02, 0x00, 0x00,
+      // 1541189938000 milliseconds since the epoch
+      0x00, 0x00, 0x01, 0x66, 0xd6, 0x14, 0x2b, 0x50, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x07,  // 7 total nodes
+      0x20,                    // 32 byte hash
+      0xd1, 0xa0, 0xd3, 0x94, 0x7d, 0xb4, 0xae, 0x83, 0x05, 0xf2, 0xac, 0x32,
+      0x98, 0x59, 0x57, 0xe0, 0x26, 0x59, 0xb2, 0xea, 0x3c, 0x10, 0xda, 0x52,
+      0xa4, 0x8d, 0x25, 0x26, 0xe9, 0xaf, 0x3b, 0xbc, 0x00,
+      0x00,  // no extensions
+             // missing signature
+  };
+  Input signedTreeHeadInput = InputForBuffer(signedTreeHeadBuffer);
+
+  SignedTreeHeadDataV2 sth;
+  EXPECT_EQ(Result::ERROR_BAD_DER,
+            DecodeAndVerifySignedTreeHead(subjectPublicKeyInfoInput,
+                                          pkix::DigestAlgorithm::sha256,
+                                          pkix::der::PublicKeyAlgorithm::ECDSA,
+                                          signedTreeHeadInput, sth));
+}
+
+}  // namespace ct
+}  // namespace mozilla
-- 
cgit v1.2.3