Merge "Add auth token fetching"
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 @@
                                     // (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 @@
     }
 
     /**
+     * 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 @@
 };
 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 @@
         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 @@
         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 @@
                 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 @@
             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 @@
                 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 @@
                 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 @@
     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 @@
     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 @@
 
 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 @@
 }
 
 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 @@
 
     *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 @@
         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 @@
 
 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 @@
     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 @@
     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;