diff options
author | Shawn Willden <swillden@google.com> | 2015-06-18 18:23:54 -0600 |
---|---|---|
committer | Shawn Willden <swillden@google.com> | 2015-06-19 20:02:22 -0600 |
commit | 9221bff2f13451ef330135bb32ea96de2a8b09cc (patch) | |
tree | e824126f98cb26ee895af41448a914bf595eecf4 | |
parent | 84c14f0957b365fd33534b88b7eec97b287b67b9 (diff) | |
download | security-9221bff2f13451ef330135bb32ea96de2a8b09cc.tar.gz |
Add keymaster authorization policy enforcement to keystore.
Bug: 19511945
Change-Id: I76c04e8d3253ba490cedac53bbc75943ec68df1d
-rw-r--r-- | keystore/Android.mk | 3 | ||||
-rw-r--r-- | keystore/keystore.cpp | 68 | ||||
-rw-r--r-- | keystore/keystore_keymaster_enforcement.h | 65 | ||||
-rw-r--r-- | keystore/operation.cpp | 9 | ||||
-rw-r--r-- | keystore/operation.h | 14 |
5 files changed, 142 insertions, 17 deletions
diff --git a/keystore/Android.mk b/keystore/Android.mk index 9463f3d0..e18b2d89 100644 --- a/keystore/Android.mk +++ b/keystore/Android.mk @@ -33,7 +33,8 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libselinux \ libsoftkeymasterdevice \ - libkeymaster_messages + libkeymaster_messages \ + libkeymaster1 LOCAL_MODULE := keystore LOCAL_MODULE_TAGS := optional LOCAL_C_INCLUES := system/keymaster/ diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp index ae3b1e4a..b36f65fb 100644 --- a/keystore/keystore.cpp +++ b/keystore/keystore.cpp @@ -67,6 +67,7 @@ #include "auth_token_table.h" #include "defaults.h" +#include "keystore_keymaster_enforcement.h" #include "operation.h" /* KeyStore is a secured storage for key-value pairs. In this implementation, @@ -2480,6 +2481,26 @@ public: keymaster_key_param_set_t outParams = {NULL, 0}; err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle); + // Create a keyid for this key. + keymaster::km_id_t keyid; + if (!enforcement_policy.CreateKeyId(key, &keyid)) { + ALOGE("Failed to create a key ID for authorization checking."); + result->resultCode = KM_ERROR_UNKNOWN_ERROR; + return; + } + + // Check that all key authorization policy requirements are met. + keymaster::AuthorizationSet key_auths(characteristics->hw_enforced); + key_auths.push_back(characteristics->sw_enforced); + keymaster::AuthorizationSet operation_params(inParams); + err = enforcement_policy.AuthorizeOperation(purpose, keyid, key_auths, operation_params, + 0 /* op_handle */, + true /* is_begin_operation */); + if (err) { + result->resultCode = err; + return; + } + // If there are too many operations abort the oldest operation that was // started as pruneable and try again. while (err == KM_ERROR_TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) { @@ -2495,8 +2516,8 @@ public: return; } - sp<IBinder> operationToken = mOperationMap.addOperation(handle, purpose, dev, appToken, - characteristics.release(), + sp<IBinder> operationToken = mOperationMap.addOperation(handle, keyid, purpose, dev, + appToken, characteristics.release(), pruneable); if (authToken) { mOperationMap.setOperationAuthToken(operationToken, authToken); @@ -2524,7 +2545,9 @@ public: const keymaster1_device_t* dev; keymaster_operation_handle_t handle; keymaster_purpose_t purpose; - if (!mOperationMap.getOperation(token, &handle, &purpose, &dev, NULL)) { + keymaster::km_id_t keyid; + const keymaster_key_characteristics_t* characteristics; + if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE; return; } @@ -2540,6 +2563,18 @@ public: keymaster_blob_t output = {NULL, 0}; keymaster_key_param_set_t outParams = {NULL, 0}; + // Check that all key authorization policy requirements are met. + keymaster::AuthorizationSet key_auths(characteristics->hw_enforced); + key_auths.push_back(characteristics->sw_enforced); + keymaster::AuthorizationSet operation_params(inParams); + result->resultCode = + enforcement_policy.AuthorizeOperation(purpose, keyid, key_auths, + operation_params, handle, + false /* is_begin_operation */); + if (result->resultCode) { + return; + } + keymaster_error_t err = dev->update(dev, handle, &inParams, &input, &consumed, &outParams, &output); result->data.reset(const_cast<uint8_t*>(output.data)); @@ -2562,7 +2597,9 @@ public: const keymaster1_device_t* dev; keymaster_operation_handle_t handle; keymaster_purpose_t purpose; - if (!mOperationMap.getOperation(token, &handle, &purpose, &dev, NULL)) { + keymaster::km_id_t keyid; + const keymaster_key_characteristics_t* characteristics; + if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE; return; } @@ -2589,6 +2626,18 @@ public: keymaster_blob_t input = {signature, signatureLength}; keymaster_blob_t output = {NULL, 0}; keymaster_key_param_set_t outParams = {NULL, 0}; + + // Check that all key authorization policy requirements are met. + keymaster::AuthorizationSet key_auths(characteristics->hw_enforced); + key_auths.push_back(characteristics->sw_enforced); + keymaster::AuthorizationSet operation_params(inParams); + err = enforcement_policy.AuthorizeOperation(purpose, keyid, key_auths, operation_params, + handle, false /* is_begin_operation */); + if (err) { + result->resultCode = err; + return; + } + err = dev->finish(dev, handle, &inParams, &input, &outParams, &output); // Remove the operation regardless of the result mOperationMap.removeOperation(token); @@ -2607,7 +2656,8 @@ public: const keymaster1_device_t* dev; keymaster_operation_handle_t handle; keymaster_purpose_t purpose; - if (!mOperationMap.getOperation(token, &handle, &purpose, &dev, NULL)) { + keymaster::km_id_t keyid; + if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, NULL)) { return KM_ERROR_INVALID_OPERATION_HANDLE; } mOperationMap.removeOperation(token); @@ -2629,7 +2679,8 @@ public: keymaster_operation_handle_t handle; const keymaster_key_characteristics_t* characteristics; keymaster_purpose_t purpose; - if (!mOperationMap.getOperation(token, &handle, &purpose, &dev, &characteristics)) { + keymaster::km_id_t keyid; + if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { return false; } const hw_auth_token_t* authToken = NULL; @@ -2894,7 +2945,9 @@ private: keymaster_operation_handle_t handle; const keymaster_key_characteristics_t* characteristics = NULL; keymaster_purpose_t purpose; - if (!mOperationMap.getOperation(token, &handle, &purpose, &dev, &characteristics)) { + keymaster::km_id_t keyid; + if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, + &characteristics)) { return KM_ERROR_INVALID_OPERATION_HANDLE; } int32_t result = getAuthToken(characteristics, handle, purpose, &authToken); @@ -3034,6 +3087,7 @@ private: ::KeyStore* mKeyStore; OperationMap mOperationMap; keymaster::AuthTokenTable mAuthTokenTable; + KeystoreKeymasterEnforcement enforcement_policy; }; }; // namespace android diff --git a/keystore/keystore_keymaster_enforcement.h b/keystore/keystore_keymaster_enforcement.h new file mode 100644 index 00000000..904bf668 --- /dev/null +++ b/keystore/keystore_keymaster_enforcement.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef KEYSTORE_KEYMASTER_ENFORCEMENT_H_ +#define KEYSTORE_KEYMASTER_ENFORCEMENT_H_ + +#include <time.h> + +#include <keymaster/keymaster_enforcement.h> + +/** + * This is a specialization of the KeymasterEnforcement class to be used by Keystore to enforce + * keymaster requirements on all key operation. + */ +class KeystoreKeymasterEnforcement : public keymaster::KeymasterEnforcement { + public: + KeystoreKeymasterEnforcement() : KeymasterEnforcement(64, 64) {} + + uint32_t get_current_time() const override { + struct timespec tp; + int err = clock_gettime(CLOCK_MONOTONIC, &tp); + if (err || tp.tv_sec < 0) + return 0; + return static_cast<uint32_t>(tp.tv_sec); + } + + bool activation_date_valid(uint64_t activation_date) const override { + // Convert java date to time_t, non-portably. + time_t activation_time = activation_date / 1000; + return difftime(time(NULL), activation_time) >= 0; + } + + bool expiration_date_passed(uint64_t expiration_date) const override { + // Convert jave date to time_t, non-portably. + time_t expiration_time = expiration_date / 1000; + return difftime(time(NULL), expiration_time) > 0; + } + + bool auth_token_timed_out(const hw_auth_token_t&, uint32_t) const { + // Non-secure world cannot check token timeouts because it doesn't have access to the secure + // clock. Assume the token is good. + return true; + } + + bool ValidateTokenSignature(const hw_auth_token_t&) const override { + // Non-secure world cannot validate token signatures because it doesn't have access to the + // signing key. Assume the token is good. + return true; + } +}; + +#endif // KEYSTORE_KEYMASTER_ENFORCEMENT_H_ diff --git a/keystore/operation.cpp b/keystore/operation.cpp index 087beffc..aa37101f 100644 --- a/keystore/operation.cpp +++ b/keystore/operation.cpp @@ -25,13 +25,13 @@ OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient) } sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle, - keymaster_purpose_t purpose, + uint64_t keyid, keymaster_purpose_t purpose, const keymaster1_device_t* dev, sp<IBinder> appToken, keymaster_key_characteristics_t* characteristics, bool pruneable) { sp<IBinder> token = new BBinder(); - mMap[token] = std::move(Operation(handle, purpose, dev, characteristics, appToken)); + mMap[token] = std::move(Operation(handle, keyid, purpose, dev, characteristics, appToken)); if (pruneable) { mLru.push_back(token); } @@ -43,7 +43,7 @@ sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle, } bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle, - keymaster_purpose_t* outPurpose, + uint64_t* outKeyid, keymaster_purpose_t* outPurpose, const keymaster1_device_t** outDevice, const keymaster_key_characteristics_t** outCharacteristics) { if (!outHandle || !outDevice) { @@ -56,6 +56,7 @@ bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* updateLru(token); *outHandle = entry->second.handle; + *outKeyid = entry->second.keyid; *outPurpose = entry->second.purpose; *outDevice = entry->second.device; if (outCharacteristics) { @@ -142,11 +143,13 @@ std::vector<sp<IBinder>> OperationMap::getOperationsForToken(sp<IBinder> appToke } OperationMap::Operation::Operation(keymaster_operation_handle_t handle_, + uint64_t keyid_, keymaster_purpose_t purpose_, const keymaster1_device_t* device_, keymaster_key_characteristics_t* characteristics_, sp<IBinder> appToken_) : handle(handle_), + keyid(keyid_), purpose(purpose_), device(device_), characteristics(characteristics_), diff --git a/keystore/operation.h b/keystore/operation.h index d0e65a52..6806388d 100644 --- a/keystore/operation.h +++ b/keystore/operation.h @@ -47,12 +47,13 @@ typedef std::unique_ptr<keymaster_key_characteristics_t, keymaster_key_character class OperationMap { public: OperationMap(IBinder::DeathRecipient* deathRecipient); - sp<IBinder> addOperation(keymaster_operation_handle_t handle, keymaster_purpose_t purpose, - const keymaster1_device_t* dev, sp<IBinder> appToken, - keymaster_key_characteristics_t* characteristics, bool pruneable); - bool hasOperation(sp<IBinder> token); + sp<IBinder> addOperation(keymaster_operation_handle_t handle, uint64_t keyid, + keymaster_purpose_t purpose, const keymaster1_device_t* dev, + sp<IBinder> appToken, keymaster_key_characteristics_t* characteristics, + bool pruneable); bool getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle, - keymaster_purpose_t* outPurpose, const keymaster1_device_t** outDev, + uint64_t* outKeyid, keymaster_purpose_t* outPurpose, + const keymaster1_device_t** outDev, const keymaster_key_characteristics_t** outCharacteristics); bool removeOperation(sp<IBinder> token); bool hasPruneableOperation(); @@ -66,10 +67,11 @@ private: void removeOperationTracking(sp<IBinder> token, sp<IBinder> appToken); struct Operation { Operation(); - Operation(keymaster_operation_handle_t handle, keymaster_purpose_t purpose, + Operation(keymaster_operation_handle_t handle, uint64_t keyid, keymaster_purpose_t purpose, const keymaster1_device_t* device, keymaster_key_characteristics_t* characteristics, sp<IBinder> appToken); keymaster_operation_handle_t handle; + uint64_t keyid; keymaster_purpose_t purpose; const keymaster1_device_t* device; Unique_keymaster_key_characteristics characteristics; |