diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/SctVerificationResult.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/SctVerificationResult.kt index cdac9209..5004d08f 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/SctVerificationResult.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/SctVerificationResult.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ package com.appmattus.certificatetransparency import com.appmattus.certificatetransparency.internal.verifier.model.SignedCertificateTimestamp -import java.time.Instant /** * Abstract class providing the results of verifying a Signed Certificate Timestamp @@ -66,7 +65,7 @@ public sealed interface SctVerificationResult { * @property timestamp The timestamp of the SCT * @property now The time now */ - public data class FutureTimestamp(val timestamp: Instant, val now: Instant) : Invalid { + public data class FutureTimestamp(val timestamp: Long, val now: Long) : Invalid { /** * Returns a string representation of the object. */ @@ -78,7 +77,7 @@ public sealed interface SctVerificationResult { * @property timestamp The timestamp of the SCT * @property logServerValidUntil The time the log server was valid till */ - public data class LogServerUntrusted(val timestamp: Instant, val logServerValidUntil: Instant) : Invalid { + public data class LogServerUntrusted(val timestamp: Long, val logServerValidUntil: Long) : Invalid { /** * Returns a string representation of the object. */ diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339Deserializer.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339Deserializer.kt index 4034efa9..3994c309 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339Deserializer.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339Deserializer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,18 @@ package com.appmattus.certificatetransparency.internal.loglist.deserializer -import com.appmattus.certificatetransparency.internal.utils.toRfc3339Instant +import com.appmattus.certificatetransparency.internal.utils.toRfc3339Long import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -import java.time.Instant -internal class Rfc3339Deserializer : KSerializer { +internal class Rfc3339Deserializer : KSerializer { override val descriptor = PrimitiveSerialDescriptor("Rfc3339", PrimitiveKind.STRING) - override fun deserialize(decoder: Decoder) = decoder.decodeString().toRfc3339Instant() + override fun deserialize(decoder: Decoder) = decoder.decodeString().toRfc3339Long() - override fun serialize(encoder: Encoder, value: Instant) = error("Serialization not supported") + override fun serialize(encoder: Encoder, value: Long) = error("Serialization not supported") } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3.kt index 6bde7f92..e367f44b 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ package com.appmattus.certificatetransparency.internal.loglist.model.v3 import com.appmattus.certificatetransparency.internal.loglist.deserializer.Rfc3339Deserializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import java.time.Instant /** * @property logListTimestamp The time at which this version of the log list was published. @@ -34,7 +33,7 @@ import java.time.Instant internal data class LogListV3( @Serializable(with = Rfc3339Deserializer::class) @SerialName("log_list_timestamp") - val logListTimestamp: Instant, + val logListTimestamp: Long, @SerialName("version") val version: String, @SerialName("operators") val operators: List ) diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/PreviousOperator.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/PreviousOperator.kt index aa2cd418..eed5b3cc 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/PreviousOperator.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/PreviousOperator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package com.appmattus.certificatetransparency.internal.loglist.model.v3 import com.appmattus.certificatetransparency.internal.loglist.deserializer.Rfc3339Deserializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import java.time.Instant /** * @property name Name of the log operator @@ -30,6 +29,6 @@ import java.time.Instant internal data class PreviousOperator( @Serializable(with = Rfc3339Deserializer::class) @SerialName("end_time") - val endDate: Instant, + val endDate: Long, @SerialName("name") val name: String ) diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/State.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/State.kt index baab0638..8bd6e919 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/State.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/State.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,14 +23,13 @@ package com.appmattus.certificatetransparency.internal.loglist.model.v3 import com.appmattus.certificatetransparency.internal.loglist.deserializer.Rfc3339Deserializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import java.time.Instant /** * @property timestamp The time at which the log entered this state. */ @Serializable internal sealed class State { - abstract val timestamp: Instant + abstract val timestamp: Long /** * An SCT associated with this log server would be treated as untrusted @@ -40,7 +39,7 @@ internal sealed class State { data class Pending( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant + override val timestamp: Long ) : State() /** @@ -51,7 +50,7 @@ internal sealed class State { data class Qualified( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant + override val timestamp: Long ) : State() /** @@ -62,7 +61,7 @@ internal sealed class State { data class Usable( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant + override val timestamp: Long ) : State() /** @@ -74,7 +73,7 @@ internal sealed class State { data class ReadOnly( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant, + override val timestamp: Long, @SerialName("final_tree_head") val finalTreeHead: FinalTreeHead ) : State() @@ -86,7 +85,7 @@ internal sealed class State { data class Retired( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant + override val timestamp: Long ) : State() /** @@ -97,6 +96,6 @@ internal sealed class State { data class Rejected( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - override val timestamp: Instant + override val timestamp: Long ) : State() } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/TemporalInterval.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/TemporalInterval.kt index 260ebd7d..c6619b30 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/TemporalInterval.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/TemporalInterval.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ package com.appmattus.certificatetransparency.internal.loglist.model.v3 import com.appmattus.certificatetransparency.internal.loglist.deserializer.Rfc3339Deserializer import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import java.time.Instant /** * @property startInclusive All certificates must expire on this date or later. (format: date-time) @@ -33,8 +32,8 @@ import java.time.Instant internal data class TemporalInterval( @Serializable(with = Rfc3339Deserializer::class) @SerialName("start_inclusive") - val startInclusive: Instant, + val startInclusive: Long, @Serializable(with = Rfc3339Deserializer::class) @SerialName("end_exclusive") - val endExclusive: Instant + val endExclusive: Long ) diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/serialization/Deserializer.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/serialization/Deserializer.kt index 92c26e3a..cb5fe2f6 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/serialization/Deserializer.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/serialization/Deserializer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2020 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,6 @@ import com.appmattus.certificatetransparency.internal.verifier.model.SignedCerti import com.appmattus.certificatetransparency.internal.verifier.model.Version import java.io.IOException import java.io.InputStream -import java.time.Instant import kotlin.math.ceil import kotlin.math.log2 @@ -50,7 +49,7 @@ internal object Deserializer { val keyId = inputStream.readFixedLength(CTConstants.KEY_ID_LENGTH) - val timestamp = Instant.ofEpochMilli(inputStream.readNumber(CTConstants.TIMESTAMP_LENGTH)) + val timestamp = inputStream.readNumber(CTConstants.TIMESTAMP_LENGTH) val extensions = inputStream.readVariableLength(CTConstants.MAX_EXTENSIONS_LENGTH) diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339.kt index a60d7202..19848ffa 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339.kt @@ -14,18 +14,18 @@ * Derived from https://github.com/googleapis/google-http-java-client/blob/dev/google-http-client/src/main/java/com/google/api/client/util/DateTime.java * * Modified 2018 by Babylon Partners Limited - * Modified 2021-2023 by Appmattus Limited + * Modified 2021-2024 by Appmattus Limited */ package com.appmattus.certificatetransparency.internal.utils -import java.time.Duration -import java.time.Instant -import java.time.LocalDate -import java.time.LocalTime -import java.time.ZoneOffset +import java.util.Calendar +import java.util.GregorianCalendar +import java.util.TimeZone import kotlin.math.pow +private val GMT = TimeZone.getTimeZone("GMT") + /** Regular expression for parsing RFC3339 date/times. */ private val Rfc3339Pattern = Regex( // yyyy-MM-dd @@ -53,50 +53,53 @@ private val Rfc3339Pattern = Regex( */ // Magic numbers accepted as very much linked to the pattern @Suppress("MagicNumber") -internal fun String.toRfc3339Instant(): Instant { - val results = Rfc3339Pattern.matchEntire(this) ?: throw NumberFormatException( - "Invalid RFC3339 date/time format: $this" - ) +internal fun String.toRfc3339Long(): Long { + val results = Rfc3339Pattern.matchEntire(this) ?: throw NumberFormatException("Invalid RFC3339 date/time format: $this") - val localDate = LocalDate.of( - results.groupValues[1].toInt(), // yyyy - results.groupValues[2].toInt(), // MM - results.groupValues[3].toInt() // dd - ) + val year = results.groupValues[1].toInt() // yyyy + val month = results.groupValues[2].toInt() - 1 // MM + val day = results.groupValues[3].toInt() // dd val isTimeGiven = results.groupValues[4].isNotEmpty() // 'T'HH:mm:ss.milliseconds val tzShiftRegexGroup = results.groupValues[9] // 'Z', or time zone shift HH:mm following '+'/'-' val isTzShiftGiven = tzShiftRegexGroup.isNotEmpty() + var hourOfDay = 0 + var minute = 0 + var second = 0 + var milliseconds = 0 if (isTzShiftGiven && !isTimeGiven) { - throw NumberFormatException( - "Invalid RFC33339 date/time format, cannot specify time zone shift without specifying time: $this" - ) + throw NumberFormatException("Invalid RFC33339 date/time format, cannot specify time zone shift without specifying time: $this") } - val localTime = if (isTimeGiven) { - LocalTime.of( - results.groupValues[5].toInt(), // HH - results.groupValues[6].toInt(), // mm - results.groupValues[7].toInt(), // ss - results.groupValues[8].ifEmpty { ".000" }.substring(1).let { // nanoseconds - // The number of digits after the dot may not be 3. Need to renormalize. - val fractionDigits = it.length - 3 - (it.toDouble() / 10.0.pow(fractionDigits.toDouble())).toInt() * 1_000_000 - } - ) - } else { - LocalTime.MIN + if (isTimeGiven) { + hourOfDay = results.groupValues[5].toInt() // HH + minute = results.groupValues[6].toInt() // mm + second = results.groupValues[7].toInt() // ss + if (results.groupValues[8].isNotEmpty()) { // contains .milliseconds? + milliseconds = results.groupValues[8].substring(1).toInt() // milliseconds + // The number of digits after the dot may not be 3. Need to renormalize. + val fractionDigits = results.groupValues[8].substring(1).length - 3 + milliseconds = (milliseconds.toDouble() / 10.0.pow(fractionDigits.toDouble())).toInt() + } } + val dateTime = GregorianCalendar(GMT) + dateTime.set(year, month, day, hourOfDay, minute, second) + dateTime.set(Calendar.MILLISECOND, milliseconds) + var value = dateTime.timeInMillis - val tzShift = if (isTzShiftGiven && tzShiftRegexGroup[0].uppercaseChar() != 'Z') { - // time zone shift HH - (results.groupValues[11].toInt() * 60 + results.groupValues[12].toInt()) * - // time zone shift + or - - (if (results.groupValues[10][0] == '-') -1 else 1) - } else { - 0 + if (isTimeGiven && isTzShiftGiven) { + @Suppress("EXPERIMENTAL_API_USAGE_ERROR") + if (tzShiftRegexGroup[0].uppercaseChar() != 'Z') { + var tzShift = ( + results.groupValues[11].toInt() * 60 + // time zone shift HH + results.groupValues[12].toInt() + ) // time zone shift mm + if (results.groupValues[10][0] == '-') { // time zone shift + or - + tzShift = -tzShift + } + value -= tzShift * 60000L // e.g. if 1 hour ahead of UTC, subtract an hour to get UTC time + } } - // e.g. if 1 hour ahead of UTC, subtract an hour to get UTC time - return localDate.atTime(localTime).toInstant(ZoneOffset.UTC) - Duration.ofMinutes(tzShift.toLong()) + return value } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1.kt index ec341c36..25d3e5f3 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2023-2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ internal fun ByteBuffer.header(logger: ASN1Logger): ASN1Header { return ASN1Header(tag, headerLength.offset, headerLength.length) } -@Suppress("MagicNumber") +@Suppress("MagicNumber", "CyclomaticComplexMethod") internal fun ByteBuffer.toAsn1(logger: ASN1Logger = EmptyLogger): ASN1Object { val header = header(logger) @@ -58,7 +58,8 @@ internal fun ByteBuffer.toAsn1(logger: ASN1Logger = EmptyLogger): ASN1Object { tag.isUniversal(0x0c) -> ASN1PrintableStringUS.create(tag, encoded, logger) tag.isUniversal(0x10) || tag.isUniversal(0x11) -> ASN1Sequence.create(tag, encoded, logger) tag.isUniversal(0x13) -> ASN1PrintableStringTeletex.create(tag, encoded, logger) - tag.isUniversal(0x17) -> ASN1Time.create(tag, encoded, logger) + tag.isUniversal(0x17) -> UTCTime.create(tag, encoded, logger) + tag.isUniversal(0x18) -> GeneralizedTime.create(tag, encoded, logger) tag.isContextSpecific(0x00) -> Version.create(tag, encoded, logger) tag.isContextSpecific(0x03) -> Extensions.create(tag, encoded, logger) else -> ASN1Unspecified.create(tag, encoded, logger) diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1Time.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1Time.kt index 50d53c54..46414089 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1Time.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/ASN1Time.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,32 +16,8 @@ package com.appmattus.certificatetransparency.internal.utils.asn1 -import com.appmattus.certificatetransparency.internal.utils.asn1.bytes.ByteBuffer -import com.appmattus.certificatetransparency.internal.utils.asn1.header.ASN1HeaderTag -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneOffset -import java.time.format.DateTimeFormatter +import java.util.Date -internal class ASN1Time private constructor( - override val tag: ASN1HeaderTag, - override val encoded: ByteBuffer, - override val logger: ASN1Logger -) : ASN1Object() { - - val value: Instant by lazy { - @Suppress("MagicNumber") - val pattern = if (encoded.size == 13) "yyMMddHHmmss'Z'" else "yyyyMMddHHmmss'Z'" - val formatter = DateTimeFormatter.ofPattern(pattern) - - val time = encoded.toList().toByteArray().decodeToString() - - LocalDateTime.parse(time, formatter).toInstant(ZoneOffset.UTC) - } - - override fun toString(): String = "TIME $value" - - companion object { - fun create(tag: ASN1HeaderTag, encoded: ByteBuffer, logger: ASN1Logger) = ASN1Time(tag, encoded, logger) - } +internal interface ASN1Time { + val value: Date } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/GeneralizedTime.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/GeneralizedTime.kt new file mode 100644 index 00000000..a464a8c1 --- /dev/null +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/GeneralizedTime.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Appmattus Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.appmattus.certificatetransparency.internal.utils.asn1 + +import com.appmattus.certificatetransparency.internal.utils.asn1.bytes.ByteBuffer +import com.appmattus.certificatetransparency.internal.utils.asn1.header.ASN1HeaderTag +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +internal class GeneralizedTime private constructor( + override val tag: ASN1HeaderTag, + override val encoded: ByteBuffer, + override val logger: ASN1Logger +) : ASN1Object(), ASN1Time { + + override val value: Date by lazy { + // RFC5280 specifies: + // For the purposes of this profile, GeneralizedTime values MUST be + // expressed in Greenwich Mean Time (Zulu) and MUST include seconds + // (i.e., times are YYYYMMDDHHMMSSZ), even where the number of seconds + // is zero. GeneralizedTime values MUST NOT include fractional seconds. + // https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5.2 + val time = encoded.toList().toByteArray().decodeToString() + SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.ROOT).parse(time) + } + + override fun toString(): String = "TIME $value" + + companion object { + fun create(tag: ASN1HeaderTag, encoded: ByteBuffer, logger: ASN1Logger) = GeneralizedTime(tag, encoded, logger) + } +} diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/UTCTime.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/UTCTime.kt new file mode 100644 index 00000000..e2637689 --- /dev/null +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/UTCTime.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2024 Appmattus Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.appmattus.certificatetransparency.internal.utils.asn1 + +import com.appmattus.certificatetransparency.internal.utils.asn1.bytes.ByteBuffer +import com.appmattus.certificatetransparency.internal.utils.asn1.header.ASN1HeaderTag +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +internal class UTCTime private constructor( + override val tag: ASN1HeaderTag, + override val encoded: ByteBuffer, + override val logger: ASN1Logger +) : ASN1Object(), ASN1Time { + + override val value: Date by lazy { + // RFC5280 specifies: + // For the purposes of this profile, UTCTime values MUST be expressed in + // Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are + // YYMMDDHHMMSSZ), even where the number of seconds is zero. Conforming + // systems MUST interpret the year field (YY) as follows: + // - Where YY is greater than or equal to 50, the year SHALL be + // interpreted as 19YY; and + // - Where YY is less than 50, the year SHALL be interpreted as 20YY. + val time = encoded.toList().toByteArray().decodeToString() + SimpleDateFormat("yyMMddHHmmss'Z'", Locale.ROOT).parse(time) + } + + override fun toString(): String = "TIME $value" + + companion object { + fun create(tag: ASN1HeaderTag, encoded: ByteBuffer, logger: ASN1Logger) = UTCTime(tag, encoded, logger) + } +} diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/x509/Validity.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/x509/Validity.kt index bc3aaf48..ff19d55f 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/x509/Validity.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/utils/asn1/x509/Validity.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,6 @@ import com.appmattus.certificatetransparency.internal.utils.asn1.ASN1Sequence import com.appmattus.certificatetransparency.internal.utils.asn1.ASN1Time import com.appmattus.certificatetransparency.internal.utils.asn1.bytes.ByteBuffer import com.appmattus.certificatetransparency.internal.utils.asn1.header.ASN1HeaderTag -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle internal class Validity private constructor(private val sequence: ASN1Sequence) : ASN1Object() { @@ -43,13 +40,9 @@ internal class Validity private constructor(private val sequence: ASN1Sequence) override fun toString(): String = "Not Valid Before ${ - notValidBefore.value.atZone(ZoneId.systemDefault()).format( - DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL) - ) + notValidBefore.value }\nNot Valid After ${ - notValidAfter.value.atZone(ZoneId.systemDefault()).format( - DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL) - ) + notValidAfter.value }" companion object { diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicy.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicy.kt index 16a63a5d..0472f49c 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicy.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicy.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,10 +24,11 @@ import com.appmattus.certificatetransparency.CTPolicy import com.appmattus.certificatetransparency.SctVerificationResult import com.appmattus.certificatetransparency.VerificationResult import java.security.cert.X509Certificate -import java.time.Instant -import java.time.ZoneOffset -import java.time.ZonedDateTime -import java.time.temporal.ChronoUnit +import java.util.Calendar +import java.util.Date +import java.util.GregorianCalendar +import java.util.concurrent.TimeUnit +import kotlin.math.abs /** * Default [CTPolicy] which follows most of the rules of https://github.com/GoogleChrome/CertificateTransparency/blob/master/ct_policy.md @@ -42,14 +43,15 @@ internal class DefaultPolicy : CTPolicy { val validScts = sctResults.values.filterIsInstance() // By default we use the 2022 policy when there are no valid SCTs - val issuanceDate = validScts.minOfOrNull { it.sct.timestamp } ?: Instant.MAX - val use2022policy = issuanceDate >= policyUpdateDate + val issuanceDate = validScts.minOfOrNull { it.sct.timestamp } ?: Long.MAX_VALUE + val use2022policy = issuanceDate >= POLICY_UPDATE_DATE - val before = leafCertificate.notBefore.toInstant().atZone(ZoneOffset.UTC) - val after = leafCertificate.notAfter.toInstant().atZone(ZoneOffset.UTC) + val before = leafCertificate.notBefore + val after = leafCertificate.notAfter + val daysBetween = TimeUnit.DAYS.convert(after.time - before.time, TimeUnit.MILLISECONDS) val minimumValidSignedCertificateTimestamps = if (use2022policy) { - if (ChronoUnit.DAYS.between(before, after) > 180) 3 else 2 + if (daysBetween > 180) 3 else 2 } else { val (lifetimeInMonths, hasPartialMonth) = roundedDownMonthDifference(before, after) @@ -70,22 +72,25 @@ internal class DefaultPolicy : CTPolicy { } } - private fun roundedDownMonthDifference(start: ZonedDateTime, expiry: ZonedDateTime): MonthDifference { + private fun roundedDownMonthDifference(start: Date, expiry: Date): MonthDifference { if (expiry < start) { return MonthDifference(roundedMonthDifference = 0, hasPartialMonth = false) } @Suppress("MagicNumber") return MonthDifference( - roundedMonthDifference = ChronoUnit.MONTHS.between(start, expiry).toInt(), + roundedMonthDifference = (abs(start.time - expiry.time) / 2629746000).toInt(), hasPartialMonth = expiry.dayOfMonth != start.dayOfMonth ) } + private val Date.dayOfMonth: Int + get() = GregorianCalendar().apply { time = this@dayOfMonth }.get(Calendar.DAY_OF_MONTH) + private data class MonthDifference(val roundedMonthDifference: Int, val hasPartialMonth: Boolean) companion object { // 15 April 2022 - private val policyUpdateDate = Instant.ofEpochMilli(1649980800000) + private const val POLICY_UPDATE_DATE = 1649980800000 } } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifier.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifier.kt index 8d13ba32..8dbac1d3 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifier.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -56,7 +56,6 @@ import java.security.cert.CertificateEncodingException import java.security.cert.CertificateException import java.security.cert.CertificateParsingException import java.security.cert.X509Certificate -import java.time.Instant /** * Verifies signatures from a given CT Log. @@ -69,7 +68,7 @@ internal class LogSignatureVerifier(private val logServer: LogServer) : Signatur @Suppress("ReturnCount", "ComplexMethod") override fun verifySignature(sct: SignedCertificateTimestamp, chain: List): SctVerificationResult { // If the timestamp is in the future then we have to reject it - val now = Instant.now() + val now = System.currentTimeMillis() if (sct.timestamp > now) { return SctVerificationResult.Invalid.FutureTimestamp(sct.timestamp, now) } @@ -283,7 +282,7 @@ internal class LogSignatureVerifier(private val logServer: LogServer) : Signatur require(sct.sctVersion == Version.V1) { "Can only serialize SCT v1 for now." } writeUint(sct.sctVersion.number.toLong(), VERSION_LENGTH) // ct::V1 writeUint(0, 1) // ct::CERTIFICATE_TIMESTAMP - writeUint(sct.timestamp.toEpochMilli(), TIMESTAMP_LENGTH) // Timestamp + writeUint(sct.timestamp, TIMESTAMP_LENGTH) // Timestamp } companion object { diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/model/SignedCertificateTimestamp.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/model/SignedCertificateTimestamp.kt index e575d091..148171e1 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/model/SignedCertificateTimestamp.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/internal/verifier/model/SignedCertificateTimestamp.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,8 +20,6 @@ package com.appmattus.certificatetransparency.internal.verifier.model -import java.time.Instant - /** * A signed certificate timestamp. If the [sctVersion] is not [Version.V1], then a v1 client may be unable to verify the signature. * @@ -37,7 +35,7 @@ import java.time.Instant public data class SignedCertificateTimestamp( val sctVersion: Version = Version.UNKNOWN_VERSION, val id: LogId, - val timestamp: Instant, + val timestamp: Long, val signature: DigitallySigned, val extensions: ByteArray ) { diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSource.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSource.kt index f5a380db..607232f4 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSource.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2023-2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,6 @@ import com.appmattus.certificatetransparency.internal.loglist.LogListZipNetworkD import com.appmattus.certificatetransparency.internal.loglist.ResourcesCache import com.appmattus.certificatetransparency.internal.loglist.parser.RawLogListToLogListResultTransformer import java.security.PublicKey -import java.time.Duration -import java.time.Instant @Suppress("LongParameterList") internal class LogListCacheManagementDataSource constructor( @@ -34,7 +32,7 @@ internal class LogListCacheManagementDataSource constructor( private val networkCache: LogListZipNetworkDataSource, private val publicKey: PublicKey, private val transformer: RawLogListToLogListResultTransformer = RawLogListToLogListResultTransformer(publicKey), - private val now: () -> Instant + private val now: () -> Long ) : DataSource { @Suppress("ReturnCount") @@ -134,8 +132,8 @@ internal class LogListCacheManagementDataSource constructor( } companion object { - private val ONE_DAY = Duration.ofMillis(86400000) - private val FOURTEEN_DAYS = Duration.ofMillis(1209600000) - private val SEVENTY_DAYS = Duration.ofMillis(6048000000) + private const val ONE_DAY = 86400000 + private const val FOURTEEN_DAYS = 1209600000 + private const val SEVENTY_DAYS = 6048000000 } } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactory.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactory.kt index d8238676..1df33e01 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactory.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactory.kt @@ -36,7 +36,6 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.internal.platform.Platform import java.security.PublicKey -import java.time.Instant import java.util.concurrent.TimeUnit import javax.net.ssl.X509TrustManager @@ -111,10 +110,7 @@ public object LogListDataSourceFactory { logListService: LogListService = createLogListService(), diskCache: DiskCache? = null, publicKey: PublicKey = GoogleLogListPublicKey, - now: () -> Instant = { - @Suppress("NewApi") - Instant.now() - } + now: () -> Long = { System.currentTimeMillis() } ): DataSource = LogListCacheManagementDataSource( inMemoryCache = InMemoryCache(), diskCache = diskCache, diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListResult.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListResult.kt index ef37ef3a..74b1aef2 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListResult.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogListResult.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,23 +22,22 @@ package com.appmattus.certificatetransparency.loglist import com.appmattus.certificatetransparency.internal.utils.stringStackTrace import kotlinx.serialization.SerializationException -import java.time.Instant public sealed interface LogListResult { /** * Interface representing log list loading successful */ public sealed interface Valid : LogListResult { - public val timestamp: Instant + public val timestamp: Long public val servers: List - public data class Success(override val timestamp: Instant, override val servers: List) : Valid + public data class Success(override val timestamp: Long, override val servers: List) : Valid /** * Network is returning stale data so this denotes we are returning locally cached data to reduce the chance of replay attacks */ public data class StaleNetworkUsingCachedData( - override val timestamp: Instant, + override val timestamp: Long, override val servers: List, val networkResult: Valid ) : Valid @@ -47,7 +46,7 @@ public sealed interface LogListResult { * Network is returning stale data so this denotes there is potentially a network issue */ public data class StaleNetworkUsingNetworkData( - override val timestamp: Instant, + override val timestamp: Long, override val servers: List ) : Valid } @@ -55,7 +54,7 @@ public sealed interface LogListResult { /** * Class representing log list stale data */ - public data class DisableChecks(val timestamp: Instant, val networkResult: LogListResult) : LogListResult + public data class DisableChecks(val timestamp: Long, val networkResult: LogListResult) : LogListResult /** * Interface representing log list loading failed diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogServer.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogServer.kt index f740e511..239927ea 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogServer.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/LogServer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,6 @@ package com.appmattus.certificatetransparency.loglist import com.appmattus.certificatetransparency.internal.utils.sha256Hash import java.security.PublicKey -import java.time.Instant /** * Representation of a log server, usually loaded from log-list.json @@ -31,7 +30,7 @@ import java.time.Instant */ public data class LogServer( val key: PublicKey, - val validUntil: Instant? = null, + val validUntil: Long? = null, val operator: String, val previousOperators: List ) { @@ -40,7 +39,7 @@ public data class LogServer( */ val id: ByteArray = key.sha256Hash() - public fun operatorAt(timestamp: Instant): String { + public fun operatorAt(timestamp: Long): String { previousOperators.sortedBy { it.endDate }.forEach { if (timestamp < it.endDate) return it.name } diff --git a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/PreviousOperator.kt b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/PreviousOperator.kt index ec44fda2..d4006677 100644 --- a/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/PreviousOperator.kt +++ b/certificatetransparency/src/main/kotlin/com/appmattus/certificatetransparency/loglist/PreviousOperator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package com.appmattus.certificatetransparency.loglist -import java.time.Instant - -public data class PreviousOperator(val name: String, val endDate: Instant) { +public data class PreviousOperator(val name: String, val endDate: Long) { public companion object } diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyBaseTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyBaseTest.kt index a287ddf4..e82b4790 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyBaseTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyBaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -43,7 +43,6 @@ import org.junit.Test import org.mockito.kotlin.spy import org.mockito.kotlin.whenever import java.security.cert.X509Certificate -import java.time.Instant import javax.net.ssl.SSLPeerUnverifiedException import javax.net.ssl.X509TrustManager @@ -102,7 +101,7 @@ internal class CertificateTransparencyBaseTest { val ctb = CertificateTransparencyBase( logListDataSource = object : DataSource { override suspend fun get() = LogListResult.DisableChecks( - Instant.now(), + System.currentTimeMillis(), LogListResult.Invalid.LogListJsonFailedLoading ) @@ -128,7 +127,7 @@ internal class CertificateTransparencyBaseTest { override suspend fun get() = LogListResult.Valid.StaleNetworkUsingCachedData( timestamp = (LogListDataSourceTestFactory.logListDataSource.get() as LogListResult.Valid.Success).timestamp, servers = (LogListDataSourceTestFactory.logListDataSource.get() as LogListResult.Valid.Success).servers, - networkResult = LogListResult.Valid.Success(Instant.now(), emptyList()) + networkResult = LogListResult.Valid.Success(System.currentTimeMillis(), emptyList()) ) override suspend fun set(value: LogListResult) = Unit @@ -177,9 +176,9 @@ internal class CertificateTransparencyBaseTest { val ctb = CertificateTransparencyBase( logListDataSource = object : DataSource { override suspend fun get() = LogListResult.Valid.StaleNetworkUsingCachedData( - timestamp = Instant.now(), + timestamp = System.currentTimeMillis(), servers = emptyList(), - networkResult = LogListResult.Valid.Success(Instant.now(), emptyList()) + networkResult = LogListResult.Valid.Success(System.currentTimeMillis(), emptyList()) ) override suspend fun set(value: LogListResult) = Unit @@ -202,7 +201,7 @@ internal class CertificateTransparencyBaseTest { val ctb = CertificateTransparencyBase( logListDataSource = object : DataSource { override suspend fun get() = LogListResult.Valid.StaleNetworkUsingNetworkData( - timestamp = Instant.now(), + timestamp = System.currentTimeMillis(), servers = emptyList(), ) diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyProviderIntegrationTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyProviderIntegrationTest.kt index f2059f37..8daf54df 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyProviderIntegrationTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/CertificateTransparencyProviderIntegrationTest.kt @@ -38,6 +38,7 @@ import org.junit.Assert.assertThrows import org.junit.Assert.assertTrue import org.junit.Test import java.security.Security +import java.util.concurrent.TimeUnit import javax.net.ssl.SSLHandshakeException internal class CertificateTransparencyProviderIntegrationTest { @@ -243,6 +244,8 @@ internal class CertificateTransparencyProviderIntegrationTest { .build() val client = OkHttpClient.Builder() + .connectTimeout(20, TimeUnit.SECONDS) + .readTimeout(20, TimeUnit.SECONDS) .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager) .build() diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339DeserializerTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339DeserializerTest.kt index 77b166f1..943d37e6 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339DeserializerTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/deserializer/Rfc3339DeserializerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,6 @@ import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized -import java.time.Instant @RunWith(Parameterized::class) internal class Rfc3339DeserializerTest { @@ -43,7 +42,7 @@ internal class Rfc3339DeserializerTest { data class TestObject( @Serializable(with = Rfc3339Deserializer::class) @SerialName("timestamp") - val timestamp: Instant + val timestamp: Long ) @Test @@ -55,7 +54,7 @@ internal class Rfc3339DeserializerTest { } else { val result = json.decodeFromString(TestObject.serializer(), "{\"timestamp\":\"$input\"}").timestamp - assertEquals(Instant.ofEpochMilli(expected.toLong()), result) + assertEquals(expected.toLong(), result) } } diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3Test.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3Test.kt index 97f2d3b2..b331cd78 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3Test.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/model/v3/LogListV3Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2025 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,6 @@ import kotlinx.serialization.json.Json import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test -import java.time.Instant internal class LogListV3Test { @@ -53,6 +52,6 @@ internal class LogListV3Test { val nimbusLog = cloudflare.logs.first { it.description == "Cloudflare 'Nimbus2022' Log" } assertEquals(86400, nimbusLog.maximumMergeDelay) // Suppressing MobSF warning as false positive, no logging occurs here - assertEquals(Instant.ofEpochMilli(1572549720000), nimbusLog.state?.timestamp) // mobsf-ignore: android_kotlin_logging + assertEquals(1572549720000, nimbusLog.state?.timestamp) // mobsf-ignore: android_kotlin_logging } } diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/LogListJsonParserV3Test.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/LogListJsonParserV3Test.kt index 34e8112a..df9f96f6 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/LogListJsonParserV3Test.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/LogListJsonParserV3Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test -import java.time.Instant internal class LogListJsonParserV3Test { @@ -84,7 +83,7 @@ internal class LogListJsonParserV3Test { val logServer = result.servers.first { it.id.contentEquals(symantecId) } assertNotNull(logServer.validUntil) - assertEquals(Instant.ofEpochMilli(1588550440000), logServer.validUntil) + assertEquals(1588550440000, logServer.validUntil) } companion object { diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/RawLogListToLogListResultTransformerTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/RawLogListToLogListResultTransformerTest.kt index 3bfcadc1..18b0a2cd 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/RawLogListToLogListResultTransformerTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/loglist/parser/RawLogListToLogListResultTransformerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2020 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,7 +37,6 @@ import java.security.KeyPair import java.security.KeyPairGenerator import java.security.PrivateKey import java.security.Signature -import java.time.Instant import javax.net.ssl.SSLException internal class RawLogListToLogListResultTransformerTest { @@ -190,7 +189,7 @@ internal class RawLogListToLogListResultTransformerTest { assertIsA(result) val logServer = result.servers[3] assertNotNull(logServer.validUntil) - assertEquals(Instant.ofEpochMilli(1550275200000), logServer.validUntil) + assertEquals(1550275200000, logServer.validUntil) } private fun calculateSignature(privateKey: PrivateKey, data: ByteArray): ByteArray { diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/serialization/OutputStreamExtTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/serialization/OutputStreamExtTest.kt index 0a085224..1757fef4 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/serialization/OutputStreamExtTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/serialization/OutputStreamExtTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,6 @@ import com.appmattus.certificatetransparency.utils.TestData import org.junit.Assert.assertArrayEquals import org.junit.Test import java.io.ByteArrayOutputStream -import java.time.Instant /** Test serialization. */ internal class OutputStreamExtTest { @@ -50,7 +49,7 @@ internal class OutputStreamExtTest { val sct = SignedCertificateTimestamp( sctVersion = Version.V1, - timestamp = Instant.ofEpochMilli(1365181456089L), + timestamp = 1365181456089L, id = LogId(Base64.decode(keyIdBase64)), signature = signature, extensions = ByteArray(0) @@ -65,7 +64,7 @@ internal class OutputStreamExtTest { return ByteArrayOutputStream().use { it.writeUint(sct.sctVersion.number.toLong(), CTConstants.VERSION_LENGTH) it.write(sct.id.keyId) - it.writeUint(sct.timestamp.toEpochMilli(), CTConstants.TIMESTAMP_LENGTH) + it.writeUint(sct.timestamp, CTConstants.TIMESTAMP_LENGTH) it.writeVariableLength(sct.extensions, CTConstants.MAX_EXTENSIONS_LENGTH) it.writeUint(sct.signature.hashAlgorithm.number.toLong(), HASH_ALG_LENGTH) it.writeUint(sct.signature.signatureAlgorithm.number.toLong(), SIGNATURE_ALG_LENGTH) diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339Test.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339Test.kt index fa3066c0..67e5d750 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339Test.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/utils/Rfc3339Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,6 @@ import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized -import java.time.Instant @RunWith(Parameterized::class) internal class Rfc3339Test { @@ -39,10 +38,10 @@ internal class Rfc3339Test { fun test() { if (expected == "fail") { assertThrows(NumberFormatException::class.java) { - input.toRfc3339Instant() + input.toRfc3339Long() } } else { - assertEquals(Instant.ofEpochMilli(expected.toLong()), input.toRfc3339Instant()) + assertEquals(expected.toLong(), input.toRfc3339Long()) } } diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicyTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicyTest.kt index 6aa776b6..c294d9eb 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicyTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/DefaultPolicyTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,9 +35,6 @@ import org.junit.runners.Parameterized import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import java.security.cert.X509Certificate -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneId import java.util.Calendar import java.util.Date import java.util.UUID @@ -295,7 +292,8 @@ fun date(year: Int, month: Int, dayOfMonth: Int, hour: Int, minute: Int, second: private val oldPolicySct get() = SignedCertificateTimestamp( id = LogId(Random.nextBytes(10)), - timestamp = LocalDateTime.of(2022, 1, 1, 0, 0, 0).atZone(ZoneId.systemDefault()).toInstant(), + // 1 January 2022 + timestamp = 1640995200000, extensions = byteArrayOf(), signature = DigitallySigned(signature = byteArrayOf()) ) @@ -304,7 +302,7 @@ private val newPolicySct get() = SignedCertificateTimestamp( id = LogId(Random.nextBytes(10)), // 15 April 2022 - timestamp = Instant.ofEpochMilli(1649980800000), + timestamp = 1649980800000, extensions = byteArrayOf(), signature = DigitallySigned(signature = byteArrayOf()) ) diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifierTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifierTest.kt index c0e490b5..34619eb6 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifierTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/internal/verifier/LogSignatureVerifierTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,8 +61,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test import java.io.File -import java.time.Duration -import java.time.Instant /** * This test verifies that the data is correctly serialized for signature comparison, so signature @@ -276,7 +274,7 @@ internal class LogSignatureVerifierTest { // given we have an SCT with a future timestamp val certs = loadCertificates(TEST_CERT) val sct = Deserializer.parseSctFromBinary(TestData.file(TEST_CERT_SCT).inputStream()) - val futureSct = sct.copy(timestamp = Instant.now() + Duration.ofMillis(10000)) + val futureSct = sct.copy(timestamp = System.currentTimeMillis() + 10000) // when the signature is verified assertIsA(verifier.verifySignature(futureSct, certs)) @@ -290,7 +288,7 @@ internal class LogSignatureVerifierTest { // when we have a log server which is no longer valid val logInfo = LogServer.fromKeyFile(TestData.fileName(TEST_LOG_KEY)) - val verifier = LogSignatureVerifier(logInfo.copy(validUntil = sct.timestamp - Duration.ofMillis(10000))) + val verifier = LogSignatureVerifier(logInfo.copy(validUntil = sct.timestamp - 10000)) // then the signature is rejected assertIsA(verifier.verifySignature(sct, certs)) diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSourceTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSourceTest.kt index 649a7f6a..57e9cc3a 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSourceTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListCacheManagementDataSourceTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023 Appmattus Limited + * Copyright 2023-2024 Appmattus Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,8 +35,6 @@ import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.whenever import java.io.IOException -import java.time.Duration -import java.time.Instant import kotlin.random.Random internal class LogListCacheManagementDataSourceTest { @@ -68,7 +66,7 @@ internal class LogListCacheManagementDataSourceTest { on { transform(networkRawResult) } doReturn LogListResult.Invalid.NoLogServers } - private var now: Instant = defaultLogListTimestamp + private var now: Long = defaultLogListTimestamp private val dataSource = LogListCacheManagementDataSource( inMemoryCache = memoryCacheMock, diskCache = diskCacheMock, @@ -85,7 +83,7 @@ internal class LogListCacheManagementDataSourceTest { givenNetworkResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is 14 days (inclusive) old or less of the log list - now = defaultLogListTimestamp + Duration.ofMillis(Random.nextLong(FOURTEEN_DAYS_IN_MILLISECONDS + 1)) + now = defaultLogListTimestamp + Random.nextLong(FOURTEEN_DAYS_IN_MILLISECONDS + 1) // When we get data val result = dataSource.get() @@ -104,9 +102,7 @@ internal class LogListCacheManagementDataSourceTest { // Given no data in memory or disk cache and the network returns successfully givenNetworkResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is between 14 days (exclusive) and 70 days (inclusive) old of the log list - now = defaultLogListTimestamp + Duration.ofMillis( - Random.nextLong(FOURTEEN_DAYS_IN_MILLISECONDS + 1, SEVENTY_DAYS_IN_MILLISECONDS + 1) - ) + now = defaultLogListTimestamp + Random.nextLong(FOURTEEN_DAYS_IN_MILLISECONDS + 1, SEVENTY_DAYS_IN_MILLISECONDS + 1) // When we get data val result = dataSource.get() @@ -125,7 +121,7 @@ internal class LogListCacheManagementDataSourceTest { // Given no data in memory or disk cache and network returns successfully givenNetworkResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is more than 70 days (exclusive) old of the log list - now = defaultLogListTimestamp + Duration.ofMillis(SEVENTY_DAYS_IN_MILLISECONDS + 1) + now = defaultLogListTimestamp + SEVENTY_DAYS_IN_MILLISECONDS + 1 // When we get data val result = dataSource.get() @@ -144,7 +140,7 @@ internal class LogListCacheManagementDataSourceTest { // Given data in memory givenMemoryResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is 1 day (inclusive) old or less of the log list - now = defaultLogListTimestamp + Duration.ofMillis(Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1)) + now = defaultLogListTimestamp + Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1) // When we get data val result = dataSource.get() @@ -163,7 +159,7 @@ internal class LogListCacheManagementDataSourceTest { // Given no data in memory cache and disk cache returns successfully givenDiskResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is 1 day (inclusive) old or less of the log list - now = defaultLogListTimestamp + Duration.ofMillis(Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1)) + now = defaultLogListTimestamp + Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1) // When we get data val result = dataSource.get() @@ -183,7 +179,7 @@ internal class LogListCacheManagementDataSourceTest { // Given no data in memory cache and disk cache returns successfully givenResourcesResult(LogListResult.Valid.Success(defaultLogListTimestamp, emptyList())) // and the time now is 1 day (inclusive) old or less of the log list - now = defaultLogListTimestamp + Duration.ofMillis(Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1)) + now = defaultLogListTimestamp + Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1) // When we get data val result = dataSource.get() @@ -205,14 +201,14 @@ internal class LogListCacheManagementDataSourceTest { // Given data in memory is older than a day givenMemoryResult( LogListResult.Valid.Success( - defaultLogListTimestamp - Duration.ofMillis(ONE_DAY_IN_MILLISECONDS + 1), + defaultLogListTimestamp - ONE_DAY_IN_MILLISECONDS - 1, emptyList() ) ) // And data in disk is one day or less old givenDiskResult( LogListResult.Valid.Success( - defaultLogListTimestamp - Duration.ofMillis(Random.nextLong(ONE_DAY_IN_MILLISECONDS)), + defaultLogListTimestamp - Random.nextLong(ONE_DAY_IN_MILLISECONDS), emptyList() ) ) @@ -233,12 +229,12 @@ internal class LogListCacheManagementDataSourceTest { fun `returns success stale network when memory data newer than network data`() { runBlocking { // Given data in memory older than one day - val memoryTimestamp = defaultLogListTimestamp - Duration.ofMillis(ONE_DAY_IN_MILLISECONDS + 1) + val memoryTimestamp = defaultLogListTimestamp - ONE_DAY_IN_MILLISECONDS - 1 givenMemoryResult(LogListResult.Valid.Success(memoryTimestamp, emptyList())) // And network data is older than memory data givenNetworkResult( LogListResult.Valid.Success( - memoryTimestamp - Duration.ofMillis(Random.nextLong(1, ONE_DAY_IN_MILLISECONDS)), + memoryTimestamp - Random.nextLong(1, ONE_DAY_IN_MILLISECONDS), emptyList() ) ) @@ -256,17 +252,17 @@ internal class LogListCacheManagementDataSourceTest { fun `returns success stale network when disk data newer than network data`() { runBlocking { // Given data in disk older than one day - val diskTimestamp = defaultLogListTimestamp - Duration.ofMillis(ONE_DAY_IN_MILLISECONDS + 1) + val diskTimestamp = defaultLogListTimestamp - ONE_DAY_IN_MILLISECONDS - 1 givenDiskResult( LogListResult.Valid.Success( - defaultLogListTimestamp - Duration.ofMillis(ONE_DAY_IN_MILLISECONDS + 1), + defaultLogListTimestamp - ONE_DAY_IN_MILLISECONDS - 1, emptyList() ) ) // And network data that is older than memory givenNetworkResult( LogListResult.Valid.Success( - diskTimestamp - Duration.ofMillis(Random.nextLong(1, ONE_DAY_IN_MILLISECONDS)), + diskTimestamp - Random.nextLong(1, ONE_DAY_IN_MILLISECONDS), emptyList() ) ) @@ -300,10 +296,8 @@ internal class LogListCacheManagementDataSourceTest { // Given network failure and no data in memory or disk givenNetworkResult(LogListResult.Invalid.LogListZipFailedLoadingWithException(IOException())) // And memory data is between 1 day and 70 days - val memoryTimestamp = - defaultLogListTimestamp - Duration.ofMillis( - Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1, SEVENTY_DAYS_IN_MILLISECONDS) - ) + val memoryTimestamp = defaultLogListTimestamp - Random.nextLong(ONE_DAY_IN_MILLISECONDS + 1, SEVENTY_DAYS_IN_MILLISECONDS) + givenMemoryResult(LogListResult.Valid.Success(memoryTimestamp, emptyList())) // When we get data @@ -321,7 +315,7 @@ internal class LogListCacheManagementDataSourceTest { // Given network failure and no data in memory or disk givenNetworkResult(LogListResult.Invalid.LogListZipFailedLoadingWithException(IOException())) // And memory data is older than 70 days - val memoryTimestamp = defaultLogListTimestamp - Duration.ofMillis(SEVENTY_DAYS_IN_MILLISECONDS + 1) + val memoryTimestamp = defaultLogListTimestamp - SEVENTY_DAYS_IN_MILLISECONDS - 1 givenMemoryResult(LogListResult.Valid.Success(memoryTimestamp, emptyList())) // When we get data @@ -351,7 +345,7 @@ internal class LogListCacheManagementDataSourceTest { } companion object { - private val defaultLogListTimestamp = Instant.ofEpochMilli(1663678537000L) + private const val defaultLogListTimestamp = 1663678537000L private const val ONE_DAY_IN_MILLISECONDS = 86400000L private const val FOURTEEN_DAYS_IN_MILLISECONDS = 1209600000L diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactoryTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactoryTest.kt index 324501c2..f1603b73 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactoryTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogListDataSourceFactoryTest.kt @@ -32,7 +32,6 @@ import org.mockito.kotlin.doReturn import org.mockito.kotlin.whenever import java.io.IOException import java.net.SocketTimeoutException -import java.time.Instant import java.util.concurrent.TimeUnit import java.util.logging.Level import java.util.logging.Logger @@ -113,7 +112,7 @@ public class LogListDataSourceFactoryTest { val dataSource = LogListDataSourceFactory.createDataSource( logListService = logListService, - now = { Instant.ofEpochMilli(1000000) } + now = { 1000000 } ) val result = dataSource.get() diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogServerTest.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogServerTest.kt index 534f76fe..15a1461d 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogServerTest.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/loglist/LogServerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2019 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,6 @@ import com.appmattus.certificatetransparency.internal.utils.PublicKeyFactory import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test -import java.time.Instant /** Mostly for verifying the log info calculates the log ID correctly. */ internal class LogServerTest { @@ -57,10 +56,10 @@ internal class LogServerTest { val logServer = LogServer( key = PublicKeyFactory.fromByteArray(PUBLIC_KEY_RSA), operator = "Appmattus", - previousOperators = listOf(PreviousOperator("Google", 1000.fromEpochMillis())) + previousOperators = listOf(PreviousOperator("Google", 1000)) ) - assertEquals("Appmattus", logServer.operatorAt(1200.fromEpochMillis())) + assertEquals("Appmattus", logServer.operatorAt(1200)) } @Test @@ -71,7 +70,7 @@ internal class LogServerTest { previousOperators = emptyList() ) - assertEquals("Appmattus", logServer.operatorAt(1200.fromEpochMillis())) + assertEquals("Appmattus", logServer.operatorAt(1200)) } @Test @@ -80,12 +79,12 @@ internal class LogServerTest { key = PublicKeyFactory.fromByteArray(PUBLIC_KEY_RSA), operator = "Appmattus", previousOperators = listOf( - PreviousOperator("Google", 1000.fromEpochMillis()), - PreviousOperator("Cloudflare", 800.fromEpochMillis()) + PreviousOperator("Google", 1000), + PreviousOperator("Cloudflare", 800) ) ) - assertEquals("Google", logServer.operatorAt(900.fromEpochMillis())) + assertEquals("Google", logServer.operatorAt(900)) } @Test @@ -94,12 +93,12 @@ internal class LogServerTest { key = PublicKeyFactory.fromByteArray(PUBLIC_KEY_RSA), operator = "Appmattus", previousOperators = listOf( - PreviousOperator("Google", 1000.fromEpochMillis()), - PreviousOperator("Cloudflare", 800.fromEpochMillis()) + PreviousOperator("Google", 1000), + PreviousOperator("Cloudflare", 800) ) ) - assertEquals("Cloudflare", logServer.operatorAt(700.fromEpochMillis())) + assertEquals("Cloudflare", logServer.operatorAt(700)) } companion object { @@ -122,7 +121,5 @@ internal class LogServerTest { ) private val LOG_ID_RSA: ByteArray = Base64.decode("oCQsumIkVhezsKvGJ+spTJIM9H+jy/OdvSGDIX0VsgY=") - - private fun Int.fromEpochMillis() = Instant.ofEpochMilli(toLong()) } } diff --git a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/utils/LogListDataSourceTestFactory.kt b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/utils/LogListDataSourceTestFactory.kt index eb55abca..0d850989 100644 --- a/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/utils/LogListDataSourceTestFactory.kt +++ b/certificatetransparency/src/test/kotlin/com/appmattus/certificatetransparency/utils/LogListDataSourceTestFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2023 Appmattus Limited + * Copyright 2021-2024 Appmattus Limited * Copyright 2020 Babylon Partners Limited * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,6 @@ import com.appmattus.certificatetransparency.loglist.LogListDataSourceFactory import com.appmattus.certificatetransparency.loglist.LogListResult import com.appmattus.certificatetransparency.loglist.LogServer import kotlinx.serialization.json.Json -import java.time.Instant internal object LogListDataSourceTestFactory { @@ -48,7 +47,7 @@ internal object LogListDataSourceTestFactory { previousOperators = emptyList() ) } - }.flatten().let { LogListResult.Valid.Success(Instant.now(), it) } + }.flatten().let { LogListResult.Valid.Success(System.currentTimeMillis(), it) } object : DataSource { override suspend fun get() = list @@ -59,7 +58,7 @@ internal object LogListDataSourceTestFactory { val emptySource: DataSource by lazy { object : DataSource { - override suspend fun get() = LogListResult.Valid.Success(Instant.now(), emptyList()) + override suspend fun get() = LogListResult.Valid.Success(System.currentTimeMillis(), emptyList()) override suspend fun set(value: LogListResult) = Unit }