summaryrefslogtreecommitdiff
path: root/security/certverifier/tests/gtest/CTSerializationTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'security/certverifier/tests/gtest/CTSerializationTest.cpp')
-rw-r--r--security/certverifier/tests/gtest/CTSerializationTest.cpp271
1 files changed, 271 insertions, 0 deletions
diff --git a/security/certverifier/tests/gtest/CTSerializationTest.cpp b/security/certverifier/tests/gtest/CTSerializationTest.cpp
new file mode 100644
index 0000000000..7c5aadd23a
--- /dev/null
+++ b/security/certverifier/tests/gtest/CTSerializationTest.cpp
@@ -0,0 +1,271 @@
+/* -*- 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 "CTSerialization.h"
+#include "CTTestUtils.h"
+#include "gtest/gtest.h"
+#include "mozilla/Move.h"
+
+namespace mozilla { namespace ct {
+
+using namespace pkix;
+
+class CTSerializationTest : public ::testing::Test
+{
+public:
+ void SetUp() override
+ {
+ mTestDigitallySigned = GetTestDigitallySigned();
+ mTestSignatureData = GetTestDigitallySignedData();
+ }
+
+protected:
+ Buffer mTestDigitallySigned;
+ Buffer mTestSignatureData;
+};
+
+TEST_F(CTSerializationTest, DecodesDigitallySigned)
+{
+ Input digitallySigned = InputForBuffer(mTestDigitallySigned);
+ Reader digitallySignedReader(digitallySigned);
+
+ DigitallySigned parsed;
+ ASSERT_EQ(Success,
+ DecodeDigitallySigned(digitallySignedReader, parsed));
+ EXPECT_TRUE(digitallySignedReader.AtEnd());
+
+ EXPECT_EQ(DigitallySigned::HashAlgorithm::SHA256,
+ parsed.hashAlgorithm);
+ EXPECT_EQ(DigitallySigned::SignatureAlgorithm::ECDSA,
+ parsed.signatureAlgorithm);
+ EXPECT_EQ(mTestSignatureData, parsed.signatureData);
+}
+
+TEST_F(CTSerializationTest, FailsToDecodePartialDigitallySigned)
+{
+ Input partial;
+ ASSERT_EQ(Success,
+ partial.Init(mTestDigitallySigned.begin(),
+ mTestDigitallySigned.length() - 5));
+ Reader partialReader(partial);
+
+ DigitallySigned parsed;
+
+ EXPECT_NE(Success, DecodeDigitallySigned(partialReader, parsed));
+}
+
+TEST_F(CTSerializationTest, EncodesDigitallySigned)
+{
+ DigitallySigned digitallySigned;
+ digitallySigned.hashAlgorithm =
+ DigitallySigned::HashAlgorithm::SHA256;
+ digitallySigned.signatureAlgorithm =
+ DigitallySigned::SignatureAlgorithm::ECDSA;
+ digitallySigned.signatureData = cloneBuffer(mTestSignatureData);
+
+ Buffer encoded;
+
+ ASSERT_EQ(Success, EncodeDigitallySigned(digitallySigned, encoded));
+ EXPECT_EQ(mTestDigitallySigned, encoded);
+}
+
+TEST_F(CTSerializationTest, EncodesLogEntryForX509Cert)
+{
+ LogEntry entry;
+ GetX509CertLogEntry(entry);
+
+ Buffer encoded;
+ ASSERT_EQ(Success, EncodeLogEntry(entry, encoded));
+ EXPECT_EQ((718U + 5U), encoded.length());
+ // First two bytes are log entry type. Next, length:
+ // Length is 718 which is 512 + 206, which is 0x2ce
+ Buffer expectedPrefix;
+ MOZ_RELEASE_ASSERT(expectedPrefix.append("\0\0\0\x2\xCE", 5));
+ Buffer encodedPrefix;
+ MOZ_RELEASE_ASSERT(encodedPrefix.
+ append(encoded.begin(), encoded.begin() + 5));
+ EXPECT_EQ(expectedPrefix, encodedPrefix);
+}
+
+TEST_F(CTSerializationTest, EncodesLogEntryForPrecert)
+{
+ LogEntry entry;
+ GetPrecertLogEntry(entry);
+
+ Buffer encoded;
+ ASSERT_EQ(Success, EncodeLogEntry(entry, encoded));
+ // log entry type + issuer key + length + tbsCertificate
+ EXPECT_EQ((2U + 32U + 3U + entry.tbsCertificate.length()), encoded.length());
+
+ // First two bytes are log entry type.
+ Buffer expectedPrefix;
+ MOZ_RELEASE_ASSERT(expectedPrefix.append("\0\x1", 2));
+ Buffer encodedPrefix;
+ MOZ_RELEASE_ASSERT(encodedPrefix.
+ append(encoded.begin(), encoded.begin() + 2));
+ EXPECT_EQ(expectedPrefix, encodedPrefix);
+
+ // Next is the issuer key (32 bytes).
+ Buffer encodedKeyHash;
+ MOZ_RELEASE_ASSERT(encodedKeyHash.
+ append(encoded.begin() + 2, encoded.begin() + 2 + 32));
+ EXPECT_EQ(GetDefaultIssuerKeyHash(), encodedKeyHash);
+}
+
+TEST_F(CTSerializationTest, EncodesV1SCTSignedData)
+{
+ uint64_t timestamp = UINT64_C(0x139fe353cf5);
+ const uint8_t DUMMY_BYTES[] = { 0x61, 0x62, 0x63 }; // abc
+ Input dummyEntry(DUMMY_BYTES);
+ Input emptyExtensions;
+ Buffer encoded;
+ ASSERT_EQ(Success, EncodeV1SCTSignedData(
+ timestamp, dummyEntry, emptyExtensions, encoded));
+ EXPECT_EQ((size_t) 15, encoded.length());
+
+ const uint8_t EXPECTED_BYTES[] = {
+ 0x00, // version
+ 0x00, // signature type
+ 0x00, 0x00, 0x01, 0x39, 0xFE, 0x35, 0x3C, 0xF5, // timestamp
+ 0x61, 0x62, 0x63, // log signature
+ 0x00, 0x00 // extensions (empty)
+ };
+ Buffer expectedBuffer;
+ MOZ_RELEASE_ASSERT(
+ expectedBuffer.append(EXPECTED_BYTES, sizeof(EXPECTED_BYTES)));
+ EXPECT_EQ(expectedBuffer, encoded);
+}
+
+TEST_F(CTSerializationTest, DecodesSCTList)
+{
+ // Two items in the list: "abc", "def"
+ const uint8_t ENCODED[] = {
+ 0x00, 0x0a, 0x00, 0x03, 0x61, 0x62, 0x63, 0x00, 0x03, 0x64, 0x65, 0x66
+ };
+ const uint8_t DECODED_1[] = { 0x61, 0x62, 0x63 };
+ const uint8_t DECODED_2[] = { 0x64, 0x65, 0x66 };
+
+ Reader listReader;
+ ASSERT_EQ(Success, DecodeSCTList(Input(ENCODED), listReader));
+
+ Input decoded1;
+ ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded1));
+
+ Input decoded2;
+ ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded2));
+
+ EXPECT_TRUE(listReader.AtEnd());
+ EXPECT_TRUE(InputsAreEqual(decoded1, Input(DECODED_1)));
+ EXPECT_TRUE(InputsAreEqual(decoded2, Input(DECODED_2)));
+}
+
+TEST_F(CTSerializationTest, FailsDecodingInvalidSCTList)
+{
+ // A list with one item that's too short (the second one)
+ const uint8_t ENCODED[] = {
+ 0x00, 0x0a, 0x00, 0x03, 0x61, 0x62, 0x63, 0x00, 0x05, 0x64, 0x65, 0x66
+ };
+
+ Reader listReader;
+ ASSERT_EQ(Success, DecodeSCTList(Input(ENCODED), listReader));
+ Input decoded1;
+ EXPECT_EQ(Success, ReadSCTListItem(listReader, decoded1));
+ Input decoded2;
+ EXPECT_NE(Success, ReadSCTListItem(listReader, decoded2));
+}
+
+TEST_F(CTSerializationTest, EncodesSCTList)
+{
+ const uint8_t SCT_1[] = { 0x61, 0x62, 0x63 };
+ const uint8_t SCT_2[] = { 0x64, 0x65, 0x66 };
+
+ Vector<Input> list;
+ ASSERT_TRUE(list.append(Move(Input(SCT_1))));
+ ASSERT_TRUE(list.append(Move(Input(SCT_2))));
+
+ Buffer encodedList;
+ ASSERT_EQ(Success, EncodeSCTList(list, encodedList));
+
+ Reader listReader;
+ ASSERT_EQ(Success, DecodeSCTList(InputForBuffer(encodedList), listReader));
+
+ Input decoded1;
+ ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded1));
+ EXPECT_TRUE(InputsAreEqual(decoded1, Input(SCT_1)));
+
+ Input decoded2;
+ ASSERT_EQ(Success, ReadSCTListItem(listReader, decoded2));
+ EXPECT_TRUE(InputsAreEqual(decoded2, Input(SCT_2)));
+
+ EXPECT_TRUE(listReader.AtEnd());
+}
+
+TEST_F(CTSerializationTest, DecodesSignedCertificateTimestamp)
+{
+ Buffer encodedSctBuffer = GetTestSignedCertificateTimestamp();
+ Input encodedSctInput = InputForBuffer(encodedSctBuffer);
+ Reader encodedSctReader(encodedSctInput);
+
+ SignedCertificateTimestamp sct;
+ ASSERT_EQ(Success,
+ DecodeSignedCertificateTimestamp(encodedSctReader, sct));
+ EXPECT_EQ(SignedCertificateTimestamp::Version::V1, sct.version);
+ EXPECT_EQ(GetTestPublicKeyId(), sct.logId);
+ const uint64_t expectedTime = 1365181456089;
+ EXPECT_EQ(expectedTime, sct.timestamp);
+ const size_t expectedSignatureLength = 71;
+ EXPECT_EQ(expectedSignatureLength, sct.signature.signatureData.length());
+ EXPECT_TRUE(sct.extensions.empty());
+}
+
+TEST_F(CTSerializationTest, FailsDecodingInvalidSignedCertificateTimestamp)
+{
+ SignedCertificateTimestamp sct;
+
+ // Invalid version
+ const uint8_t INVALID_VERSION_BYTES[] = { 0x02, 0x00 };
+ Input invalidVersionSctInput(INVALID_VERSION_BYTES);
+ Reader invalidVersionSctReader(invalidVersionSctInput);
+ EXPECT_EQ(Result::ERROR_BAD_DER,
+ DecodeSignedCertificateTimestamp(invalidVersionSctReader, sct));
+
+ // Valid version, invalid length (missing data)
+ const uint8_t INVALID_LENGTH_BYTES[] = { 0x00, 0x0a, 0x0b, 0x0c };
+ Input invalidLengthSctInput(INVALID_LENGTH_BYTES);
+ Reader invalidLengthSctReader(invalidLengthSctInput);
+ EXPECT_EQ(Result::ERROR_BAD_DER,
+ DecodeSignedCertificateTimestamp(invalidLengthSctReader, sct));
+}
+
+TEST_F(CTSerializationTest, EncodesValidSignedTreeHead)
+{
+ SignedTreeHead signedTreeHead;
+ GetSampleSignedTreeHead(signedTreeHead);
+
+ Buffer encoded;
+ ASSERT_EQ(Success,
+ EncodeTreeHeadSignature(signedTreeHead, encoded));
+ // Expected size is 50 bytes:
+ // Byte 0 is version, byte 1 is signature type
+ // Bytes 2-9 are timestamp
+ // Bytes 10-17 are tree size
+ // Bytes 18-49 are sha256 root hash
+ ASSERT_EQ(50u, encoded.length());
+ const uint8_t EXPECTED_BYTES_PREFIX[] = {
+ 0x00, // version
+ 0x01, // signature type
+ 0x00, 0x00, 0x01, 0x45, 0x3c, 0x5f, 0xb8, 0x35, // timestamp
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15 // tree size
+ // sha256 root hash should follow
+ };
+ Buffer expectedBuffer;
+ MOZ_RELEASE_ASSERT(expectedBuffer.append(EXPECTED_BYTES_PREFIX, 18));
+ Buffer hash = GetSampleSTHSHA256RootHash();
+ MOZ_RELEASE_ASSERT(expectedBuffer.append(hash.begin(), hash.length()));
+ EXPECT_EQ(expectedBuffer, encoded);
+}
+
+} } // namespace mozilla::ct