Add expiry parsing into CertificateView.

PiperOrigin-RevId: 314437222
Change-Id: Ia7ff932ea0c21ef064f68f6242179d7b579d2a9f
diff --git a/common/platform/api/quiche_time_utils.h b/common/platform/api/quiche_time_utils.h
new file mode 100644
index 0000000..7319568
--- /dev/null
+++ b/common/platform/api/quiche_time_utils.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
+#define QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
+
+#include <cstdint>
+
+#include "net/quiche/common/platform/impl/quiche_time_utils_impl.h"
+
+namespace quiche {
+
+// Converts a civil time specified in UTC into a number of seconds since the
+// Unix epoch.  This function is strict about validity of accepted dates.  For
+// instance, it will reject February 29 on non-leap years, or 25 hours in a day.
+// As a notable exception, 60 seconds is accepted to deal with potential leap
+// seconds.  If the date predates Unix epoch, nullopt will be returned.
+inline QuicheOptional<int64_t> QuicheUtcDateTimeToUnixSeconds(int year,
+                                                              int month,
+                                                              int day,
+                                                              int hour,
+                                                              int minute,
+                                                              int second) {
+  return QuicheUtcDateTimeToUnixSecondsImpl(year, month, day, hour, minute,
+                                            second);
+}
+
+}  // namespace quiche
+
+#endif  // QUICHE_COMMON_PLATFORM_API_QUICHE_TIME_UTILS_H_
diff --git a/common/platform/api/quiche_time_utils_test.cc b/common/platform/api/quiche_time_utils_test.cc
new file mode 100644
index 0000000..0f32b10
--- /dev/null
+++ b/common/platform/api/quiche_time_utils_test.cc
@@ -0,0 +1,51 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/common/platform/api/quiche_time_utils.h"
+
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_test.h"
+
+namespace quiche {
+namespace {
+
+TEST(QuicheTimeUtilsTest, Basic) {
+  EXPECT_EQ(1, QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 0, 1));
+  EXPECT_EQ(365 * 86400, QuicheUtcDateTimeToUnixSeconds(1971, 1, 1, 0, 0, 0));
+  // Some arbitrary timestamps closer to the present, compared to the output of
+  // "Date(...).getTime()" from the JavaScript console.
+  EXPECT_EQ(1152966896,
+            QuicheUtcDateTimeToUnixSeconds(2006, 7, 15, 12, 34, 56));
+  EXPECT_EQ(1591130001, QuicheUtcDateTimeToUnixSeconds(2020, 6, 2, 20, 33, 21));
+
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 2, 29, 0, 0, 1));
+  EXPECT_NE(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1972, 2, 29, 0, 0, 1));
+}
+
+TEST(QuicheTimeUtilsTest, Bounds) {
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 1, 32, 0, 0, 1));
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 4, 31, 0, 0, 1));
+  EXPECT_EQ(QuicheNullOpt, QuicheUtcDateTimeToUnixSeconds(1970, 1, 0, 0, 0, 1));
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 13, 1, 0, 0, 1));
+  EXPECT_EQ(QuicheNullOpt, QuicheUtcDateTimeToUnixSeconds(1970, 0, 1, 0, 0, 1));
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 24, 0, 0));
+  EXPECT_EQ(QuicheNullOpt,
+            QuicheUtcDateTimeToUnixSeconds(1970, 1, 1, 0, 60, 0));
+}
+
+TEST(QuicheTimeUtilsTest, LeapSecond) {
+  EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 23, 59, 60),
+            QuicheUtcDateTimeToUnixSeconds(2015, 7, 1, 0, 0, 0));
+  EXPECT_EQ(QuicheUtcDateTimeToUnixSeconds(2015, 6, 30, 25, 59, 60),
+            QuicheNullOpt);
+}
+
+}  // namespace
+}  // namespace quiche
diff --git a/common/quiche_data_reader.cc b/common/quiche_data_reader.cc
index 3445013..2242fea 100644
--- a/common/quiche_data_reader.cc
+++ b/common/quiche_data_reader.cc
@@ -10,6 +10,7 @@
 #include "net/third_party/quiche/src/common/platform/api/quiche_logging.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_text_utils.h"
 
 namespace quiche {
 
@@ -119,6 +120,15 @@
   return ReadBytes(tag, sizeof(*tag));
 }
 
+bool QuicheDataReader::ReadDecimal64(size_t num_digits, uint64_t* result) {
+  quiche::QuicheStringPiece digits;
+  if (!ReadStringPiece(&digits, num_digits)) {
+    return false;
+  }
+
+  return QuicheTextUtils::StringToUint64(digits, result);
+}
+
 quiche::QuicheStringPiece QuicheDataReader::ReadRemainingPayload() {
   quiche::QuicheStringPiece payload = PeekRemainingPayload();
   pos_ = len_;
diff --git a/common/quiche_data_reader.h b/common/quiche_data_reader.h
index cf62a16..f74f90d 100644
--- a/common/quiche_data_reader.h
+++ b/common/quiche_data_reader.h
@@ -87,6 +87,11 @@
   // endian.
   bool ReadTag(uint32_t* tag);
 
+  // Reads a sequence of a fixed number of decimal digits, parses them as an
+  // unsigned integer and returns them as a uint64_t.  Forwards internal
+  // iterator on success, may forward it even in case of failure.
+  bool ReadDecimal64(size_t num_digits, uint64_t* result);
+
   // Returns the remaining payload as a quiche::QuicheStringPiece.
   //
   // NOTE: Does not copy but rather references strings in the underlying buffer.