platform_system_security/keystore/keymaster_worker.cpp
Hasini Gunasinghe 242460eac7 Log keystore key operation events using statsd.
This is the second CL on migrating keystore logging to statsd.
This migrates the logging for key operation events.
Three new ResponseCodes are added for the logging purpose of the
	abort operations.

Test: Adding tests for logging is yet to be decided.
Change-Id: Iede72341b0f4c80199c9e16cef96a5d98bca8754
Merged-In: I68c1d89beeb733e4b6ba493b8d95935b7e73df60
2020-08-12 15:11:11 +00:00

1144 lines
48 KiB
C++

/*
**
** 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 <log/log_event_list.h>
#include <private/android_logger.h>
#include "KeyStore.h"
#include "keymaster_enforcement.h"
#include "key_creation_log_handler.h"
#include "keystore_utils.h"
#include <chrono>
namespace keystore {
using namespace std::chrono;
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_);
terminate_ = true;
pending_requests_cond_var_.notify_all();
pending_requests_cond_var_.wait(lock, [this] { return !running_; });
}
void Worker::addRequest(WorkerTask request) {
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
bool start_thread = !running_;
running_ = true;
pending_requests_.push(std::move(request));
lock.unlock();
pending_requests_cond_var_.notify_all();
if (start_thread) {
auto worker = std::thread([this] {
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
while (running_) {
// Wait for 30s if the request queue is empty, then kill die.
// Die immediately if termiate_ was set which happens in the destructor.
auto status = pending_requests_cond_var_.wait_for(
lock, 30s, [this]() { return !pending_requests_.empty() || terminate_; });
if (status && !terminate_) {
auto request = std::move(pending_requests_.front());
lock.unlock();
request();
lock.lock();
pending_requests_.pop();
} else {
running_ = false;
}
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);
}
void KeymasterWorker::deleteOldKeyOnUpgrade(const LockedKeyBlobEntry& blobfile, Blob keyBlob) {
// if we got the blob successfully, we try and delete it from the keymaster device
auto& dev = keymasterDevice_;
uid_t uid = blobfile->uid();
const auto& alias = blobfile->alias();
if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
auto ret = KS_HANDLE_HIDL_ERROR(dev, dev->deleteKey(blob2hidlVec(keyBlob)));
// A device doesn't have to implement delete_key.
bool success = ret == ErrorCode::OK || ret == ErrorCode::UNIMPLEMENTED;
if (__android_log_security()) {
android_log_event_list(SEC_TAG_KEY_DESTROYED)
<< int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY;
}
if (!success) {
LOG(ERROR) << "Keymaster delete for key " << alias << " of uid " << uid << " failed";
}
}
}
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;
}
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;
}
deleteOldKeyOnUpgrade(lockedEntry, std::move(blob));
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,
ResponseCode reason_for_abort) {
auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */,
static_cast<int32_t>(reason_for_abort));
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, ResponseCode::PRUNED);
keyStore_->removeOperationDevice(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, rc.getErrorCode());
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(), rc.getErrorCode());
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, ResponseCode::ABORT_CALLED));
});
}
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([&] {
logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
rc.getErrorCode());
});
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();
logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
error.getErrorCode());
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;
KeyStoreServiceReturnCode error;
Finalize logOnFail([&] {
logKeystoreKeyCreationEvent(keyParams, false /*wasCreationSuccessful*/,
error.getErrorCode());
});
KeyCharacteristics outCharacteristics;
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();
logKeystoreKeyCreationEvent(keyParams, true /*wasCreationSuccessful*/,
error.getErrorCode());
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, ResponseCode::BINDER_DIED);
keyStore_->removeOperationDevice(token);
}
});
}
} // namespace keystore