Merge "Move auth token checking to begin"
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 32354df..dcb6032 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -41,6 +41,7 @@
WRONG_PASSWORD_2 = 12,
WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
SIGNATURE_INVALID = 14,
+ OP_AUTH_NEEDED = 15, // Auth is needed for this operation before it can be used.
};
/*
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 8db8dab..c3896b5 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -2510,93 +2510,6 @@
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_characteristics_t& characteristics,
- keymaster_operation_handle_t handle,
- std::vector<keymaster_key_param_t>* params,
- bool failOnTokenMissing=true) {
- if (!checkAllowedOperationParams(*params)) {
- return KM_ERROR_INVALID_ARGUMENT;
- }
- std::vector<keymaster_key_param_t> allCharacteristics;
- for (size_t i = 0; i < characteristics.sw_enforced.length; i++) {
- allCharacteristics.push_back(characteristics.sw_enforced.params[i]);
- }
- for (size_t i = 0; i < characteristics.hw_enforced.length; i++) {
- allCharacteristics.push_back(characteristics.hw_enforced.params[i]);
- }
- // Check for auth token and add it to the param list if present.
- const hw_auth_token_t* authToken;
- switch (mAuthTokenTable.FindAuthorization(allCharacteristics.data(),
- allCharacteristics.size(), 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;
- }
-
- keymaster_error_t getOperationCharacteristics(const keymaster_key_blob_t& key,
- const keymaster1_device_t* dev,
- const std::vector<keymaster_key_param_t>& params,
- keymaster_key_characteristics_t* out) {
- UniquePtr<keymaster_blob_t> appId;
- UniquePtr<keymaster_blob_t> appData;
- for (auto param : params) {
- if (param.tag == KM_TAG_APPLICATION_ID) {
- appId.reset(new keymaster_blob_t);
- appId->data = param.blob.data;
- appId->data_length = param.blob.data_length;
- } else if (param.tag == KM_TAG_APPLICATION_DATA) {
- appData.reset(new keymaster_blob_t);
- appData->data = param.blob.data;
- appData->data_length = param.blob.data_length;
- }
- }
- keymaster_key_characteristics_t* result = NULL;
- if (!dev->get_key_characteristics) {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t error = dev->get_key_characteristics(dev, &key, appId.get(),
- appData.get(), &result);
- if (result) {
- *out = *result;
- free(result);
- }
- return error;
- }
void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose,
bool pruneable, const KeymasterArguments& params, const uint8_t* entropy,
@@ -2611,6 +2524,10 @@
result->resultCode = ::PERMISSION_DENIED;
return;
}
+ if (!checkAllowedOperationParams(params.params)) {
+ result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+ return;
+ }
Blob keyBlob;
String8 name8(name);
ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
@@ -2635,15 +2552,17 @@
result->resultCode = err;
return;
}
- // 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(*characteristics, 0, &opParams,
+ const hw_auth_token_t* authToken = NULL;
+ int32_t authResult = getAuthToken(characteristics.get(), 0, &authToken,
/*failOnTokenMissing*/ false);
- if (authResult) {
- result->resultCode = err;
+ // If per-operation auth is needed we need to begin the operation and
+ // the client will need to authorize that operation before calling
+ // update. Any other auth issues stop here.
+ if (authResult != ::NO_ERROR && authResult != ::OP_AUTH_NEEDED) {
+ result->resultCode = authResult;
return;
}
+ addAuthToParams(&opParams, authToken);
// Add entropy to the device first.
if (entropy) {
if (dev->add_rng_entropy) {
@@ -2656,8 +2575,6 @@
return;
}
}
- // 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);
@@ -2669,8 +2586,7 @@
if (abort(oldest) != ::NO_ERROR) {
break;
}
- err = dev->begin(dev, purpose, &key, params.params.data(),
- params.params.size(), &out, &outSize,
+ err = dev->begin(dev, purpose, &key, opParams.data(), opParams.size(), &out, &outSize,
&handle);
}
if (err) {
@@ -2685,17 +2601,28 @@
sp<IBinder> operationToken = mOperationMap.addOperation(handle, dev, appToken,
characteristics.release(),
pruneable);
- result->resultCode = ::NO_ERROR;
+ if (authToken) {
+ mOperationMap.setOperationAuthToken(operationToken, authToken);
+ }
+ // Return the authentication lookup result. If this is a per operation
+ // auth'd key then the resultCode will be ::OP_AUTH_NEEDED and the
+ // application should get an auth token using the handle before the
+ // first call to update, which will fail if keystore hasn't received the
+ // auth token.
+ result->resultCode = authResult;
result->token = operationToken;
result->handle = handle;
}
void update(const sp<IBinder>& token, const KeymasterArguments& params, const uint8_t* data,
size_t dataLength, OperationResult* result) {
+ if (!checkAllowedOperationParams(params.params)) {
+ result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+ return;
+ }
const keymaster1_device_t* dev;
keymaster_operation_handle_t handle;
- const keymaster_key_characteristics_t* characteristics;
- if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+ if (!mOperationMap.getOperation(token, &handle, &dev, NULL)) {
result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE;
return;
}
@@ -2703,8 +2630,8 @@
size_t output_length = 0;
size_t consumed = 0;
std::vector<keymaster_key_param_t> opParams(params.params);
- int32_t authResult = authorizeOperation(*characteristics, handle, &opParams);
- if (authResult) {
+ int32_t authResult = addOperationAuthTokenIfNeeded(token, &opParams);
+ if (authResult != ::NO_ERROR) {
result->resultCode = authResult;
return;
}
@@ -2718,21 +2645,25 @@
void finish(const sp<IBinder>& token, const KeymasterArguments& params,
const uint8_t* signature, size_t signatureLength, OperationResult* result) {
+ if (!checkAllowedOperationParams(params.params)) {
+ result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+ return;
+ }
const keymaster1_device_t* dev;
keymaster_operation_handle_t handle;
- const keymaster_key_characteristics_t* characteristics;
- if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+ if (!mOperationMap.getOperation(token, &handle, &dev, NULL)) {
result->resultCode = KM_ERROR_INVALID_OPERATION_HANDLE;
return;
}
uint8_t* output_buf = NULL;
size_t output_length = 0;
std::vector<keymaster_key_param_t> opParams(params.params);
- int32_t authResult = authorizeOperation(*characteristics, handle, &opParams);
- if (authResult) {
+ int32_t authResult = addOperationAuthTokenIfNeeded(token, &opParams);
+ if (authResult != ::NO_ERROR) {
result->resultCode = authResult;
return;
}
+
keymaster_error_t err = dev->finish(dev, handle, opParams.data(), opParams.size(),
signature, signatureLength, &output_buf,
&output_length);
@@ -2771,9 +2702,11 @@
if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
return false;
}
+ const hw_auth_token_t* authToken = NULL;
+ mOperationMap.getOperationAuthToken(token, &authToken);
std::vector<keymaster_key_param_t> ignored;
- int32_t authResult = authorizeOperation(*characteristics, handle, &ignored);
- return authResult == KM_ERROR_OK;
+ int32_t authResult = addOperationAuthTokenIfNeeded(token, &ignored);
+ return authResult == ::NO_ERROR;
}
int32_t addAuthToken(const uint8_t* token, size_t length) {
@@ -2900,6 +2833,137 @@
}
}
+ /**
+ * 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;
+ }
+
+ keymaster_error_t getOperationCharacteristics(const keymaster_key_blob_t& key,
+ const keymaster1_device_t* dev,
+ const std::vector<keymaster_key_param_t>& params,
+ keymaster_key_characteristics_t* out) {
+ UniquePtr<keymaster_blob_t> appId;
+ UniquePtr<keymaster_blob_t> appData;
+ for (auto param : params) {
+ if (param.tag == KM_TAG_APPLICATION_ID) {
+ appId.reset(new keymaster_blob_t);
+ appId->data = param.blob.data;
+ appId->data_length = param.blob.data_length;
+ } else if (param.tag == KM_TAG_APPLICATION_DATA) {
+ appData.reset(new keymaster_blob_t);
+ appData->data = param.blob.data;
+ appData->data_length = param.blob.data_length;
+ }
+ }
+ keymaster_key_characteristics_t* result = NULL;
+ if (!dev->get_key_characteristics) {
+ return KM_ERROR_UNIMPLEMENTED;
+ }
+ keymaster_error_t error = dev->get_key_characteristics(dev, &key, appId.get(),
+ appData.get(), &result);
+ if (result) {
+ *out = *result;
+ free(result);
+ }
+ return error;
+ }
+
+ /**
+ * Get the auth token for this operation from the auth token table.
+ *
+ * Returns ::NO_ERROR if the auth token was set or none was required.
+ * ::OP_AUTH_NEEDED if it is a per op authorization, no
+ * authorization token exists for that operation and
+ * failOnTokenMissing is false.
+ * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
+ * token for the operation
+ */
+ int32_t getAuthToken(const keymaster_key_characteristics_t* characteristics,
+ keymaster_operation_handle_t handle,
+ const hw_auth_token_t** authToken,
+ bool failOnTokenMissing = true) {
+
+ std::vector<keymaster_key_param_t> allCharacteristics;
+ for (size_t i = 0; i < characteristics->sw_enforced.length; i++) {
+ allCharacteristics.push_back(characteristics->sw_enforced.params[i]);
+ }
+ for (size_t i = 0; i < characteristics->hw_enforced.length; i++) {
+ allCharacteristics.push_back(characteristics->hw_enforced.params[i]);
+ }
+ keymaster::AuthTokenTable::Error err =
+ mAuthTokenTable.FindAuthorization(allCharacteristics.data(),
+ allCharacteristics.size(), handle, authToken);
+ switch (err) {
+ case keymaster::AuthTokenTable::OK:
+ case keymaster::AuthTokenTable::AUTH_NOT_REQUIRED:
+ return ::NO_ERROR;
+ case keymaster::AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
+ case keymaster::AuthTokenTable::AUTH_TOKEN_EXPIRED:
+ case keymaster::AuthTokenTable::AUTH_TOKEN_WRONG_SID:
+ return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
+ case keymaster::AuthTokenTable::OP_HANDLE_REQUIRED:
+ return failOnTokenMissing ? (int32_t) KM_ERROR_KEY_USER_NOT_AUTHENTICATED :
+ (int32_t) ::OP_AUTH_NEEDED;
+ default:
+ ALOGE("Unexpected FindAuthorization return value %d", err);
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+ }
+
+ inline void addAuthToParams(std::vector<keymaster_key_param_t>* params,
+ const hw_auth_token_t* token) {
+ if (token) {
+ params->push_back(keymaster_param_blob(KM_TAG_AUTH_TOKEN,
+ reinterpret_cast<const uint8_t*>(token),
+ sizeof(hw_auth_token_t)));
+ }
+ }
+
+ /**
+ * Add the auth token for the operation to the param list if the operation
+ * requires authorization. Uses the cached result in the OperationMap if available
+ * otherwise gets the token from the AuthTokenTable and caches the result.
+ *
+ * Returns ::NO_ERROR if the auth token was added or not needed.
+ * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not
+ * authenticated.
+ * KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid
+ * operation token.
+ */
+ int32_t addOperationAuthTokenIfNeeded(sp<IBinder> token,
+ std::vector<keymaster_key_param_t>* params) {
+ const hw_auth_token_t* authToken = NULL;
+ bool authTokenNeeded = !mOperationMap.getOperationAuthToken(token, &authToken);
+ if (authTokenNeeded) {
+ const keymaster1_device_t* dev;
+ keymaster_operation_handle_t handle;
+ const keymaster_key_characteristics_t* characteristics = NULL;
+ if (!mOperationMap.getOperation(token, &handle, &dev, &characteristics)) {
+ return KM_ERROR_INVALID_OPERATION_HANDLE;
+ }
+ int32_t result = getAuthToken(characteristics, handle, &authToken);
+ if (result != ::NO_ERROR) {
+ return result;
+ }
+ if (authToken) {
+ mOperationMap.setOperationAuthToken(token, authToken);
+ }
+ }
+ addAuthToParams(params, authToken);
+ return ::NO_ERROR;
+ }
+
::KeyStore* mKeyStore;
OperationMap mOperationMap;
keymaster::AuthTokenTable mAuthTokenTable;
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index e871f83..667f456 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -110,6 +110,29 @@
return mLru[0];
}
+bool OperationMap::getOperationAuthToken(sp<IBinder> token, const hw_auth_token_t** outToken) {
+ auto entry = mMap.find(token);
+ if (entry == mMap.end()) {
+ return false;
+ }
+ if (entry->second.authToken.get() != NULL) {
+ *outToken = *entry->second.authToken;
+ } else {
+ *outToken = NULL;
+ }
+ return true;
+}
+
+bool OperationMap::setOperationAuthToken(sp<IBinder> token, const hw_auth_token_t* authToken) {
+ auto entry = mMap.find(token);
+ if (entry == mMap.end()) {
+ return false;
+ }
+ entry->second.authToken.reset(new const hw_auth_token_t*);
+ *entry->second.authToken = authToken;
+ return true;
+}
+
std::vector<sp<IBinder>> OperationMap::getOperationsForToken(sp<IBinder> appToken) {
auto appEntry = mAppTokenMap.find(appToken);
if (appEntry != mAppTokenMap.end()) {
diff --git a/keystore/operation.h b/keystore/operation.h
index a312528..fb9583f 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -17,6 +17,7 @@
#ifndef KEYSTORE_OPERATION_H_
#define KEYSTORE_OPERATION_H_
+#include <hardware/hw_auth_token.h>
#include <hardware/keymaster1.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
@@ -54,6 +55,8 @@
const keymaster_key_characteristics_t** outCharacteristics);
bool removeOperation(sp<IBinder> token);
bool hasPruneableOperation();
+ bool getOperationAuthToken(sp<IBinder> token, const hw_auth_token_t** outToken);
+ bool setOperationAuthToken(sp<IBinder> token, const hw_auth_token_t* authToken);
sp<IBinder> getOldestPruneableOperation();
std::vector<sp<IBinder>> getOperationsForToken(sp<IBinder> appToken);
@@ -68,6 +71,7 @@
const keymaster1_device_t* device;
Unique_keymaster_key_characteristics characteristics;
sp<IBinder> appToken;
+ std::unique_ptr<const hw_auth_token_t*> authToken;
};
std::map<sp<IBinder>, struct Operation> mMap;
std::vector<sp<IBinder>> mLru;