/* ** ** 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 #include #include #include "KeyStore.h" #include "keymaster_enforcement.h" #include "key_proto_handler.h" #include "keystore_utils.h" #include 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 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 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 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 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 KeymasterWorker::upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry, const AuthorizationSet& params) { LOG(INFO) << "upgradeKeyBlob " << lockedEntry->alias() << " " << (uint32_t)lockedEntry->uid(); std::tuple 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& 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 KeymasterWorker::createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry, const hidl_vec& clientId, const hidl_vec& appData, Blob keyBlob, Blob charBlob) { std::tuple 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 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(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& 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 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); 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 appToken, Blob keyBlob, Blob charBlob, bool pruneable, KeyPurpose purpose, AuthorizationSet opParams, hidl_vec 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 clientId; hidl_vec 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& 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 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 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 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 f_; public: explicit Finalize(std::function f) : f_(f) {} ~Finalize() { if (f_) f_(); } void release() { f_ = {}; } }; } // namespace void KeymasterWorker::update(sp token, AuthorizationSet params, hidl_vec 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& outParams, const ::std::vector& 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 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 token, AuthorizationSet params, hidl_vec input, hidl_vec signature, hidl_vec 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 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& outParams, const ::std::vector& 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 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 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 data, addRngEntropy_cb _hidl_cb) { addRequest(&Keymaster::addRngEntropy, std::move(_hidl_cb), std::move(data)); } namespace { bool containsTag(const hidl_vec& 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& params) { return !containsTag(params, Tag::NO_AUTH_REQUIRED); } } // namespace void KeymasterWorker::generateKey(LockedKeyBlobEntry lockedEntry, hidl_vec keyParams, hidl_vec 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& 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 keyParams, generateKey2_cb worker_cb) { addRequest(&Keymaster::generateKey, std::move(worker_cb), std::move(keyParams)); } void KeymasterWorker::getKeyCharacteristics(LockedKeyBlobEntry lockedEntry, hidl_vec clientId, hidl_vec 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 keyParams, KeyFormat keyFormat, hidl_vec 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& 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 wrappedKeyData, hidl_vec maskingKey, hidl_vec 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& 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 clientId, hidl_vec 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& 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 keyToAttest, hidl_vec attestParams, attestKey_cb worker_cb) { addRequest(&Keymaster::attestKey, std::move(worker_cb), std::move(keyToAttest), std::move(attestParams)); } void KeymasterWorker::deleteKey(hidl_vec keyBlob, deleteKey_cb _hidl_cb) { addRequest(&Keymaster::deleteKey, std::move(_hidl_cb), std::move(keyBlob)); } void KeymasterWorker::binderDied(android::wp who) { Worker::addRequest([this, who]() { auto operations = operationMap_.getOperationsForToken(who.unsafe_get()); for (const auto& token : operations) { abort(token); keyStore_->removeOperationDevice(token); } }); } } // namespace keystore