/* -*- 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 #include #include #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(""), 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('0' + (static_cast(t) / 10u)), \ static_cast('0' + (static_cast(t) % 10u)) // Calls TimeChoice on the UTCTime variant of the given generalized time. template 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 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 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 { }; ::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()); }