#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 , 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) {
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) {
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());
Tag tag;
Input value;
ASSERT_FALSE(inner_sequence.ReadTagAndValue(&tag, &value));
}
TEST(ParserTest, ReadOptionalTagPresent) {
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) {
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) {
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) {
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 , 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 , 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) {
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) {
{
const uint8_t der[] = {0x04, 0x00};
Parser parser((Input(der)));
Tag tag;
Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
EXPECT_EQ(kOctetString, tag);
}
{
const uint8_t der[] = {0x30, 0x00};
Parser parser((Input(der)));
Tag tag;
Input value;
ASSERT_TRUE(parser.ReadTagAndValue(&tag, &value));
EXPECT_EQ(kSequence, tag);
}
{
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);
}
{
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);
}
{
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) {
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) {
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) {
const uint8_t der[] = {
0x04, 0x83, 0x80, 0x81, 0x80,
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) {
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));
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());
}
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]);
}
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());
}
}