diff options
Diffstat (limited to 'security/certverifier/tests/gtest/CTSerializationTest.cpp')
-rw-r--r-- | security/certverifier/tests/gtest/CTSerializationTest.cpp | 271 |
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 |