什么是Keybox
Android O 开始谷歌要求每台机器预制谷歌提供的 attestation key的需求,该需求要求,每台机器都预制谷歌提供的 key,因此需要 oem 厂商在工厂完成预制。没有预制该key 将直接导致机器 cts 相关测试项失败。Google attestation key的集合又称作为Google keybox。不同的attestation key通过DeviceID 来区分,在配置时选择不同的 DeviceID 可以进行不同的 attestion key 配置。Keybox包含若干组key, 每组key包含了ECDSA和RSA两种算法,KmInstallKeybox将每组key写入到手机的安全内存中,已知的地方有RPMB和Persist分区;
当Google GSM app或第三方APP需要使用key时,调用keymaster接口,使用该key进行签名、认证等。
每条 Attestion key 由两条证书链组成,分别对应算法为 ECDSA和 RSA,证书链包括一个私钥和三级证书,以ECDSA算法为例,具体形式如下,其中有一个私钥和三组证书;
< Key algorithm = "ecdsa">
<PrivateKey format="pem">
.............................
</PrivateKey >
<CertificatedChain>
<NumberOfCertificates>3</NumberOfCertificates>
<Certificate format="pem"> ...................... </Certificate>
<Certificate format="pem"> ...................... </Certificate>
<Certificate format="pem"> ...................... </Certificate>
</CertificateChain>
</Key>
通常我们会向Google申请keybox,结合可能得出货量,提供如下信息给到的Google。
1. fingerprint : branch/deivce/product/user/build
2. device id 列表 : 这里的device id是一个临时定义的名称。
举个例子,我预计将要生产1KK的设备,并销往欧美。那么需要为10个device id申请keybox。由于单个device id的keybox可以生产并安装在100K的设备上,那么我们需要10个这样的device id。逻辑上讲,一种类型的设备,我为什么需要不同的device id?这里确实是个知识点,晚点提个google case 问一下。
Keybox内容
这里的DeviceID对应keybox中的DeviceID,通常就是对应key的名称。简单看一个我最新申请的keybox内容和简单的标注。
目前是单个Devcice ID可以在100K的设备上安装同一个keybox。那么n个Device ID也就是对应n*100K的设备。
Keybox 安装
KmInstallKeybox
由于使用的是QC code中自带的命令工具:KmInstallKeybox.
安装前提条件(RPMB 初始化)
在预制 attestion key 前需要保证 RPMB 已经初始化,否则 RPMB 无法使用会导致预制key 功能失效。
初始化 RPMB(手机连接电脑,确保 adb 可以使用)
adb root
adb shell
qseecom_sample_client smple64 v 14 1
一般情况下,安装步骤如下:
- adb root
- adb push keybox.xml data/
- adb shell LD_LIBIRARY_PATH=/vendor/lib64/hw KmInstallKeybox data/keybox.xml DeviceID false // 一共是5个参数,0,1,2,3,4
KminstallKeybox代码内容
using namespace keymasterdevice;
int main(int argc, char** argv) {
if ((argc != 4) && (argc != 5) && (argc != 7) && (argc != 8)) {
cout << "usage: LD_LIBRARY_PATH=/vendor/lib64/hw KmInstallKeybox Keybox_file Device_ID "
"provision_device_ids(true/false)"
"Strongbox_Keybox_file Strongbox_Device_ID "
"strongbox_provision_device_ids(true/false)"
<< endl;
cout << "e.g.,: LD_LIBRARY_PATH=/vendor/lib64/hw KmInstallKeybox keybox.xml "
"mfgID_xxxx_0000 true"
"strongbox_keybox.xml strongbox_mfgID_xxxx_0000 true"
<< endl;
cout << "KmInstallKeybox will install the attestation"
"keys (both RSA and ECC) along with all the device identifiers\n"
"(brand, device, product, serial#, IMEI, MEID (if available), model"
"and manufacturer).\n"
"\n"
"The tool will use KM HAL API's to genrate RSA / ECC keys and\n"
"verify the attestation certificate signed with the provisioned keys.\n"
"If the validation is successful, the tool will set 'Provisioning Success'"
"to KM TA / KM Strongbox.\n"
"Else all the provisioned keys are deleted and it can be re-provisioned"
"\n"
"Once 'Provisioning Success' state is set in KM TA / Strongbox,\n"
"attestation keys / Device ID's cannot be re-provisioned\n"
"\n"
"\n"
"**RMA Use Case **\n"
"For RMA use case, OEM's can set the following devcfg parameter in "
"'keymaster_oem_config.xml'\n"
"Please ensure to sign this debug devcfg with the serial# of the device as this "
"will enable\n"
"re-provisioning of keys and if used incorrectly can open up the device to be "
"re-provisioned.\n"
"<props name=\"allow_reprovision\" type=DALPROP_ATTR_TYPE_UINT32>\n"
"1"
"Strongbox provisioning is optional and is only supported on chipsets SPU/ "
"strongbox is supported."
<< endl;
exit(-1);
}
std::string deviceId(argv[2]);
// TEE
bool provision_device_id = false;
if (!memcmp(argv[3], "true", strlen("true")))
provision_device_id = true;
else if (!memcmp(argv[3], "false", strlen("false")))
provision_device_id = false;
else
return GENERIC_FAILURE;
bool provision_only_device_id = false;
if (argc==5 && !memcmp(argv[4], "rkp", strlen("rkp")))
provision_only_device_id = true;
else if (argc==8 && !memcmp(argv[7], "rkp", strlen("rkp")))
provision_only_device_id = true;
int ret = GENERIC_FAILURE;
// This is required only for offtarget emulator, will be compiled out.
SetUpOffTarget();
KeymasterHalDevice device(KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
SetUpOffTargetConfig(&device, 0, 0, 0);
InstallKeybox installer(argv[1], deviceId, provision_device_id,
KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
PROV_EXIT(installer.ParseFile(provision_only_device_id));
if (!provision_only_device_id)
PROV_EXIT(installer.ValidateProvisionedKeys());
cout << "TEE done" << endl;
if (argc == 7 || argc == 8) {
std::string deviceIdSb(argv[5]);
// SB
bool provision_device_sb_id = false;
if (!memcmp(argv[6], "true", strlen("true")))
provision_device_sb_id = true;
else if (!memcmp(argv[6], "false", strlen("false")))
provision_device_sb_id = false;
else
return GENERIC_FAILURE;
InstallKeybox installer_sb(argv[4], deviceIdSb, provision_device_sb_id,
keymaster::KM_SECURITY_LEVEL_STRONGBOX);
PROV_EXIT(installer_sb.ParseFile(false));
PROV_EXIT(installer_sb.ValidateProvisionedKeys());
}
cout << "InstallKeybox is done!" << endl;
return 0;
}
针对这个工具,其实我们也可以结合实际进行定制。
Attestation Key的相关使用
简单例子如下:
// 导入相关库
import android.hardware.biometrics.BiometricManager;
import android.security.KeyCharacteristics;
import android.security.keystore.KeyProperties;
import android.util.Base64;
// ...
BiometricManager biometricManager = BiometricManager.from(context);
KeymasterArguments keygenArgs = new KeymasterArguments.Builder()
.setOperation(KeymasterOperation.KEY_GEN)
.setAlias("my_key")
.setLabels("application-specific", "encryption")
.setKeyProperties(new KeyProperties.Builder()
.setAlgorithm(KeyProperties.AES)
.setKeySize(256)
.setUserAuthenticationRequired(true)
.build())
.build();
// 请求用户输入密码
String password = getPasswordFromUser();
// 执行密钥生成
try {
KeymasterOperationResult result = KeymasterHelper.generateKey(context, keygenArgs, password);
if (result.getResult()) {
// 如果成功,获取并保存密钥
byte[] key = result.getKey();
String encryptedData = Base64.encodeToString(encryptData(key), Base64.DEFAULT);
saveEncryptedDataToFile(encryptedData);
} else {
handleEncryptionError(result.getErrorCode());
}
} catch (Exception e) {
logError(e);
}