Skip to content

Commit

Permalink
prepare supreme-based attestation
Browse files Browse the repository at this point in the history
  • Loading branch information
JesusMcCloud committed Sep 30, 2024
1 parent 6cd4a20 commit cfa50f1
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 7 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
plugins { id("at.asitplus.gradle.conventions") version "2.0.20+20240904" }
plugins { id("at.asitplus.gradle.conventions") version "2.0.20+20240920" }

group = "at.asitplus"
3 changes: 0 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,3 +0,0 @@
[versions]
serialization = "1.7.1"
kmmresult = "1.6.1"
2 changes: 1 addition & 1 deletion warden/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ sourceSets.test {
dependencies {
api("at.asitplus:warden-roboto:$androidAttestationVersion")
api(datetime())
implementation("at.asitplus.signum:indispensable:3.6.0")
implementation("at.asitplus.signum:indispensable:3.9.0")
implementation("ch.veehait.devicecheck:devicecheck-appattest:0.9.6")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.14.2")
implementation("net.swiftzer.semver:semver:1.2.0")
Expand Down
25 changes: 23 additions & 2 deletions warden/src/main/kotlin/AttestationService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import at.asitplus.attestation.AttestationException
import at.asitplus.attestation.IOSAttestationConfiguration.AppData
import at.asitplus.attestation.android.*
import at.asitplus.attestation.android.exceptions.AttestationValueException
import at.asitplus.signum.indispensable.CryptoPublicKey
import at.asitplus.signum.indispensable.fromJcaPublicKey
import at.asitplus.signum.indispensable.*
import ch.veehait.devicecheck.appattest.assertion.Assertion
import ch.veehait.devicecheck.appattest.attestation.ValidatedAttestation
import com.google.android.attestation.AttestationApplicationId
Expand Down Expand Up @@ -247,6 +246,8 @@ abstract class AttestationService {
): AttestationResult


abstract fun verifyKeyAttestation(attestationProof: Attestation, challenge: ByteArray): KeyAttestation<PublicKey>

/**
* Verifies key attestation for both Android and Apple devices.
*
Expand All @@ -273,6 +274,11 @@ abstract class AttestationService {
*
* @return [KeyAttestation] containing the attested public key on success or null in case of failure (see [KeyAttestation])
*/
@Deprecated(
"This uses the legacy attestation format, which is not future-proof, makes too few guarantees wrt. encoding, " +
"guesses the platform based on the number of elements in the attestation proof, etc.",
ReplaceWith("AttestationService.verifyAttestation(attestationProof, challenge)")
)
fun <T : PublicKey> verifyKeyAttestation(
attestationProof: List<ByteArray>,
expectedChallenge: ByteArray,
Expand Down Expand Up @@ -610,6 +616,21 @@ object NoopAttestationService : AttestationService() {
if (attestationProof.size > 2) AttestationResult.Android.NOOP(attestationProof)
else AttestationResult.IOS.NOOP(clientData)

override fun verifyKeyAttestation(attestationProof: Attestation, challenge: ByteArray): KeyAttestation<PublicKey> =
when (attestationProof) {
is IosHomebrewAttestation -> KeyAttestation(
attestationProof.parsedClientData.publicKey.getJcaPublicKey().getOrThrow(),
AttestationResult.IOS.NOOP(attestationProof.parsedClientData.publicKey.encodeToDer())
)

is AndroidKeystoreAttestation -> KeyAttestation(
attestationProof.certificateChain.first().publicKey.getJcaPublicKey().getOrThrow(),
AttestationResult.Android.NOOP(attestationProof.certificateChain.map { it.encodeToDer() })
)

else -> KeyAttestation(null, AttestationResult.Error("Unsupported attestation proof type"))
}

override val ios: IOS
get() = object : IOS {
override fun verifyAppAttestation(attestationObject: ByteArray, challenge: ByteArray) =
Expand Down
55 changes: 55 additions & 0 deletions warden/src/main/kotlin/Warden.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package at.asitplus.attestation
import at.asitplus.attestation.android.*
import at.asitplus.attestation.android.exceptions.AttestationValueException
import at.asitplus.attestation.android.exceptions.CertificateInvalidException
import at.asitplus.signum.indispensable.*
import ch.veehait.devicecheck.appattest.AppleAppAttest
import ch.veehait.devicecheck.appattest.assertion.Assertion
import ch.veehait.devicecheck.appattest.assertion.AssertionChallengeValidator
Expand Down Expand Up @@ -186,6 +187,60 @@ class Warden(
}
}

override fun verifyKeyAttestation(
attestationProof: Attestation,
challenge: ByteArray
): KeyAttestation<PublicKey> =
when (attestationProof) {
is SelfAttestation, is IosLegacyHomebrewAttestation -> KeyAttestation<PublicKey>(
null,
AttestationResult.Error("${attestationProof::class.simpleName} is unsupported")
)

is IosHomebrewAttestation -> {
if (IosHomebrewAttestation.ClientData(
attestationProof.parsedClientData.publicKey,
challenge
) != attestationProof.parsedClientData
)
KeyAttestation(
null, AttestationResult.Error(
"Challenge mismatch",
AttestationException.Content.iOS(cause = IosAttestationException(reason = IosAttestationException.Reason.CHALLENGE))
)
)
else
verifyAttestationApple(
attestationProof.attestation,
attestationProof.clientDataJSON,
assertionData = null,
counter = 0L
).let {
when (it) {
is AttestationResult.IOS -> KeyAttestation(
attestationProof.parsedClientData.publicKey.getJcaPublicKey().getOrThrow(), it
)

else -> KeyAttestation(null, AttestationResult.Error("This must never happen!"))
}
}
}

is AndroidKeystoreAttestation -> verifyAttestationAndroid(
attestationProof.certificateChain.map { it.encodeToDer() },
challenge
).let {
when (it) {
is AttestationResult.Android -> KeyAttestation(
attestationProof.certificateChain.first().publicKey.getJcaPublicKey().getOrThrow(), it
)

else -> KeyAttestation(null, AttestationResult.Error("This must never happen!"))
}
}

}

/**
* Verifies [Android Key Attestation](https://developer.android.com/training/articles/security-key-attestation) based
* the provided certificate chain (the leaf ist the attestation certificate, the root must be one of the
Expand Down

0 comments on commit cfa50f1

Please sign in to comment.