Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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
*
*
* 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());
}