diff options
author | Chad Brubaker <cbrubaker@google.com> | 2015-04-01 17:58:48 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-04-01 17:58:48 +0000 |
commit | c1e78258bb0b5ea1f761f21c3f5e7305aa4cc8ea (patch) | |
tree | 24442bb51298c1bf442943c84e8725e7d0eb26f6 | |
parent | 8c195ad7de989aaee3800dda96472d86289cd82e (diff) | |
parent | 06801e0a7ccabbe8f22cff29b7edb7c7d02d7692 (diff) | |
download | security-android-wear-5.1.1_r1.tar.gz |
Merge "Add auth token fetching"android-wear-5.1.1_r1android-wear-5.1.0_r1
-rw-r--r-- | keystore/auth_token_table.h | 23 | ||||
-rw-r--r-- | keystore/keystore.cpp | 131 | ||||
-rw-r--r-- | keystore/operation.cpp | 23 | ||||
-rw-r--r-- | keystore/operation.h | 7 |
4 files changed, 158 insertions, 26 deletions
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h index d1184e9f..7c183676 100644 --- a/keystore/auth_token_table.h +++ b/keystore/auth_token_table.h @@ -19,6 +19,7 @@ #include <hardware/hw_auth_token.h> #include <keymaster/authorization_set.h> +#include <keymaster/key_blob.h> #ifndef SYSTEM_KEYMASTER_AUTH_TOKEN_TABLE_H #define SYSTEM_KEYMASTER_AUTH_TOKEN_TABLE_H @@ -53,6 +54,7 @@ class AuthTokenTable { // (e.g. new fingerprint enrolled). OP_HANDLE_REQUIRED = -4, // The key requires auth per use but op_handle was zero. AUTH_TOKEN_NOT_FOUND = -5, + AUTH_BAD_PARAMS = -6, }; /** @@ -89,6 +91,27 @@ class AuthTokenTable { } /** + * Find an authorization token that authorizes the operation specified by \p handle on + * a key with the characteristics specified in \p blob. + * + * The table retains ownership of the returned object. + */ + Error FindAuthorization(const keymaster_key_blob_t& blob, keymaster_operation_handle_t handle, + const hw_auth_token_t** found) { + KeyBlob key(blob); + if (key.error()) { + return AUTH_BAD_PARAMS; + } + AuthorizationSet auths(key.unenforced()); + for (auto param : key.enforced()) { + auths.push_back(param); + } + return FindAuthorization(auths, handle, found); + + } + + + /** * Mark operation completed. This allows tokens associated with the specified operation to be * superseded by new tokens. */ diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp index 4b4d4561..f1553cc0 100644 --- a/keystore/keystore.cpp +++ b/keystore/keystore.cpp @@ -105,6 +105,15 @@ struct PKCS8_PRIV_KEY_INFO_Delete { }; typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; +struct keymaster_key_blob_t_Delete { + void operator()(keymaster_key_blob_t* blob) const { + if (blob) { + delete[] blob->key_material; + } + delete blob; + } +}; +typedef UniquePtr<keymaster_key_blob_t, keymaster_key_blob_t_Delete> Unique_keymaster_key_blob; static int keymaster_device_initialize(keymaster0_device_t** dev) { int rc; @@ -2697,6 +2706,56 @@ public: result->resultCode = rc ? rc : ::NO_ERROR; } + /** + * Check that all keymaster_key_param_t's provided by the application are + * allowed. Any parameter that keystore adds itself should be disallowed here. + */ + bool checkAllowedOperationParams(const std::vector<keymaster_key_param_t>& params) { + for (auto param: params) { + switch (param.tag) { + case KM_TAG_AUTH_TOKEN: + return false; + default: + break; + } + } + return true; + } + + int authorizeOperation(const keymaster_key_blob_t& key, + keymaster_operation_handle_t handle, + std::vector<keymaster_key_param_t>* params, + bool failOnTokenMissing=true) { + if (!checkAllowedOperationParams(*params)) { + return KM_ERROR_INVALID_ARGUMENT; + } + // Check for auth token and add it to the param list if present. + const hw_auth_token_t* authToken; + switch (mAuthTokenTable.FindAuthorization(key, handle, &authToken)) { + case keymaster::AuthTokenTable::OK: + // Auth token found. + params->push_back(keymaster_param_blob(KM_TAG_AUTH_TOKEN, + reinterpret_cast<const uint8_t*>(authToken), + sizeof(hw_auth_token_t))); + break; + case keymaster::AuthTokenTable::AUTH_NOT_REQUIRED: + return KM_ERROR_OK; + case keymaster::AuthTokenTable::AUTH_TOKEN_NOT_FOUND: + case keymaster::AuthTokenTable::OP_HANDLE_REQUIRED: + case keymaster::AuthTokenTable::AUTH_TOKEN_EXPIRED: + if (failOnTokenMissing) { + return KM_ERROR_KEY_USER_NOT_AUTHENTICATED; + } + break; + case keymaster::AuthTokenTable::AUTH_TOKEN_WRONG_SID: + return KM_ERROR_KEY_USER_NOT_AUTHENTICATED; + default: + return KM_ERROR_INVALID_ARGUMENT; + } + // TODO: Enforce the rest of authorization + return KM_ERROR_OK; + } + void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose, bool pruneable, const KeymasterArguments& params, const uint8_t* entropy, size_t entropyLength, KeymasterArguments* outParams, OperationResult* result) { @@ -2726,6 +2785,16 @@ public: keymaster_operation_handle_t handle; keymaster1_device_t* dev = mKeyStore->getDeviceForBlob(keyBlob); keymaster_error_t err = KM_ERROR_UNIMPLEMENTED; + std::vector<keymaster_key_param_t> opParams(params.params); + // Don't require an auth token for the call to begin, authentication can + // require an operation handle. Update and finish will require the token + // be present and valid. + int32_t authResult = authorizeOperation(key, 0, &opParams, + /*failOnTokenMissing*/ false); + if (authResult) { + result->resultCode = err; + return; + } // Add entropy to the device first. if (entropy) { if (dev->add_rng_entropy) { @@ -2738,9 +2807,10 @@ public: return; } } - // TODO: Check authorization. - err = dev->begin(dev, purpose, &key, params.params.data(), params.params.size(), &out, - &outSize, &handle); + // Don't do an auth check here, we need begin to succeed for + // per-operation auth. update/finish will be doing the auth checks. + err = dev->begin(dev, purpose, &key, opParams.data(), opParams.size(), &out, &outSize, + &handle); // If there are too many operations abort the oldest operation that was // started as pruneable and try again. @@ -2763,7 +2833,8 @@ public: free(out); } - sp<IBinder> operationToken = mOperationMap.addOperation(handle, dev, appToken, pruneable); + sp<IBinder> operationToken = mOperationMap.addOperation(handle, dev, appToken, key, + pruneable); result->resultCode = ::NO_ERROR; result->token = operationToken; result->handle = handle; @@ -2773,17 +2844,23 @@ public: size_t dataLength, OperationResult* result) { const keymaster1_device_t* dev; keymaster_operation_handle_t handle; - if (!mOperationMap.getOperation(token, &handle, &dev)) { + Unique_keymaster_key_blob key(new keymaster_key_blob_t); + *key = {NULL, 0}; + if (!mOperationMap.getOperation(token, &handle, &dev, key.get())) { result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE; return; } uint8_t* output_buf = NULL; size_t output_length = 0; size_t consumed = 0; - // TODO: Check authorization. - keymaster_error_t err = dev->update(dev, handle, params.params.data(), - params.params.size(), data, dataLength, - &consumed, &output_buf, &output_length); + std::vector<keymaster_key_param_t> opParams(params.params); + int32_t authResult = authorizeOperation(*key, handle, &opParams); + if (authResult) { + result->resultCode = authResult; + return; + } + keymaster_error_t err = dev->update(dev, handle, opParams.data(), opParams.size(), data, + dataLength, &consumed, &output_buf, &output_length); result->data.reset(output_buf); result->dataLength = output_length; result->inputConsumed = consumed; @@ -2794,18 +2871,26 @@ public: const uint8_t* signature, size_t signatureLength, OperationResult* result) { const keymaster1_device_t* dev; keymaster_operation_handle_t handle; - if (!mOperationMap.getOperation(token, &handle, &dev)) { + Unique_keymaster_key_blob key(new keymaster_key_blob_t); + *key = {NULL, 0}; + if (!mOperationMap.getOperation(token, &handle, &dev, key.get())) { result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE; return; } uint8_t* output_buf = NULL; size_t output_length = 0; - // TODO: Check authorization. - keymaster_error_t err = dev->finish(dev, handle, params.params.data(), - params.params.size(), signature, signatureLength, - &output_buf, &output_length); + std::vector<keymaster_key_param_t> opParams(params.params); + int32_t authResult = authorizeOperation(*key, handle, &opParams); + if (authResult) { + result->resultCode = authResult; + return; + } + keymaster_error_t err = dev->finish(dev, handle, opParams.data(), opParams.size(), + signature, signatureLength, &output_buf, + &output_length); // Remove the operation regardless of the result mOperationMap.removeOperation(token); + mAuthTokenTable.MarkCompleted(handle); result->data.reset(output_buf); result->dataLength = output_length; result->resultCode = err ? (int32_t) err : ::NO_ERROR; @@ -2814,14 +2899,17 @@ public: int32_t abort(const sp<IBinder>& token) { const keymaster1_device_t* dev; keymaster_operation_handle_t handle; - if (!mOperationMap.getOperation(token, &handle, &dev)) { + if (!mOperationMap.getOperation(token, &handle, &dev, NULL)) { return KM_ERROR_INVALID_OPERATION_HANDLE; } mOperationMap.removeOperation(token); + int32_t rc; if (!dev->abort) { - return KM_ERROR_UNIMPLEMENTED; + rc = KM_ERROR_UNIMPLEMENTED; + } else { + rc = dev->abort(dev, handle); } - int32_t rc = dev->abort(dev, handle); + mAuthTokenTable.MarkCompleted(handle); if (rc) { return rc; } @@ -2831,11 +2919,14 @@ public: bool isOperationAuthorized(const sp<IBinder>& token) { const keymaster1_device_t* dev; keymaster_operation_handle_t handle; - if(!mOperationMap.getOperation(token, &handle, &dev)) { + Unique_keymaster_key_blob key(new keymaster_key_blob_t); + *key = {NULL, 0}; + if(!mOperationMap.getOperation(token, &handle, &dev, key.get())) { return false; } - // TODO: Check authorization. - return true; + std::vector<keymaster_key_param_t> ignored; + int32_t authResult = authorizeOperation(*key, handle, &ignored); + return authResult == KM_ERROR_OK; } int32_t addAuthToken(const uint8_t* token, size_t length) { diff --git a/keystore/operation.cpp b/keystore/operation.cpp index 0d5b17b8..2fde0da8 100644 --- a/keystore/operation.cpp +++ b/keystore/operation.cpp @@ -26,9 +26,10 @@ OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient) sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle, const keymaster1_device_t* dev, - sp<IBinder> appToken, bool pruneable) { + sp<IBinder> appToken, + const keymaster_key_blob_t& key, bool pruneable) { sp<IBinder> token = new BBinder(); - mMap[token] = Operation(handle, dev, appToken); + mMap[token] = Operation(handle, dev, key, appToken); if (pruneable) { mLru.push_back(token); } @@ -40,7 +41,8 @@ sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle, } bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle, - const keymaster1_device_t** outDevice) { + const keymaster1_device_t** outDevice, + keymaster_key_blob_t* key) { if (!outHandle || !outDevice) { return false; } @@ -52,6 +54,13 @@ bool OperationMap::getOperation(sp<IBinder> token, keymaster_operation_handle_t* *outHandle = entry->second.handle; *outDevice = entry->second.device; + if (key) { + key->key_material_size = entry->second.key.key_material_size; + uint8_t* material = new uint8_t[key->key_material_size]; + memcpy(reinterpret_cast<void*>(material), entry->second.key.key_material, + key->key_material_size); + key->key_material = material; + } return true; } @@ -69,6 +78,7 @@ bool OperationMap::removeOperation(sp<IBinder> token) { return false; } sp<IBinder> appToken = entry->second.appToken; + delete[] entry->second.key.key_material; mMap.erase(entry); auto lruEntry = std::find(mLru.begin(), mLru.end(), token); if (lruEntry != mLru.end()) { @@ -115,12 +125,19 @@ std::vector<sp<IBinder>> OperationMap::getOperationsForToken(sp<IBinder> appToke OperationMap::Operation::Operation(keymaster_operation_handle_t handle_, const keymaster1_device_t* device_, + const keymaster_key_blob_t& key_, sp<IBinder> appToken_) : handle(handle_), device(device_), appToken(appToken_) { + uint8_t* material = new uint8_t[key_.key_material_size]; + memcpy(material, key_.key_material, key_.key_material_size); + key.key_material = material; + key.key_material_size = key_.key_material_size; } OperationMap::Operation::Operation() : handle(0), device(NULL), appToken(NULL) { + key.key_material = NULL; + key.key_material_size = 0; } } // namespace android diff --git a/keystore/operation.h b/keystore/operation.h index f6f3ea72..60768362 100644 --- a/keystore/operation.h +++ b/keystore/operation.h @@ -39,9 +39,9 @@ public: OperationMap(IBinder::DeathRecipient* deathRecipient); sp<IBinder> addOperation(keymaster_operation_handle_t handle, const keymaster1_device_t* dev, sp<IBinder> appToken, - bool pruneable); + const keymaster_key_blob_t& key, bool pruneable); bool getOperation(sp<IBinder> token, keymaster_operation_handle_t* outHandle, - const keymaster1_device_t** outDev); + const keymaster1_device_t** outDev, keymaster_key_blob_t* outKey); bool removeOperation(sp<IBinder> token); bool hasPruneableOperation(); sp<IBinder> getOldestPruneableOperation(); @@ -53,9 +53,10 @@ private: struct Operation { Operation(); Operation(keymaster_operation_handle_t handle, const keymaster1_device_t* device, - sp<IBinder> appToken); + const keymaster_key_blob_t& key, sp<IBinder> appToken); keymaster_operation_handle_t handle; const keymaster1_device_t* device; + keymaster_key_blob_t key; sp<IBinder> appToken; }; std::map<sp<IBinder>, struct Operation> mMap; |