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