summaryrefslogtreecommitdiffstats
path: root/security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp1276
1 files changed, 1276 insertions, 0 deletions
diff --git a/security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp b/security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp
new file mode 100644
index 0000000000..4e6f7582fb
--- /dev/null
+++ b/security/nss/gtests/mozpkix_gtest/pkixder_universal_types_tests.cpp
@@ -0,0 +1,1276 @@
+/* -*- 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 <limits>
+#include <stdint.h>
+#include <vector>
+
+#include "pkixgtest.h"
+
+#include "mozpkix/pkixder.h"
+
+using namespace mozilla::pkix;
+using namespace mozilla::pkix::der;
+using namespace mozilla::pkix::test;
+using namespace std;
+
+class pkixder_universal_types_tests : public ::testing::Test { };
+
+TEST_F(pkixder_universal_types_tests, BooleanTrue01)
+{
+ const uint8_t DER_BOOLEAN_TRUE_01[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0x01 // invalid
+ };
+ Input input(DER_BOOLEAN_TRUE_01);
+ Reader reader(input);
+ bool value = false;
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(reader, value));
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanTrue42)
+{
+ const uint8_t DER_BOOLEAN_TRUE_42[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0x42 // invalid
+ };
+ Input input(DER_BOOLEAN_TRUE_42);
+ Reader reader(input);
+ bool value = false;
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(reader, value));
+}
+
+static const uint8_t DER_BOOLEAN_TRUE[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0xff // true
+};
+
+TEST_F(pkixder_universal_types_tests, BooleanTrueFF)
+{
+ Input input(DER_BOOLEAN_TRUE);
+ Reader reader(input);
+ bool value = false;
+ ASSERT_EQ(Success, Boolean(reader, value));
+ ASSERT_TRUE(value);
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanFalse)
+{
+ const uint8_t DER_BOOLEAN_FALSE[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0x00 // false
+ };
+ Input input(DER_BOOLEAN_FALSE);
+ Reader reader(input);
+
+ bool value = true;
+ ASSERT_EQ(Success, Boolean(reader, value));
+ ASSERT_FALSE(value);
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanInvalidLength)
+{
+ const uint8_t DER_BOOLEAN_INVALID_LENGTH[] = {
+ 0x01, // BOOLEAN
+ 0x02, // length
+ 0x42, 0x42 // invalid
+ };
+ Input input(DER_BOOLEAN_INVALID_LENGTH);
+ Reader reader(input);
+
+ bool value = true;
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(reader, value));
+}
+
+TEST_F(pkixder_universal_types_tests, BooleanInvalidZeroLength)
+{
+ const uint8_t DER_BOOLEAN_INVALID_ZERO_LENGTH[] = {
+ 0x01, // BOOLEAN
+ 0x00 // length
+ };
+ Input input(DER_BOOLEAN_INVALID_ZERO_LENGTH);
+ Reader reader(input);
+
+ bool value = true;
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(reader, value));
+}
+
+// OptionalBoolean implements decoding of OPTIONAL BOOLEAN DEFAULT FALSE.
+// If the field is present, it must be a valid encoding of a BOOLEAN with
+// value TRUE. If the field is not present, it defaults to FALSE. For
+// compatibility reasons, OptionalBoolean also accepts encodings where the field
+// is present with value FALSE (this is technically not a valid DER encoding).
+TEST_F(pkixder_universal_types_tests, OptionalBooleanValidEncodings)
+{
+ {
+ const uint8_t DER_OPTIONAL_BOOLEAN_PRESENT_TRUE[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0xff // true
+ };
+ Input input(DER_OPTIONAL_BOOLEAN_PRESENT_TRUE);
+ Reader reader(input);
+ bool value = false;
+ ASSERT_EQ(Success, OptionalBoolean(reader, value)) <<
+ "Should accept the only valid encoding of a present OPTIONAL BOOLEAN";
+ ASSERT_TRUE(value);
+ ASSERT_TRUE(reader.AtEnd());
+ }
+
+ {
+ // The OPTIONAL BOOLEAN is omitted in this data.
+ const uint8_t DER_INTEGER_05[] = {
+ 0x02, // INTEGER
+ 0x01, // length
+ 0x05
+ };
+ Input input(DER_INTEGER_05);
+ Reader reader(input);
+ bool value = true;
+ ASSERT_EQ(Success, OptionalBoolean(reader, value)) <<
+ "Should accept a valid encoding of an omitted OPTIONAL BOOLEAN";
+ ASSERT_FALSE(value);
+ ASSERT_FALSE(reader.AtEnd());
+ }
+
+ {
+ Input input;
+ ASSERT_EQ(Success, input.Init(reinterpret_cast<const uint8_t*>(""), 0));
+ Reader reader(input);
+ bool value = true;
+ ASSERT_EQ(Success, OptionalBoolean(reader, value)) <<
+ "Should accept another valid encoding of an omitted OPTIONAL BOOLEAN";
+ ASSERT_FALSE(value);
+ ASSERT_TRUE(reader.AtEnd());
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, OptionalBooleanInvalidEncodings)
+{
+ const uint8_t DER_OPTIONAL_BOOLEAN_PRESENT_FALSE[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0x00 // false
+ };
+
+ {
+ Input input(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE);
+ Reader reader(input);
+ bool value = true;
+ ASSERT_EQ(Success, OptionalBoolean(reader, value)) <<
+ "Should accept an invalid, default-value encoding of OPTIONAL BOOLEAN";
+ ASSERT_FALSE(value);
+ ASSERT_TRUE(reader.AtEnd());
+ }
+
+ const uint8_t DER_OPTIONAL_BOOLEAN_PRESENT_42[] = {
+ 0x01, // BOOLEAN
+ 0x01, // length
+ 0x42 // (invalid value for a BOOLEAN)
+ };
+
+ {
+ Input input(DER_OPTIONAL_BOOLEAN_PRESENT_42);
+ Reader reader(input);
+ bool value;
+ ASSERT_EQ(Result::ERROR_BAD_DER, OptionalBoolean(reader, value)) <<
+ "Should reject an invalid-valued encoding of OPTIONAL BOOLEAN";
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, Enumerated)
+{
+ const uint8_t DER_ENUMERATED[] = {
+ 0x0a, // ENUMERATED
+ 0x01, // length
+ 0x42 // value
+ };
+ Input input(DER_ENUMERATED);
+ Reader reader(input);
+
+ uint8_t value = 0;
+ ASSERT_EQ(Success, Enumerated(reader, value));
+ ASSERT_EQ(0x42, value);
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedNotShortestPossibleDER)
+{
+ const uint8_t DER_ENUMERATED[] = {
+ 0x0a, // ENUMERATED
+ 0x02, // length
+ 0x00, 0x01 // value
+ };
+ Input input(DER_ENUMERATED);
+ Reader reader(input);
+
+ uint8_t value = 0;
+ ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING, Enumerated(reader, value));
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedOutOfAcceptedRange)
+{
+ // Although this is a valid ENUMERATED value according to ASN.1, we
+ // intentionally don't support these large values because there are no
+ // ENUMERATED values in X.509 certs or OCSP this large, and we're trying to
+ // keep the parser simple and fast.
+ const uint8_t DER_ENUMERATED_INVALID_LENGTH[] = {
+ 0x0a, // ENUMERATED
+ 0x02, // length
+ 0x12, 0x34 // value
+ };
+ Input input(DER_ENUMERATED_INVALID_LENGTH);
+ Reader reader(input);
+
+ uint8_t value = 0;
+ ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING, Enumerated(reader, value));
+}
+
+TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
+{
+ const uint8_t DER_ENUMERATED_INVALID_ZERO_LENGTH[] = {
+ 0x0a, // ENUMERATED
+ 0x00 // length
+ };
+ Input input(DER_ENUMERATED_INVALID_ZERO_LENGTH);
+ Reader reader(input);
+
+ uint8_t value = 0;
+ ASSERT_EQ(Result::ERROR_INVALID_INTEGER_ENCODING, Enumerated(reader, value));
+}
+
+////////////////////////////////////////
+// GeneralizedTime and TimeChoice
+//
+// From RFC 5280 section 4.1.2.5.2
+//
+// For the purposes of this profile, GeneralizedTime values MUST be
+// expressed in Greenwich Mean Time (Zulu) and MUST include seconds
+// (i.e., times are YYYYMMDDHHMMSSZ), even where the number of seconds
+// is zero. GeneralizedTime values MUST NOT include fractional seconds.
+//
+// And from from RFC 6960 (OCSP) section 4.2.2.1:
+//
+// Responses can contain four times -- thisUpdate, nextUpdate,
+// producedAt, and revocationTime. The semantics of these fields are
+// defined in Section 2.4. The format for GeneralizedTime is as
+// specified in Section 4.1.2.5.2 of [RFC5280].
+//
+// So while we can could accept other ASN1 (ITU-T X.680) encodings for
+// GeneralizedTime we should not accept them, and breaking reading of these
+// other encodings is actually encouraged.
+
+// e.g. TWO_CHARS(53) => '5', '3'
+#define TWO_CHARS(t) \
+ static_cast<uint8_t>('0' + (static_cast<uint8_t>(t) / 10u)), \
+ static_cast<uint8_t>('0' + (static_cast<uint8_t>(t) % 10u))
+
+// Calls TimeChoice on the UTCTime variant of the given generalized time.
+template <uint16_t LENGTH>
+Result
+TimeChoiceForEquivalentUTCTime(const uint8_t (&generalizedTimeDER)[LENGTH],
+ /*out*/ Time& value)
+{
+ static_assert(LENGTH >= 4,
+ "TimeChoiceForEquivalentUTCTime input too small");
+ uint8_t utcTimeDER[LENGTH - 2];
+ utcTimeDER[0] = 0x17; // tag UTCTime
+ utcTimeDER[1] = LENGTH - 1/*tag*/ - 1/*value*/ - 2/*century*/;
+ // Copy the value except for the first two digits of the year
+ for (size_t i = 2; i < LENGTH - 2; ++i) {
+ utcTimeDER[i] = generalizedTimeDER[i + 2];
+ }
+
+ Input input(utcTimeDER);
+ Reader reader(input);
+ return TimeChoice(reader, value);
+}
+
+template <uint16_t LENGTH>
+void
+ExpectGoodTime(Time expectedValue,
+ const uint8_t (&generalizedTimeDER)[LENGTH])
+{
+ // GeneralizedTime
+ {
+ Input input(generalizedTimeDER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, GeneralizedTime(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(generalizedTimeDER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, TimeChoice(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+
+ // TimeChoice: UTCTime
+ {
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success,
+ TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+}
+
+template <uint16_t LENGTH>
+void
+ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
+{
+ // GeneralizedTime
+ {
+ Input input(generalizedTimeDER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, GeneralizedTime(reader, value));
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(generalizedTimeDER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, TimeChoice(reader, value));
+ }
+
+ // TimeChoice: UTCTime
+ {
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME,
+ TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
+ }
+}
+
+// Control value: a valid time
+TEST_F(pkixder_universal_types_tests, ValidControl)
+{
+ const uint8_t GT_DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'
+ };
+ ExpectGoodTime(YMDHMS(1991, 5, 6, 16, 45, 40), GT_DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeTimeZoneOffset)
+{
+ const uint8_t DER_GENERALIZED_TIME_OFFSET[] = {
+ 0x18, // Generalized Time
+ 19, // Length = 19
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', '-',
+ '0', '7', '0', '0'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_OFFSET);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidZeroLength)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH[] = {
+ 0x18, // GeneralizedTime
+ 0x00 // Length = 0
+ };
+
+ Time value(Time::uninitialized);
+
+ // GeneralizedTime
+ Input gtBuf(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH);
+ Reader gt(gtBuf);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, GeneralizedTime(gt, value));
+
+ // TimeChoice: GeneralizedTime
+ Input tc_gt_buf(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH);
+ Reader tc_gt(tc_gt_buf);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, TimeChoice(tc_gt, value));
+
+ // TimeChoice: UTCTime
+ const uint8_t DER_UTCTIME_INVALID_ZERO_LENGTH[] = {
+ 0x17, // UTCTime
+ 0x00 // Length = 0
+ };
+ Input tc_utc_buf(DER_UTCTIME_INVALID_ZERO_LENGTH);
+ Reader tc_utc(tc_utc_buf);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, TimeChoice(tc_utc, value));
+}
+
+// A non zulu time should fail
+TEST_F(pkixder_universal_types_tests, TimeInvalidLocal)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_LOCAL[] = {
+ 0x18, // Generalized Time
+ 14, // Length = 14
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_LOCAL);
+}
+
+// A time missing seconds and zulu should fail
+TEST_F(pkixder_universal_types_tests, TimeInvalidTruncated)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_TRUNCATED[] = {
+ 0x18, // Generalized Time
+ 12, // Length = 12
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_TRUNCATED);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeNoSeconds)
+{
+ const uint8_t DER_GENERALIZED_TIME_NO_SECONDS[] = {
+ 0x18, // Generalized Time
+ 13, // Length = 13
+ '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', 'Z'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_NO_SECONDS);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidPrefixedYear)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_PREFIXED_YEAR[] = {
+ 0x18, // Generalized Time
+ 16, // Length = 16
+ ' ', '1', '9', '9', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', 'Z'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_PREFIXED_YEAR);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeTooManyDigits)
+{
+ const uint8_t DER_GENERALIZED_TIME_TOO_MANY_DIGITS[] = {
+ 0x18, // Generalized Time
+ 16, // Length = 16
+ '1', '1', '1', '1', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', 'Z'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_TOO_MANY_DIGITS);
+}
+
+// In order to ensure we we don't run into any trouble with conversions to and
+// from time_t we only accept times from 1970 onwards.
+TEST_F(pkixder_universal_types_tests, GeneralizedTimeYearValidRange)
+{
+ // Note that by using the last second of the last day of the year, we're also
+ // effectively testing all the accumulated conversions from Gregorian to to
+ // Julian time, including in particular the effects of leap years.
+
+ for (uint16_t i = 1970; i <= 9999; ++i) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ TWO_CHARS(i / 100), TWO_CHARS(i % 100), // YYYY
+ '1', '2', '3', '1', // 12-31
+ '2', '3', '5', '9', '5', '9', 'Z' // 23:59:59Z
+ };
+
+ Time expectedValue = YMDHMS(i, 12, 31, 23, 59, 59);
+
+ // We have to test GeneralizedTime separately from UTCTime instead of using
+ // ExpectGooDtime because the range of UTCTime is less than the range of
+ // GeneralizedTime.
+
+ // GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, GeneralizedTime(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, TimeChoice(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+
+ // TimeChoice: UTCTime, which is limited to years less than 2049.
+ if (i <= 2049) {
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, TimeChoiceForEquivalentUTCTime(DER, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+ }
+}
+
+// In order to ensure we we don't run into any trouble with conversions to and
+// from time_t we only accept times from 1970 onwards.
+TEST_F(pkixder_universal_types_tests, TimeYearInvalid1969)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '6', '9', '1', '2', '3', '1', // !!!1969!!!-12-31
+ '2', '3', '5', '9', '5', '9', 'Z' // 23:59:59Z
+ };
+ ExpectBadTime(DER);
+}
+
+static const uint8_t DAYS_IN_MONTH[] = {
+ 0, // unused
+ 31, // January
+ 28, // February (leap years tested separately)
+ 31, // March
+ 30, // April
+ 31, // May
+ 30, // Jun
+ 31, // July
+ 31, // August
+ 30, // September
+ 31, // October
+ 30, // November
+ 31, // December
+};
+
+TEST_F(pkixder_universal_types_tests, TimeMonthDaysValidRange)
+{
+ for (uint16_t month = 1; month <= 12; ++month) {
+ for (uint8_t day = 1; day <= DAYS_IN_MONTH[month]; ++day) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '5', TWO_CHARS(month), TWO_CHARS(day), // (2015-mm-dd)
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectGoodTime(YMDHMS(2015, month, day, 16, 45, 40), DER);
+ }
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthInvalid0)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '5', '0', '0', '1', '5', // 2015-!!!00!!!-15
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthInvalid13)
+{
+ const uint8_t DER_GENERALIZED_TIME_13TH_MONTH[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', '1', //YYYY (1991)
+ '1', '3', //MM 13th month of the year
+ '0', '6', '1', '6', '4', '5', '4', '0', 'Z'
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_13TH_MONTH);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeDayInvalid0)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '5', '0', '1', '0', '0', // 2015-01-!!!00!!!
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthDayInvalidPastEndOfMonth)
+{
+ for (int16_t month = 1; month <= 12; ++month) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', '1', // YYYY 1991
+ TWO_CHARS(month), // MM
+ TWO_CHARS(1 + (month == 2 ? 29 : DAYS_IN_MONTH[month])), // !!!DD!!!
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectBadTime(DER);
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2016)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '6', '0', '2', '2', '9', // 2016-02-29
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectGoodTime(YMDHMS(2016, 2, 29, 16, 45, 40), DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2000)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '0', '0', '0', '2', '2', '9', // 2000-02-29
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectGoodTime(YMDHMS(2000, 2, 29, 16, 45, 40), DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2400)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '4', '0', '0', '0', '2', '2', '9', // 2400-02-29
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+
+ // We don't use ExpectGoodTime here because UTCTime can't represent 2400.
+
+ Time expectedValue = YMDHMS(2400, 2, 29, 16, 45, 40);
+
+ // GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, GeneralizedTime(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Success, TimeChoice(reader, value));
+ EXPECT_EQ(expectedValue, value);
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthFebNotLeapYear2014)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '4', '0', '2', '2', '9', // 2014-02-29
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMonthFebNotLeapYear2100)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '1', '0', '0', '0', '2', '2', '9', // 2100-02-29
+ '1', '6', '4', '5', '4', '0', 'Z' // 16:45:40
+ };
+
+ // We don't use ExpectBadTime here because UTCTime can't represent 2100.
+
+ // GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, GeneralizedTime(reader, value));
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(DER);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, TimeChoice(reader, value));
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeHoursValidRange)
+{
+ for (uint8_t i = 0; i <= 23; ++i) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ TWO_CHARS(i), '5', '9', '0', '1', 'Z' // HHMMSSZ (!!!!ii!!!!:59:01 Zulu)
+ };
+ ExpectGoodTime(YMDHMS(2012, 6, 30, i, 59, 1), DER);
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeHoursInvalid_24_00_00)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '4', '0', '0', '0', '0', 'Z' // HHMMSSZ (!!24!!:00:00 Zulu)
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMinutesValidRange)
+{
+ for (uint8_t i = 0; i <= 59; ++i) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', TWO_CHARS(i), '0', '1', 'Z' // HHMMSSZ (23:!!!!ii!!!!:01 Zulu)
+ };
+ ExpectGoodTime(YMDHMS(2012, 6, 30, 23, i, 1), DER);
+ }
+}
+
+TEST_F(pkixder_universal_types_tests, TimeMinutesInvalid60)
+{
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '6', '0', '5', '9', 'Z' // HHMMSSZ (23:!!!60!!!:01 Zulu)
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeSecondsValidRange)
+{
+ for (uint8_t i = 0; i <= 59; ++i) {
+ const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '5', '9', TWO_CHARS(i), 'Z' // HHMMSSZ (23:59:!!!!ii!!!! Zulu)
+ };
+ ExpectGoodTime(YMDHMS(2012, 6, 30, 23, 59, i), DER);
+ }
+}
+
+// No Leap Seconds (60)
+TEST_F(pkixder_universal_types_tests, TimeSecondsInvalid60)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '5', '9', '6', '0', 'Z' // HHMMSSZ (23:59:!!!!60!!!! Zulu)
+ };
+ ExpectBadTime(DER);
+}
+
+// No Leap Seconds (61)
+TEST_F(pkixder_universal_types_tests, TimeSecondsInvalid61)
+{
+ static const uint8_t DER[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '5', '9', '6', '1', 'Z' // HHMMSSZ (23:59:!!!!61!!!! Zulu)
+ };
+ ExpectBadTime(DER);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidZulu)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_ZULU[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '5', '9', '5', '9', 'z' // HHMMSSZ (23:59:59 !!!z!!!) should be Z
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_ZULU);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidExtraData)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_EXTRA_DATA[] = {
+ 0x18, // Generalized Time
+ 16, // Length = 16
+ '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
+ '2', '3', '5', '9', '5', '9', 'Z', // HHMMSSZ (23:59:59Z)
+ 0 // Extra null character
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_EXTRA_DATA);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidCenturyChar)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ 'X', '9', '9', '1', '1', '2', '0', '6', // YYYYMMDD (X991-12-06)
+ '1', '6', '4', '5', '4', '0', 'Z' // HHMMSSZ (16:45:40Z)
+ };
+
+ // We can't use ExpectBadTime here, because ExpectBadTime requires
+ // consistent results for GeneralizedTime and UTCTime, but the results
+ // for this input are different.
+
+ // GeneralizedTime
+ {
+ Input input(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, GeneralizedTime(reader, value));
+ }
+
+ // TimeChoice: GeneralizedTime
+ {
+ Input input(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR);
+ Reader reader(input);
+ Time value(Time::uninitialized);
+ ASSERT_EQ(Result::ERROR_INVALID_DER_TIME, TimeChoice(reader, value));
+ }
+
+ // This test is not applicable to TimeChoice: UTCTime
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidYearChar)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_YEAR_CHAR[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', 'I', '0', '1', '0', '6', // YYYYMMDD (199I-12-06)
+ '1', '6', '4', '5', '4', '0', 'Z' // HHMMSSZ (16:45:40Z)
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_YEAR_CHAR);
+}
+
+TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidMonthChar)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_MONTH_CHAR[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', '1', '0', 'I', '0', '6', // YYYYMMDD (1991-0I-06)
+ '1', '6', '4', '5', '4', '0', 'Z' // HHMMSSZ (16:45:40Z)
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_MONTH_CHAR);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidDayChar)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_DAY_CHAR[] = {
+ 0x18, // Generalized Time
+ 15, // Length = 15
+ '1', '9', '9', '1', '0', '1', '0', 'S', // YYYYMMDD (1991-01-0S)
+ '1', '6', '4', '5', '4', '0', 'Z' // HHMMSSZ (16:45:40Z)
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_DAY_CHAR);
+}
+
+TEST_F(pkixder_universal_types_tests, TimeInvalidFractionalSeconds)
+{
+ const uint8_t DER_GENERALIZED_TIME_INVALID_FRACTIONAL_SECONDS[] = {
+ 0x18, // Generalized Time
+ 17, // Length = 17
+ '1', '9', '9', '1', '0', '1', '0', '1', // YYYYMMDD (1991-01-01)
+ '1', '6', '4', '5', '4', '0', '.', '3', 'Z' // HHMMSS.FFF (16:45:40.3Z)
+ };
+ ExpectBadTime(DER_GENERALIZED_TIME_INVALID_FRACTIONAL_SECONDS);
+}
+
+struct IntegerTestParams
+{
+ ByteString encoded;
+ struct PositiveIntegerParams
+ {
+ Result expectedResult;
+ Input::size_type significantBytesIfValid;
+ } positiveInteger;
+ struct SmallNonnegativeIntegerParams
+ {
+ Result expectedResult;
+ uint8_t valueIfValid;
+ } smallNonnegativeInteger;
+};
+
+class pkixder_universal_types_tests_Integer
+ : public ::testing::Test
+ , public ::testing::WithParamInterface<IntegerTestParams>
+{
+};
+
+::std::ostream& operator<<(::std::ostream& os, const IntegerTestParams&)
+{
+ return os << "TODO (bug 1318770)";
+}
+
+#define INVALID 0xFF
+
+static const IntegerTestParams INTEGER_TEST_PARAMS[] =
+{
+ // Zero is encoded with one value byte of 0x00.
+ { TLV(2, ByteString()),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x00"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Success, 0 } },
+
+ // Positive single-byte values
+ { TLV(2, "\x01"), { Success, 1 }, { Success, 1} },
+ { TLV(2, "\x02"), { Success, 1 }, { Success, 2} },
+ { TLV(2, "\x7e"), { Success, 1 }, { Success, 0x7e} },
+ { TLV(2, "\x7f"), { Success, 1 }, { Success, 0x7f} },
+
+ // Negative single-byte values
+ { TLV(2, "\x80"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x81"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\xFE"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\xFF"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // Positive two-byte values not starting with 0x00
+ { TLV(2, "\x7F\x00"),
+ { Success, 2 },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x01\x00"),
+ { Success, 2 },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x01\x02"),
+ { Success, 2 },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // Negative two-byte values not starting with 0xFF
+ { TLV(2, "\x80\x00"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x80\x7F"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x80\x80"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x80\xFF"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // The leading zero is necessary.
+ { TLV(2, "\x00\x80"),
+ { Success, 1},
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x00\x81"),
+ { Success, 1},
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x00\xFF"),
+ { Success, 1},
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // The leading zero is unnecessary.
+ { TLV(2, "\x00\x01"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\x00\x7F"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // The leading 0xFF is necessary.
+ { TLV(2, "\xFF\x00"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\xFF\x7F"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // The leading 0xFF is unnecessary.
+ { TLV(2, "\xFF\x80"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2, "\xFF\xFF"),
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+
+ // Truncated values
+ { TLV(2, 1, ByteString(/*missing value*/)),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 3, "\x11\x22" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 4, "\x11\x22" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 2, "\x00" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 2, "\xFF" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 3, "\x00\x80" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+ { TLV(2, 3, "\xFF\x00" /*truncated*/),
+ { Result::ERROR_BAD_DER, INVALID },
+ { Result::ERROR_BAD_DER, INVALID } },
+
+ // Misc. larger values
+ { TLV(2, 4, "\x11\x22\x33\x44"),
+ { Success, 4 },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+ { TLV(2,
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00"),
+ { Success, 256 },
+ { Result::ERROR_INVALID_INTEGER_ENCODING, INVALID } },
+};
+
+TEST_P(pkixder_universal_types_tests_Integer, Integer)
+{
+ const IntegerTestParams& params(GetParam());
+ Input input;
+ ASSERT_EQ(Success, input.Init(params.encoded.data(),
+ params.encoded.length()));
+ Reader reader(input);
+ Result expectedResult = params.smallNonnegativeInteger.expectedResult;
+ uint8_t value;
+ ASSERT_EQ(expectedResult, der::Integer(reader, value));
+ if (expectedResult == Success) {
+ ASSERT_EQ(params.smallNonnegativeInteger.valueIfValid, value);
+ ASSERT_TRUE(reader.AtEnd());
+ }
+}
+
+TEST_P(pkixder_universal_types_tests_Integer,
+ PositiveInteger_without_significantBytes)
+{
+ const IntegerTestParams& params(GetParam());
+ Input input;
+ ASSERT_EQ(Success, input.Init(params.encoded.data(),
+ params.encoded.length()));
+ Reader reader(input);
+ Result expectedResult = params.positiveInteger.expectedResult;
+ Input value;
+ ASSERT_EQ(expectedResult, der::PositiveInteger(reader, value));
+ if (expectedResult == Success) {
+ Reader anotherReader(input);
+ Input expectedValue;
+ ASSERT_EQ(Success, ExpectTagAndGetValue(anotherReader,
+ der::INTEGER, expectedValue));
+ ASSERT_TRUE(InputsAreEqual(expectedValue, value));
+ ASSERT_TRUE(reader.AtEnd());
+ }
+}
+
+TEST_P(pkixder_universal_types_tests_Integer,
+ PositiveInteger_with_significantBytes)
+{
+ const IntegerTestParams& params(GetParam());
+ Input input;
+ ASSERT_EQ(Success, input.Init(params.encoded.data(),
+ params.encoded.length()));
+ Reader reader(input);
+ Result expectedResult = params.positiveInteger.expectedResult;
+ Input value;
+ Input::size_type significantBytes = INVALID;
+ ASSERT_EQ(expectedResult, der::PositiveInteger(reader, value,
+ &significantBytes));
+ if (expectedResult == Success) {
+ ASSERT_NE(INVALID, params.positiveInteger.significantBytesIfValid);
+ ASSERT_EQ(params.positiveInteger.significantBytesIfValid,
+ significantBytes);
+
+ Reader anotherReader(input);
+ Input expectedValue;
+ ASSERT_EQ(Success, ExpectTagAndGetValue(anotherReader,
+ der::INTEGER, expectedValue));
+ ASSERT_TRUE(InputsAreEqual(expectedValue, value));
+ ASSERT_TRUE(reader.AtEnd());
+ }
+}
+
+#undef INVALID
+
+INSTANTIATE_TEST_SUITE_P(pkixder_universal_types_tests_Integer,
+ pkixder_universal_types_tests_Integer,
+ testing::ValuesIn(INTEGER_TEST_PARAMS));
+
+TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefault)
+{
+ // The input is a BOOLEAN and not INTEGER for the input so we'll not parse
+ // anything and instead use the default value.
+ Input input(DER_BOOLEAN_TRUE);
+ Reader reader(input);
+
+ long value = 1;
+ ASSERT_EQ(Success, OptionalInteger(reader, -1, value));
+ ASSERT_EQ(-1, value);
+ bool boolValue;
+ ASSERT_EQ(Success, Boolean(reader, boolValue));
+}
+
+TEST_F(pkixder_universal_types_tests, OptionalIntegerUnsupportedDefault)
+{
+ // The same as the previous test, except with an unsupported default value
+ // passed in.
+ Input input(DER_BOOLEAN_TRUE);
+ Reader reader(input);
+
+ long value;
+ ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, OptionalInteger(reader, 0, value));
+}
+
+TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefaultAtEnd)
+{
+ static const uint8_t dummy = 1;
+ Input input;
+ ASSERT_EQ(Success, input.Init(&dummy, 0));
+ Reader reader(input);
+
+ long value = 1;
+ ASSERT_EQ(Success, OptionalInteger(reader, -1, value));
+ ASSERT_EQ(-1, value);
+}
+
+TEST_F(pkixder_universal_types_tests, OptionalIntegerNonDefaultValue)
+{
+ static const uint8_t DER[] = {
+ 0x02, // INTEGER
+ 0x01, // length
+ 0x00
+ };
+ Input input(DER);
+ Reader reader(input);
+
+ long value = 2;
+ ASSERT_EQ(Success, OptionalInteger(reader, -1, value));
+ ASSERT_EQ(0, value);
+ ASSERT_TRUE(reader.AtEnd());
+}
+
+TEST_F(pkixder_universal_types_tests, Null)
+{
+ const uint8_t DER_NUL[] = {
+ 0x05,
+ 0x00
+ };
+ Input input(DER_NUL);
+ Reader reader(input);
+
+ ASSERT_EQ(Success, Null(reader));
+}
+
+TEST_F(pkixder_universal_types_tests, NullWithBadLength)
+{
+ const uint8_t DER_NULL_BAD_LENGTH[] = {
+ 0x05,
+ 0x01,
+ 0x00
+ };
+ Input input(DER_NULL_BAD_LENGTH);
+ Reader reader(input);
+
+ ASSERT_EQ(Result::ERROR_BAD_DER, Null(reader));
+}
+
+TEST_F(pkixder_universal_types_tests, OID)
+{
+ const uint8_t DER_VALID_OID[] = {
+ 0x06,
+ 0x09,
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+ Input input(DER_VALID_OID);
+ Reader reader(input);
+
+ const uint8_t expectedOID[] = {
+ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
+ };
+
+ ASSERT_EQ(Success, OID(reader, expectedOID));
+}
+
+TEST_F(pkixder_universal_types_tests, SkipOptionalImplicitPrimitiveTag)
+{
+ const uint8_t DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1[] = {
+ 0x81,
+ 0x04,
+ 0x00,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ };
+ Input input(DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1);
+ Reader reader(input);
+
+ ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 1));
+ ASSERT_TRUE(reader.AtEnd());
+}
+
+TEST_F(pkixder_universal_types_tests, SkipOptionalImplicitPrimitiveTagMismatch)
+{
+ const uint8_t DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1[] = {
+ 0x81,
+ 0x04,
+ 0x00,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ };
+ Input input(DER_IMPLICIT_BIT_STRING_WITH_CLASS_NUMBER_1);
+ Reader reader(input);
+
+ ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 2));
+ ASSERT_FALSE(reader.AtEnd());
+}
+
+TEST_F(pkixder_universal_types_tests, NoSkipOptionalImplicitConstructedTag)
+{
+ const uint8_t DER_IMPLICIT_SEQUENCE_WITH_CLASS_NUMBER_1[] = {
+ 0xA1,
+ 0x03,
+ 0x05,
+ 0x01,
+ 0x00,
+ };
+ Input input(DER_IMPLICIT_SEQUENCE_WITH_CLASS_NUMBER_1);
+ Reader reader(input);
+
+ ASSERT_EQ(Success, SkipOptionalImplicitPrimitiveTag(reader, 1));
+ ASSERT_FALSE(reader.AtEnd());
+}