diff --git a/security/pkix/lib/pkixder.cpp b/security/pkix/lib/pkixder.cpp --- 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(days) * 24u * 60u * 60u) + (static_cast(hours) * 60u * 60u) + (static_cast(minutes) * 60u) + seconds; + if (haveOffset) { + uint64_t offsetInSeconds = + (static_cast(hourOffset) * 60u * 60u) + + (static_cast(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,