diff options
Diffstat (limited to 'security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp')
-rw-r--r-- | security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp | 941 |
1 files changed, 941 insertions, 0 deletions
diff --git a/security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp b/security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp new file mode 100644 index 0000000000..2667e32b5c --- /dev/null +++ b/security/nss/gtests/mozpkix_gtest/pkixder_input_tests.cpp @@ -0,0 +1,941 @@ +/* -*- 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 code is made available to you under your choice of the following sets + * of licensing terms: + */ +/* 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/. + */ +/* Copyright 2013 Mozilla Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <functional> +#include <vector> +#include "pkixgtest.h" + +#include "mozpkix/pkixder.h" + +using namespace mozilla::pkix; +using namespace mozilla::pkix::der; + +namespace { + +class pkixder_input_tests : public ::testing::Test { }; + +static const uint8_t DER_SEQUENCE_EMPTY[] = { + 0x30, // SEQUENCE + 0x00, // length +}; + +static const uint8_t DER_SEQUENCE_NOT_EMPTY[] = { + 0x30, // SEQUENCE + 0x01, // length + 'X', // value +}; + +static const uint8_t DER_SEQUENCE_NOT_EMPTY_VALUE[] = { + 'X', // value +}; + +static const uint8_t DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED[] = { + 0x30, // SEQUENCE + 0x01, // length +}; + +const uint8_t DER_SEQUENCE_OF_INT8[] = { + 0x30, // SEQUENCE + 0x09, // length + 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01 + 0x02, 0x01, 0x02, // INTEGER length 1 value 0x02 + 0x02, 0x01, 0x03 // INTEGER length 1 value 0x03 +}; + +const uint8_t DER_TRUNCATED_SEQUENCE_OF_INT8[] = { + 0x30, // SEQUENCE + 0x09, // length + 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01 + 0x02, 0x01, 0x02 // INTEGER length 1 value 0x02 + // MISSING DATA HERE ON PURPOSE +}; + +const uint8_t DER_OVERRUN_SEQUENCE_OF_INT8[] = { + 0x30, // SEQUENCE + 0x09, // length + 0x02, 0x01, 0x01, // INTEGER length 1 value 0x01 + 0x02, 0x01, 0x02, // INTEGER length 1 value 0x02 + 0x02, 0x02, 0xFF, 0x03 // INTEGER length 2 value 0xFF03 +}; + +const uint8_t DER_INT16[] = { + 0x02, // INTEGER + 0x02, // length + 0x12, 0x34 // 0x1234 +}; + +static const Input EMPTY_INPUT; + +TEST_F(pkixder_input_tests, InputInit) +{ + Input buf; + ASSERT_EQ(Success, + buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8)); +} + +TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength) +{ + Input buf; + ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 0)); + + ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 100)); + + // Though it seems odd to initialize with zero-length and non-null ptr, this + // is working as intended. The Reader class was intended to protect against + // buffer overflows, and there's no risk with the current behavior. See bug + // 1000354. + ASSERT_EQ(Success, buf.Init((const uint8_t*) "hello", 0)); + ASSERT_TRUE(buf.GetLength() == 0); +} + +TEST_F(pkixder_input_tests, InputInitWithLargeData) +{ + Input buf; + // Data argument length does not matter, it is not touched, just + // needs to be non-null + ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init((const uint8_t*) "", 0xffff+1)); + + ASSERT_EQ(Success, buf.Init((const uint8_t*) "", 0xffff)); +} + +TEST_F(pkixder_input_tests, InputInitMultipleTimes) +{ + Input buf; + + ASSERT_EQ(Success, + buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8)); + + ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, + buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8)); +} + +TEST_F(pkixder_input_tests, PeekWithinBounds) +{ + const uint8_t der[] = { 0x11, 0x11 }; + Input buf(der); + Reader input(buf); + ASSERT_TRUE(input.Peek(0x11)); + ASSERT_FALSE(input.Peek(0x22)); +} + +TEST_F(pkixder_input_tests, PeekPastBounds) +{ + const uint8_t der[] = { 0x11, 0x22 }; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 1)); + Reader input(buf); + + uint8_t readByte; + ASSERT_EQ(Success, input.Read(readByte)); + ASSERT_EQ(0x11, readByte); + ASSERT_FALSE(input.Peek(0x22)); +} + +TEST_F(pkixder_input_tests, ReadByte) +{ + const uint8_t der[] = { 0x11, 0x22 }; + Input buf(der); + Reader input(buf); + + uint8_t readByte1; + ASSERT_EQ(Success, input.Read(readByte1)); + ASSERT_EQ(0x11, readByte1); + + uint8_t readByte2; + ASSERT_EQ(Success, input.Read(readByte2)); + ASSERT_EQ(0x22, readByte2); +} + +TEST_F(pkixder_input_tests, ReadBytePastEnd) +{ + const uint8_t der[] = { 0x11, 0x22 }; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 1)); + Reader input(buf); + + uint8_t readByte1 = 0; + ASSERT_EQ(Success, input.Read(readByte1)); + ASSERT_EQ(0x11, readByte1); + + uint8_t readByte2 = 0; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readByte2)); + ASSERT_NE(0x22, readByte2); +} + +TEST_F(pkixder_input_tests, ReadByteWrapAroundPointer) +{ + // The original implementation of our buffer read overflow checks was + // susceptible to integer overflows which could make the checks ineffective. + // This attempts to verify that we've fixed that. Unfortunately, decrementing + // a null pointer is undefined behavior according to the C++ language spec., + // but this should catch the problem on at least some compilers, if not all of + // them. + uintptr_t derint = -1; + auto der = reinterpret_cast<const uint8_t*>(derint); + ASSERT_EQ(sizeof(der), sizeof(derint)) + << "underflow of pointer might not work"; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 0)); + Reader input(buf); + + uint8_t b; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b)); +} + +TEST_F(pkixder_input_tests, ReadWord) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + uint16_t readWord1 = 0; + ASSERT_EQ(Success, input.Read(readWord1)); + ASSERT_EQ(0x1122, readWord1); + + uint16_t readWord2 = 0; + ASSERT_EQ(Success, input.Read(readWord2)); + ASSERT_EQ(0x3344, readWord2); +} + +TEST_F(pkixder_input_tests, ReadWordPastEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 2)); // Initialize with too-short length + Reader input(buf); + + uint16_t readWord1 = 0; + ASSERT_EQ(Success, input.Read(readWord1)); + ASSERT_EQ(0x1122, readWord1); + + uint16_t readWord2 = 0; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord2)); + ASSERT_NE(0x3344, readWord2); +} + +TEST_F(pkixder_input_tests, ReadWordWithInsufficentData) +{ + const uint8_t der[] = { 0x11, 0x22 }; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 1)); + Reader input(buf); + + uint16_t readWord1 = 0; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord1)); + ASSERT_NE(0x1122, readWord1); +} + +static void UNSANITIZED_ReadWordWrapAroundPointer() +#if defined(__clang__) + /* Use "undefined" instead of more specific "pointer-overflow" for + * clang 4.0.0 backward compatability. */ + __attribute__((no_sanitize("undefined"))) +#endif +{ + const uint8_t* der = nullptr; + --der; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 0)); + Reader input(buf); + uint16_t b; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b)); +} + +TEST_F(pkixder_input_tests, ReadWordWrapAroundPointer) { + // The original implementation of our buffer read overflow checks was + // susceptible to integer overflows which could make the checks ineffective. + // This attempts to verify that we've fixed that. Unfortunately, decrementing + // a null pointer is undefined behavior according to the C++ language spec., + // but this should catch the problem on at least some compilers, if not all of + // them. + UNSANITIZED_ReadWordWrapAroundPointer(); +} + +TEST_F(pkixder_input_tests, Skip) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + ASSERT_EQ(Success, input.Skip(1)); + + uint8_t readByte1 = 0; + ASSERT_EQ(Success, input.Read(readByte1)); + ASSERT_EQ(0x22, readByte1); + + ASSERT_EQ(Success, input.Skip(1)); + + uint8_t readByte2 = 0; + ASSERT_EQ(Success, input.Read(readByte2)); + ASSERT_EQ(0x44, readByte2); +} + +TEST_F(pkixder_input_tests, Skip_ToEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + ASSERT_EQ(Success, input.Skip(sizeof der)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, Skip_PastEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1)); +} + +TEST_F(pkixder_input_tests, Skip_ToNewInput) +{ + const uint8_t der[] = { 0x01, 0x02, 0x03, 0x04 }; + Input buf(der); + Reader input(buf); + + Reader skippedInput; + ASSERT_EQ(Success, input.Skip(3, skippedInput)); + + uint8_t readByte1 = 0; + ASSERT_EQ(Success, input.Read(readByte1)); + ASSERT_EQ(0x04, readByte1); + + ASSERT_TRUE(input.AtEnd()); + + // Reader has no Remaining() or Length() so we simply read the bytes + // and then expect to be at the end. + + for (uint8_t i = 1; i <= 3; ++i) { + uint8_t readByte = 0; + ASSERT_EQ(Success, skippedInput.Read(readByte)); + ASSERT_EQ(i, readByte); + } + + ASSERT_TRUE(skippedInput.AtEnd()); +} + +TEST_F(pkixder_input_tests, Skip_ToNewInputPastEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + Reader skippedInput; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der * 2, skippedInput)); +} + +TEST_F(pkixder_input_tests, Skip_ToInput) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 }; + + Input item; + ASSERT_EQ(Success, input.Skip(sizeof expectedItemData, item)); + + Input expected(expectedItemData); + ASSERT_TRUE(InputsAreEqual(expected, item)); +} + +static void UNSANITIZED_Skip_WrapAroundPointer() +#if defined(__clang__) + /* Use "undefined" instead of more specific "pointer-overflow" for + * clang 4.0.0 backward compatability. */ + __attribute__((no_sanitize("undefined"))) +#endif +{ + const uint8_t* der = nullptr; + // coverity[FORWARD_NULL] + --der; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 0)); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(1)); +} + +TEST_F(pkixder_input_tests, Skip_WrapAroundPointer) { + // The original implementation of our buffer read overflow checks was + // susceptible to integer overflows which could make the checks ineffective. + // This attempts to verify that we've fixed that. Unfortunately, decrementing + // a null pointer is undefined behavior according to the C++ language spec., + // but this should catch the problem on at least some compilers, if not all of + // them. + UNSANITIZED_Skip_WrapAroundPointer(); +} + +TEST_F(pkixder_input_tests, Skip_ToInputPastEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + Input skipped; + ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1, skipped)); +} + +TEST_F(pkixder_input_tests, SkipToEnd_ToInput) +{ + static const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + Input skipped; + ASSERT_EQ(Success, input.SkipToEnd(skipped)); +} + +TEST_F(pkixder_input_tests, SkipToEnd_ToInput_InputAlreadyInited) +{ + static const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + static const uint8_t initialValue[] = { 0x01, 0x02, 0x03 }; + Input x(initialValue); + // Fails because skipped was already initialized once, and Inputs are not + // allowed to be Init()d multiple times. + ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, input.SkipToEnd(x)); + ASSERT_TRUE(InputsAreEqual(x, Input(initialValue))); +} + +TEST_F(pkixder_input_tests, ExpectTagAndSkipValue) +{ + Input buf(DER_SEQUENCE_OF_INT8); + Reader input(buf); + + ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE)); + ASSERT_EQ(Success, End(input)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithTruncatedData) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndSkipValue(input, SEQUENCE)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithOverrunData) +{ + Input buf(DER_OVERRUN_SEQUENCE_OF_INT8); + Reader input(buf); + ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE)); + ASSERT_EQ(Result::ERROR_BAD_DER, End(input)); +} + +TEST_F(pkixder_input_tests, AtEndOnUnInitializedInput) +{ + Reader input; + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, AtEndAtBeginning) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + ASSERT_FALSE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, AtEndAtEnd) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + ASSERT_EQ(Success, input.Skip(sizeof der)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, MarkAndGetInput) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + Reader::Mark mark = input.GetMark(); + + const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 }; + + ASSERT_EQ(Success, input.Skip(sizeof expectedItemData)); + + Input item; + ASSERT_EQ(Success, input.GetInput(mark, item)); + Input expected(expectedItemData); + ASSERT_TRUE(InputsAreEqual(expected, item)); +} + +// Cannot run this test on debug builds because of the NotReached +#ifdef NDEBUG +TEST_F(pkixder_input_tests, MarkAndGetInputDifferentInput) +{ + const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 }; + Input buf(der); + Reader input(buf); + + Reader another; + Reader::Mark mark = another.GetMark(); + + ASSERT_EQ(Success, input.Skip(3)); + + Input item; + ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, input.GetInput(mark, item)); +} +#endif + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_AtEnd) +{ + Reader input(EMPTY_INPUT); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_TruncatedAfterTag) +{ + static const uint8_t DER[] = { SEQUENCE }; + Input buf(DER); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_ValidEmpty) +{ + Input buf(DER_SEQUENCE_EMPTY); + Reader input(buf); + uint8_t tag = 0; + Input value; + ASSERT_EQ(Success, ReadTagAndGetValue(input, tag, value)); + ASSERT_EQ(SEQUENCE, tag); + ASSERT_EQ(0u, value.GetLength()); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_ValidNotEmpty) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + uint8_t tag = 0; + Input value; + ASSERT_EQ(Success, ReadTagAndGetValue(input, tag, value)); + ASSERT_EQ(SEQUENCE, tag); + Input expected(DER_SEQUENCE_NOT_EMPTY_VALUE); + ASSERT_TRUE(InputsAreEqual(expected, value)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, + ReadTagAndGetValue_Input_InvalidNotEmptyValueTruncated) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidWrongLength) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm1) +{ + // High tag number form is not allowed (illegal 1 byte tag) + // + // If the decoder treats 0x1F as a valid low tag number tag, then it will + // treat the actual tag (1) as a length, and then it will return Success + // with value == { 0x00 } and tag == 0x1f. + // + // It is illegal to encode tag 1 in the high tag number form because it isn't + // the shortest encoding (the low tag number form is). + static const uint8_t DER[] = { + 0x1F, // high tag number form indicator + 1, // tag 1 (not legal!) + 0 // length zero + }; + Input buf(DER); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm2) +{ + // High tag number form is not allowed (legal 1 byte tag). + // + // ReadTagAndGetValue's check to prohibit the high tag number form has no + // effect on whether this test passes or fails, because ReadTagAndGetValue + // will interpret the second byte (31) as a length, and the input doesn't + // have 31 bytes following it. This test is here to guard against the case + // where somebody actually implements high tag number form parsing, to remind + // that person that they need to add tests here, including in particular + // tests for overly-long encodings. + static const uint8_t DER[] = { + 0x1F, // high tag number form indicator + 31, // tag 31 + 0 // length zero + }; + Input buf(DER); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ReadTagAndGetValue_Input_InvalidHighTagNumberForm3) +{ + // High tag number form is not allowed (2 byte legal tag) + // + // ReadTagAndGetValue's check to prohibit the high tag number form has no + // effect on whether this test passes or fails, because ReadTagAndGetValue + // will interpret the second byte as a length, and the input doesn't have + // that many bytes following it. This test is here to guard against the case + // where somebody actually implements high tag number form parsing, to remind + // that person that they need to add tests here, including in particular + // tests for overly-long encodings. + static const uint8_t DER[] = { + 0x1F, // high tag number form indicator + 0x80 | 0x01, 0x00, // tag 0x100 (256) + 0 // length zero + }; + Input buf(DER); + Reader input(buf); + uint8_t tag; + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ReadTagAndGetValue(input, tag, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_ValidEmpty) +{ + Input buf(DER_SEQUENCE_EMPTY); + Reader input(buf); + Reader value; + ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value)); + ASSERT_TRUE(value.AtEnd()); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_ValidNotEmpty) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Reader value; + ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value)); + ASSERT_TRUE(value.MatchRest(DER_SEQUENCE_NOT_EMPTY_VALUE)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, + ExpectTagAndGetValue_Reader_InvalidNotEmptyValueTruncated) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED); + Reader input(buf); + Reader value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, SEQUENCE, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_InvalidWrongLength) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + Reader value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, SEQUENCE, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Reader_InvalidWrongTag) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Reader value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, INTEGER, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidEmpty) +{ + Input buf(DER_SEQUENCE_EMPTY); + Reader input(buf); + Input value; + ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value)); + ASSERT_EQ(0u, value.GetLength()); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidNotEmpty) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Input value; + ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value)); + Input expected(DER_SEQUENCE_NOT_EMPTY_VALUE); + ASSERT_TRUE(InputsAreEqual(expected, value)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, + ExpectTagAndGetValue_Input_InvalidNotEmptyValueTruncated) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED); + Reader input(buf); + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, SEQUENCE, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongLength) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, SEQUENCE, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongTag) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Input value; + ASSERT_EQ(Result::ERROR_BAD_DER, + ExpectTagAndGetValue(input, INTEGER, value)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_ValidEmpty) +{ + Input buf(DER_SEQUENCE_EMPTY); + Reader input(buf); + ASSERT_EQ(Success, ExpectTagAndEmptyValue(input, SEQUENCE)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InValidNotEmpty) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE)); +} + +TEST_F(pkixder_input_tests, + ExpectTagAndEmptyValue_Input_InvalidNotEmptyValueTruncated) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InvalidWrongLength) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, SEQUENCE)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndEmptyValue_InvalidWrongTag) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndEmptyValue(input, INTEGER)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_ValidEmpty) +{ + Input buf(DER_SEQUENCE_EMPTY); + Reader input(buf); + Input tlv; + ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv)); + Input expected(DER_SEQUENCE_EMPTY); + ASSERT_TRUE(InputsAreEqual(expected, tlv)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_ValidNotEmpty) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Input tlv; + ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv)); + Input expected(DER_SEQUENCE_NOT_EMPTY); + ASSERT_TRUE(InputsAreEqual(expected, tlv)); + ASSERT_TRUE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, + ExpectTagAndGetTLV_Input_InvalidNotEmptyValueTruncated) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED); + Reader input(buf); + Input tlv; + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_InvalidWrongLength) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + Input tlv; + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv)); +} + +TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_Input_InvalidWrongTag) +{ + Input buf(DER_SEQUENCE_NOT_EMPTY); + Reader input(buf); + Input tlv; + ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, INTEGER, tlv)); +} + +TEST_F(pkixder_input_tests, EndAtEnd) +{ + Input buf(DER_INT16); + Reader input(buf); + ASSERT_EQ(Success, input.Skip(4)); + ASSERT_EQ(Success, End(input)); +} + +TEST_F(pkixder_input_tests, EndBeforeEnd) +{ + Input buf(DER_INT16); + Reader input(buf); + ASSERT_EQ(Success, input.Skip(2)); + ASSERT_EQ(Result::ERROR_BAD_DER, End(input)); +} + +TEST_F(pkixder_input_tests, EndAtBeginning) +{ + Input buf(DER_INT16); + Reader input(buf); + ASSERT_EQ(Result::ERROR_BAD_DER, End(input)); +} + +// TODO: Need tests for Nested too? + +Result NestedOfHelper(Reader& input, std::vector<uint8_t>& readValues) +{ + uint8_t value = 0; + Result rv = input.Read(value); + EXPECT_EQ(Success, rv); + if (rv != Success) { + return rv; + } + readValues.push_back(value); + return Success; +} + +TEST_F(pkixder_input_tests, NestedOf) +{ + Input buf(DER_SEQUENCE_OF_INT8); + Reader input(buf); + + std::vector<uint8_t> readValues; + ASSERT_EQ(Success, + NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No, + [&readValues](Reader& r) { + return NestedOfHelper(r, readValues); + })); + ASSERT_EQ(3u, readValues.size()); + ASSERT_EQ(0x01, readValues[0]); + ASSERT_EQ(0x02, readValues[1]); + ASSERT_EQ(0x03, readValues[2]); + ASSERT_EQ(Success, End(input)); +} + +TEST_F(pkixder_input_tests, NestedOfWithTruncatedData) +{ + Input buf(DER_TRUNCATED_SEQUENCE_OF_INT8); + Reader input(buf); + + std::vector<uint8_t> readValues; + ASSERT_EQ(Result::ERROR_BAD_DER, + NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No, + [&readValues](Reader& r) { + return NestedOfHelper(r, readValues); + })); + ASSERT_EQ(0u, readValues.size()); +} + +TEST_F(pkixder_input_tests, MatchRestAtEnd) +{ + static const uint8_t der[1] = { }; + Input buf; + ASSERT_EQ(Success, buf.Init(der, 0)); + Reader input(buf); + ASSERT_TRUE(input.AtEnd()); + static const uint8_t toMatch[] = { 1 }; + ASSERT_FALSE(input.MatchRest(toMatch)); +} + +TEST_F(pkixder_input_tests, MatchRest1Match) +{ + static const uint8_t der[] = { 1 }; + Input buf(der); + Reader input(buf); + ASSERT_FALSE(input.AtEnd()); + ASSERT_TRUE(input.MatchRest(der)); +} + +TEST_F(pkixder_input_tests, MatchRest1Mismatch) +{ + static const uint8_t der[] = { 1 }; + Input buf(der); + Reader input(buf); + static const uint8_t toMatch[] = { 2 }; + ASSERT_FALSE(input.MatchRest(toMatch)); + ASSERT_FALSE(input.AtEnd()); +} + +TEST_F(pkixder_input_tests, MatchRest2WithTrailingByte) +{ + static const uint8_t der[] = { 1, 2, 3 }; + Input buf(der); + Reader input(buf); + static const uint8_t toMatch[] = { 1, 2 }; + ASSERT_FALSE(input.MatchRest(toMatch)); +} + +TEST_F(pkixder_input_tests, MatchRest2Mismatch) +{ + static const uint8_t der[] = { 1, 2, 3 }; + Input buf(der); + Reader input(buf); + static const uint8_t toMatchMismatch[] = { 1, 3 }; + ASSERT_FALSE(input.MatchRest(toMatchMismatch)); + ASSERT_TRUE(input.MatchRest(der)); +} + +} // namespace |