1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-14 07:22:20 +03:00

Implement DER constraints on date formats (#6213)

The time zone must be 'Z', and cannot be an offset like '+0000'. That
is allowed by ASN.1 but not by DER.

Closes: https://github.com/square/okhttp/issues/6210
This commit is contained in:
Jesse Wilson
2020-08-05 19:50:44 -04:00
committed by GitHub
parent 9724946320
commit b1963bf8d8
2 changed files with 46 additions and 26 deletions

View File

@@ -164,7 +164,7 @@ internal object Adapters {
internal fun parseUtcTime(string: String): Long { internal fun parseUtcTime(string: String): Long {
val utc = TimeZone.getTimeZone("GMT") val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyMMddHHmmssXX").apply { val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply {
timeZone = utc timeZone = utc
set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z.
} }
@@ -179,7 +179,7 @@ internal object Adapters {
internal fun formatUtcTime(date: Long): String { internal fun formatUtcTime(date: Long): String {
val utc = TimeZone.getTimeZone("GMT") val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyMMddHHmmssXX").apply { val dateFormat = SimpleDateFormat("yyMMddHHmmss'Z'").apply {
timeZone = utc timeZone = utc
set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z. set2DigitYearStart(Date(-631152000000L)) // 1950-01-01T00:00:00Z.
} }
@@ -234,7 +234,7 @@ internal object Adapters {
internal fun parseGeneralizedTime(string: String): Long { internal fun parseGeneralizedTime(string: String): Long {
val utc = TimeZone.getTimeZone("GMT") val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyyyMMddHHmmssXX").apply { val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply {
timeZone = utc timeZone = utc
} }
@@ -248,7 +248,7 @@ internal object Adapters {
internal fun formatGeneralizedTime(date: Long): String { internal fun formatGeneralizedTime(date: Long): String {
val utc = TimeZone.getTimeZone("GMT") val utc = TimeZone.getTimeZone("GMT")
val dateFormat = SimpleDateFormat("yyyyMMddHHmmssXX").apply { val dateFormat = SimpleDateFormat("yyyyMMddHHmmss'Z'").apply {
timeZone = utc timeZone = utc
} }

View File

@@ -33,6 +33,7 @@ import okio.ByteString.Companion.encodeUtf8
import okio.ByteString.Companion.toByteString import okio.ByteString.Companion.toByteString
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert.fail import org.junit.Assert.fail
import org.junit.Ignore
import org.junit.Test import org.junit.Test
internal class DerTest { internal class DerTest {
@@ -627,9 +628,13 @@ internal class DerTest {
assertThat(Adapters.PRINTABLE_STRING.toDer("hi")).isEqualTo(bytes) assertThat(Adapters.PRINTABLE_STRING.toDer("hi")).isEqualTo(bytes)
} }
@Test fun `decode utc time with offset`() { @Test fun `cannot decode utc time with offset`() {
val time = Adapters.UTC_TIME.fromDer("17113139313231353139303231302d30383030".decodeHex()) try {
assertThat(time).isEqualTo(date("2019-12-16T03:02:10.000+0000").time) Adapters.UTC_TIME.fromDer("17113139313231353139303231302d30383030".decodeHex())
fail()
} catch (expected: ProtocolException) {
assertThat(expected).hasMessage("Failed to parse UTCTime 191215190210-0800")
}
} }
@Test fun `utc time`() { @Test fun `utc time`() {
@@ -649,10 +654,13 @@ internal class DerTest {
} }
} }
@Test fun `decode generalized time with offset`() { @Test fun `cannot decode generalized time with offset`() {
val time = Adapters.GENERALIZED_TIME try {
.fromDer("181332303139313231353139303231302d30383030".decodeHex()) Adapters.GENERALIZED_TIME.fromDer("181332303139313231353139303231302d30383030".decodeHex())
assertThat(time).isEqualTo(date("2019-12-16T03:02:10.000+0000").time) fail()
} catch (expected: ProtocolException) {
assertThat(expected).hasMessage("Failed to parse GeneralizedTime 20191215190210-0800")
}
} }
@Test fun `generalized time`() { @Test fun `generalized time`() {
@@ -672,23 +680,25 @@ internal class DerTest {
} }
} }
@Test fun `parse utc time`() {
assertThat(Adapters.parseUtcTime("920521000000Z"))
.isEqualTo(date("1992-05-21T00:00:00.000+0000").time)
assertThat(Adapters.parseUtcTime("920622123421Z"))
.isEqualTo(date("1992-06-22T12:34:21.000+0000").time)
assertThat(Adapters.parseUtcTime("920722132100Z"))
.isEqualTo(date("1992-07-22T13:21:00.000+0000").time)
}
@Test fun `decode utc time two digit year cutoff is 1950`() { @Test fun `decode utc time two digit year cutoff is 1950`() {
assertThat(Adapters.parseUtcTime("500101000000-0000")) assertThat(Adapters.parseUtcTime("500101000000Z"))
.isEqualTo(date("1950-01-01T00:00:00.000+0000").time) .isEqualTo(date("1950-01-01T00:00:00.000+0000").time)
assertThat(Adapters.parseUtcTime("500101000000-0100")) assertThat(Adapters.parseUtcTime("500101010000Z"))
.isEqualTo(date("1950-01-01T01:00:00.000+0000").time) .isEqualTo(date("1950-01-01T01:00:00.000+0000").time)
assertThat(Adapters.parseUtcTime("491231235959+0100")) assertThat(Adapters.parseUtcTime("491231225959Z"))
.isEqualTo(date("2049-12-31T22:59:59.000+0000").time) .isEqualTo(date("2049-12-31T22:59:59.000+0000").time)
assertThat(Adapters.parseUtcTime("491231235959-0000")) assertThat(Adapters.parseUtcTime("491231235959Z"))
.isEqualTo(date("2049-12-31T23:59:59.000+0000").time) .isEqualTo(date("2049-12-31T23:59:59.000+0000").time)
// Note that time zone offsets aren't honored by Java's two-digit offset boundary! A savvy time
// traveler could exploit this to get a certificate that expires 100 years later than expected.
assertThat(Adapters.parseUtcTime("500101000000+0100"))
.isEqualTo(date("2049-12-31T23:00:00.000+0000").time)
assertThat(Adapters.parseUtcTime("491231235959-0100"))
.isEqualTo(date("2050-01-01T00:59:59.000+0000").time)
} }
@Test fun `encode utc time two digit year cutoff is 1950`() { @Test fun `encode utc time two digit year cutoff is 1950`() {
@@ -699,14 +709,24 @@ internal class DerTest {
} }
@Test fun `parse generalized time`() { @Test fun `parse generalized time`() {
assertThat(Adapters.parseGeneralizedTime("18990101000000-0000")) assertThat(Adapters.parseGeneralizedTime("18990101000000Z"))
.isEqualTo(date("1899-01-01T00:00:00.000+0000").time) .isEqualTo(date("1899-01-01T00:00:00.000+0000").time)
assertThat(Adapters.parseGeneralizedTime("19500101000000-0000")) assertThat(Adapters.parseGeneralizedTime("19500101000000Z"))
.isEqualTo(date("1950-01-01T00:00:00.000+0000").time) .isEqualTo(date("1950-01-01T00:00:00.000+0000").time)
assertThat(Adapters.parseGeneralizedTime("20500101000000-0000")) assertThat(Adapters.parseGeneralizedTime("20500101000000Z"))
.isEqualTo(date("2050-01-01T00:00:00.000+0000").time) .isEqualTo(date("2050-01-01T00:00:00.000+0000").time)
assertThat(Adapters.parseGeneralizedTime("20990101000000-0000")) assertThat(Adapters.parseGeneralizedTime("20990101000000Z"))
.isEqualTo(date("2099-01-01T00:00:00.000+0000").time) .isEqualTo(date("2099-01-01T00:00:00.000+0000").time)
assertThat(Adapters.parseGeneralizedTime("19920521000000Z"))
.isEqualTo(date("1992-05-21T00:00:00.000+0000").time)
assertThat(Adapters.parseGeneralizedTime("19920622123421Z"))
.isEqualTo(date("1992-06-22T12:34:21.000+0000").time)
}
@Ignore("fractional seconds are not implemented")
@Test fun `parse generalized time with fractional seconds`() {
assertThat(Adapters.parseGeneralizedTime("19920722132100.3Z"))
.isEqualTo(date("1992-07-22T13:21:00.300+0000").time)
} }
@Test fun `format generalized time`() { @Test fun `format generalized time`() {