3a67ab
diff --git a/security/pkix/lib/pkixder.cpp b/security/pkix/lib/pkixder.cpp
3a67ab
--- a/security/pkix/lib/pkixder.cpp
3a67ab
+++ b/security/pkix/lib/pkixder.cpp
3a67ab
@@ -466,28 +466,63 @@ TimeChoice(Reader& tagged, uint8_t expec
3a67ab
   if (rv != Success) {
3a67ab
     return rv;
3a67ab
   }
3a67ab
 
3a67ab
   uint8_t b;
3a67ab
   if (input.Read(b) != Success) {
3a67ab
     return Result::ERROR_INVALID_DER_TIME;
3a67ab
   }
3a67ab
-  if (b != 'Z') {
3a67ab
+
3a67ab
+  unsigned int hourOffset = 0;
3a67ab
+  unsigned int minuteOffset = 0;
3a67ab
+  bool allowOffset = false;
3a67ab
+  bool haveOffset = false;
3a67ab
+  bool offsetIsPositive = false;
3a67ab
+
3a67ab
+  if (getenv("PKIX_ALLOW_CERT_UTCTIME_OFFSET") != 0) {
3a67ab
+    allowOffset = true;
3a67ab
+  }
3a67ab
+
3a67ab
+  if (allowOffset && (b == '+' || b == '-')) {
3a67ab
+    haveOffset = true;
3a67ab
+    rv = ReadTwoDigits(input, 0u, 23u, hourOffset);
3a67ab
+    if (rv != Success) {
3a67ab
+      return rv;
3a67ab
+    }
3a67ab
+    rv = ReadTwoDigits(input, 0u, 59u, minuteOffset);
3a67ab
+    if (rv != Success) {
3a67ab
+      return rv;
3a67ab
+    }
3a67ab
+    if (b == '+') {
3a67ab
+      offsetIsPositive = true;
3a67ab
+    }
3a67ab
+  } else if (b != 'Z') {
3a67ab
     return Result::ERROR_INVALID_DER_TIME;
3a67ab
   }
3a67ab
   if (End(input) != Success) {
3a67ab
     return Result::ERROR_INVALID_DER_TIME;
3a67ab
   }
3a67ab
 
3a67ab
   uint64_t totalSeconds = (static_cast<uint64_t>(days) * 24u * 60u * 60u) +
3a67ab
                           (static_cast<uint64_t>(hours)      * 60u * 60u) +
3a67ab
                           (static_cast<uint64_t>(minutes)          * 60u) +
3a67ab
                           seconds;
3a67ab
 
3a67ab
+  if (haveOffset) {
3a67ab
+    uint64_t offsetInSeconds =
3a67ab
+                          (static_cast<uint64_t>(hourOffset) * 60u * 60u) +
3a67ab
+                          (static_cast<uint64_t>(minuteOffset)     * 60u);
3a67ab
+    if (offsetIsPositive) {
3a67ab
+      totalSeconds -= offsetInSeconds;
3a67ab
+    } else {
3a67ab
+      totalSeconds += offsetInSeconds;
3a67ab
+    }
3a67ab
+  }
3a67ab
+
3a67ab
   time = TimeFromElapsedSecondsAD(totalSeconds);
3a67ab
   return Success;
3a67ab
 }
3a67ab
 
3a67ab
 Result
3a67ab
 IntegralBytes(Reader& input, uint8_t tag,
3a67ab
               IntegralValueRestriction valueRestriction,
3a67ab
               /*out*/ Input& value,