/*
**
** Copyright 2018, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#define LOG_TAG "keymaster_worker"

#include "keymaster_worker.h"

#include "keystore_utils.h"

#include <android-base/logging.h>

#include "KeyStore.h"
#include "keymaster_enforcement.h"

#include "key_proto_handler.h"
#include "keystore_utils.h"

namespace keystore {

constexpr size_t kMaxOperations = 15;

using AndroidKeymasterArguments = android::security::keymaster::KeymasterArguments;
using android::security::keymaster::ExportResult;
using android::security::keymaster::operationFailed;
using android::security::keymaster::OperationResult;

Worker::Worker() {}
Worker::~Worker() {
    std::unique_lock<std::mutex> lock(pending_requests_mutex_);
    pending_requests_cond_var_.wait(lock, [this] { return pending_requests_.empty(); });
}
void Worker::addRequest(WorkerTask request) {
    std::unique_lock<std::mutex> lock(pending_requests_mutex_);
    bool start_thread = pending_requests_.empty();
    pending_requests_.push(std::move(request));
    lock.unlock();
    if (start_thread) {
        auto worker = std::thread([this] {
            std::unique_lock<std::mutex> lock(pending_requests_mutex_);
            running_ = true;
            while (!pending_requests_.empty()) {
                auto request = std::move(pending_requests_.front());
                lock.unlock();
                request();
                lock.lock();
                pending_requests_.pop();
                pending_requests_cond_var_.notify_all();
            }
        });
        worker.detach();
    }
}

KeymasterWorker::KeymasterWorker(sp<Keymaster> keymasterDevice, KeyStore* keyStore)
    : keymasterDevice_(std::move(keymasterDevice)), operationMap_(keyStore), keyStore_(keyStore) {
    // make sure that hal version is cached.
    if (keymasterDevice_) keymasterDevice_->halVersion();
}

void KeymasterWorker::logIfKeymasterVendorError(ErrorCode ec) const {
    keymasterDevice_->logIfKeymasterVendorError(ec);
}

std::tuple<KeyStoreServiceReturnCode, Blob>
KeymasterWorker::upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry,
                                const AuthorizationSet& params) {
    LOG(INFO) << "upgradeKeyBlob " << lockedEntry->alias() << " " << (uint32_t)lockedEntry->uid();

    std::tuple<KeyStoreServiceReturnCode, Blob> result;

    auto userState = keyStore_->getUserStateDB().getUserStateByUid(lockedEntry->uid());

    Blob& blob = std::get<1>(result);
    KeyStoreServiceReturnCode& error = std::get<0>(result);

    Blob charBlob;
    ResponseCode rc;

    std::tie(rc, blob, charBlob) =
        lockedEntry.readBlobs(userState->getEncryptionKey(), userState->getState());

    userState = {};

    if (rc != ResponseCode::NO_ERROR) {
        return error = rc, result;
    }

    auto hidlKey = blob2hidlVec(blob);
    auto& dev = keymasterDevice_;

    auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
        dev->logIfKeymasterVendorError(ret);
        error = ret;
        if (!error.isOk()) {
            if (error == ErrorCode::INVALID_KEY_BLOB) {
                log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
            }
            return;
        }

        error = keyStore_->del(lockedEntry);
        if (!error.isOk()) {
            ALOGI("upgradeKeyBlob keystore->del failed %d", error.getErrorCode());
            return;
        }

        Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
                     0 /* infoLength */, ::TYPE_KEYMASTER_10);
        newBlob.setSecurityLevel(blob.getSecurityLevel());
        newBlob.setEncrypted(blob.isEncrypted());
        newBlob.setSuperEncrypted(blob.isSuperEncrypted());
        newBlob.setCriticalToDeviceEncryption(blob.isCriticalToDeviceEncryption());

        error = keyStore_->put(lockedEntry, newBlob, charBlob);
        if (!error.isOk()) {
            ALOGI("upgradeKeyBlob keystore->put failed %d", error.getErrorCode());
            return;
        }
        blob = std::move(newBlob);
    };

    KeyStoreServiceReturnCode error2;
    error2 = KS_HANDLE_HIDL_ERROR(dev, dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
    if (!error2.isOk()) {
        return error = error2, result;
    }

    return result;
}

std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
KeymasterWorker::createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry,
                                               const hidl_vec<uint8_t>& clientId,
                                               const hidl_vec<uint8_t>& appData, Blob keyBlob,
                                               Blob charBlob) {
    std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob> result;

#if __cplusplus == 201703L
    auto& [rc, resultCharacteristics, outBlob, charOutBlob] = result;
#else
    KeyStoreServiceReturnCode& rc = std::get<0>(result);
    KeyCharacteristics& resultCharacteristics = std::get<1>(result);
    Blob& outBlob = std::get<2>(result);
    Blob& charOutBlob = std::get<3>(result);
#endif

    rc = ResponseCode::SYSTEM_ERROR;
    if (!keyBlob) return result;
    auto hidlKeyBlob = blob2hidlVec(keyBlob);
    auto& dev = keymasterDevice_;

    KeyStoreServiceReturnCode error;

    AuthorizationSet hwEnforced, swEnforced;
    bool success = true;

    if (charBlob) {
        std::tie(success, hwEnforced, swEnforced) = charBlob.getKeyCharacteristics();
    }
    if (!success) {
        LOG(ERROR) << "Failed to read cached key characteristics";
        return rc = ResponseCode::SYSTEM_ERROR, result;
    }

    auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
        dev->logIfKeymasterVendorError(ret);
        error = ret;
        if (!error.isOk()) {
            if (error == ErrorCode::INVALID_KEY_BLOB) {
                log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
            }
            return;
        }

        // Replace the sw_enforced set with those persisted to disk, minus hw_enforced
        AuthorizationSet softwareEnforced = keyCharacteristics.softwareEnforced;
        hwEnforced = keyCharacteristics.hardwareEnforced;
        swEnforced.Union(softwareEnforced);
        softwareEnforced.Subtract(hwEnforced);

        // We only get the characteristics from keymaster if there was no cache file or the
        // the chach file was a legacy cache file. So lets write a new cache file for the next time.
        Blob newCharBlob;
        success = newCharBlob.putKeyCharacteristics(hwEnforced, swEnforced);
        if (!success) {
            error = ResponseCode::SYSTEM_ERROR;
            LOG(ERROR) << "Failed to serialize cached key characteristics";
            return;
        }

        error = keyStore_->put(lockedEntry, {}, newCharBlob);
        if (!error.isOk()) {
            ALOGE("Failed to write key characteristics cache");
            return;
        }
        charBlob = std::move(newCharBlob);
    };

    if (!charBlob || charBlob.getType() == TYPE_KEY_CHARACTERISTICS) {
        // this updates the key characteristics cache file to the new format or creates one in
        // in the first place
        rc = KS_HANDLE_HIDL_ERROR(
            dev, dev->getKeyCharacteristics(hidlKeyBlob, clientId, appData, hidlCb));
        if (!rc.isOk()) {
            return result;
        }

        if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
            AuthorizationSet upgradeParams;
            if (clientId.size()) {
                upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
            }
            if (appData.size()) {
                upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
            }
            std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
            if (!rc.isOk()) {
                return result;
            }

            auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);

            rc = KS_HANDLE_HIDL_ERROR(
                dev, dev->getKeyCharacteristics(upgradedHidlKeyBlob, clientId, appData, hidlCb));
            if (!rc.isOk()) {
                return result;
            }
        }
    }

    resultCharacteristics.hardwareEnforced = hwEnforced.hidl_data();
    resultCharacteristics.softwareEnforced = swEnforced.hidl_data();

    outBlob = std::move(keyBlob);
    charOutBlob = std::move(charBlob);
    rc = error;
    return result;
}

/**
 * Get the auth token for this operation from the auth token table.
 *
 * Returns ResponseCode::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
 */
std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
KeymasterWorker::getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle,
                              KeyPurpose purpose, bool failOnTokenMissing) {

    AuthorizationSet allCharacteristics(characteristics.softwareEnforced);
    allCharacteristics.append(characteristics.hardwareEnforced.begin(),
                              characteristics.hardwareEnforced.end());

    HardwareAuthToken authToken;
    AuthTokenTable::Error err;
    std::tie(err, authToken) = keyStore_->getAuthTokenTable().FindAuthorization(
        allCharacteristics, static_cast<KeyPurpose>(purpose), handle);

    KeyStoreServiceReturnCode rc;

    switch (err) {
    case AuthTokenTable::OK:
    case AuthTokenTable::AUTH_NOT_REQUIRED:
        rc = ResponseCode::NO_ERROR;
        break;

    case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
    case AuthTokenTable::AUTH_TOKEN_EXPIRED:
    case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
        ALOGE("getAuthToken failed: %d", err);  // STOPSHIP: debug only, to be removed
        rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
        break;

    case AuthTokenTable::OP_HANDLE_REQUIRED:
        rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
                                : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
        break;

    default:
        ALOGE("Unexpected FindAuthorization return value %d", err);
        rc = ErrorCode::INVALID_ARGUMENT;
    }

    return {rc, std::move(authToken)};
}

KeyStoreServiceReturnCode KeymasterWorker::abort(const sp<IBinder>& token) {
    auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */);
    if (op) {
        keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
        return KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
    } else {
        return ErrorCode::INVALID_OPERATION_HANDLE;
    }
}

/**
 * Prune the oldest pruneable operation.
 */
bool KeymasterWorker::pruneOperation() {
    sp<IBinder> oldest = operationMap_.getOldestPruneableOperation();
    ALOGD("Trying to prune operation %p", oldest.get());
    size_t op_count_before_abort = operationMap_.getOperationCount();
    // We mostly ignore errors from abort() because all we care about is whether at least
    // one operation has been removed.
    auto rc = abort(oldest);
    if (operationMap_.getOperationCount() >= op_count_before_abort) {
        ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), rc.getErrorCode());
        return false;
    }
    return true;
}

// My IDE defines "CAPTURE_MOVE(x) x" because it does not understand generalized lambda captures.
// It should never be redefined by a build system though.
#ifndef CAPTURE_MOVE
#define CAPTURE_MOVE(x) x = std::move(x)
#endif

void KeymasterWorker::begin(LockedKeyBlobEntry lockedEntry, sp<IBinder> appToken, Blob keyBlob,
                            Blob charBlob, bool pruneable, KeyPurpose purpose,
                            AuthorizationSet opParams, hidl_vec<uint8_t> entropy,
                            worker_begin_cb worker_cb) {

    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(appToken),
                        CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob), pruneable, purpose,
                        CAPTURE_MOVE(opParams), CAPTURE_MOVE(entropy),
                        CAPTURE_MOVE(worker_cb)]() mutable {
        // Concurrently executed

        auto& dev = keymasterDevice_;

        KeyCharacteristics characteristics;

        {
            hidl_vec<uint8_t> clientId;
            hidl_vec<uint8_t> appData;
            for (const auto& param : opParams) {
                if (param.tag == Tag::APPLICATION_ID) {
                    clientId = authorizationValue(TAG_APPLICATION_ID, param).value();
                } else if (param.tag == Tag::APPLICATION_DATA) {
                    appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
                }
            }
            KeyStoreServiceReturnCode error;
            std::tie(error, characteristics, keyBlob, charBlob) = createKeyCharacteristicsCache(
                lockedEntry, clientId, appData, std::move(keyBlob), std::move(charBlob));
            if (!error.isOk()) {
                worker_cb(operationFailed(error));
                return;
            }
        }

        KeyStoreServiceReturnCode rc, authRc;
        HardwareAuthToken authToken;
        std::tie(authRc, authToken) = getAuthToken(characteristics, 0 /* no challenge */, purpose,
                                                   /*failOnTokenMissing*/ false);

        // 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 (!authRc.isOk() && authRc != ResponseCode::OP_AUTH_NEEDED) {
            return worker_cb(operationFailed(authRc));
        }

        // Add entropy to the device first.
        if (entropy.size()) {
            rc = KS_HANDLE_HIDL_ERROR(dev, dev->addRngEntropy(entropy));
            if (!rc.isOk()) {
                return worker_cb(operationFailed(rc));
            }
        }

        // Create a keyid for this key.
        auto keyid = KeymasterEnforcement::CreateKeyId(blob2hidlVec(keyBlob));
        if (!keyid) {
            ALOGE("Failed to create a key ID for authorization checking.");
            return worker_cb(operationFailed(ErrorCode::UNKNOWN_ERROR));
        }

        // Check that all key authorization policy requirements are met.
        AuthorizationSet key_auths = characteristics.hardwareEnforced;
        key_auths.append(characteristics.softwareEnforced.begin(),
                         characteristics.softwareEnforced.end());

        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(
            purpose, *keyid, key_auths, opParams, authToken, 0 /* op_handle */,
            true /* is_begin_operation */);
        if (!rc.isOk()) {
            return worker_cb(operationFailed(rc));
        }

        // If there are more than kMaxOperations, abort the oldest operation that was started as
        // pruneable.
        while (operationMap_.getOperationCount() >= kMaxOperations) {
            ALOGD("Reached or exceeded concurrent operations limit");
            if (!pruneOperation()) {
                break;
            }
        }

        android::security::keymaster::OperationResult result;

        auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
                          uint64_t operationHandle) {
            dev->logIfKeymasterVendorError(ret);
            result.resultCode = ret;
            if (!result.resultCode.isOk()) {
                if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
                    log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
                }
                return;
            }
            result.handle = operationHandle;
            result.outParams = outParams;
        };

        do {
            rc = KS_HANDLE_HIDL_ERROR(dev, dev->begin(purpose, blob2hidlVec(keyBlob),
                                                      opParams.hidl_data(), authToken, hidlCb));
            if (!rc.isOk()) {
                LOG(ERROR) << "Got error " << rc << " from begin()";
                return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
            }

            if (result.resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
                std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, opParams);
                if (!rc.isOk()) {
                    return worker_cb(operationFailed(rc));
                }

                rc = KS_HANDLE_HIDL_ERROR(dev, dev->begin(purpose, blob2hidlVec(keyBlob),
                                                          opParams.hidl_data(), authToken, hidlCb));
                if (!rc.isOk()) {
                    LOG(ERROR) << "Got error " << rc << " from begin()";
                    return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
                }
            }
            // If there are too many operations abort the oldest operation that was
            // started as pruneable and try again.
        } while (result.resultCode == ErrorCode::TOO_MANY_OPERATIONS && pruneOperation());

        rc = result.resultCode;
        if (!rc.isOk()) {
            return worker_cb(operationFailed(rc));
        }

        // Note: The operation map takes possession of the contents of "characteristics".
        // It is safe to use characteristics after the following line but it will be empty.
        sp<IBinder> operationToken =
            operationMap_.addOperation(result.handle, *keyid, purpose, dev, appToken,
                                       std::move(characteristics), opParams.hidl_data(), pruneable);
        assert(characteristics.hardwareEnforced.size() == 0);
        assert(characteristics.softwareEnforced.size() == 0);
        result.token = operationToken;

        auto operation = operationMap_.getOperation(operationToken);
        if (!operation) {
            return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
        }

        if (authRc.isOk() && authToken.mac.size() &&
            dev->halVersion().securityLevel == SecurityLevel::STRONGBOX) {
            operation->authTokenFuture = operation->authTokenPromise.get_future();
            std::weak_ptr<Operation> weak_operation = operation;

            auto verifyTokenCB = [weak_operation](KeyStoreServiceReturnCode rc,
                                                  HardwareAuthToken authToken,
                                                  VerificationToken verificationToken) {
                auto operation = weak_operation.lock();
                if (!operation) {
                    // operation aborted, nothing to do
                    return;
                }
                if (rc.isOk()) {
                    operation->authToken = std::move(authToken);
                    operation->verificationToken = std::move(verificationToken);
                }
                operation->authTokenPromise.set_value(rc);
            };
            auto teeKmDevice = keyStore_->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
            teeKmDevice->verifyAuthorization(result.handle, {}, std::move(authToken),
                                             std::move(verifyTokenCB));
        }

        // 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.
        if (result.resultCode.isOk()) {
            result.resultCode = authRc;
        }
        return worker_cb(result);
    });
}

KeyStoreServiceReturnCode
KeymasterWorker::getOperationAuthTokenIfNeeded(std::shared_ptr<Operation> op) {
    if (!op) return ErrorCode::INVALID_OPERATION_HANDLE;

    if (op->authTokenFuture.valid()) {
        LOG(INFO) << "Waiting for verification token";
        op->authTokenFuture.wait();
        auto rc = op->authTokenFuture.get();
        if (!rc.isOk()) {
            return rc;
        }
        op->authTokenFuture = {};
    } else if (!op->hasAuthToken()) {
        KeyStoreServiceReturnCode rc;
        HardwareAuthToken found;
        std::tie(rc, found) = getAuthToken(op->characteristics, op->handle, op->purpose);
        if (!rc.isOk()) return rc;
        op->authToken = std::move(found);
    }

    return ResponseCode::NO_ERROR;
}

namespace {

class Finalize {
  private:
    std::function<void()> f_;

  public:
    explicit Finalize(std::function<void()> f) : f_(f) {}
    ~Finalize() {
        if (f_) f_();
    }
    void release() { f_ = {}; }
};

}  // namespace

void KeymasterWorker::update(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> data,
                             update_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(data),
                        CAPTURE_MOVE(worker_cb)]() {
        KeyStoreServiceReturnCode rc;
        auto op = operationMap_.getOperation(token);
        if (!op) {
            return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
        }

        Finalize abort_operation_in_case_of_error([&] {
            operationMap_.removeOperation(token, false);
            keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
            KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
        });

        rc = getOperationAuthTokenIfNeeded(op);
        if (!rc.isOk()) return worker_cb(operationFailed(rc));

        // Check that all key authorization policy requirements are met.
        AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
        key_auths.append(op->characteristics.softwareEnforced.begin(),
                         op->characteristics.softwareEnforced.end());

        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
                                                                  params, op->authToken, op->handle,
                                                                  false /* is_begin_operation */);
        if (!rc.isOk()) return worker_cb(operationFailed(rc));

        OperationResult result;
        auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
                          const hidl_vec<KeyParameter>& outParams,
                          const ::std::vector<uint8_t>& output) {
            op->device->logIfKeymasterVendorError(ret);
            result.resultCode = ret;
            if (result.resultCode.isOk()) {
                result.inputConsumed = inputConsumed;
                result.outParams = outParams;
                result.data = output;
            }
        };

        rc = KS_HANDLE_HIDL_ERROR(op->device,
                                  op->device->update(op->handle, params.hidl_data(), data,
                                                     op->authToken, op->verificationToken, hidlCb));

        // just a reminder: on success result->resultCode was set in the callback. So we only
        // overwrite it if there was a communication error indicated by the ErrorCode.
        if (!rc.isOk()) result.resultCode = rc;
        if (result.resultCode.isOk()) {
            // if everything went well we don't abort the operation.
            abort_operation_in_case_of_error.release();
        }
        return worker_cb(std::move(result));
    });
}

/**
 * Check that all KeyParameters provided by the application are allowed. Any parameter that keystore
 * adds itself should be disallowed here.
 */
template <typename ParamsIter>
static bool checkAllowedOperationParams(ParamsIter begin, const ParamsIter end) {
    while (begin != end) {
        switch (begin->tag) {
        case Tag::ATTESTATION_APPLICATION_ID:
        case Tag::RESET_SINCE_ID_ROTATION:
            return false;
        default:
            break;
        }
        ++begin;
    }
    return true;
}

void KeymasterWorker::finish(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> input,
                             hidl_vec<uint8_t> signature, hidl_vec<uint8_t> entropy,
                             finish_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(input),
                        CAPTURE_MOVE(signature), CAPTURE_MOVE(entropy),
                        CAPTURE_MOVE(worker_cb)]() mutable {
        KeyStoreServiceReturnCode rc;
        auto op = operationMap_.getOperation(token);
        if (!op) {
            return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
        }

        bool finished = false;
        Finalize abort_operation_in_case_of_error([&] {
            operationMap_.removeOperation(token, finished && rc.isOk());
            keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
            if (!finished)
                KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
        });

        if (!checkAllowedOperationParams(params.begin(), params.end())) {
            return worker_cb(operationFailed(ErrorCode::INVALID_ARGUMENT));
        }

        rc = getOperationAuthTokenIfNeeded(op);
        if (!rc.isOk()) return worker_cb(operationFailed(rc));

        // Check that all key authorization policy requirements are met.
        AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
        key_auths.append(op->characteristics.softwareEnforced.begin(),
                         op->characteristics.softwareEnforced.end());

        if (key_auths.Contains(Tag::TRUSTED_CONFIRMATION_REQUIRED)) {
            hidl_vec<uint8_t> confirmationToken =
                keyStore_->getConfirmationManager().getLatestConfirmationToken();
            if (confirmationToken.size() == 0) {
                LOG(ERROR) << "Confirmation token required but none found";
                return worker_cb(operationFailed(ErrorCode::NO_USER_CONFIRMATION));
            }
            params.push_back(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken));
        }

        rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
                                                                  params, op->authToken, op->handle,
                                                                  false /* is_begin_operation */);
        if (!rc.isOk()) return worker_cb(operationFailed(rc));

        if (entropy.size()) {
            rc = KS_HANDLE_HIDL_ERROR(op->device, op->device->addRngEntropy(entropy));
            if (!rc.isOk()) {
                return worker_cb(operationFailed(rc));
            }
        }

        OperationResult result;
        auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
                          const ::std::vector<uint8_t>& output) {
            op->device->logIfKeymasterVendorError(ret);
            result.resultCode = ret;
            if (result.resultCode.isOk()) {
                result.outParams = outParams;
                result.data = output;
            }
        };

        rc = KS_HANDLE_HIDL_ERROR(op->device, op->device->finish(op->handle, params.hidl_data(),
                                                                 input, signature, op->authToken,
                                                                 op->verificationToken, hidlCb));

        if (rc.isOk()) {
            // inform the finalizer that the finish call went through
            finished = true;
            // and what the result was
            rc = result.resultCode;
        } else {
            return worker_cb(operationFailed(rc));
        }
        return worker_cb(std::move(result));
    });
}

void KeymasterWorker::abort(sp<IBinder> token, abort_cb worker_cb) {
    Worker::addRequest(
        [this, CAPTURE_MOVE(token), CAPTURE_MOVE(worker_cb)]() { return worker_cb(abort(token)); });
}

void KeymasterWorker::verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
                                          HardwareAuthToken token,
                                          verifyAuthorization_cb worker_cb) {
    Worker::addRequest([this, challenge, CAPTURE_MOVE(params), CAPTURE_MOVE(token),
                        CAPTURE_MOVE(worker_cb)]() {
        KeyStoreServiceReturnCode error;
        VerificationToken verificationToken;
        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
            keymasterDevice_,
            keymasterDevice_->verifyAuthorization(
                challenge, params, token, [&](ErrorCode ret, const VerificationToken& vToken) {
                    keymasterDevice_->logIfKeymasterVendorError(ret);
                    error = ret;
                    verificationToken = vToken;
                }));
        worker_cb(rc.isOk() ? error : rc, std::move(token), std::move(verificationToken));
    });
}

void KeymasterWorker::addRngEntropy(hidl_vec<uint8_t> data, addRngEntropy_cb _hidl_cb) {
    addRequest(&Keymaster::addRngEntropy, std::move(_hidl_cb), std::move(data));
}

namespace {
bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
    return params.end() !=
           std::find_if(params.begin(), params.end(),
                        [&](const KeyParameter& param) { return param.tag == tag; });
}

bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
    return !containsTag(params, Tag::NO_AUTH_REQUIRED);
}
}  // namespace

void KeymasterWorker::generateKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
                                  hidl_vec<uint8_t> entropy, int flags, generateKey_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams),
                        CAPTURE_MOVE(entropy), CAPTURE_MOVE(worker_cb), flags]() mutable {
        KeyStoreServiceReturnCode rc =
            KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->addRngEntropy(entropy));
        if (!rc.isOk()) {
            return worker_cb(rc, {});
        }

        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;

        // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
        // by KeyStore::getFallbackDevice()
        bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;

        Finalize logOnFail(
            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });

        KeyCharacteristics outCharacteristics;
        KeyStoreServiceReturnCode error;
        auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
                           const KeyCharacteristics& keyCharacteristics) {
            keymasterDevice_->logIfKeymasterVendorError(ret);
            error = ret;
            if (!error.isOk()) {
                return;
            }
            consider_fallback = false;
            outCharacteristics = keyCharacteristics;

            Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
            keyBlob.setSecurityLevel(securityLevel);
            keyBlob.setCriticalToDeviceEncryption(flags &
                                                  KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
            if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
                keyBlob.setSuperEncrypted(true);
            }
            keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);

            AuthorizationSet sw_enforced = keyParams;
            sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
            sw_enforced.Union(outCharacteristics.softwareEnforced);
            sw_enforced.Filter([](const KeyParameter& param) -> bool {
                return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
            });
            if (!sw_enforced.Contains(Tag::USER_ID)) {
                // Most Java processes don't have access to this tag
                sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
            }
            Blob keyCharBlob;
            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
            error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
        };

        rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
                                  keymasterDevice_->generateKey(keyParams, hidl_cb));
        if (!rc.isOk()) {
            return worker_cb(rc, {});
        }

        if (consider_fallback && !error.isOk()) {
            auto fallback = keyStore_->getFallbackDevice();
            if (!fallback) {
                return worker_cb(error, {});
            }
            // No fallback for 3DES
            for (auto& param : keyParams) {
                auto algorithm = authorizationValue(TAG_ALGORITHM, param);
                if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
                    return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
                }
            }

            // delegate to fallback worker
            fallback->generateKey(std::move(lockedEntry), std::move(keyParams), std::move(entropy),
                                  flags, std::move(worker_cb));
            // let fallback do the logging
            logOnFail.release();
            return;
        }

        if (!error.isOk()) return worker_cb(error, {});

        // log on success
        logOnFail.release();
        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);

        return worker_cb(error, std::move(outCharacteristics));
    });
}

void KeymasterWorker::generateKey(hidl_vec<KeyParameter> keyParams, generateKey2_cb worker_cb) {
    addRequest(&Keymaster::generateKey, std::move(worker_cb), std::move(keyParams));
}

void KeymasterWorker::getKeyCharacteristics(LockedKeyBlobEntry lockedEntry,
                                            hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData,
                                            Blob keyBlob, Blob charBlob,
                                            getKeyCharacteristics_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(clientId),
                        CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
                        CAPTURE_MOVE(worker_cb)]() {
        auto result = createKeyCharacteristicsCache(lockedEntry, clientId, appData,
                                                    std::move(keyBlob), std::move(charBlob));
        return worker_cb(std::get<0>(result), std::move(std::get<1>(result)));
    });
}

void KeymasterWorker::importKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
                                KeyFormat keyFormat, hidl_vec<uint8_t> keyData, int flags,
                                importKey_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams), keyFormat,
                        CAPTURE_MOVE(keyData), flags, CAPTURE_MOVE(worker_cb)]() mutable {
        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;

        // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
        // by KeyStore::getFallbackDevice()
        bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;

        Finalize logOnFail(
            [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });

        KeyCharacteristics outCharacteristics;
        KeyStoreServiceReturnCode error;
        auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
                           const KeyCharacteristics& keyCharacteristics) {
            keymasterDevice_->logIfKeymasterVendorError(ret);
            error = ret;
            if (!error.isOk()) {
                LOG(INFO) << "importKey failed";
                return;
            }
            consider_fallback = false;
            outCharacteristics = keyCharacteristics;

            Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
            keyBlob.setSecurityLevel(securityLevel);
            keyBlob.setCriticalToDeviceEncryption(flags &
                                                  KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
            if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
                keyBlob.setSuperEncrypted(true);
            }
            keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);

            AuthorizationSet sw_enforced = keyParams;
            sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
            sw_enforced.Union(outCharacteristics.softwareEnforced);
            sw_enforced.Filter([](const KeyParameter& param) -> bool {
                return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
            });
            if (!sw_enforced.Contains(Tag::USER_ID)) {
                // Most Java processes don't have access to this tag
                sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
            }
            Blob keyCharBlob;
            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
            error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
        };

        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
            keymasterDevice_, keymasterDevice_->importKey(keyParams, keyFormat, keyData, hidl_cb));
        if (!rc.isOk()) {
            return worker_cb(rc, {});
        }

        if (consider_fallback && !error.isOk()) {
            auto fallback = keyStore_->getFallbackDevice();
            if (!fallback) {
                return worker_cb(error, {});
            }
            // No fallback for 3DES
            for (auto& param : keyParams) {
                auto algorithm = authorizationValue(TAG_ALGORITHM, param);
                if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
                    return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
                }
            }

            // delegate to fallback worker
            fallback->importKey(std::move(lockedEntry), std::move(keyParams), keyFormat,
                                std::move(keyData), flags, std::move(worker_cb));
            // let fallback to the logging
            logOnFail.release();
            return;
        }

        if (!error.isOk()) return worker_cb(error, {});

        // log on success
        logOnFail.release();
        uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);

        return worker_cb(error, std::move(outCharacteristics));
    });
}

void KeymasterWorker::importWrappedKey(LockedKeyBlobEntry wrappingLockedEntry,
                                       LockedKeyBlobEntry wrapppedLockedEntry,
                                       hidl_vec<uint8_t> wrappedKeyData,
                                       hidl_vec<uint8_t> maskingKey,
                                       hidl_vec<KeyParameter> unwrappingParams, Blob wrappingBlob,
                                       Blob wrappingCharBlob, uint64_t passwordSid,
                                       uint64_t biometricSid, importWrappedKey_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(wrappingLockedEntry), CAPTURE_MOVE(wrapppedLockedEntry),
                        CAPTURE_MOVE(wrappedKeyData), CAPTURE_MOVE(maskingKey),
                        CAPTURE_MOVE(unwrappingParams), CAPTURE_MOVE(wrappingBlob),
                        CAPTURE_MOVE(wrappingCharBlob), passwordSid, biometricSid,
                        CAPTURE_MOVE(worker_cb)]() mutable {
        auto hidlWrappingKey = blob2hidlVec(wrappingBlob);

        SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;

        KeyCharacteristics outCharacteristics;
        KeyStoreServiceReturnCode error;

        auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
                          const KeyCharacteristics& keyCharacteristics) {
            keymasterDevice_->logIfKeymasterVendorError(ret);
            error = ret;
            if (!error.isOk()) {
                return;
            }
            outCharacteristics = keyCharacteristics;

            Blob keyBlob(hidlKeyBlob.data(), hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
            keyBlob.setSecurityLevel(securityLevel);
            if (isAuthenticationBound(keyCharacteristics.hardwareEnforced)) {
                keyBlob.setSuperEncrypted(true);
            }

            AuthorizationSet sw_enforced = outCharacteristics.softwareEnforced;
            if (!sw_enforced.Contains(Tag::USER_ID)) {
                // Most Java processes don't have access to this tag
                sw_enforced.push_back(keymaster::TAG_USER_ID,
                                      get_user_id(wrapppedLockedEntry->uid()));
            }
            Blob keyCharBlob;
            keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
            error = keyStore_->put(wrapppedLockedEntry, std::move(keyBlob), std::move(keyCharBlob));
        };

        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
            keymasterDevice_, keymasterDevice_->importWrappedKey(
                                  wrappedKeyData, hidlWrappingKey, maskingKey, unwrappingParams,
                                  passwordSid, biometricSid, hidlCb));

        // possible hidl error
        if (!rc.isOk()) {
            return worker_cb(rc, {});
        }

        if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
            std::tie(rc, wrappingBlob) = upgradeKeyBlob(wrappingLockedEntry, {});
            if (!rc.isOk()) {
                return worker_cb(rc, {});
            }

            auto upgradedHidlKeyBlob = blob2hidlVec(wrappingBlob);

            rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
                                      keymasterDevice_->importWrappedKey(
                                          wrappedKeyData, upgradedHidlKeyBlob, maskingKey,
                                          unwrappingParams, passwordSid, biometricSid, hidlCb));
            if (!rc.isOk()) {
                error = rc;
            }
        }
        return worker_cb(error, std::move(outCharacteristics));
    });
}

void KeymasterWorker::exportKey(LockedKeyBlobEntry lockedEntry, KeyFormat exportFormat,
                                hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData, Blob keyBlob,
                                Blob charBlob, exportKey_cb worker_cb) {
    Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), exportFormat, CAPTURE_MOVE(clientId),
                        CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
                        CAPTURE_MOVE(worker_cb)]() mutable {
        auto key = blob2hidlVec(keyBlob);

        ExportResult result;
        auto hidlCb = [&](ErrorCode ret,
                          const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
            keymasterDevice_->logIfKeymasterVendorError(ret);
            result.resultCode = ret;
            if (!result.resultCode.isOk()) {
                if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
                    log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
                }
                return;
            }
            result.exportData = keyMaterial;
        };
        KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
            keymasterDevice_,
            keymasterDevice_->exportKey(exportFormat, key, clientId, appData, hidlCb));

        // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
        // callback hidlCb.
        if (!rc.isOk()) {
            result.resultCode = rc;
        }

        if (result.resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
            AuthorizationSet upgradeParams;
            if (clientId.size()) {
                upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
            }
            if (appData.size()) {
                upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
            }
            std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
            if (!rc.isOk()) {
                return worker_cb(std::move(result));
            }

            auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);

            rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
                                      keymasterDevice_->exportKey(exportFormat, upgradedHidlKeyBlob,
                                                                  clientId, appData, hidlCb));
            if (!rc.isOk()) {
                result.resultCode = rc;
            }
        }
        return worker_cb(std::move(result));
    });
}
void KeymasterWorker::attestKey(hidl_vec<uint8_t> keyToAttest, hidl_vec<KeyParameter> attestParams,
                                attestKey_cb worker_cb) {
    addRequest(&Keymaster::attestKey, std::move(worker_cb), std::move(keyToAttest),
               std::move(attestParams));
}

void KeymasterWorker::deleteKey(hidl_vec<uint8_t> keyBlob, deleteKey_cb _hidl_cb) {
    addRequest(&Keymaster::deleteKey, std::move(_hidl_cb), std::move(keyBlob));
}

void KeymasterWorker::binderDied(android::wp<IBinder> who) {
    Worker::addRequest([this, who]() {
        auto operations = operationMap_.getOperationsForToken(who.unsafe_get());
        for (const auto& token : operations) {
            abort(token);
        }
    });
}

}  // namespace keystore
