diff options
author | Shawn Willden <swillden@google.com> | 2016-03-20 09:10:18 -0600 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2016-03-29 18:17:07 -0600 |
commit | 98c5916d4a807614fad5fdfb63aa10d724b9ef0a (patch) | |
tree | f2ad3ba116d8aeeef670151e2c81431018e6926b | |
parent | 814a6e725cd89ad6bf27a9951d25025dc9ace9a8 (diff) | |
download | security-98c5916d4a807614fad5fdfb63aa10d724b9ef0a.tar.gz |
Implement key upgrade in keystore.
Change-Id: I0cf169d9366aee1de32f1cc4501af76e6e1bc505
-rw-r--r-- | keystore/key_store_service.cpp | 81 | ||||
-rw-r--r-- | keystore/key_store_service.h | 13 |
2 files changed, 90 insertions, 4 deletions
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp index e02ef8b6..ba0182cd 100644 --- a/keystore/key_store_service.cpp +++ b/keystore/key_store_service.cpp @@ -30,6 +30,11 @@ #include "defaults.h" #include "keystore_utils.h" +using keymaster::AuthorizationSet; +using keymaster::AuthorizationSetBuilder; +using keymaster::TAG_APPLICATION_DATA; +using keymaster::TAG_APPLICATION_ID; + namespace android { const size_t MAX_OPERATIONS = 15; @@ -39,6 +44,10 @@ struct BIGNUM_Delete { }; typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM; +struct Malloc_Delete { + void operator()(uint8_t* p) const { free(p); } +}; + void KeyStoreService::binderDied(const wp<IBinder>& who) { auto operations = mOperationMap.getOperationsForToken(who.unsafe_get()); for (auto token : operations) { @@ -680,16 +689,29 @@ int32_t KeyStoreService::getKeyCharacteristics(const String16& name, if (responseCode != ::NO_ERROR) { return responseCode; } - keymaster_key_blob_t key; - key.key_material_size = keyBlob.getLength(); - key.key_material = keyBlob.getValue(); + keymaster_key_blob_t key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())}; auto* dev = mKeyStore->getDeviceForBlob(keyBlob); - keymaster_key_characteristics_t out = {{nullptr, 0}, {nullptr, 0}}; + keymaster_key_characteristics_t out = {}; if (!dev->get_key_characteristics) { ALOGE("device does not implement get_key_characteristics"); return KM_ERROR_UNIMPLEMENTED; } rc = dev->get_key_characteristics(dev, &key, clientId, appData, &out); + if (rc == KM_ERROR_KEY_REQUIRES_UPGRADE) { + AuthorizationSet upgradeParams; + if (clientId && clientId->data && clientId->data_length) { + upgradeParams.push_back(TAG_APPLICATION_ID, *clientId); + } + if (appData && appData->data && appData->data_length) { + upgradeParams.push_back(TAG_APPLICATION_DATA, *appData); + } + rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob); + if (rc != ::NO_ERROR) { + return rc; + } + key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())}; + rc = dev->get_key_characteristics(dev, &key, clientId, appData, &out); + } if (rc != KM_ERROR_OK) { return rc; } @@ -827,6 +849,16 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, Unique_keymaster_key_characteristics characteristics; characteristics.reset(new keymaster_key_characteristics_t); err = getOperationCharacteristics(key, dev, opParams, characteristics.get()); + if (err == KM_ERROR_KEY_REQUIRES_UPGRADE) { + int32_t rc = upgradeKeyBlob(name, targetUid, + AuthorizationSet(opParams.data(), opParams.size()), &keyBlob); + if (rc != ::NO_ERROR) { + result->resultCode = rc; + return; + } + key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())}; + err = getOperationCharacteristics(key, dev, opParams, characteristics.get()); + } if (err) { result->resultCode = err; return; @@ -1504,4 +1536,45 @@ int32_t KeyStoreService::doLegacySignVerify(const String16& name, const uint8_t* return ::NO_ERROR; } +int32_t KeyStoreService::upgradeKeyBlob(const String16& name, uid_t uid, + const AuthorizationSet& params, Blob* blob) { + // Read the blob rather than assuming the caller provided the right name/uid/blob triplet. + String8 name8(name); + ResponseCode responseCode = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10); + if (responseCode != ::NO_ERROR) { + return responseCode; + } + + keymaster_key_blob_t key = {blob->getValue(), static_cast<size_t>(blob->getLength())}; + auto* dev = mKeyStore->getDeviceForBlob(*blob); + keymaster_key_blob_t upgraded_key; + int32_t rc = dev->upgrade_key(dev, &key, ¶ms, &upgraded_key); + if (rc != KM_ERROR_OK) { + return rc; + } + UniquePtr<uint8_t, Malloc_Delete> upgraded_key_deleter( + const_cast<uint8_t*>(upgraded_key.key_material)); + + rc = del(name, uid); + if (rc != ::NO_ERROR) { + return rc; + } + + String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid)); + Blob newBlob(upgraded_key.key_material, upgraded_key.key_material_size, nullptr /* info */, + 0 /* infoLength */, ::TYPE_KEYMASTER_10); + newBlob.setFallback(blob->isFallback()); + newBlob.setEncrypted(blob->isEncrypted()); + + rc = mKeyStore->put(filename.string(), &newBlob, get_user_id(uid)); + + // Re-read blob for caller. We can't use newBlob because writing it modified it. + responseCode = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10); + if (responseCode != ::NO_ERROR) { + return responseCode; + } + + return rc; +} + } // namespace android diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h index 12a342e7..7d559199 100644 --- a/keystore/key_store_service.h +++ b/keystore/key_store_service.h @@ -19,6 +19,8 @@ #include <keystore/IKeystoreService.h> +#include <keymaster/authorization_set.h> + #include "auth_token_table.h" #include "keystore.h" #include "keystore_keymaster_enforcement.h" @@ -222,6 +224,17 @@ class KeyStoreService : public BnKeystoreService, public IBinder::DeathRecipient uint8_t** out, size_t* outLength, const uint8_t* signature, size_t signatureLength, keymaster_purpose_t purpose); + /** + * Upgrade a key blob under alias "name", returning the new blob in "blob". If "blob" + * previously contained data, it will be overwritten. + * + * Returns ::NO_ERROR if the key was upgraded successfully. + * KM_ERROR_VERSION_MISMATCH if called on a key whose patch level is greater than or + * equal to the current system patch level. + */ + int32_t upgradeKeyBlob(const String16& name, uid_t targetUid, + const keymaster::AuthorizationSet& params, Blob* blob); + ::KeyStore* mKeyStore; OperationMap mOperationMap; keymaster::AuthTokenTable mAuthTokenTable; |