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
diff --git a/keystore/Android.bp b/keystore/Android.bp
index de11ec6..cedbfa9 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -26,6 +26,7 @@
         "Keymaster4.cpp",
         "auth_token_table.cpp",
         "blob.cpp",
+        "confirmation_manager.cpp",
         "entropy.cpp",
         "grant_store.cpp",
         "key_store_service.cpp",
@@ -40,6 +41,7 @@
         "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 @@
     ],
     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 0000000..d8c5378
--- /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 0000000..4bf4b8d
--- /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 b13441b..d00a04b 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -55,6 +55,7 @@
 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 @@
         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 @@
     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 @@
         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 @@
         }
     };
 
-    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 @@
     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 @@
     };
 
     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 @@
     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 fec44ec..958b0dc 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 @@
 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 @@
                     ::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 @@
         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 @@
     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 c6d9a55..1850032 100644
--- a/keystore/keymaster_enforcement.cpp
+++ b/keystore/keymaster_enforcement.cpp
@@ -345,6 +345,8 @@
         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 6e995e0..870a548 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 @@
            "          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 @@
     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 @@
         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();
     }