diff --git a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt index b0ec0cd75788..6105d9505c83 100644 --- a/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt +++ b/okhttp-tls/src/main/kotlin/okhttp3/tls/internal/der/Adapters.kt @@ -17,7 +17,7 @@ package okhttp3.tls.internal.der import java.math.BigInteger import java.net.ProtocolException -import java.text.ParseException +import java.text.ParsePosition import java.text.SimpleDateFormat import java.util.Date import java.util.TimeZone @@ -235,15 +235,16 @@ internal object Adapters { val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply { timeZone = utc + isLenient = false set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. } - try { - val parsed = dateFormat.parse(string) - return parsed.time - } catch (e: ParseException) { + val position = ParsePosition(0) + val parsed = dateFormat.parse(string, position) + if (parsed == null || position.index != string.length) { throw ProtocolException("Failed to parse UTCTime $string") } + return parsed.time } internal fun formatUtcTime(date: Long): String { @@ -317,14 +318,15 @@ internal object Adapters { val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply { timeZone = utc + isLenient = false } - try { - val parsed = dateFormat.parse(string) - return parsed.time - } catch (e: ParseException) { + val position = ParsePosition(0) + val parsed = dateFormat.parse(string, position) + if (parsed == null || position.index != string.length) { throw ProtocolException("Failed to parse GeneralizedTime $string") } + return parsed.time } internal fun formatGeneralizedTime(date: Long): String { diff --git a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt index 418491ab02e5..538aeb08297e 100644 --- a/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt +++ b/okhttp-tls/src/test/java/okhttp3/tls/internal/der/DerTest.kt @@ -691,6 +691,36 @@ internal class DerTest { } } + @Test fun `cannot decode utc time with out of range field`() { + // "191316030210Z" carries month 13. + val bytes = "170d3139313331363033303231305a".decodeHex() + assertFailsWith { + Adapters.UTC_TIME.fromDer(bytes) + }.also { expected -> + assertThat(expected).hasMessage("Failed to parse UTCTime 191316030210Z") + } + } + + @Test fun `cannot decode utc time with trailing data`() { + // A valid "191216030210Z" followed by a stray '0' inside the declared length. + val bytes = "170e3139313231363033303231305a30".decodeHex() + assertFailsWith { + Adapters.UTC_TIME.fromDer(bytes) + }.also { expected -> + assertThat(expected).hasMessage("Failed to parse UTCTime 191216030210Z0") + } + } + + @Test fun `cannot decode generalized time with out of range field`() { + // "20191316030210Z" carries month 13. + val bytes = "180f32303139313331363033303231305a".decodeHex() + assertFailsWith { + Adapters.GENERALIZED_TIME.fromDer(bytes) + }.also { expected -> + assertThat(expected).hasMessage("Failed to parse GeneralizedTime 20191316030210Z") + } + } + @Test fun `parse utc time`() { assertThat(Adapters.parseUtcTime("920521000000Z")) .isEqualTo(date("1992-05-21T00:00:00.000+0000").time)