Bug 1019770, Part 2: modify existing GeneralizedTime tests to test TimeChoice too, r=cviecco
authorBrian Smith <brian@briansmith.org>
Tue, 24 Jun 2014 10:51:53 -0700
changeset 191821 278f163756bdca4670846a9c28998d7d4b85bb6a
parent 191820 d2ed7720fc40367f88482b370b706980c6ef9989
child 191822 a83d5a927c90e662120a4fc89d1a1753a9f96ae1
push id27063
push usercbook@mozilla.com
push dateWed, 02 Jul 2014 12:51:47 +0000
treeherdermozilla-central@49e7fc49dd4e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscviecco
bugs1019770
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1019770, Part 2: modify existing GeneralizedTime tests to test TimeChoice too, r=cviecco
security/pkix/test/gtest/pkixder_universal_types_tests.cpp
--- a/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
@@ -300,18 +300,35 @@ TEST_F(pkixder_universal_types_tests, En
   ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_ZERO_LENGTH,
                                 sizeof DER_ENUMERATED_INVALID_ZERO_LENGTH));
 
   uint8_t value = 0;
   ASSERT_EQ(Failure, Enumerated(input, value));
   ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
 }
 
+static PRTime
+YMDHMS(int16_t year, int16_t month, int16_t day,
+       int16_t hour, int16_t minutes, int16_t seconds)
+{
+  PRExplodedTime tm;
+  tm.tm_usec = 0;
+  tm.tm_sec = seconds;
+  tm.tm_min = minutes;
+  tm.tm_hour = hour;
+  tm.tm_mday = day;
+  tm.tm_month = month - 1; // tm_month is zero-based
+  tm.tm_year = year;
+  tm.tm_params.tp_gmt_offset = 0;
+  tm.tm_params.tp_dst_offset = 0;
+  return PR_ImplodeTime(&tm);
+}
+
 ////////////////////////////////////////
-// GeneralizedTime
+// 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.
 //
@@ -321,415 +338,397 @@ TEST_F(pkixder_universal_types_tests, En
 //   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.
 
-// TODO(Bug 1023605) a GeneralizedTimes with a timezone offset are should not
-// be considered valid
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeOffset)
+// Given a DER-encoded GeneralizedTime where we want to extract the value, we
+// need to skip two bytes: the tag and the length.
+static const uint16_t GT_VALUE_OFFSET = 2;
+
+// Given a DER-encoded GeneralizedTime where we want to extract the value as
+// though it were a UTC time, we need to skip four bytes: the tag, the length
+// and the first two digits of the year.
+static const uint16_t UTC_VALUE_OFFSET = 4;
+
+static const uint16_t GENERALIZED_TIME_LENGTH = 17; // tvYYYYMMDDHHMMSSZ
+
+template <uint16_t LENGTH>
+void
+ExpectGoodTime(PRTime expectedValue,
+               const uint8_t (&generalizedTimeDER)[LENGTH])
+{
+  static_assert(LENGTH >= UTC_VALUE_OFFSET,
+                "ExpectGoodTime requires input at least UTC_VALUE_OFFSET bytes");
+
+  // GeneralizedTime
+  {
+    Input input;
+    ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
+    PRTime value = 0;
+    ASSERT_EQ(Success, GeneralizedTime(input, value));
+    EXPECT_EQ(expectedValue, value);
+  }
+
+  // TimeChoice: GeneralizedTime
+  {
+    Input input;
+    ASSERT_EQ(Success, input.Init(generalizedTimeDER + GT_VALUE_OFFSET,
+                                  LENGTH - GT_VALUE_OFFSET));
+    PRTime value = 0;
+    ASSERT_EQ(Success, TimeChoice(siGeneralizedTime, input, value));
+    EXPECT_EQ(expectedValue, value);
+  }
+
+  // TimeChoice: UTCTime
+  {
+    Input input;
+    ASSERT_EQ(Success, input.Init(generalizedTimeDER + UTC_VALUE_OFFSET,
+                                  LENGTH - UTC_VALUE_OFFSET));
+    PRTime value = 0;
+    ASSERT_EQ(Success, TimeChoice(siUTCTime, input, value));
+    EXPECT_EQ(expectedValue, value);
+  }
+}
+
+template <uint16_t LENGTH>
+void
+ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
+{
+  static_assert(LENGTH >= UTC_VALUE_OFFSET,
+                "ExpectBadTime requires input at least UTC_VALUE_OFFSET bytes");
+
+
+  // GeneralizedTime
+  {
+    Input input;
+    ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
+    PRTime value;
+    ASSERT_EQ(Failure, GeneralizedTime(input, value));
+    EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  }
+
+  // TimeChoice: GeneralizedTime
+  {
+    Input input;
+    ASSERT_EQ(Success,
+              input.Init(generalizedTimeDER + GT_VALUE_OFFSET,
+                         LENGTH - GT_VALUE_OFFSET));
+    PRTime value;
+    ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, input, value));
+    EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  }
+
+  // TimeChoice: UTCTime
+  {
+    Input input;
+    ASSERT_EQ(Success,
+              input.Init(generalizedTimeDER + UTC_VALUE_OFFSET,
+                         LENGTH - UTC_VALUE_OFFSET));
+    PRTime value;
+    ASSERT_EQ(Failure, TimeChoice(siUTCTime, input, value));
+    EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  }
+}
+
+// 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'
   };
-
-  Input input;
-  ASSERT_EQ(Success, input.Init(DER_GENERALIZED_TIME_OFFSET,
-                                sizeof DER_GENERALIZED_TIME_OFFSET));
-
-  PRTime value = 0;
-  ASSERT_EQ(Success, GeneralizedTime(input, value));
-  ASSERT_EQ(673573540000000, value);
+  ExpectBadTime(DER_GENERALIZED_TIME_OFFSET);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeGMT)
-{
-  const uint8_t DER_GENERALIZED_TIME_GMT[] = {
-    0x18,                           // Generalized Time
-    15,                             // Length = 15
-    '1', '9', '9', '1', '0', '5', '0', '6', '1', '6', '4', '5', '4', '0', 'Z'
-  };
-
-  Input input;
-  ASSERT_EQ(Success, input.Init(DER_GENERALIZED_TIME_GMT,
-                                sizeof DER_GENERALIZED_TIME_GMT));
-  PRTime value = 0;
-  ASSERT_EQ(Success, GeneralizedTime(input, value));
-  ASSERT_EQ(673548340000000, value);
-}
-
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidZeroLength)
+TEST_F(pkixder_universal_types_tests, TimeInvalidZeroLength)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH[] = {
     0x18,                           // GeneralizedTime
     0x00                            // Length = 0
   };
 
-  Input input;
+  PRTime value;
+
+  // GeneralizedTime
+  Input gt;
   ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
-                       sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
+            gt.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
+                    sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
+  ASSERT_EQ(Failure, GeneralizedTime(gt, value));
+  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+
+  static const uint8_t dummy[1] = { 'X' };
 
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
+  // TimeChoice: GeneralizedTime
+  Input tc_gt;
+  ASSERT_EQ(Success, tc_gt.Init(dummy, 0));
+  ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, tc_gt, value));
+  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+
+  // TimeChoice: UTCTime
+  Input tc_utc;
+  ASSERT_EQ(Success, tc_utc.Init(dummy, 0));
+  ASSERT_EQ(Failure, TimeChoice(siUTCTime, tc_utc, value));
   ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
 }
 
 // A non zulu time should fail
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidLocal)
+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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_LOCAL,
-                       sizeof DER_GENERALIZED_TIME_INVALID_LOCAL));
-
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_LOCAL);
 }
 
 // A time missing seconds and zulu should fail
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidTruncated)
+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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_TRUNCATED,
-                       sizeof DER_GENERALIZED_TIME_INVALID_TRUNCATED));
-
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_TRUNCATED);
 }
 
-// TODO(bug 1023605) Generalized Times without seconds should not be
-// considered valid
 TEST_F(pkixder_universal_types_tests, GeneralizedTimeNoSeconds)
 {
   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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_NO_SECONDS,
-                       sizeof DER_GENERALIZED_TIME_NO_SECONDS));
-  PRTime value = 0;
-  ASSERT_EQ(Success, GeneralizedTime(input, value));
-  ASSERT_EQ(673548300000000, value);
+  ExpectBadTime(DER_GENERALIZED_TIME_NO_SECONDS);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidPrefixedYear)
+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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_PREFIXED_YEAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_PREFIXED_YEAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_PREFIXED_YEAR);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalid5DigitYear)
+TEST_F(pkixder_universal_types_tests, TimeTooManyDigits)
 {
-  const uint8_t DER_GENERALIZED_TIME_INVALID_5_DIGIT_YEAR[] = {
+  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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_5_DIGIT_YEAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_5_DIGIT_YEAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_TOO_MANY_DIGITS);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidMonth)
+TEST_F(pkixder_universal_types_tests, Time13thMonth)
 {
-  const uint8_t DER_GENERALIZED_TIME_INVALID_MONTH[] = {
+  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'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_MONTH,
-                       sizeof DER_GENERALIZED_TIME_INVALID_MONTH));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_13TH_MONTH);
 }
 
-// TODO(bug 1023437) Generalized times with invalid days for a given month
-// should be rejected
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidDayFeb)
+TEST_F(pkixder_universal_types_tests, TimeInvalidDayFeb)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_DAY_FEB[] = {
     0x18,                           // Generalized Time
     15,                             // Length = 15
     '1', '9', '9', '1', // YYYY 1991
     '0', '2', // MM (February)
     '3', '0', // DD (the 30th which does not exist)
     '1', '6', '4', '5', '4', '0', 'Z'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_DAY_FEB,
-                       sizeof DER_GENERALIZED_TIME_INVALID_DAY_FEB));
-  PRTime value = 0;
-  ASSERT_EQ(Success, GeneralizedTime(input, value));
-  // The current invalid returned value is Sat, 02 Mar 1991 16:45:40 GMT
-  ASSERT_EQ(667932340000000, value);
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_DAY_FEB);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidDayDec)
+TEST_F(pkixder_universal_types_tests, TimeInvalidDayDec)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_DAY_DEC[] = {
     0x18,                           // Generalized Time
     15,                             // Length = 15
     '1', '9', '9', '1', // YYYY 1991
     '1', '2', // MM (December)
     '3', '2', // DD (the 32nd which does not exist)
     '1', '6', '4', '5', '4', '0', 'Z'
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_DAY_DEC,
-                       sizeof DER_GENERALIZED_TIME_INVALID_DAY_DEC));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_DAY_DEC);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeLeapSecondJune)
+TEST_F(pkixder_universal_types_tests, TimeLeapSecondJune)
 {
   // No leap seconds ever (allowing them would be non-trivial).
   const uint8_t DER_GENERALIZED_TIME_LEAP_SECOND_JUNE[] = {
     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)
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_LEAP_SECOND_JUNE,
-                       sizeof DER_GENERALIZED_TIME_LEAP_SECOND_JUNE));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_LEAP_SECOND_JUNE);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidHours)
+TEST_F(pkixder_universal_types_tests, TimeInvalidHours)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_HOURS[] = {
     0x18,                           // Generalized Time
     15,                             // Length = 15
     '2', '0', '1', '2', '0', '6', '3', '0', // YYYYMMDD (2012-06-30)
     '2', '5', '5', '9', '0', '1', 'Z' // HHMMSSZ (!!25!!:59:01 Zulu)
   };
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_HOURS,
-                       sizeof DER_GENERALIZED_TIME_INVALID_HOURS));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_HOURS);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidMinutes)
+TEST_F(pkixder_universal_types_tests, TimeInvalidMinutes)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_MINUTES[] = {
     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)
   };
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_MINUTES,
-                       sizeof DER_GENERALIZED_TIME_INVALID_MINUTES));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_MINUTES);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidSeconds)
+TEST_F(pkixder_universal_types_tests, TimeInvalidSeconds)
 {
   const uint8_t DER_GENERALIZED_TIME_INVALID_SECONDS[] = {
     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)
   };
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_SECONDS,
-                       sizeof DER_GENERALIZED_TIME_INVALID_SECONDS));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_SECONDS);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidZulu)
+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
   };
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_ZULU,
-                       sizeof DER_GENERALIZED_TIME_INVALID_ZULU));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_ZULU);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidExtraData)
+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
   };
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_EXTRA_DATA,
-                       sizeof DER_GENERALIZED_TIME_INVALID_EXTRA_DATA));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_EXTRA_DATA);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidCenturyChar)
+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)
   };
 
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  // 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;
+    ASSERT_EQ(Success,
+              input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
+                         sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
+    PRTime value = 0;
+    ASSERT_EQ(Failure, GeneralizedTime(input, value));
+    EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  }
+
+  // TimeChoice: GeneralizedTime
+  {
+    Input input;
+    ASSERT_EQ(Success,
+              input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
+                         sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
+    PRTime value = 0;
+    ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, input, value));
+    EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  }
+
+  // This test is not applicable to TimeChoice: UTCTime
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidYearChar)
+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)
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_YEAR_CHAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_YEAR_CHAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  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)
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_MONTH_CHAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_MONTH_CHAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_MONTH_CHAR);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidDayChar)
+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)
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_DAY_CHAR,
-                       sizeof DER_GENERALIZED_TIME_INVALID_DAY_CHAR));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_DAY_CHAR);
 }
 
-TEST_F(pkixder_universal_types_tests, GeneralizedTimeInvalidFractionalSeconds)
+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)
   };
-
-  Input input;
-  ASSERT_EQ(Success,
-            input.Init(DER_GENERALIZED_TIME_INVALID_FRACTIONAL_SECONDS,
-                       sizeof DER_GENERALIZED_TIME_INVALID_FRACTIONAL_SECONDS));
-  PRTime value = 0;
-  ASSERT_EQ(Failure, GeneralizedTime(input, value));
-  ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
+  ExpectBadTime(DER_GENERALIZED_TIME_INVALID_FRACTIONAL_SECONDS);
 }
 
 TEST_F(pkixder_universal_types_tests, Integer_0_127)
 {
   for (uint8_t i = 0; i <= 127; ++i) {
     const uint8_t DER[] = {
       0x02, // INTEGER
       0x01, // length