summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChad Brubaker <cbrubaker@google.com>2015-03-31 15:13:13 -0700
committerChad Brubaker <cbrubaker@google.com>2015-04-01 10:42:44 -0700
commit06801e0a7ccabbe8f22cff29b7edb7c7d02d7692 (patch)
tree24442bb51298c1bf442943c84e8725e7d0eb26f6
parent8c195ad7de989aaee3800dda96472d86289cd82e (diff)
downloadandroid_system_security-06801e0a7ccabbe8f22cff29b7edb7c7d02d7692.tar.gz
android_system_security-06801e0a7ccabbe8f22cff29b7edb7c7d02d7692.tar.bz2
android_system_security-06801e0a7ccabbe8f22cff29b7edb7c7d02d7692.zip
Add auth token fetching
Auth tokens are now fetched from the table in begin update and finish if needed. Begin will not fail on a missing/expired auth token since some authorization requires a valid operation handle. This doesn't yet do any enforcement of the token beyond what the auth token table does, that should happen in the keymaster auth code when it is done. This also includes the key in the operation map since authorization works based off that and not the handle. Change-Id: I62a395b74a925b819f4cde75ae3bfab8b8928cd1
-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 d1184e9..7c18367 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 4b4d456..f1553cc 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 0d5b17b..2fde0da 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 f6f3ea7..6076836 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;