Add device ID attestation method to keymaster
Device ID attestation consists of three steps: * Generate a temporary key * Attest the key and desired device IDs * Delete the temporary key Rather than being spread over three keymaster APIs, these operations should happen automatically in a single keymaster method. Bug: 34734938 Test: GTS com.google.android.gts.security.DeviceIdAttestationHostTest Change-Id: Icbbc2dfc84f8b4f39d0e7ea880844d4f38b63f66
This commit is contained in:
parent
e0256a8dbb
commit
5aa93e08a8
4 changed files with 168 additions and 51 deletions
|
@ -878,6 +878,31 @@ class BpKeystoreService : public BpInterface<IKeystoreService> {
|
|||
return ret;
|
||||
}
|
||||
|
||||
KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params,
|
||||
hidl_vec<hidl_vec<uint8_t>>* outChain) override {
|
||||
if (!outChain) return ErrorCode::OUTPUT_PARAMETER_NULL;
|
||||
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
|
||||
nullable(writeParamSetToParcel, params, &data);
|
||||
|
||||
status_t status = remote()->transact(BnKeystoreService::ATTEST_DEVICE_IDS, data, &reply);
|
||||
if (status != NO_ERROR) {
|
||||
ALOGD("attestDeviceIds() count not contact remote: %d\n", status);
|
||||
return ResponseCode::SYSTEM_ERROR;
|
||||
}
|
||||
int32_t err = reply.readExceptionCode();
|
||||
ResponseCode ret = ResponseCode(reply.readInt32());
|
||||
if (err < 0) {
|
||||
ALOGD("attestDeviceIds() caught exception %d\n", err);
|
||||
return ResponseCode::SYSTEM_ERROR;
|
||||
}
|
||||
if (reply.readInt32() != 0) {
|
||||
*outChain = readCertificateChainFromParcel(reply);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
KeyStoreServiceReturnCode onDeviceOffBody() override {
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
|
||||
|
@ -1305,6 +1330,19 @@ status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel
|
|||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
case ATTEST_DEVICE_IDS: {
|
||||
CHECK_INTERFACE(IKeystoreService, data, reply);
|
||||
auto params = nullable(readParamSetFromParcel, data);
|
||||
hidl_vec<hidl_vec<uint8_t>> chain;
|
||||
int ret = attestDeviceIds(params.value(), &chain);
|
||||
reply->writeNoException();
|
||||
reply->writeInt32(ret);
|
||||
nullable(writeCertificateChainToParcel, chain, reply);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
case ON_DEVICE_OFF_BODY: {
|
||||
CHECK_INTERFACE(IKeystoreService, data, reply);
|
||||
int32_t ret = onDeviceOffBody();
|
||||
|
|
|
@ -112,7 +112,8 @@ class IKeystoreService : public IInterface {
|
|||
ON_USER_ADDED = IBinder::FIRST_CALL_TRANSACTION + 33,
|
||||
ON_USER_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 34,
|
||||
ATTEST_KEY = IBinder::FIRST_CALL_TRANSACTION + 35,
|
||||
ON_DEVICE_OFF_BODY = IBinder::FIRST_CALL_TRANSACTION + 36,
|
||||
ATTEST_DEVICE_IDS = IBinder::FIRST_CALL_TRANSACTION + 36,
|
||||
ON_DEVICE_OFF_BODY = IBinder::FIRST_CALL_TRANSACTION + 37,
|
||||
};
|
||||
|
||||
DECLARE_META_INTERFACE(KeystoreService);
|
||||
|
@ -234,6 +235,10 @@ class IKeystoreService : public IInterface {
|
|||
attestKey(const String16& name, const ::keystore::hidl_vec<::keystore::KeyParameter>& params,
|
||||
::keystore::hidl_vec<::keystore::hidl_vec<uint8_t>>* outChain) = 0;
|
||||
|
||||
virtual ::keystore::KeyStoreServiceReturnCode attestDeviceIds(
|
||||
const ::keystore::hidl_vec<::keystore::KeyParameter>& params,
|
||||
::keystore::hidl_vec<::keystore::hidl_vec<uint8_t>>* outChain) = 0;
|
||||
|
||||
virtual ::keystore::KeyStoreServiceReturnCode onDeviceOffBody() = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -89,6 +89,36 @@ std::pair<KeyStoreServiceReturnCode, bool> hadFactoryResetSinceIdRotation() {
|
|||
return {ResponseCode::NO_ERROR, true};
|
||||
}
|
||||
|
||||
constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
|
||||
|
||||
KeyStoreServiceReturnCode updateParamsForAttestation(uid_t callingUid, AuthorizationSet* params) {
|
||||
KeyStoreServiceReturnCode responseCode;
|
||||
bool factoryResetSinceIdRotation;
|
||||
std::tie(responseCode, factoryResetSinceIdRotation) = hadFactoryResetSinceIdRotation();
|
||||
|
||||
if (!responseCode.isOk()) return responseCode;
|
||||
if (factoryResetSinceIdRotation) params->push_back(TAG_RESET_SINCE_ID_ROTATION);
|
||||
|
||||
auto asn1_attestation_id_result = security::gather_attestation_application_id(callingUid);
|
||||
if (!asn1_attestation_id_result.isOk()) {
|
||||
ALOGE("failed to gather attestation_id");
|
||||
return ErrorCode::ATTESTATION_APPLICATION_ID_MISSING;
|
||||
}
|
||||
std::vector<uint8_t>& asn1_attestation_id = asn1_attestation_id_result;
|
||||
|
||||
/*
|
||||
* The attestation application ID cannot be longer than
|
||||
* KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, so we truncate if too long.
|
||||
*/
|
||||
if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
|
||||
asn1_attestation_id.resize(KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
|
||||
}
|
||||
|
||||
params->push_back(TAG_ATTESTATION_APPLICATION_ID, asn1_attestation_id);
|
||||
|
||||
return ResponseCode::NO_ERROR;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void KeyStoreService::binderDied(const wp<IBinder>& who) {
|
||||
|
@ -1304,8 +1334,6 @@ KeyStoreServiceReturnCode KeyStoreService::addAuthToken(const uint8_t* token, si
|
|||
return ResponseCode::NO_ERROR;
|
||||
}
|
||||
|
||||
constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
|
||||
|
||||
bool isDeviceIdAttestationRequested(const hidl_vec<KeyParameter>& params) {
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
switch (params[i].tag) {
|
||||
|
@ -1336,54 +1364,26 @@ KeyStoreServiceReturnCode KeyStoreService::attestKey(const String16& name,
|
|||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
|
||||
bool attestingDeviceIds = isDeviceIdAttestationRequested(params);
|
||||
if (attestingDeviceIds) {
|
||||
sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
|
||||
if (binder == 0) {
|
||||
return ErrorCode::CANNOT_ATTEST_IDS;
|
||||
}
|
||||
if (!interface_cast<IPermissionController>(binder)->checkPermission(
|
||||
String16("android.permission.READ_PRIVILEGED_PHONE_STATE"),
|
||||
IPCThreadState::self()->getCallingPid(), callingUid)) {
|
||||
return ErrorCode::CANNOT_ATTEST_IDS;
|
||||
}
|
||||
if (isDeviceIdAttestationRequested(params)) {
|
||||
// There is a dedicated attestDeviceIds() method for device ID attestation.
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
|
||||
AuthorizationSet mutableParams = params;
|
||||
|
||||
KeyStoreServiceReturnCode responseCode;
|
||||
bool factoryResetSinceIdRotation;
|
||||
std::tie(responseCode, factoryResetSinceIdRotation) = hadFactoryResetSinceIdRotation();
|
||||
|
||||
if (!responseCode.isOk()) return responseCode;
|
||||
if (factoryResetSinceIdRotation) mutableParams.push_back(TAG_RESET_SINCE_ID_ROTATION);
|
||||
KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
|
||||
if (!rc.isOk()) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Blob keyBlob;
|
||||
String8 name8(name);
|
||||
responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
|
||||
if (!responseCode.isOk()) {
|
||||
return responseCode;
|
||||
rc = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
|
||||
if (!rc.isOk()) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
auto asn1_attestation_id_result = security::gather_attestation_application_id(callingUid);
|
||||
if (!asn1_attestation_id_result.isOk()) {
|
||||
ALOGE("failed to gather attestation_id");
|
||||
return ErrorCode::ATTESTATION_APPLICATION_ID_MISSING;
|
||||
}
|
||||
std::vector<uint8_t>& asn1_attestation_id = asn1_attestation_id_result;
|
||||
|
||||
/*
|
||||
* The attestation application ID cannot be longer than
|
||||
* KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, so we truncate if too long.
|
||||
*/
|
||||
if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
|
||||
asn1_attestation_id.resize(KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
|
||||
}
|
||||
|
||||
mutableParams.push_back(TAG_ATTESTATION_APPLICATION_ID, blob2hidlVec(asn1_attestation_id));
|
||||
|
||||
KeyStoreServiceReturnCode error;
|
||||
auto hidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
|
||||
error = ret;
|
||||
|
@ -1395,15 +1395,86 @@ KeyStoreServiceReturnCode KeyStoreService::attestKey(const String16& name,
|
|||
|
||||
auto hidlKey = blob2hidlVec(keyBlob);
|
||||
auto& dev = mKeyStore->getDevice(keyBlob);
|
||||
KeyStoreServiceReturnCode attestationRc =
|
||||
KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
|
||||
|
||||
KeyStoreServiceReturnCode deletionRc;
|
||||
if (attestingDeviceIds) {
|
||||
// When performing device id attestation, treat the key as ephemeral and delete it straight
|
||||
// away.
|
||||
deletionRc = del(name, callingUid);
|
||||
rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
|
||||
if (!rc.isOk()) {
|
||||
return rc;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyParameter>& params,
|
||||
hidl_vec<hidl_vec<uint8_t>>* outChain) {
|
||||
if (!outChain) {
|
||||
return ErrorCode::OUTPUT_PARAMETER_NULL;
|
||||
}
|
||||
|
||||
if (!checkAllowedOperationParams(params)) {
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!isDeviceIdAttestationRequested(params)) {
|
||||
// There is an attestKey() method for attesting keys without device ID attestation.
|
||||
return ErrorCode::INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uid_t callingUid = IPCThreadState::self()->getCallingUid();
|
||||
sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
|
||||
if (binder == 0) {
|
||||
return ErrorCode::CANNOT_ATTEST_IDS;
|
||||
}
|
||||
if (!interface_cast<IPermissionController>(binder)->checkPermission(
|
||||
String16("android.permission.READ_PRIVILEGED_PHONE_STATE"),
|
||||
IPCThreadState::self()->getCallingPid(), callingUid)) {
|
||||
return ErrorCode::CANNOT_ATTEST_IDS;
|
||||
}
|
||||
|
||||
AuthorizationSet mutableParams = params;
|
||||
KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
|
||||
if (!rc.isOk()) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Generate temporary key.
|
||||
auto& dev = mKeyStore->getDevice();
|
||||
KeyStoreServiceReturnCode error;
|
||||
hidl_vec<uint8_t> hidlKey;
|
||||
|
||||
AuthorizationSet keyCharacteristics;
|
||||
keyCharacteristics.push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
|
||||
keyCharacteristics.push_back(TAG_ALGORITHM, Algorithm::EC);
|
||||
keyCharacteristics.push_back(TAG_DIGEST, Digest::SHA_2_256);
|
||||
keyCharacteristics.push_back(TAG_NO_AUTH_REQUIRED);
|
||||
keyCharacteristics.push_back(TAG_EC_CURVE, EcCurve::P_256);
|
||||
auto generateHidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
|
||||
const KeyCharacteristics&) {
|
||||
error = ret;
|
||||
if (!error.isOk()) {
|
||||
return;
|
||||
}
|
||||
hidlKey = hidlKeyBlob;
|
||||
};
|
||||
|
||||
rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(keyCharacteristics.hidl_data(), generateHidlCb));
|
||||
if (!rc.isOk()) {
|
||||
return rc;
|
||||
}
|
||||
if (!error.isOk()) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// Attest key and device IDs.
|
||||
auto attestHidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
|
||||
error = ret;
|
||||
if (!error.isOk()) {
|
||||
return;
|
||||
}
|
||||
*outChain = certChain;
|
||||
};
|
||||
KeyStoreServiceReturnCode attestationRc =
|
||||
KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), attestHidlCb));
|
||||
|
||||
// Delete temporary key.
|
||||
KeyStoreServiceReturnCode deletionRc = KS_HANDLE_HIDL_ERROR(dev->deleteKey(hidlKey));
|
||||
|
||||
if (!attestationRc.isOk()) {
|
||||
return attestationRc;
|
||||
|
|
|
@ -131,6 +131,9 @@ class KeyStoreService : public android::BnKeystoreService, public android::IBind
|
|||
const hidl_vec<KeyParameter>& params,
|
||||
hidl_vec<hidl_vec<uint8_t>>* outChain) override;
|
||||
|
||||
KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params,
|
||||
hidl_vec<hidl_vec<uint8_t>>* outChain) override;
|
||||
|
||||
KeyStoreServiceReturnCode onDeviceOffBody() override;
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue