1 package android.security.attestationverification 2 3 import android.app.Activity 4 import android.os.Bundle 5 import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE 6 import android.security.attestationverification.AttestationVerificationManager.PARAM_PUBLIC_KEY 7 import android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE 8 import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE 9 import android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE 10 import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY 11 import android.security.attestationverification.AttestationVerificationManager.TYPE_UNKNOWN 12 import androidx.test.ext.junit.rules.ActivityScenarioRule 13 import androidx.test.ext.junit.runners.AndroidJUnit4 14 import androidx.test.filters.SmallTest 15 import androidx.test.platform.app.InstrumentationRegistry 16 import com.google.common.truth.Truth.assertThat 17 import org.junit.Before 18 import org.junit.Rule 19 import org.junit.Test 20 import org.junit.runner.RunWith 21 import java.io.ByteArrayOutputStream 22 import java.security.cert.CertificateFactory 23 import java.util.concurrent.CompletableFuture 24 import java.util.concurrent.TimeUnit 25 26 /** Test for system-defined attestation verifiers. */ 27 @SmallTest 28 @RunWith(AndroidJUnit4::class) 29 class PeerDeviceSystemAttestationVerificationTest { 30 31 @get:Rule 32 val rule = ActivityScenarioRule(TestActivity::class.java) 33 34 private val certifcateFactory = CertificateFactory.getInstance("X.509") 35 private lateinit var activity: Activity 36 private lateinit var avm: AttestationVerificationManager 37 private lateinit var invalidAttestationByteArray: ByteArray 38 39 @Before 40 fun setup() { 41 rule.getScenario().onActivity { 42 avm = it.getSystemService(AttestationVerificationManager::class.java) 43 activity = it 44 } 45 invalidAttestationByteArray = TEST_ATTESTATION_CERT_FILENAME.fromPEMFileToByteArray() 46 } 47 48 @Test 49 fun verifyAttestation_returnsFailureWrongBindingType() { 50 val future = CompletableFuture<Int>() 51 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 52 avm.verifyAttestation(profile, TYPE_UNKNOWN, Bundle(), 53 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 54 future.complete(result) 55 } 56 57 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 58 } 59 60 @Test 61 fun verifyAttestation_returnsFailureEmptyRequirements() { 62 val future = CompletableFuture<Int>() 63 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 64 avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), 65 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 66 future.complete(result) 67 } 68 69 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 70 } 71 72 @Test 73 fun verifyAttestation_returnsFailureMismatchBindingType() { 74 val future = CompletableFuture<Int>() 75 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 76 val publicKeyRequirements = Bundle() 77 publicKeyRequirements.putByteArray(PARAM_PUBLIC_KEY, "publicKeyStr".encodeToByteArray()) 78 avm.verifyAttestation(profile, TYPE_CHALLENGE, publicKeyRequirements, 79 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 80 future.complete(result) 81 } 82 83 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 84 85 val future2 = CompletableFuture<Int>() 86 val challengeRequirements = Bundle() 87 challengeRequirements.putByteArray(PARAM_CHALLENGE, "challengeStr".encodeToByteArray()) 88 avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, challengeRequirements, 89 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 90 future2.complete(result) 91 } 92 93 assertThat(future2.getSoon()).isEqualTo(RESULT_FAILURE) 94 } 95 96 @Test 97 fun verifyAttestation_returnsFailureWrongResourceKey() { 98 val future = CompletableFuture<Int>() 99 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 100 val wrongKeyRequirements = Bundle() 101 wrongKeyRequirements.putByteArray("wrongReqKey", "publicKeyStr".encodeToByteArray()) 102 avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, wrongKeyRequirements, 103 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 104 future.complete(result) 105 } 106 107 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 108 } 109 110 @Test 111 fun verifyAttestation_returnsFailureEmptyAttestation() { 112 val future = CompletableFuture<Int>() 113 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 114 val requirements = Bundle() 115 requirements.putByteArray(PARAM_PUBLIC_KEY, "publicKeyStr".encodeToByteArray()) 116 avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, requirements, ByteArray(0), 117 activity.mainExecutor) { result, _ -> 118 future.complete(result) 119 } 120 121 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 122 } 123 124 @Test 125 fun verifyAttestation_returnsFailureTrustAnchorMismatch() { 126 val future = CompletableFuture<Int>() 127 val profile = AttestationProfile(PROFILE_PEER_DEVICE) 128 val challengeRequirements = Bundle() 129 challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) 130 avm.verifyAttestation(profile, TYPE_CHALLENGE, challengeRequirements, 131 invalidAttestationByteArray, activity.mainExecutor) { result, _ -> 132 future.complete(result) 133 } 134 assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE) 135 } 136 137 private fun <T> CompletableFuture<T>.getSoon(): T { 138 return this.get(1, TimeUnit.SECONDS) 139 } 140 141 private fun String.fromPEMFileToByteArray(): ByteArray { 142 val certs = certifcateFactory.generateCertificates( 143 InstrumentationRegistry.getInstrumentation().getContext().getResources().getAssets() 144 .open(this)) 145 val bos = ByteArrayOutputStream() 146 certs.forEach { 147 bos.write(it.encoded) 148 } 149 return bos.toByteArray() 150 } 151 152 class TestActivity : Activity() { 153 override fun onCreate(savedInstanceState: Bundle?) { 154 super.onCreate(savedInstanceState) 155 } 156 } 157 158 companion object { 159 private const val TEST_ATTESTATION_CERT_FILENAME = "test_attestation_wrong_root_certs.pem" 160 } 161 } 162