| // Copyright 2015 The Chromium Authors | |
| // | |
| // 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 | |
| // | |
| // https://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 "parser.h" | |
| #include <gtest/gtest.h> | |
| #include "input.h" | |
| #include "parse_values.h" | |
| BSSL_NAMESPACE_BEGIN | |
| namespace der::test { | |
| TEST(ParserTest, ConsumesAllBytesOfTLV) { | |
| const uint8_t der[] = {0x04 /* OCTET STRING */, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, CanReadRawTLV) { | |
| const uint8_t der[] = {0x02, 0x01, 0x01}; | |
| Parser parser((Input(der))); | |
| Input tlv; | |
| ASSERT_TRUE(parser.ReadRawTLV(&tlv)); | |
| ByteReader tlv_reader(tlv); | |
| size_t tlv_len = tlv_reader.BytesLeft(); | |
| ASSERT_EQ(3u, tlv_len); | |
| Input tlv_data; | |
| ASSERT_TRUE(tlv_reader.ReadBytes(tlv_len, &tlv_data)); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, IgnoresContentsOfInnerValues) { | |
| // This is a SEQUENCE which has one member. The member is another SEQUENCE | |
| // with an invalid encoding - its length is too long. | |
| const uint8_t der[] = {0x30, 0x02, 0x30, 0x7e}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| } | |
| TEST(ParserTest, FailsIfLengthOverlapsAnotherTLV) { | |
| // This DER encoding has 2 top-level TLV tuples. The first is a SEQUENCE; | |
| // the second is an INTEGER. The SEQUENCE contains an INTEGER, but its length | |
| // is longer than what it has contents for. | |
| const uint8_t der[] = {0x30, 0x02, 0x02, 0x01, 0x02, 0x01, 0x01}; | |
| Parser parser((Input(der))); | |
| Parser inner_sequence; | |
| ASSERT_TRUE(parser.ReadSequence(&inner_sequence)); | |
| uint64_t int_value; | |
| ASSERT_TRUE(parser.ReadUint64(&int_value)); | |
| ASSERT_EQ(1u, int_value); | |
| ASSERT_FALSE(parser.HasMore()); | |
| // Try to read the INTEGER from the SEQUENCE, which should fail. | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(inner_sequence.ReadTagAndValue(&tag, &value)); | |
| } | |
| TEST(ParserTest, ReadOptionalTagPresent) { | |
| // DER encoding of 2 top-level TLV values: | |
| // INTEGER { 1 } | |
| // OCTET_STRING { `02` } | |
| const uint8_t der[] = {0x02, 0x01, 0x01, 0x04, 0x01, 0x02}; | |
| Parser parser((Input(der))); | |
| Input value; | |
| bool present; | |
| ASSERT_TRUE(parser.ReadOptionalTag(CBS_ASN1_INTEGER, &value, &present)); | |
| ASSERT_TRUE(present); | |
| const uint8_t expected_int_value[] = {0x01}; | |
| ASSERT_EQ(Input(expected_int_value), value); | |
| CBS_ASN1_TAG tag; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| const uint8_t expected_octet_string_value[] = {0x02}; | |
| ASSERT_EQ(Input(expected_octet_string_value), value); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, ReadOptionalTag2Present) { | |
| // DER encoding of 2 top-level TLV values: | |
| // INTEGER { 1 } | |
| // OCTET_STRING { `02` } | |
| const uint8_t der[] = {0x02, 0x01, 0x01, 0x04, 0x01, 0x02}; | |
| Parser parser((Input(der))); | |
| std::optional<Input> optional_value; | |
| ASSERT_TRUE(parser.ReadOptionalTag(CBS_ASN1_INTEGER, &optional_value)); | |
| ASSERT_TRUE(optional_value.has_value()); | |
| const uint8_t expected_int_value[] = {0x01}; | |
| ASSERT_EQ(Input(expected_int_value), *optional_value); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| const uint8_t expected_octet_string_value[] = {0x02}; | |
| ASSERT_EQ(Input(expected_octet_string_value), value); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, ReadOptionalTagNotPresent) { | |
| // DER encoding of 1 top-level TLV value: | |
| // OCTET_STRING { `02` } | |
| const uint8_t der[] = {0x04, 0x01, 0x02}; | |
| Parser parser((Input(der))); | |
| Input value; | |
| bool present; | |
| ASSERT_TRUE(parser.ReadOptionalTag(CBS_ASN1_INTEGER, &value, &present)); | |
| ASSERT_FALSE(present); | |
| CBS_ASN1_TAG tag; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| const uint8_t expected_octet_string_value[] = {0x02}; | |
| ASSERT_EQ(Input(expected_octet_string_value), value); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, ReadOptionalTag2NotPresent) { | |
| // DER encoding of 1 top-level TLV value: | |
| // OCTET_STRING { `02` } | |
| const uint8_t der[] = {0x04, 0x01, 0x02}; | |
| Parser parser((Input(der))); | |
| std::optional<Input> optional_value; | |
| ASSERT_TRUE(parser.ReadOptionalTag(CBS_ASN1_INTEGER, &optional_value)); | |
| ASSERT_FALSE(optional_value.has_value()); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| const uint8_t expected_octet_string_value[] = {0x02}; | |
| ASSERT_EQ(Input(expected_octet_string_value), value); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, CanSkipOptionalTagAtEndOfInput) { | |
| const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| bool present; | |
| ASSERT_TRUE(parser.ReadOptionalTag(CBS_ASN1_INTEGER, &value, &present)); | |
| ASSERT_FALSE(present); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, SkipOptionalTagDoesntConsumePresentNonMatchingTLVs) { | |
| const uint8_t der[] = {0x02 /* INTEGER */, 0x01, 0x01}; | |
| Parser parser((Input(der))); | |
| bool present; | |
| ASSERT_TRUE(parser.SkipOptionalTag(CBS_ASN1_OCTETSTRING, &present)); | |
| ASSERT_FALSE(present); | |
| ASSERT_TRUE(parser.SkipOptionalTag(CBS_ASN1_INTEGER, &present)); | |
| ASSERT_TRUE(present); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, TagNumbersAboveThirtySupported) { | |
| // Context-specific class, tag number 31, length 0. | |
| const uint8_t der[] = {0x9f, 0x1f, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_CONTEXT_SPECIFIC | 31u, tag); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, ParseTags) { | |
| { | |
| // Universal primitive tag, tag number 4. | |
| const uint8_t der[] = {0x04, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_OCTETSTRING, tag); | |
| } | |
| { | |
| // Universal constructed tag, tag number 16. | |
| const uint8_t der[] = {0x30, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_SEQUENCE, tag); | |
| } | |
| { | |
| // Application primitive tag, tag number 1. | |
| const uint8_t der[] = {0x41, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_APPLICATION | 1, tag); | |
| } | |
| { | |
| // Context-specific constructed tag, tag number 30. | |
| const uint8_t der[] = {0xbe, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 30, tag); | |
| } | |
| { | |
| // Private primitive tag, tag number 15. | |
| const uint8_t der[] = {0xcf, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value)); | |
| EXPECT_EQ(CBS_ASN1_PRIVATE | 15, tag); | |
| } | |
| } | |
| TEST(ParserTest, IncompleteEncodingTagOnly) { | |
| const uint8_t der[] = {0x01}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_TRUE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, IncompleteEncodingLengthTruncated) { | |
| // Tag: octet string; length: long form, should have 2 total octets, but | |
| // the last one is missing. (There's also no value.) | |
| const uint8_t der[] = {0x04, 0x81}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_TRUE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, IncompleteEncodingValueShorterThanLength) { | |
| // Tag: octet string; length: 2; value: first octet 'T', second octet missing. | |
| const uint8_t der[] = {0x04, 0x02, 0x84}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_TRUE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, LengthMustBeEncodedWithMinimumNumberOfOctets) { | |
| const uint8_t der[] = {0x01, 0x81, 0x01, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_TRUE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, LengthMustNotHaveLeadingZeroes) { | |
| // Tag: octet string; length: 3 bytes of length encoding a value of 128 | |
| // (it should be encoded in only 2 bytes). Value: 128 bytes of 0. | |
| const uint8_t der[] = { | |
| 0x04, 0x83, 0x80, 0x81, 0x80, // group the 0s separately | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG tag; | |
| Input value; | |
| ASSERT_FALSE(parser.ReadTagAndValue(&tag, &value)); | |
| ASSERT_TRUE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, ReadConstructedFailsForNonConstructedTags) { | |
| // Tag number is for SEQUENCE, but the constructed bit isn't set. | |
| const uint8_t der[] = {0x10, 0x00}; | |
| Parser parser((Input(der))); | |
| CBS_ASN1_TAG expected_tag = 0x10; | |
| Parser sequence_parser; | |
| ASSERT_FALSE(parser.ReadConstructed(expected_tag, &sequence_parser)); | |
| // Check that we didn't fail above because of a tag mismatch or an improperly | |
| // encoded TLV. | |
| Input value; | |
| ASSERT_TRUE(parser.ReadTag(expected_tag, &value)); | |
| ASSERT_FALSE(parser.HasMore()); | |
| } | |
| TEST(ParserTest, CannotAdvanceAfterReadOptionalTag) { | |
| const uint8_t der[] = {0x02, 0x01, 0x01}; | |
| Parser parser((Input(der))); | |
| Input value; | |
| bool present; | |
| ASSERT_TRUE(parser.ReadOptionalTag(0x04, &value, &present)); | |
| ASSERT_FALSE(present); | |
| ASSERT_FALSE(parser.Advance()); | |
| } | |
| // Reads a valid BIT STRING with 1 unused bit. | |
| TEST(ParserTest, ReadBitString) { | |
| const uint8_t der[] = {0x03, 0x03, 0x01, 0xAA, 0xBE}; | |
| Parser parser((Input(der))); | |
| std::optional<BitString> bit_string = parser.ReadBitString(); | |
| ASSERT_TRUE(bit_string.has_value()); | |
| EXPECT_FALSE(parser.HasMore()); | |
| EXPECT_EQ(1u, bit_string->unused_bits()); | |
| ASSERT_EQ(2u, bit_string->bytes().size()); | |
| EXPECT_EQ(0xAA, bit_string->bytes()[0]); | |
| EXPECT_EQ(0xBE, bit_string->bytes()[1]); | |
| } | |
| // Tries reading a BIT STRING. This should fail because the tag is not for a | |
| // BIT STRING. | |
| TEST(ParserTest, ReadBitStringBadTag) { | |
| const uint8_t der[] = {0x05, 0x03, 0x01, 0xAA, 0xBE}; | |
| Parser parser((Input(der))); | |
| std::optional<BitString> bit_string = parser.ReadBitString(); | |
| EXPECT_FALSE(bit_string.has_value()); | |
| } | |
| } // namespace der::test | |
| BSSL_NAMESPACE_END |