Skip to content

Commit 645f6c9

Browse files
committed
update to latest awesome signum
1 parent 2fa4078 commit 645f6c9

7 files changed

Lines changed: 136 additions & 123 deletions

File tree

supreme/common/src/jvmTest/kotlin/DebugStatementParserTest.kt

Lines changed: 120 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import at.asitplus.io.MultiBase
55
import at.asitplus.signum.indispensable.encodeToDer
66
import at.asitplus.signum.indispensable.io.Base64UrlStrict
77
import at.asitplus.signum.indispensable.toKmpCertificate
8+
import at.asitplus.testballoon.matrix.CompactReport
9+
import at.asitplus.testballoon.matrix.ExecutionMode
10+
import at.asitplus.testballoon.matrix.matrixConfig
11+
import at.asitplus.testballoon.matrix.matrixSuite
812
import com.android.keyattestation.verifier.KeyDescription
913
import com.google.android.attestation.ParsedAttestationRecord
10-
import at.asitplus.testballoon.matrix.*
1114
import io.kotest.assertions.withClue
1215
import io.kotest.matchers.nulls.shouldBeNull
1316
import io.kotest.matchers.nulls.shouldNotBeNull
@@ -42,7 +45,7 @@ val DebugStmt.details get() = third
4245

4346

4447
@OptIn(ExperimentalAtomicApi::class)
45-
val DebugStatementParserTest by matrixSuite {
48+
val DebugStatementParserTest by matrixSuite(matrixConfig { execution = ExecutionMode.Sequential }) {
4649
val json = Json { ignoreUnknownKeys = true }
4750
val classLoader = Thread.currentThread().contextClassLoader
4851

@@ -90,42 +93,12 @@ val DebugStatementParserTest by matrixSuite {
9093
"No private test data present" {}
9194
return@matrixSuite
9295
}
93-
94-
data("proofs", proofs.withIndex().toList(), nameFn = { _, value -> "${value.index}: ${value.value.first.size} certs" }) - { (index, it) ->
95-
val attestationCertChain =
96-
it.certificateChain.map {
97-
val certBytes = Base64.getUrlDecoder().decode(it)
98-
catchingUnwrapped {
99-
certificateFactory.generateCertificate(
100-
ByteArrayInputStream(
101-
certBytes
102-
)
103-
) as X509Certificate
104-
}.getOrNull()
105-
}.filterNotNull()
106-
107-
if (attestationCertChain.isNotEmpty()) {
108-
109-
110-
val androidAttestationExtension = attestationCertChain.first().androidAttestationExtension
111-
"from chain should be same as from leaf" {
112-
androidAttestationExtension shouldBe attestationCertChain.androidAttestationExtension
113-
}
114-
"convert" - {
115-
data("certificates", attestationCertChain, nameFn = { _, value -> value.subjectX500Principal.toString() }) test {
116-
it.toKmpCertificate().isSuccess shouldBe true
117-
118-
var own = it.toKmpCertificate().getOrThrow()
119-
if (!own.encodeToDer().contentEquals(it.encoded)) {
120-
System.err.println("OWN: ${own.encodeToDer().toHexString()}")
121-
System.err.println("ORI: ${it.encoded.toHexString()}")
122-
}
123-
own.encodeToDer() shouldBe it.encoded
124-
}
125-
}
126-
127-
if (index > 0) {
128-
val prev = proofs[index - 1].certificateChain.map {
96+
compact("${proofs.size} collected real-world proofs") { report = CompactReport.FailuresOnly } - {
97+
data(
98+
proofs.withIndex().toList(),
99+
nameFn = { _, value -> "${value.index}: ${value.value.first.size} certs" }) - { (index, it) ->
100+
val attestationCertChain =
101+
it.certificateChain.map {
129102
val certBytes = Base64.getUrlDecoder().decode(it)
130103
catchingUnwrapped {
131104
certificateFactory.generateCertificate(
@@ -136,87 +109,126 @@ val DebugStatementParserTest by matrixSuite {
136109
}.getOrNull()
137110
}.filterNotNull()
138111

139-
if (prev.isNotEmpty() && ((androidAttestationExtension != null) && prev.androidAttestationExtension != null)) {
140-
"concatenating two chains (current = $index) should get the same exnt as just from the current chain" {
141-
//leaf = fist in chain, root = last in chain. so we went the closest to CURRENT root. hence we need to prepent
142-
//s.t. the chain gets extended below the leaf and not above the root
143-
(prev + attestationCertChain).androidAttestationExtension shouldBe attestationCertChain.androidAttestationExtension
112+
if (attestationCertChain.isNotEmpty()) {
113+
114+
115+
val androidAttestationExtension = attestationCertChain.first().androidAttestationExtension
116+
"from chain should be same as from leaf" {
117+
androidAttestationExtension shouldBe attestationCertChain.androidAttestationExtension
118+
}
119+
"convert" - {
120+
data(
121+
"certificates",
122+
attestationCertChain,
123+
nameFn = { _, value -> value.subjectX500Principal.toString() }) test {
124+
it.toKmpCertificate().isSuccess shouldBe true
125+
126+
var own = it.toKmpCertificate().getOrThrow()
127+
if (!own.encodeToDer().contentEquals(it.encoded)) {
128+
System.err.println("OWN: ${own.encodeToDer().toHexString()}")
129+
System.err.println("ORI: ${it.encoded.toHexString()}")
130+
}
131+
own.encodeToDer() shouldBe it.encoded
132+
}
133+
}
134+
135+
if (index > 0) {
136+
val prev = proofs[index - 1].certificateChain.map {
137+
val certBytes = Base64.getUrlDecoder().decode(it)
138+
catchingUnwrapped {
139+
certificateFactory.generateCertificate(
140+
ByteArrayInputStream(
141+
certBytes
142+
)
143+
) as X509Certificate
144+
}.getOrNull()
145+
}.filterNotNull()
146+
147+
if (prev.isNotEmpty() && ((androidAttestationExtension != null) && prev.androidAttestationExtension != null)) {
148+
"concatenating two chains (current = $index) should get the same exnt as just from the current chain" {
149+
//leaf = fist in chain, root = last in chain. so we went the closest to CURRENT root. hence we need to prepent
150+
//s.t. the chain gets extended below the leaf and not above the root
151+
(prev + attestationCertChain).androidAttestationExtension shouldBe attestationCertChain.androidAttestationExtension
152+
}
144153
}
145154
}
146-
}
147155

148-
val fromGoogle =
149-
catchingUnwrapped { ParsedAttestationRecord.createParsedAttestationRecord(attestationCertChain) }.getOrNull()
156+
val fromGoogle =
157+
catchingUnwrapped { ParsedAttestationRecord.createParsedAttestationRecord(attestationCertChain) }.getOrNull()
150158

151-
"Own" {
152-
if (fromGoogle == null) {
153-
System.err.println("Old Google parser glitched out")
154-
val newParser = catchingUnwrapped { KeyDescription.parseFrom(attestationCertChain.first()) }
159+
"Own" {
160+
if (fromGoogle == null) {
161+
System.err.println("Old Google parser glitched out")
162+
val newParser = catchingUnwrapped { KeyDescription.parseFrom(attestationCertChain.first()) }
155163

156-
attestationCertChain.androidAttestationExtension.shouldBeNull()
157-
return@invoke//well, well, well…}
158-
}
159-
androidAttestationExtension.shouldNotBeNull()
160-
attestationCertChain.androidAttestationExtension shouldBe androidAttestationExtension
161-
catchingUnwrapped {
162-
163-
val reencoded = androidAttestationExtension.encodeToDer()
164-
val original = (DEROctetString.fromByteArray(
165-
attestationCertChain.first().getExtensionValue(
166-
AttestationKeyDescription.oid.toString()
167-
)
168-
) as ASN1OctetString).octets
169-
if (!reencoded.contentEquals(original)) {
170-
System.err.println("OWN: ${reencoded.toHexString()}")
171-
System.err.println("ORI: ${original.toHexString()}")
164+
attestationCertChain.androidAttestationExtension.shouldBeNull()
165+
return@invoke//well, well, well…}
172166
}
173-
reencoded shouldBe original
167+
androidAttestationExtension.shouldNotBeNull()
168+
attestationCertChain.androidAttestationExtension shouldBe androidAttestationExtension
169+
catchingUnwrapped {
174170

175-
}.getOrElse {
176-
throw it
177-
}
178-
assertSemanticallyEqual(fromGoogle, androidAttestationExtension)
171+
val reencoded = androidAttestationExtension.encodeToDer()
172+
val original = (DEROctetString.fromByteArray(
173+
attestationCertChain.first().getExtensionValue(
174+
AttestationKeyDescription.oid.toString()
175+
)
176+
) as ASN1OctetString).octets
177+
if (!reencoded.contentEquals(original)) {
178+
System.err.println("OWN: ${reencoded.toHexString()}")
179+
System.err.println("ORI: ${original.toHexString()}")
180+
}
181+
reencoded shouldBe original
179182

183+
}.getOrElse {
184+
throw it
185+
}
186+
assertSemanticallyEqual(fromGoogle, androidAttestationExtension)
180187

181-
}
182-
"Roboto Engine Check" - {
183-
val stmt = it
184-
//not only is revocation slow. it will also have us run into rate limits
185-
//plus, many have been revoked and we also want success results!
186-
val rSupreme = stmt.cfg.copy(supremeParser = true, revocation = emptyList())
187-
val rLegacy = stmt.cfg.copy(supremeParser = false, revocation = emptyList())
188-
189-
compact("config pairs") {
190-
report = CompactReport.FailuresOnly
191-
} - {
192-
data(listOf(
193-
rSupreme to rLegacy,
194-
rSupreme.copy(patchLevel = PatchLevel(2025, 1)) to
195-
rLegacy.copy(patchLevel = PatchLevel(2025, 1)),
196-
rSupreme.copy(patchLevel = null, androidVersion = null) to
197-
rLegacy.copy(patchLevel = null, androidVersion = null),
198-
rSupreme.copy(requireRemoteKeyProvisioning = true) to rLegacy.copy(requireRemoteKeyProvisioning = true),
199-
rSupreme.copy(ignoreLeafValidity = false) to rLegacy.copy(ignoreLeafValidity = false),
200-
rSupreme.copy(requireStrongBox = true) to rLegacy.copy(requireStrongBox = true),
201-
rSupreme.copy(enableSoftwareAttestation = true) to rLegacy.copy(enableSoftwareAttestation = true),
202-
rSupreme.copy(allowBootloaderUnlock = true) to rLegacy.copy(allowBootloaderUnlock = true),
203-
//get the "UnknownPackage" one step further
204-
rSupreme.copy(
205-
applications = listOf(
206-
AndroidAttestationConfiguration.AppData(
207-
"UnknownPackage",
208-
signerFingerprints = setOf(byteArrayOf())
188+
189+
}
190+
"Roboto Engine Check" - {
191+
val stmt = it
192+
//not only is revocation slow. it will also have us run into rate limits
193+
//plus, many have been revoked and we also want success results!
194+
val rSupreme = stmt.cfg.copy(supremeParser = true, revocation = emptyList())
195+
val rLegacy = stmt.cfg.copy(supremeParser = false, revocation = emptyList())
196+
197+
data(
198+
"config pairs",
199+
listOf(
200+
rSupreme to rLegacy,
201+
rSupreme.copy(patchLevel = PatchLevel(2025, 1)) to
202+
rLegacy.copy(patchLevel = PatchLevel(2025, 1)),
203+
rSupreme.copy(patchLevel = null, androidVersion = null) to
204+
rLegacy.copy(patchLevel = null, androidVersion = null),
205+
rSupreme.copy(requireRemoteKeyProvisioning = true) to rLegacy.copy(
206+
requireRemoteKeyProvisioning = true
207+
),
208+
rSupreme.copy(ignoreLeafValidity = false) to rLegacy.copy(ignoreLeafValidity = false),
209+
rSupreme.copy(requireStrongBox = true) to rLegacy.copy(requireStrongBox = true),
210+
rSupreme.copy(enableSoftwareAttestation = true) to rLegacy.copy(
211+
enableSoftwareAttestation = true
212+
),
213+
rSupreme.copy(allowBootloaderUnlock = true) to rLegacy.copy(allowBootloaderUnlock = true),
214+
//get the "UnknownPackage" one step further
215+
rSupreme.copy(
216+
applications = listOf(
217+
AndroidAttestationConfiguration.AppData(
218+
"UnknownPackage",
219+
signerFingerprints = setOf(byteArrayOf())
220+
)
209221
)
210-
)
211-
) to rLegacy.copy(
212-
applications = listOf(
213-
AndroidAttestationConfiguration.AppData(
214-
"UnknownPackage",
215-
signerFingerprints = setOf(byteArrayOf())
222+
) to rLegacy.copy(
223+
applications = listOf(
224+
AndroidAttestationConfiguration.AppData(
225+
"UnknownPackage",
226+
signerFingerprints = setOf(byteArrayOf())
227+
)
216228
)
217229
)
218230
)
219-
)) test { (rSupreme, rLegacy) ->
231+
) test { (rSupreme, rLegacy) ->
220232
val supreme = Roboto(rSupreme).verify(
221233
attestationCertChain,
222234
stmt.details.verificationTime,
@@ -234,8 +246,7 @@ val DebugStatementParserTest by matrixSuite {
234246
}
235247
}
236248
}
237-
}
238-
239-
} else "Empty chain" {}
249+
} else "Empty chain" {}
250+
}
240251
}
241252
}

supreme/config-hoplite/src/test/kotlin/HopliteLoaderContractTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import at.asitplus.attestation.android.TrustedRoot
99
import at.asitplus.attestation.android.VerifiedBootKey
1010
import at.asitplus.attestation.android.parseHex
1111
import at.asitplus.attestation.supreme.SupremeConfiguration
12-
import at.asitplus.signum.indispensable.asn1.encodeToPEM
12+
import at.asitplus.signum.indispensable.encodeToPem
1313
import at.asitplus.signum.indispensable.io.Base64UrlStrict
1414
import at.asitplus.signum.indispensable.toCryptoPublicKey
1515
import at.asitplus.signum.indispensable.toKmpCertificate
@@ -371,8 +371,8 @@ private object HopliteFixtures {
371371
}
372372

373373
private fun trustedRootPem(root: TrustedRoot): String = when (root) {
374-
is TrustedRoot.Certificate -> root.certificate.toKmpCertificate().getOrThrow().encodeToPEM().getOrThrow()
375-
is TrustedRoot.PublicKey -> root.publicKey.toCryptoPublicKey().getOrThrow().encodeToPEM().getOrThrow()
374+
is TrustedRoot.Certificate -> root.certificate.toKmpCertificate().getOrThrow().encodeToPem()
375+
is TrustedRoot.PublicKey -> root.publicKey.toCryptoPublicKey().getOrThrow().encodeToPem()
376376
}
377377

378378
private fun JsonElement.recaseKeys(style: PropertyCaseStyle): JsonElement = when (this) {

supreme/config-spring/src/test/kotlin/Config-Spring-Boot-App.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import at.asitplus.attestation.android.*
55
import at.asitplus.attestation.fromSpringEnvironment
66
import at.asitplus.attestation.fromSpringMap
77
import at.asitplus.attestation.supreme.SupremeConfiguration
8-
import at.asitplus.signum.indispensable.asn1.encodeToPEM
8+
import at.asitplus.signum.indispensable.encodeToPem
99
import at.asitplus.signum.indispensable.toCryptoPublicKey
1010
import at.asitplus.signum.indispensable.toKmpCertificate
1111
import at.asitplus.testballoon.matrix.*
@@ -405,6 +405,6 @@ private fun withTempConfigDir(
405405
}
406406

407407
private fun trustedRootPem(root: TrustedRoot): String = when (root) {
408-
is TrustedRoot.Certificate -> root.certificate.toKmpCertificate().getOrThrow().encodeToPEM().getOrThrow()
409-
is TrustedRoot.PublicKey -> root.publicKey.toCryptoPublicKey().getOrThrow().encodeToPEM().getOrThrow()
408+
is TrustedRoot.Certificate -> root.certificate.toKmpCertificate().getOrThrow().encodeToPem()
409+
is TrustedRoot.PublicKey -> root.publicKey.toCryptoPublicKey().getOrThrow().encodeToPem()
410410
}

supreme/verifier/src/jvmMain/kotlin/AttestationVerifier.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import at.asitplus.attestation.android.exceptions.AttestationValueException
77
import at.asitplus.attestation.supreme.AttestationResponse.Failure
88
import at.asitplus.attestation.supreme.AttestationResponse.Failure.Type
99
import at.asitplus.attestation.supreme.PreAttestationError.ChallengeVerification
10+
import at.asitplus.awesn1.ObjectIdentifier
1011
import at.asitplus.catchingUnwrapped
1112
import at.asitplus.signum.indispensable.*
12-
import at.asitplus.awesn1.ObjectIdentifier
1313
import at.asitplus.signum.indispensable.pki.CertificateChain
1414
import at.asitplus.signum.indispensable.pki.CertificationRequest
1515
import at.asitplus.signum.indispensable.pki.TbsCertificationRequest
@@ -254,8 +254,7 @@ constructor(
254254
}
255255
}
256256

257-
private fun CertificationRequest.jcaSignature(): KmmResult<Signature> =
258-
(signatureAlgorithm as SpecializedSignatureAlgorithm).getJCASignatureInstance()
257+
private fun CertificationRequest.jcaSignature(): KmmResult<Signature> = signatureAlgorithm.getJCASignatureInstance()
259258

260259
private suspend fun csrReason(
261260
onAttestationError: suspend AttestationResult.Error.(WardenDebugAttestationStatement) -> String?,

supreme/verifier/src/jvmTest/kotlin/examples/Readme-Backend.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package examples.docs.service
22

3+
import at.asitplus.awesn1.nextPositiveAsn1Integer
34
import at.asitplus.signum.indispensable.decodeFromDer
45
import at.asitplus.signum.indispensable.pki.*
56
import at.asitplus.signum.supreme.sign
@@ -13,6 +14,7 @@ import io.ktor.server.plugins.contentnegotiation.*
1314
import io.ktor.server.request.*
1415
import io.ktor.server.response.*
1516
import io.ktor.server.routing.*
17+
import org.kotlincrypto.random.CryptoRand
1618
import kotlin.random.Random
1719
import kotlin.time.Clock
1820
import kotlin.time.Duration.Companion.days
@@ -59,8 +61,7 @@ val server = embeddedServer(Netty, port = 8080) {
5961
/*(7)!*/
6062
val leafCertificate = signer.sign(
6163
/*(8)!*/TbsCertificate(
62-
//TODO: replace once we have a generator
63-
/*(9)!*/serialNumber = byteArrayOf(0.toByte(), *Random.nextBytes(32).dropWhile { it == 0.toByte() }.toByteArray()),
64+
/*(9)!*/serialNumber = CryptoRand.nextPositiveAsn1Integer(20),
6465
/*(10)!*/publicKey = it.tbsCsr.publicKey,
6566
signatureAlgorithm = signer.signatureAlgorithm,
6667
validFrom = (Clock.System.now()),

0 commit comments

Comments
 (0)