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:
Bartosz Fabianowski 2017-04-24 13:54:49 +02:00
parent e0256a8dbb
commit 5aa93e08a8
4 changed files with 168 additions and 51 deletions

View file

@ -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();

View file

@ -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;
};

View file

@ -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;

View file

@ -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: