summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <zeuthen@google.com>2017-11-27 11:33:55 -0500
committerDavid Zeuthen <zeuthen@google.com>2018-01-17 15:38:44 -0500
commitc6eb7cd999397ff52251beaf8351e7497854746c (patch)
tree8beddf269a19f977ac1fa49d11fe9fd2ec51bfa4
parentc8cdf0ec734ec181bf705b1d4f1a6a787bcd2054 (diff)
downloadsecurity-c6eb7cd999397ff52251beaf8351e7497854746c.tar.gz
Add support for confirmation APIs.
This code implements new keystore APIs for confirmations. Also add new 'confirmation' verb to the keystore_cli_v2 command to be used for testing confirmations. It will block until there's a callback. Example invocations: phone:/ # keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --ui_options=1,2,3 Waiting for prompt to complete - use Ctrl+C to abort... Confirmation prompt completed responseCode = 0 dataThatWasConfirmed[30] = {0xa2, 0x66, 0x70, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x6b, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x65, 0x65, 0x78, 0x74, 0x72, 0x61, 0x43, 0x01, 0x02, 0x03} phone:/ # If a prompt is already being shown, the |OperationPending| return code (code 3) is returned: phone:/ # keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --ui_options=1,2,3 Presenting confirmation prompt failed with return code 3. Canceling a prompt: phone:/# keystore_cli_v2 confirmation --prompt_text="Hello World" --extra_data=010203 --cancel_after=1.5 Sleeping 1.5 seconds before canceling prompt... Waiting for prompt to complete - use Ctrl+C to abort... Confirmation prompt completed responseCode = 2 dataThatWasConfirmed[0] = {} Bug: 63928580 Test: Manually tested. Change-Id: Ida14706ad066d5350b9081eb7821c7b1a1472dd2
-rw-r--r--keystore/Android.bp7
-rw-r--r--keystore/confirmation_manager.cpp195
-rw-r--r--keystore/confirmation_manager.h98
-rw-r--r--keystore/key_store_service.cpp45
-rw-r--r--keystore/key_store_service.h21
-rw-r--r--keystore/keymaster_enforcement.cpp2
-rw-r--r--keystore/keystore_cli_v2.cpp142
7 files changed, 505 insertions, 5 deletions
diff --git a/keystore/Android.bp b/keystore/Android.bp
index de11ec63..cedbfa90 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -26,6 +26,7 @@ cc_binary {
"Keymaster4.cpp",
"auth_token_table.cpp",
"blob.cpp",
+ "confirmation_manager.cpp",
"entropy.cpp",
"grant_store.cpp",
"key_store_service.cpp",
@@ -40,6 +41,7 @@ cc_binary {
"user_state.cpp",
],
shared_libs: [
+ "android.hardware.confirmationui@1.0",
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"android.system.wifi.keystore@1.0",
@@ -108,12 +110,17 @@ cc_binary {
],
srcs: ["keystore_cli_v2.cpp"],
shared_libs: [
+ "android.hardware.confirmationui@1.0",
"android.hardware.keymaster@3.0",
+ "libbinder",
"libchrome",
+ "libutils",
"libhidlbase",
"libhwbinder",
"libkeymaster4support",
+ "libkeystore_aidl",
"libkeystore_binder",
+ "libkeystore_parcelables",
],
local_include_dirs: ["include"],
diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp
new file mode 100644
index 00000000..d8c53784
--- /dev/null
+++ b/keystore/confirmation_manager.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 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 "ConfirmationManager"
+
+#include "confirmation_manager.h"
+
+#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/security/BpConfirmationPromptCallback.h>
+#include <binder/BpBinder.h>
+#include <binder/Parcel.h>
+
+#include "keystore_aidl_hidl_marshalling_utils.h"
+
+namespace keystore {
+
+using android::IBinder;
+using android::sp;
+using android::String16;
+using android::String8;
+using android::wp;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
+using android::hardware::confirmationui::V1_0::IConfirmationUI;
+using android::hardware::confirmationui::V1_0::UIOption;
+
+using android::security::BpConfirmationPromptCallback;
+using std::lock_guard;
+using std::mutex;
+using std::vector;
+
+ConfirmationManager::ConfirmationManager(IBinder::DeathRecipient* deathRecipient)
+ : IConfirmationResultCallback(), mDeathRecipient(deathRecipient) {}
+
+// Called by keystore main thread.
+Status ConfirmationManager::presentConfirmationPrompt(const sp<IBinder>& listener,
+ const String16& promptText,
+ const hidl_vec<uint8_t>& extraData,
+ const String16& locale, int uiOptionsAsFlags,
+ int32_t* aidl_return) {
+ lock_guard<mutex> lock(mMutex);
+
+ if (mCurrentListener != nullptr) {
+ *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
+ return Status::ok();
+ }
+
+ sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
+ if (confirmationUI == nullptr) {
+ ALOGW("Error getting confirmationUI service\n");
+ *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::Unimplemented);
+ return Status::ok();
+ }
+
+ String8 promptText8(promptText);
+ String8 locale8(locale);
+ vector<UIOption> uiOptionsVector;
+ for (int n = 0; n < 32; n++) {
+ if (uiOptionsAsFlags & (1 << n)) {
+ uiOptionsVector.push_back(UIOption(n));
+ }
+ }
+ ConfirmationResponseCode responseCode;
+ responseCode = confirmationUI->promptUserConfirmation(sp<IConfirmationResultCallback>(this),
+ promptText8.string(), extraData,
+ locale8.string(), uiOptionsVector);
+ if (responseCode != ConfirmationResponseCode::OK) {
+ ALOGW("Unexpecxted responseCode %d from promptUserConfirmation\n", responseCode);
+ *aidl_return = static_cast<int32_t>(responseCode);
+ return Status::ok();
+ }
+
+ listener->linkToDeath(mDeathRecipient);
+ confirmationUI->linkToDeath(this, 0);
+ mCurrentListener = listener;
+ mCurrentConfirmationUI = confirmationUI;
+
+ *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
+ return Status::ok();
+}
+
+// Called by keystore main thread.
+Status ConfirmationManager::cancelConfirmationPrompt(const sp<IBinder>& listener,
+ int32_t* aidl_return) {
+ mMutex.lock();
+ if (mCurrentListener != listener) {
+ // If the prompt was displayed by another application, return
+ // OperationPending.
+ mMutex.unlock();
+ *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending);
+ return Status::ok();
+ }
+ mMutex.unlock();
+
+ finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true);
+
+ *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
+ return Status::ok();
+}
+
+void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode,
+ hidl_vec<uint8_t> dataThatWasConfirmed,
+ bool callAbortOnHal) {
+ // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back
+ // into our process resulting in confirmationResultCallback() to be called... this in turn
+ // calls finalizeTransaction(). So we have to be careful a) not holding any locks;
+ // and b) ensure state has been cleared; before doing this...
+
+ mMutex.lock();
+ sp<IBinder> listener = mCurrentListener;
+ if (mCurrentListener != nullptr) {
+ mCurrentListener->unlinkToDeath(mDeathRecipient);
+ mCurrentListener = nullptr;
+ }
+ sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
+ if (mCurrentConfirmationUI != nullptr) {
+ mCurrentConfirmationUI->unlinkToDeath(this);
+ mCurrentConfirmationUI = nullptr;
+ }
+ mMutex.unlock();
+
+ // Tell the HAL to shut down the confirmation dialog, if requested.
+ if (confirmationUI != nullptr && callAbortOnHal) {
+ confirmationUI->abort();
+ }
+
+ // Deliver result to the application that started the operation.
+ if (listener != nullptr) {
+ sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener);
+ Status status = obj->onConfirmationPromptCompleted(static_cast<int32_t>(responseCode),
+ dataThatWasConfirmed);
+ if (!status.isOk()) {
+ ALOGW("Error sending onConfirmationPromptCompleted - status: %s\n",
+ status.toString8().c_str());
+ }
+ }
+}
+
+// Called by hwbinder thread (not keystore main thread).
+Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode,
+ const hidl_vec<uint8_t>& dataThatWasConfirmed,
+ const hidl_vec<uint8_t>& confirmationToken) {
+ finalizeTransaction(responseCode, dataThatWasConfirmed, false);
+ lock_guard<mutex> lock(mMutex);
+ mLatestConfirmationToken = confirmationToken;
+ return Return<void>();
+}
+
+// Called by keystore main thread.
+hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() {
+ lock_guard<mutex> lock(mMutex);
+ return mLatestConfirmationToken;
+}
+
+void ConfirmationManager::binderDied(const wp<IBinder>& who) {
+ // This is also called for other binders so need to check it's for
+ // us before acting on it.
+ mMutex.lock();
+ if (who == mCurrentListener) {
+ // Clear this so we don't call back into the already dead
+ // binder in finalizeTransaction().
+ mCurrentListener->unlinkToDeath(mDeathRecipient);
+ mCurrentListener = nullptr;
+ mMutex.unlock();
+ ALOGW("The process which requested the confirmation dialog died.\n");
+ finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true);
+ } else {
+ mMutex.unlock();
+ }
+}
+
+void ConfirmationManager::serviceDied(uint64_t /* cookie */,
+ const wp<android::hidl::base::V1_0::IBase>& /* who */) {
+ ALOGW("The ConfirmationUI HAL died.\n");
+ finalizeTransaction(ConfirmationResponseCode::SystemError, {}, false);
+}
+
+} // namespace keystore
diff --git a/keystore/confirmation_manager.h b/keystore/confirmation_manager.h
new file mode 100644
index 00000000..4bf4b8d6
--- /dev/null
+++ b/keystore/confirmation_manager.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef KEYSTORE_CONFIRMATION_MANAGER_H_
+#define KEYSTORE_CONFIRMATION_MANAGER_H_
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/Status.h>
+#include <keystore/keymaster_types.h>
+#include <map>
+#include <mutex>
+#include <utils/LruCache.h>
+#include <utils/StrongPointer.h>
+#include <vector>
+
+namespace keystore {
+
+using android::binder::Status;
+using android::hardware::confirmationui::V1_0::IConfirmationResultCallback;
+using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
+
+class ConfirmationManager;
+
+class ConfirmationManager : public android::hardware::hidl_death_recipient,
+ public IConfirmationResultCallback {
+ public:
+ explicit ConfirmationManager(android::IBinder::DeathRecipient* deathRecipient);
+
+ // Calls into the confirmationui HAL to start a new prompt.
+ //
+ // Returns OperationPending if another application is already
+ // showing a confirmation. Otherwise returns the return code from
+ // the HAL.
+ Status presentConfirmationPrompt(const android::sp<android::IBinder>& listener,
+ const android::String16& promptText,
+ const hidl_vec<uint8_t>& extraData,
+ const android::String16& locale, int uiOptionsAsFlags,
+ int32_t* aidl_return);
+
+ // Calls into the confirmationui HAL to cancel displaying a
+ // prompt.
+ //
+ // Returns OperatingPending if another application is showing a
+ // confirmation. Otherwise returns the return code from the HAL.
+ Status cancelConfirmationPrompt(const android::sp<android::IBinder>& listener,
+ int32_t* aidl_return);
+
+ // Gets the latest confirmation token received from the ConfirmationUI HAL.
+ hidl_vec<uint8_t> getLatestConfirmationToken();
+
+ // Called by KeyStoreService when a client binder has died.
+ void binderDied(const android::wp<android::IBinder>& who);
+
+ // hidl_death_recipient overrides:
+ virtual void serviceDied(uint64_t cookie,
+ const android::wp<android::hidl::base::V1_0::IBase>& who) override;
+
+ // IConfirmationResultCallback overrides:
+ android::hardware::Return<void> result(ConfirmationResponseCode responseCode,
+ const hidl_vec<uint8_t>& dataThatWasConfirmed,
+ const hidl_vec<uint8_t>& confirmationToken) override;
+
+ private:
+ friend class ConfirmationResultCallback;
+
+ void finalizeTransaction(ConfirmationResponseCode responseCode,
+ hidl_vec<uint8_t> dataThatWasConfirmed, bool callAbortOnHal);
+
+ // This mutex protects all data below it.
+ std::mutex mMutex;
+
+ // The mCurrentListener and mCurrentConfirmationUI fields are set
+ // if and only if a prompt is currently showing.
+ android::sp<android::IBinder> mCurrentListener;
+ android::sp<android::hardware::confirmationui::V1_0::IConfirmationUI> mCurrentConfirmationUI;
+ android::IBinder::DeathRecipient* mDeathRecipient;
+ hidl_vec<uint8_t> mLatestConfirmationToken;
+};
+
+} // namespace keystore
+
+#endif // KEYSTORE_CONFIRMATION_MANAGER_H_
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index b13441b6..d00a04bf 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -55,6 +55,7 @@ using android::security::keymaster::KeymasterArguments;
using android::security::keymaster::KeymasterBlob;
using android::security::keymaster::KeymasterCertificateChain;
using android::security::keymaster::OperationResult;
+using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
constexpr size_t kMaxOperations = 15;
constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
@@ -138,6 +139,7 @@ void KeyStoreService::binderDied(const wp<IBinder>& who) {
int32_t unused_result;
abort(token, &unused_result);
}
+ mConfirmationManager->binderDied(who);
}
Status KeyStoreService::getState(int32_t userId, int32_t* aidl_return) {
@@ -1359,6 +1361,23 @@ Status KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name,
return Status::ok();
}
+void KeyStoreService::appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
+ std::vector<KeyParameter>* params) {
+ if (!(containsTag(keyCharacteristics.softwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED) ||
+ containsTag(keyCharacteristics.hardwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED))) {
+ return;
+ }
+
+ hidl_vec<uint8_t> confirmationToken = mConfirmationManager->getLatestConfirmationToken();
+ if (confirmationToken.size() == 0) {
+ return;
+ }
+
+ params->push_back(
+ Authorization(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken)));
+ ALOGD("Appending confirmation token\n");
+}
+
Status KeyStoreService::update(const sp<IBinder>& token, const KeymasterArguments& params,
const ::std::vector<uint8_t>& data, OperationResult* result) {
if (!checkAllowedOperationParams(params.getParameters())) {
@@ -1387,6 +1406,9 @@ Status KeyStoreService::update(const sp<IBinder>& token, const KeymasterArgument
false /* is_begin_operation */);
if (!result->resultCode.isOk()) return Status::ok();
+ std::vector<KeyParameter> inParams = params.getParameters();
+ appendConfirmationTokenIfNeeded(op.characteristics, &inParams);
+
auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
const hidl_vec<KeyParameter>& outParams,
const ::std::vector<uint8_t>& output) {
@@ -1398,8 +1420,8 @@ Status KeyStoreService::update(const sp<IBinder>& token, const KeymasterArgument
}
};
- KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(op.device->update(
- op.handle, params.getParameters(), data, authToken, VerificationToken(), hidlCb));
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+ op.device->update(op.handle, inParams, data, authToken, 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.
@@ -1438,6 +1460,9 @@ Status KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArgument
key_auths.append(op.characteristics.softwareEnforced.begin(),
op.characteristics.softwareEnforced.end());
+ std::vector<KeyParameter> inParams = params.getParameters();
+ appendConfirmationTokenIfNeeded(op.characteristics, &inParams);
+
result->resultCode = enforcement_policy.AuthorizeOperation(
op.purpose, op.keyid, key_auths, params.getParameters(), authToken, op.handle,
false /* is_begin_operation */);
@@ -1453,7 +1478,7 @@ Status KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArgument
};
KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
- op.device->finish(op.handle, params.getParameters(),
+ op.device->finish(op.handle, inParams,
::std::vector<uint8_t>() /* TODO(swillden): wire up input to finish() */,
signature, authToken, VerificationToken(), hidlCb));
mOperationMap.removeOperation(token);
@@ -1796,6 +1821,20 @@ Status KeyStoreService::importWrappedKey(
return AIDL_RETURN(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(callingUid)));
}
+Status KeyStoreService::presentConfirmationPrompt(const sp<IBinder>& listener,
+ const String16& promptText,
+ const ::std::vector<uint8_t>& extraData,
+ const String16& locale, int32_t uiOptionsAsFlags,
+ int32_t* aidl_return) {
+ return mConfirmationManager->presentConfirmationPrompt(listener, promptText, extraData, locale,
+ uiOptionsAsFlags, aidl_return);
+}
+
+Status KeyStoreService::cancelConfirmationPrompt(const sp<IBinder>& listener,
+ int32_t* aidl_return) {
+ return mConfirmationManager->cancelConfirmationPrompt(listener, aidl_return);
+}
+
/**
* Prune the oldest pruneable operation.
*/
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index fec44ec6..958b0dcb 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -20,6 +20,7 @@
#include <android/security/BnKeystoreService.h>
#include "auth_token_table.h"
+#include "confirmation_manager.h"
#include "KeyStore.h"
#include "keystore_keymaster_enforcement.h"
@@ -36,7 +37,9 @@ namespace keystore {
class KeyStoreService : public android::security::BnKeystoreService,
android::IBinder::DeathRecipient {
public:
- explicit KeyStoreService(KeyStore* keyStore) : mKeyStore(keyStore), mOperationMap(this) {}
+ explicit KeyStoreService(KeyStore* keyStore)
+ : mKeyStore(keyStore), mOperationMap(this),
+ mConfirmationManager(new ConfirmationManager(this)) {}
virtual ~KeyStoreService() = default;
void binderDied(const android::wp<android::IBinder>& who);
@@ -160,6 +163,7 @@ class KeyStoreService : public android::security::BnKeystoreService,
::android::security::keymaster::KeymasterCertificateChain* chain,
int32_t* _aidl_return) override;
::android::binder::Status onDeviceOffBody(int32_t* _aidl_return) override;
+
::android::binder::Status importWrappedKey(
const ::android::String16& wrappedKeyAlias, const ::std::vector<uint8_t>& wrappedKey,
const ::android::String16& wrappingKeyAlias, const ::std::vector<uint8_t>& maskingKey,
@@ -167,6 +171,14 @@ class KeyStoreService : public android::security::BnKeystoreService,
int64_t fingerprintSid, ::android::security::keymaster::KeyCharacteristics* characteristics,
int32_t* _aidl_return) override;
+ ::android::binder::Status presentConfirmationPrompt(
+ const ::android::sp<::android::IBinder>& listener, const ::android::String16& promptText,
+ const ::std::vector<uint8_t>& extraData, const ::android::String16& locale,
+ int32_t uiOptionsAsFlags, int32_t* _aidl_return) override;
+ ::android::binder::Status
+ cancelConfirmationPrompt(const ::android::sp<::android::IBinder>& listener,
+ int32_t* _aidl_return) override;
+
private:
static const int32_t UID_SELF = -1;
@@ -276,8 +288,15 @@ class KeyStoreService : public android::security::BnKeystoreService,
KeyStoreServiceReturnCode upgradeKeyBlob(const android::String16& name, uid_t targetUid,
const AuthorizationSet& params, Blob* blob);
+ /**
+ * Adds a Confirmation Token to the key parameters if needed.
+ */
+ void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
+ std::vector<KeyParameter>* params);
+
KeyStore* mKeyStore;
OperationMap mOperationMap;
+ android::sp<ConfirmationManager> mConfirmationManager;
keystore::AuthTokenTable mAuthTokenTable;
KeystoreKeymasterEnforcement enforcement_policy;
};
diff --git a/keystore/keymaster_enforcement.cpp b/keystore/keymaster_enforcement.cpp
index c6d9a55c..18500320 100644
--- a/keystore/keymaster_enforcement.cpp
+++ b/keystore/keymaster_enforcement.cpp
@@ -345,6 +345,8 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k
case Tag::RESET_SINCE_ID_ROTATION:
case Tag::ALLOW_WHILE_ON_BODY:
case Tag::HARDWARE_TYPE:
+ case Tag::TRUSTED_CONFIRMATION_REQUIRED:
+ case Tag::CONFIRMATION_TOKEN:
break;
case Tag::BOOTLOADER_ONLY:
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 6e995e07..870a548e 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -19,13 +19,32 @@
#include <base/command_line.h>
#include <base/files/file_util.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
+#include <base/strings/utf_string_conversions.h>
+#include <base/threading/platform_thread.h>
#include <keystore/keymaster_types.h>
#include <keystore/keystore_client_impl.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/security/BnConfirmationPromptCallback.h>
+#include <android/security/IKeystoreService.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+//#include <keystore/keystore.h>
+
using base::CommandLine;
using keystore::KeystoreClient;
+using android::sp;
+using android::String16;
+using android::security::IKeystoreService;
+using base::CommandLine;
+using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
+
namespace {
using namespace keystore;
@@ -49,7 +68,10 @@ void PrintUsageAndExit() {
" list [--prefix=<key_name_prefix>]\n"
" sign-verify --name=<key_name>\n"
" [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n"
- " [--seclevel=software|strongbox|tee(default)]\n");
+ " [--seclevel=software|strongbox|tee(default)]\n"
+ " confirmation --prompt_text=<PromptText> --extra_data=<hex>\n"
+ " --locale=<locale> [--ui_options=<list_of_ints>]\n"
+ " --cancel_after=<seconds>\n");
exit(1);
}
@@ -438,6 +460,118 @@ uint32_t securityLevelOption2Flags(const CommandLine& cmd) {
return KEYSTORE_FLAG_NONE;
}
+class ConfirmationListener : public android::security::BnConfirmationPromptCallback {
+ public:
+ ConfirmationListener() {}
+
+ virtual ::android::binder::Status
+ onConfirmationPromptCompleted(int32_t result,
+ const ::std::vector<uint8_t>& dataThatWasConfirmed) override {
+ ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(result);
+ printf("Confirmation prompt completed\n"
+ "responseCode = %d\n",
+ responseCode);
+ printf("dataThatWasConfirmed[%zd] = {", dataThatWasConfirmed.size());
+ size_t newLineCountDown = 16;
+ bool hasPrinted = false;
+ for (uint8_t element : dataThatWasConfirmed) {
+ if (hasPrinted) {
+ printf(", ");
+ }
+ if (newLineCountDown == 0) {
+ printf("\n ");
+ newLineCountDown = 32;
+ }
+ printf("0x%02x", element);
+ hasPrinted = true;
+ }
+ printf("}\n");
+ exit(0);
+ }
+};
+
+int Confirmation(const std::string& promptText, const std::string& extraDataHex,
+ const std::string& locale, const std::string& uiOptionsStr,
+ const std::string& cancelAfter) {
+ sp<android::IServiceManager> sm = android::defaultServiceManager();
+ sp<android::IBinder> binder = sm->getService(String16("android.security.keystore"));
+ sp<IKeystoreService> service = android::interface_cast<IKeystoreService>(binder);
+ if (service == NULL) {
+ printf("error: could not connect to keystore service.\n");
+ return 1;
+ }
+
+ if (promptText.size() == 0) {
+ printf("The --promptText parameter cannot be empty.\n");
+ return 1;
+ }
+
+ std::vector<uint8_t> extraData;
+ if (!base::HexStringToBytes(extraDataHex, &extraData)) {
+ printf("The --extra_data parameter does not appear to be valid hexadecimal.\n");
+ return 1;
+ }
+
+ std::vector<std::string> pieces =
+ base::SplitString(uiOptionsStr, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ int uiOptionsAsFlags = 0;
+ for (auto& p : pieces) {
+ int value;
+ if (!base::StringToInt(p, &value)) {
+ printf("Error parsing %s in --ui_options parameter as a number.\n", p.c_str());
+ return 1;
+ }
+ uiOptionsAsFlags |= (1 << value);
+ }
+
+ double cancelAfterValue = 0.0;
+
+ if (cancelAfter.size() > 0 && !base::StringToDouble(cancelAfter, &cancelAfterValue)) {
+ printf("Error parsing %s in --cancel_after parameter as a double.\n", cancelAfter.c_str());
+ return 1;
+ }
+
+ String16 promptText16(promptText.data(), promptText.size());
+ String16 locale16(locale.data(), locale.size());
+
+ sp<ConfirmationListener> listener = new ConfirmationListener();
+
+ int32_t aidl_return;
+ android::binder::Status status = service->presentConfirmationPrompt(
+ listener, promptText16, extraData, locale16, uiOptionsAsFlags, &aidl_return);
+ if (!status.isOk()) {
+ printf("Presenting confirmation prompt failed with binder status '%s'.\n",
+ status.toString8().c_str());
+ return 1;
+ }
+ ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
+ if (responseCode != ConfirmationResponseCode::OK) {
+ printf("Presenting confirmation prompt failed with response code %d.\n", responseCode);
+ return 1;
+ }
+
+ if (cancelAfterValue > 0.0) {
+ printf("Sleeping %.1f seconds before canceling prompt...\n", cancelAfterValue);
+ base::PlatformThread::Sleep(base::TimeDelta::FromSecondsD(cancelAfterValue));
+ status = service->cancelConfirmationPrompt(listener, &aidl_return);
+ if (!status.isOk()) {
+ printf("Canceling confirmation prompt failed with binder status '%s'.\n",
+ status.toString8().c_str());
+ return 1;
+ }
+ responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
+ if (responseCode != ConfirmationResponseCode::OK) {
+ printf("Canceling confirmation prompt failed with response code %d.\n", responseCode);
+ return 1;
+ }
+ }
+
+ printf("Waiting for prompt to complete - use Ctrl+C to abort...\n");
+ // Use the main thread to process Binder transactions.
+ android::IPCThreadState::self()->joinThreadPool();
+ return 0;
+}
+
} // namespace
int main(int argc, char** argv) {
@@ -480,6 +614,12 @@ int main(int argc, char** argv) {
return Decrypt(command_line->GetSwitchValueASCII("name"),
command_line->GetSwitchValueASCII("in"),
command_line->GetSwitchValueASCII("out"));
+ } else if (args[0] == "confirmation") {
+ return Confirmation(command_line->GetSwitchValueASCII("prompt_text"),
+ command_line->GetSwitchValueASCII("extra_data"),
+ command_line->GetSwitchValueASCII("locale"),
+ command_line->GetSwitchValueASCII("ui_options"),
+ command_line->GetSwitchValueASCII("cancel_after"));
} else {
PrintUsageAndExit();
}