<lambda>null1 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