/*
**
** 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