summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Brubaker <cbrubaker@google.com>2015-04-01 17:58:48 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-01 17:58:48 +0000
commitc1e78258bb0b5ea1f761f21c3f5e7305aa4cc8ea (patch)
tree24442bb51298c1bf442943c84e8725e7d0eb26f6
parent8c195ad7de989aaee3800dda96472d86289cd82e (diff)
parent06801e0a7ccabbe8f22cff29b7edb7c7d02d7692 (diff)
downloadsecurity-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.h23
-rw-r--r--keystore/keystore.cpp131
-rw-r--r--keystore/operation.cpp23
-rw-r--r--keystore/operation.h7
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;