1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.devicediagnostics.evaluated
18
19 import android.security.keystore.KeyGenParameterSpec
20 import android.security.keystore.KeyProperties
21 import android.util.Log
22 import java.nio.ByteBuffer
23 import java.security.KeyPairGenerator
24 import java.security.KeyStore
25 import java.security.spec.ECGenParameterSpec
26
27 private const val TAG = "GetAttestation"
28 private const val EC_CURVE = "secp256r1"
29 private const val KEYSTORE_ALIAS = "attestation_collector_key"
30
getAttestationnull31 private fun getAttestation(challenge: ByteArray, withImei: Boolean): ByteArray {
32 val keyStore = KeyStore.getInstance("AndroidKeyStore")
33 keyStore.load(null)
34 keyStore.deleteEntry(KEYSTORE_ALIAS)
35 val keyPurpose = KeyProperties::PURPOSE_SIGN.get() or KeyProperties::PURPOSE_VERIFY.get()
36 var builder =
37 KeyGenParameterSpec.Builder(KEYSTORE_ALIAS, keyPurpose)
38 .setAlgorithmParameterSpec(ECGenParameterSpec(EC_CURVE))
39 .setDigests(KeyProperties.DIGEST_SHA256)
40 .setAttestationChallenge(challenge)
41
42 // Use reflection to call this system API so we can still build in Android Studio
43 if (withImei)
44 builder =
45 builder::class
46 .members
47 .firstOrNull { it.name == "setAttestationIds" }
48 ?.call(
49 builder,
50 intArrayOf(
51 1,
52 2,
53 ), // AttestationUtils.ID_TYPE_SERIAL, AttestationUtils.ID_TYPE_IMEI
54 ) as KeyGenParameterSpec.Builder
55
56 val spec = builder.build()
57
58 val keyPairGenerator =
59 KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore")
60 keyPairGenerator.initialize(spec)
61 keyPairGenerator.generateKeyPair()
62
63 var report = ByteArray(0)
64 for (cert in keyStore.getCertificateChain(KEYSTORE_ALIAS)) {
65 report +=
66 ByteBuffer.allocate(Int.SIZE_BYTES).putInt(cert.encoded.size).array() + cert.encoded
67 }
68
69 return report
70 }
71
createAttestationRecordnull72 fun createAttestationRecord(challenge: ByteArray): ByteArray {
73 // On devices without device IDs provisioned, the above code will throw ProviderException
74 // Continue without this data to support testing other functionality
75 try {
76 return getAttestation(challenge, true)
77 } catch (e: java.security.ProviderException) {
78 Log.e(TAG, "Could not get attestation with IMEI, retrying without: $e")
79 } catch (e: SecurityException) {
80 Log.e(TAG, "Could not get attestation with IMEI, retrying without: $e")
81 } catch (e: Exception) {
82 Log.e(TAG, "Could not create attestation record: $e")
83 return ByteArray(0)
84 }
85
86 try {
87 return getAttestation(challenge, false)
88 } catch (e: Exception) {
89 Log.e(TAG, "Could not create attestation record: $e")
90 return ByteArray(0)
91 }
92 }
93