diff --git a/src/main/kotlin/ConstraintConfig.kt b/src/main/kotlin/ConstraintConfig.kt index 7339e8d..8e4565f 100644 --- a/src/main/kotlin/ConstraintConfig.kt +++ b/src/main/kotlin/ConstraintConfig.kt @@ -46,7 +46,6 @@ sealed interface Constraint { */ @ThreadSafe class ConstraintConfig( - val allowSoftwareRoot: Boolean = false, val keyOrigin: Constraint? = null, val securityLevel: Constraint? = null, val rootOfTrust: Constraint? = null, @@ -66,10 +65,6 @@ class ConstraintConfig( ) .addAll(additionalConstraints) .build() - - companion object { - fun testDefault(): ConstraintConfig = ConstraintConfig(allowSoftwareRoot = true) - } } /** @@ -77,7 +72,6 @@ class ConstraintConfig( * Kotlin-idiomatic builder function is provided below. */ class ConstraintConfigBuilder() { - var allowSoftwareRoot: Boolean = false var keyOrigin: Constraint? = null var securityLevel: Constraint? = null var rootOfTrust: Constraint? = null @@ -101,7 +95,6 @@ class ConstraintConfigBuilder() { fun build(): ConstraintConfig = ConstraintConfig( - allowSoftwareRoot, keyOrigin, securityLevel, rootOfTrust, diff --git a/src/main/kotlin/SoftwareRoot.kt b/src/main/kotlin/SoftwareRoot.kt index bc544be..f89e81b 100644 --- a/src/main/kotlin/SoftwareRoot.kt +++ b/src/main/kotlin/SoftwareRoot.kt @@ -18,51 +18,26 @@ package com.android.keyattestation.verifier import java.security.cert.X509Certificate -public object SoftwareRoot { +// The software root certificate used by the Android Key Attestation standard. +// https://android.googlesource.com/platform/system/core/+/refs/heads/main/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml#97 +private const val GOOGLE_SOFTWARE_ROOT = + """-----BEGIN CERTIFICATE----- +MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG +EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll +dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD +VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw +HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT +BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq +QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59 +dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O +BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W +EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG +SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN +C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw== +-----END CERTIFICATE-----""" - // The software root certificates used by the Android Key Attestation standard. - // https://android.googlesource.com/platform/system/core/+/refs/heads/main/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml - private val GOOGLE_SOFTWARE_ROOTS = - listOf( - """-----BEGIN CERTIFICATE----- - MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG - EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll - dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD - VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw - HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx - EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT - BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq - QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH - KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59 - dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O - BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W - EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG - SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN - C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw== - -----END CERTIFICATE-----""", - """-----BEGIN CERTIFICATE----- - MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV - BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW - aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN - MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG - A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE - CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB - AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs - Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL - t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID - AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw - FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B - Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j - HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc - DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op - Lvtc9mL1J1IXvmM= - -----END CERTIFICATE-----""", - ) +val SOFTWARE_ROOT: X509Certificate by lazy { GOOGLE_SOFTWARE_ROOT.asX509Certificate() } - val SOFTWARE_ROOTS: List by lazy { - GOOGLE_SOFTWARE_ROOTS.map { it.asX509Certificate() } - } - - internal fun X509Certificate.isSoftwareRoot() = - SoftwareRoot.SOFTWARE_ROOTS.map { it.publicKey }.contains(this.publicKey) -} +internal fun X509Certificate.isSoftwareRoot() = this.publicKey == SOFTWARE_ROOT.publicKey diff --git a/src/main/kotlin/Verifier.kt b/src/main/kotlin/Verifier.kt index 01cbb9d..fc69182 100644 --- a/src/main/kotlin/Verifier.kt +++ b/src/main/kotlin/Verifier.kt @@ -17,7 +17,6 @@ package com.android.keyattestation.verifier import androidx.annotation.RequiresApi -import com.android.keyattestation.verifier.SoftwareRoot.isSoftwareRoot import com.android.keyattestation.verifier.provider.KeyAttestationCertPath import com.android.keyattestation.verifier.provider.KeyAttestationProvider import com.android.keyattestation.verifier.provider.ProvisioningMethod @@ -156,13 +155,11 @@ constructor( ) { init { Security.addProvider(KeyAttestationProvider()) - if (!constraintConfig.allowSoftwareRoot) { - for (anchor in trustAnchorsSource()) { - if (anchor.trustedCert?.isSoftwareRoot() == true) { - throw IllegalArgumentException( - "Software attestation root cannot be used as a trust anchor." - ) - } + for (anchor in trustAnchorsSource()) { + if (anchor.trustedCert?.isSoftwareRoot() == true) { + throw IllegalArgumentException( + "Software attestation root cannot be used as a trust anchor." + ) } } } diff --git a/src/test/kotlin/VerifierTest.kt b/src/test/kotlin/VerifierTest.kt index 0b08445..379c7ab 100644 --- a/src/test/kotlin/VerifierTest.kt +++ b/src/test/kotlin/VerifierTest.kt @@ -17,7 +17,6 @@ package com.android.keyattestation.verifier import kotlin.io.path.Path -import com.android.keyattestation.verifier.SoftwareRoot.SOFTWARE_ROOTS import com.android.keyattestation.verifier.VerificationResult.ConstraintViolation import com.android.keyattestation.verifier.VerificationResult.ExtensionParsingFailure import com.android.keyattestation.verifier.VerificationResult.PathValidationFailure @@ -88,31 +87,25 @@ class VerifierTest { for (pemPath in pemFiles) { val subpath = "${model}/sdk${sdk}/${pemPath.nameWithoutExtension}" val json = readJson("${subpath}.json") + + // TODO(google-internal bug): update here once sw root is supported. + if (json.attestationSecurityLevel == SecurityLevel.SOFTWARE) { + continue + } + val creationDateTime = json.softwareEnforced.creationDateTime ?: json.hardwareEnforced.creationDateTime assertThat(creationDateTime).isNotNull() val timestamp = Instant.ofEpochMilli(creationDateTime!!.toLong()) - val verifier = - Verifier( - { prodAnchors + SOFTWARE_ROOTS.map { TrustAnchor(it, null) } }, - { setOf() }, - { timestamp }, - ConstraintConfig( - allowSoftwareRoot = true, - securityLevel = IgnoredConstraint, - rootOfTrust = IgnoredConstraint, - ), - ) + val verifier = Verifier({ prodAnchors }, { setOf() }, { timestamp }) val chain = readCertList("${subpath}.pem") val result = assertIs(verifier.verify(chain)) assertThat(result.publicKey).isEqualTo(chain[0].publicKey) assertThat(result.challenge).isEqualTo(json.attestationChallenge) assertThat(result.securityLevel).isEqualTo(json.attestationSecurityLevel) assertThat(result.verifiedBootState) - .isEqualTo( - json.hardwareEnforced.rootOfTrust?.verifiedBootState ?: VerifiedBootState.UNVERIFIED - ) + .isEqualTo(json.hardwareEnforced.rootOfTrust?.verifiedBootState) assertThat(result.deviceLocked) .isEqualTo(json.hardwareEnforced.rootOfTrust?.deviceLocked ?: false) } @@ -376,11 +369,7 @@ class VerifierTest { @Test fun init_softwareRootAsTrustAnchor_fails() { assertFailsWith { - Verifier( - { setOf(TrustAnchor(SOFTWARE_ROOTS.first(), null)) }, - { setOf() }, - { Instant.now() }, - ) + Verifier({ setOf(TrustAnchor(SOFTWARE_ROOT, null)) }, { setOf() }, { Instant.now() }) } } }