366 lines
11 KiB
C++
366 lines
11 KiB
C++
// Copyright 2015 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/der/parser.h"
|
|
|
|
#include "net/der/input.h"
|
|
#include "net/der/parse_values.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace net::der::test {
|
|
|
|
TEST(ParserTest, ConsumesAllBytesOfTLV) {
|
|
const uint8_t der[] = {0x04 /* OCTET STRING */, 0x00};
|
|
Parser parser((Input(der)));
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
ASSERT_EQ(kOctetString, 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)));
|
|
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.
|
|
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(kInteger, &value, &present));
|
|
ASSERT_TRUE(present);
|
|
const uint8_t expected_int_value[] = {0x01};
|
|
ASSERT_EQ(Input(expected_int_value), value);
|
|
|
|
Tag tag;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
ASSERT_EQ(kOctetString, 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)));
|
|
|
|
absl::optional<Input> optional_value;
|
|
ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &optional_value));
|
|
ASSERT_TRUE(optional_value.has_value());
|
|
const uint8_t expected_int_value[] = {0x01};
|
|
ASSERT_EQ(Input(expected_int_value), *optional_value);
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
ASSERT_EQ(kOctetString, 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(kInteger, &value, &present));
|
|
ASSERT_FALSE(present);
|
|
|
|
Tag tag;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
ASSERT_EQ(kOctetString, 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)));
|
|
|
|
absl::optional<Input> optional_value;
|
|
ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &optional_value));
|
|
ASSERT_FALSE(optional_value.has_value());
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
ASSERT_EQ(kOctetString, 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)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
bool present;
|
|
ASSERT_TRUE(parser.ReadOptionalTag(kInteger, &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(kOctetString, &present));
|
|
ASSERT_FALSE(present);
|
|
ASSERT_TRUE(parser.SkipOptionalTag(kInteger, &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)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kTagContextSpecific | 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)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kOctetString, tag);
|
|
}
|
|
|
|
{
|
|
// Universal constructed tag, tag number 16.
|
|
const uint8_t der[] = {0x30, 0x00};
|
|
Parser parser((Input(der)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kSequence, tag);
|
|
}
|
|
|
|
{
|
|
// Application primitive tag, tag number 1.
|
|
const uint8_t der[] = {0x41, 0x00};
|
|
Parser parser((Input(der)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kTagApplication | 1, tag);
|
|
}
|
|
|
|
{
|
|
// Context-specific constructed tag, tag number 30.
|
|
const uint8_t der[] = {0xbe, 0x00};
|
|
Parser parser((Input(der)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kTagContextSpecific | kTagConstructed | 30, tag);
|
|
}
|
|
|
|
{
|
|
// Private primitive tag, tag number 15.
|
|
const uint8_t der[] = {0xcf, 0x00};
|
|
Parser parser((Input(der)));
|
|
|
|
Tag tag;
|
|
Input value;
|
|
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
|
|
EXPECT_EQ(kTagPrivate | 15, tag);
|
|
}
|
|
}
|
|
|
|
TEST(ParserTest, IncompleteEncodingTagOnly) {
|
|
const uint8_t der[] = {0x01};
|
|
Parser parser((Input(der)));
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
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)));
|
|
|
|
absl::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().Length());
|
|
EXPECT_EQ(0xAA, bit_string->bytes().UnsafeData()[0]);
|
|
EXPECT_EQ(0xBE, bit_string->bytes().UnsafeData()[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)));
|
|
|
|
absl::optional<BitString> bit_string = parser.ReadBitString();
|
|
EXPECT_FALSE(bit_string.has_value());
|
|
}
|
|
|
|
} // namespace net::der::test
|