| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/der/parse_values.h" |
| |
| #include <stdint.h> |
| |
| #include "base/macros.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace net { |
| namespace der { |
| namespace test { |
| |
| namespace { |
| |
| template <size_t N> |
| Input FromStringLiteral(const char(&data)[N]) { |
| // Strings are null-terminated. The null terminating byte shouldn't be |
| // included in the Input, so the size is N - 1 instead of N. |
| return Input(reinterpret_cast<const uint8_t*>(data), N - 1); |
| } |
| |
| } // namespace |
| |
| TEST(ParseValuesTest, ParseBool) { |
| uint8_t buf[] = {0xFF, 0x00}; |
| Input value(buf, 1); |
| bool out; |
| EXPECT_TRUE(ParseBool(value, &out)); |
| EXPECT_TRUE(out); |
| |
| buf[0] = 0; |
| EXPECT_TRUE(ParseBool(value, &out)); |
| EXPECT_FALSE(out); |
| |
| buf[0] = 1; |
| EXPECT_FALSE(ParseBool(value, &out)); |
| EXPECT_TRUE(ParseBoolRelaxed(value, &out)); |
| EXPECT_TRUE(out); |
| |
| buf[0] = 0xFF; |
| value = Input(buf, 2); |
| EXPECT_FALSE(ParseBool(value, &out)); |
| value = Input(buf, 0); |
| EXPECT_FALSE(ParseBool(value, &out)); |
| } |
| |
| TEST(ParseValuesTest, ParseTimes) { |
| GeneralizedTime out; |
| |
| EXPECT_TRUE(ParseUTCTime(FromStringLiteral("140218161200Z"), &out)); |
| |
| // DER-encoded UTCTime must end with 'Z'. |
| EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200X"), &out)); |
| |
| // Check that a negative number (-4 in this case) doesn't get parsed as |
| // a 2-digit number. |
| EXPECT_FALSE(ParseUTCTime(FromStringLiteral("-40218161200Z"), &out)); |
| |
| // Check that numbers with a leading 0 don't get parsed in octal by making |
| // the second digit an invalid octal digit (e.g. 09). |
| EXPECT_TRUE(ParseUTCTime(FromStringLiteral("090218161200Z"), &out)); |
| |
| // Check that the length is validated. |
| EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200"), &out)); |
| EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200Z0"), &out)); |
| EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("140218161200"), &out)); |
| EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("140218161200Z0"), &out)); |
| |
| // Check strictness of UTCTime parsers. |
| EXPECT_FALSE(ParseUTCTime(FromStringLiteral("1402181612Z"), &out)); |
| EXPECT_TRUE(ParseUTCTimeRelaxed(FromStringLiteral("1402181612Z"), &out)); |
| |
| // Check that the time ends in Z. |
| EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("1402181612Z0"), &out)); |
| |
| // Check that ParseUTCTimeRelaxed calls ValidateGeneralizedTime. |
| EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("1402181662Z"), &out)); |
| |
| // Check format of GeneralizedTime. |
| |
| // Years 0 and 9999 are allowed. |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("00000101000000Z"), &out)); |
| EXPECT_EQ(0, out.year); |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("99991231235960Z"), &out)); |
| EXPECT_EQ(9999, out.year); |
| |
| // Leap seconds are allowed. |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20140218161260Z"), &out)); |
| |
| // But nothing larger than a leap second. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140218161261Z"), &out)); |
| |
| // Minutes only go up to 59. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140218166000Z"), &out)); |
| |
| // Hours only go up to 23. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140218240000Z"), &out)); |
| // The 0th day of a month is invalid. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140200161200Z"), &out)); |
| // The 0th month is invalid. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140018161200Z"), &out)); |
| // Months greater than 12 are invalid. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20141318161200Z"), &out)); |
| |
| // Some months have 31 days. |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20140131000000Z"), &out)); |
| |
| // September has only 30 days. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140931000000Z"), &out)); |
| |
| // February has only 28 days... |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140229000000Z"), &out)); |
| |
| // ... unless it's a leap year. |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20160229000000Z"), &out)); |
| |
| // There aren't any leap days in years divisible by 100... |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("21000229000000Z"), &out)); |
| |
| // ...unless it's also divisible by 400. |
| EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20000229000000Z"), &out)); |
| |
| // Check more perverse invalid inputs. |
| |
| // Check that trailing null bytes are not ignored. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20001231010203Z\0"), &out)); |
| |
| // Check what happens when a null byte is in the middle of the input. |
| EXPECT_FALSE(ParseGeneralizedTime(FromStringLiteral( |
| "200\0" |
| "1231010203Z"), |
| &out)); |
| |
| // The year can't be in hex. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("0x201231000000Z"), &out)); |
| |
| // The last byte must be 'Z'. |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20001231000000X"), &out)); |
| |
| // Check that the length is validated. |
| EXPECT_FALSE(ParseGeneralizedTime(FromStringLiteral("20140218161200"), &out)); |
| EXPECT_FALSE( |
| ParseGeneralizedTime(FromStringLiteral("20140218161200Z0"), &out)); |
| } |
| |
| TEST(ParseValuesTest, TimesCompare) { |
| GeneralizedTime time1; |
| GeneralizedTime time2; |
| GeneralizedTime time3; |
| GeneralizedTime time4; |
| |
| ASSERT_TRUE( |
| ParseGeneralizedTime(FromStringLiteral("20140218161200Z"), &time1)); |
| // Test that ParseUTCTime correctly normalizes the year. |
| ASSERT_TRUE(ParseUTCTime(FromStringLiteral("150218161200Z"), &time2)); |
| ASSERT_TRUE(ParseUTCTimeRelaxed(FromStringLiteral("1503070000Z"), &time3)); |
| ASSERT_TRUE( |
| ParseGeneralizedTime(FromStringLiteral("20160218161200Z"), &time4)); |
| EXPECT_TRUE(time1 < time2); |
| EXPECT_TRUE(time2 < time3); |
| EXPECT_TRUE(time3 < time4); |
| |
| EXPECT_TRUE(time2 > time1); |
| EXPECT_TRUE(time2 >= time1); |
| EXPECT_TRUE(time3 <= time4); |
| EXPECT_TRUE(time1 <= time1); |
| EXPECT_TRUE(time1 >= time1); |
| } |
| |
| TEST(ParseValuesTest, UTCTimeRange) { |
| GeneralizedTime time; |
| ASSERT_TRUE( |
| ParseGeneralizedTime(FromStringLiteral("20140218161200Z"), &time)); |
| EXPECT_TRUE(time.InUTCTimeRange()); |
| |
| time.year = 1950; |
| EXPECT_TRUE(time.InUTCTimeRange()); |
| |
| time.year = 1949; |
| EXPECT_FALSE(time.InUTCTimeRange()); |
| |
| time.year = 2049; |
| EXPECT_TRUE(time.InUTCTimeRange()); |
| |
| time.year = 2050; |
| EXPECT_FALSE(time.InUTCTimeRange()); |
| } |
| |
| struct Uint64TestData { |
| bool should_pass; |
| const uint8_t input[9]; |
| size_t length; |
| uint64_t expected_value; |
| }; |
| |
| const Uint64TestData kUint64TestData[] = { |
| {true, {0x00}, 1, 0}, |
| // This number fails because it is not a minimal representation. |
| {false, {0x00, 0x00}, 2}, |
| {true, {0x01}, 1, 1}, |
| {false, {0xFF}, 1}, |
| {true, {0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8, INT64_MAX}, |
| {true, |
| {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, |
| 9, |
| UINT64_MAX}, |
| // This number fails because it is negative. |
| {false, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 8}, |
| {false, {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 8}, |
| {false, {0x00, 0x01}, 2}, |
| {false, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}, 9}, |
| {false, {0}, 0}, |
| }; |
| |
| TEST(ParseValuesTest, ParseUint64) { |
| for (size_t i = 0; i < arraysize(kUint64TestData); i++) { |
| const Uint64TestData& test_case = kUint64TestData[i]; |
| SCOPED_TRACE(i); |
| |
| uint64_t result; |
| EXPECT_EQ(test_case.should_pass, |
| ParseUint64(Input(test_case.input, test_case.length), &result)); |
| if (test_case.should_pass) |
| EXPECT_EQ(test_case.expected_value, result); |
| } |
| } |
| |
| struct Uint8TestData { |
| bool should_pass; |
| const uint8_t input[9]; |
| size_t length; |
| uint8_t expected_value; |
| }; |
| |
| const Uint8TestData kUint8TestData[] = { |
| {true, {0x00}, 1, 0}, |
| // This number fails because it is not a minimal representation. |
| {false, {0x00, 0x00}, 2}, |
| {true, {0x01}, 1, 1}, |
| {false, {0x01, 0xFF}, 2}, |
| {false, {0x03, 0x83}, 2}, |
| {true, {0x7F}, 1, 0x7F}, |
| {true, {0x00, 0xFF}, 2, 0xFF}, |
| // This number fails because it is negative. |
| {false, {0xFF}, 1}, |
| {false, {0x80}, 1}, |
| {false, {0x00, 0x01}, 2}, |
| {false, {0}, 0}, |
| }; |
| |
| TEST(ParseValuesTest, ParseUint8) { |
| for (size_t i = 0; i < arraysize(kUint8TestData); i++) { |
| const Uint8TestData& test_case = kUint8TestData[i]; |
| SCOPED_TRACE(i); |
| |
| uint8_t result; |
| EXPECT_EQ(test_case.should_pass, |
| ParseUint8(Input(test_case.input, test_case.length), &result)); |
| if (test_case.should_pass) |
| EXPECT_EQ(test_case.expected_value, result); |
| } |
| } |
| |
| struct IsValidIntegerTestData { |
| bool should_pass; |
| const uint8_t input[2]; |
| size_t length; |
| bool negative; |
| }; |
| |
| const IsValidIntegerTestData kIsValidIntegerTestData[] = { |
| // Empty input (invalid DER). |
| {false, {0x00}, 0}, |
| |
| // The correct encoding for zero. |
| {true, {0x00}, 1, false}, |
| |
| // Invalid representation of zero (not minimal) |
| {false, {0x00, 0x00}, 2}, |
| |
| // Valid single byte negative numbers. |
| {true, {0x80}, 1, true}, |
| {true, {0xFF}, 1, true}, |
| |
| // Non-minimal negative number. |
| {false, {0xFF, 0x80}, 2}, |
| |
| // Positive number with a legitimate leading zero. |
| {true, {0x00, 0x80}, 2, false}, |
| |
| // A legitimate negative number that starts with FF (MSB of second byte is |
| // 0 so OK). |
| {true, {0xFF, 0x7F}, 2, true}, |
| }; |
| |
| TEST(ParseValuesTest, IsValidInteger) { |
| for (size_t i = 0; i < arraysize(kIsValidIntegerTestData); i++) { |
| const auto& test_case = kIsValidIntegerTestData[i]; |
| SCOPED_TRACE(i); |
| |
| bool negative; |
| EXPECT_EQ( |
| test_case.should_pass, |
| IsValidInteger(Input(test_case.input, test_case.length), &negative)); |
| if (test_case.should_pass) |
| EXPECT_EQ(test_case.negative, negative); |
| } |
| } |
| |
| // Tests parsing an empty BIT STRING. |
| TEST(ParseValuesTest, ParseBitStringEmptyNoUnusedBits) { |
| const uint8_t kData[] = {0x00}; |
| |
| BitString bit_string; |
| ASSERT_TRUE(ParseBitString(Input(kData), &bit_string)); |
| |
| EXPECT_EQ(0u, bit_string.unused_bits()); |
| EXPECT_EQ(0u, bit_string.bytes().Length()); |
| |
| EXPECT_FALSE(bit_string.AssertsBit(0)); |
| EXPECT_FALSE(bit_string.AssertsBit(1)); |
| EXPECT_FALSE(bit_string.AssertsBit(3)); |
| } |
| |
| // Tests parsing an empty BIT STRING that incorrectly claims one unused bit. |
| TEST(ParseValuesTest, ParseBitStringEmptyOneUnusedBit) { |
| const uint8_t kData[] = {0x01}; |
| |
| BitString bit_string; |
| EXPECT_FALSE(ParseBitString(Input(kData), &bit_string)); |
| } |
| |
| // Tests parsing an empty BIT STRING that is not minmally encoded (the entire |
| // last byte is comprised of unused bits). |
| TEST(ParseValuesTest, ParseBitStringNonEmptyTooManyUnusedBits) { |
| const uint8_t kData[] = {0x08, 0x00}; |
| |
| BitString bit_string; |
| EXPECT_FALSE(ParseBitString(Input(kData), &bit_string)); |
| } |
| |
| // Tests parsing a BIT STRING of 7 bits each of which are 1. |
| TEST(ParseValuesTest, ParseBitStringSevenOneBits) { |
| const uint8_t kData[] = {0x01, 0xFE}; |
| |
| BitString bit_string; |
| ASSERT_TRUE(ParseBitString(Input(kData), &bit_string)); |
| |
| EXPECT_EQ(1u, bit_string.unused_bits()); |
| EXPECT_EQ(1u, bit_string.bytes().Length()); |
| EXPECT_EQ(0xFE, bit_string.bytes().UnsafeData()[0]); |
| |
| EXPECT_TRUE(bit_string.AssertsBit(0)); |
| EXPECT_TRUE(bit_string.AssertsBit(1)); |
| EXPECT_TRUE(bit_string.AssertsBit(2)); |
| EXPECT_TRUE(bit_string.AssertsBit(3)); |
| EXPECT_TRUE(bit_string.AssertsBit(4)); |
| EXPECT_TRUE(bit_string.AssertsBit(5)); |
| EXPECT_TRUE(bit_string.AssertsBit(6)); |
| EXPECT_FALSE(bit_string.AssertsBit(7)); |
| EXPECT_FALSE(bit_string.AssertsBit(8)); |
| } |
| |
| // Tests parsing a BIT STRING of 7 bits each of which are 1. The unused bit |
| // however is set to 1, which is an invalid encoding. |
| TEST(ParseValuesTest, ParseBitStringSevenOneBitsUnusedBitIsOne) { |
| const uint8_t kData[] = {0x01, 0xFF}; |
| |
| BitString bit_string; |
| EXPECT_FALSE(ParseBitString(Input(kData), &bit_string)); |
| } |
| |
| } // namespace test |
| } // namespace der |
| } // namespace net |