Merge "First working version of the confirmationui HAL service"
diff --git a/trusty/confirmationui/.clang-format b/trusty/confirmationui/.clang-format
new file mode 100644
index 0000000..b0dc94c
--- /dev/null
+++ b/trusty/confirmationui/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp
new file mode 100644
index 0000000..60e0e71
--- /dev/null
+++ b/trusty/confirmationui/Android.bp
@@ -0,0 +1,95 @@
+// Copyright (C) 2020 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.
+//
+
+// WARNING: Everything listed here will be built on ALL platforms,
+// including x86, the emulator, and the SDK.  Modules must be uniquely
+// named (liblights.panda), and must build everywhere, or limit themselves
+// to only building on ARM if they include assembly. Individual makefiles
+// are responsible for having their own logic, for fine-grained control.
+
+cc_binary {
+    name: "android.hardware.confirmationui@1.0-service.trusty",
+    relative_install_path: "hw",
+    vendor: true,
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui.not-so-secure-input",
+        "android.hardware.confirmationui@1.0-lib.trusty",
+        "libbase",
+        "libhidlbase",
+        "libutils",
+    ],
+
+    init_rc: ["android.hardware.confirmationui@1.0-service.trusty.rc"],
+
+    vintf_fragments: ["android.hardware.confirmationui@1.0-service.trusty.xml"],
+
+    srcs: [
+        "service.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.confirmationui@1.0-lib.trusty",
+    vendor: true,
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.keymaster@4.0",
+        "libbase",
+        "libhidlbase",
+        "libteeui_hal_support",
+        "libtrusty",
+        "libutils",
+    ],
+
+    export_include_dirs: ["include"],
+
+    srcs: [
+        "TrustyApp.cpp",
+        "TrustyConfirmationUI.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.confirmationui.not-so-secure-input",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libteeui_hal_support",
+    ],
+
+    srcs: [
+        "NotSoSecureInput.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DTEEUI_USE_STD_VECTOR",
+    ],
+}
\ No newline at end of file
diff --git a/trusty/confirmationui/NotSoSecureInput.cpp b/trusty/confirmationui/NotSoSecureInput.cpp
new file mode 100644
index 0000000..3d9a2d6
--- /dev/null
+++ b/trusty/confirmationui/NotSoSecureInput.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#include <android-base/logging.h>
+#include <endian.h>
+#include <memory>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <teeui/utils.h>
+
+#include <initializer_list>
+
+using namespace secure_input;
+
+using teeui::AuthTokenKey;
+using teeui::ByteBufferProxy;
+using teeui::Hmac;
+using teeui::optional;
+using teeui::ResponseCode;
+using teeui::TestKeyBits;
+
+constexpr const auto kTestKey = AuthTokenKey::fill(static_cast<uint8_t>(TestKeyBits::BYTE));
+
+class SecureInputHMacer {
+  public:
+    static optional<Hmac> hmac256(const AuthTokenKey& key,
+                                  std::initializer_list<ByteBufferProxy> buffers) {
+        HMAC_CTX hmacCtx;
+        HMAC_CTX_init(&hmacCtx);
+        if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+            return {};
+        }
+        for (auto& buffer : buffers) {
+            if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+                return {};
+            }
+        }
+        Hmac result;
+        if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+            return {};
+        }
+        return result;
+    }
+};
+
+using HMac = teeui::HMac<SecureInputHMacer>;
+
+Nonce generateNonce() {
+    /*
+     * Completely random nonce.
+     * Running the secure input protocol from the HAL service is not secure
+     * because we don't trust the non-secure world (i.e., HLOS/Android/Linux). So
+     * using a constant "nonce" here does not weaken security. If this code runs
+     * on a truly trustworthy source of input events this function needs to return
+     * hight entropy nonces.
+     * As of this writing the call to RAND_bytes is commented, because the
+     * emulator this HAL service runs on does not have a good source of entropy.
+     * It would block the call to RAND_bytes indefinitely.
+     */
+    Nonce result{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+                 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+                 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04};
+    // RAND_bytes(result.data(), result.size());
+    return result;
+}
+
+/**
+ * This is an implementation of the SecureInput protocol in unserspace. This is
+ * just an example and should not be used as is. The protocol implemented her
+ * should be used by a trusted input device that can assert user events with
+ * high assurance even if the HLOS kernel is compromised. A confirmationui HAL
+ * that links directly against this implementation is not secure and shal not be
+ * used on a production device.
+ */
+class NotSoSecureInput : public SecureInput {
+  public:
+    NotSoSecureInput(HsBeginCb hsBeginCb, HsFinalizeCb hsFinalizeCb, DeliverEventCb deliverEventCb,
+                     InputResultCb inputResultCb)
+        : hsBeginCb_{hsBeginCb}, hsFinalizeCb_{hsFinalizeCb}, deliverEventCb_{deliverEventCb},
+          inputResultCb_{inputResultCb}, discardEvents_{true} {}
+
+    operator bool() const override { return true; }
+
+    void handleEvent(const EventDev& evdev) override {
+        bool gotEvent;
+        input_event evt;
+        std::tie(gotEvent, evt) = evdev.readEvent();
+        while (gotEvent) {
+            if (!(discardEvents_) && evt.type == EV_KEY &&
+                (evt.code == KEY_POWER || evt.code == KEY_VOLUMEDOWN || evt.code == KEY_VOLUMEUP) &&
+                evt.value == 1) {
+                DTupKeyEvent event = DTupKeyEvent::RESERVED;
+
+                // Translate the event code into DTupKeyEvent which the TA understands.
+                switch (evt.code) {
+                case KEY_POWER:
+                    event = DTupKeyEvent::PWR;
+                    break;
+                case KEY_VOLUMEDOWN:
+                    event = DTupKeyEvent::VOL_DOWN;
+                    break;
+                case KEY_VOLUMEUP:
+                    event = DTupKeyEvent::VOL_UP;
+                    break;
+                }
+
+                // The event goes into the HMAC in network byte order.
+                uint32_t keyEventBE = htobe32(static_cast<uint32_t>(event));
+                auto signature = HMac::hmac256(kTestKey, kConfirmationUIEventLabel,
+                                               teeui::bytesCast(keyEventBE), nCi_);
+
+                teeui::ResponseCode rc;
+                InputResponse ir;
+                auto response = std::tie(rc, ir);
+                if (event != DTupKeyEvent::RESERVED) {
+                    response = deliverEventCb_(event, *signature);
+                    if (rc != ResponseCode::OK) {
+                        LOG(ERROR) << "DeliverInputEvent returned with " << uint32_t(rc);
+                        inputResultCb_(rc);
+                    } else {
+                        switch (ir) {
+                        case InputResponse::OK:
+                            inputResultCb_(rc);
+                            break;
+                        case InputResponse::PENDING_MORE:
+                            rc = performDTUPHandshake();
+                            if (rc != ResponseCode::OK) {
+                                inputResultCb_(rc);
+                            }
+                            break;
+                        case InputResponse::TIMED_OUT:
+                            inputResultCb_(rc);
+                            break;
+                        }
+                    }
+                }
+            }
+            std::tie(gotEvent, evt) = evdev.readEvent();
+        }
+    }
+
+    void start() override {
+        auto rc = performDTUPHandshake();
+        if (rc != ResponseCode::OK) {
+            inputResultCb_(rc);
+        }
+        discardEvents_ = false;
+    };
+
+  private:
+    teeui::ResponseCode performDTUPHandshake() {
+        ResponseCode rc;
+        LOG(INFO) << "Start handshake";
+        Nonce nCo;
+        std::tie(rc, nCo) = hsBeginCb_();
+        if (rc != ResponseCode::OK) {
+            LOG(ERROR) << "Failed to begin secure input handshake (" << uint32_t(rc) << ")";
+            return rc;
+        }
+
+        nCi_ = generateNonce();
+        rc =
+            hsFinalizeCb_(*HMac::hmac256(kTestKey, kConfirmationUIHandshakeLabel, nCo, nCi_), nCi_);
+
+        if (rc != ResponseCode::OK) {
+            LOG(ERROR) << "Failed to finalize secure input handshake (" << uint32_t(rc) << ")";
+            return rc;
+        }
+        return ResponseCode::OK;
+    }
+
+    HsBeginCb hsBeginCb_;
+    HsFinalizeCb hsFinalizeCb_;
+    DeliverEventCb deliverEventCb_;
+    InputResultCb inputResultCb_;
+
+    std::atomic_bool discardEvents_;
+    Nonce nCi_;
+};
+
+namespace secure_input {
+
+std::shared_ptr<SecureInput> createSecureInput(SecureInput::HsBeginCb hsBeginCb,
+                                               SecureInput::HsFinalizeCb hsFinalizeCb,
+                                               SecureInput::DeliverEventCb deliverEventCb,
+                                               SecureInput::InputResultCb inputResultCb) {
+    return std::make_shared<NotSoSecureInput>(hsBeginCb, hsFinalizeCb, deliverEventCb,
+                                              inputResultCb);
+}
+
+}  // namespace secure_input
diff --git a/trusty/confirmationui/README b/trusty/confirmationui/README
new file mode 100644
index 0000000..45d4e76
--- /dev/null
+++ b/trusty/confirmationui/README
@@ -0,0 +1,20 @@
+## Secure UI Architecture
+
+To implement confirmationui a secure UI architecture is required. This entails a way
+to display the confirmation dialog driven by a reduced trusted computing base, typically
+a trusted execution environment (TEE), without having to rely on Linux and the Android
+system for integrity and authenticity of input events. This implementation provides
+neither. But it provides most of the functionlity required to run a full Android Protected
+Confirmation feature when integrated into a secure UI architecture.
+
+## Secure input (NotSoSecureInput)
+
+This implementation does not provide any security guaranties.
+The input method (NotSoSecureInput) runs a cryptographic protocols that is
+sufficiently secure IFF the end point is implemented on a trustworthy
+secure input device. But since the endpoint is currently in the HAL
+service itself this implementation is not secure.
+
+NOTE that a secure input device end point needs a good source of entropy
+for generating nonces. The current implementation (NotSoSecureInput.cpp#generateNonce)
+uses a constant nonce.
\ No newline at end of file
diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp
new file mode 100644
index 0000000..e4c68f9
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#include "TrustyApp.h"
+
+#include <android-base/logging.h>
+#include <sys/uio.h>
+#include <trusty/tipc.h>
+
+namespace android {
+namespace trusty {
+
+// 0x1000 is the message buffer size but we need to leave some space for a protocol header.
+// This assures that packets can always be read/written in one read/write operation.
+static constexpr const uint32_t kPacketSize = 0x1000 - 32;
+
+enum class PacketType : uint32_t {
+    SND,
+    RCV,
+    ACK,
+};
+
+struct PacketHeader {
+    PacketType type;
+    uint32_t remaining;
+};
+
+const char* toString(PacketType t) {
+    switch (t) {
+    case PacketType::SND:
+        return "SND";
+    case PacketType::RCV:
+        return "RCV";
+    case PacketType::ACK:
+        return "ACK";
+    default:
+        return "UNKNOWN";
+    }
+}
+
+static constexpr const uint32_t kHeaderSize = sizeof(PacketHeader);
+static constexpr const uint32_t kPayloadSize = kPacketSize - kHeaderSize;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+                  uint8_t* iend) {
+    while (obegin != oend) {
+        PacketHeader header = {
+            .type = PacketType::SND,
+            .remaining = uint32_t(oend - obegin),
+        };
+        uint32_t body_size = std::min(kPayloadSize, header.remaining);
+        iovec iov[] = {
+            {
+                .iov_base = &header,
+                .iov_len = kHeaderSize,
+            },
+            {
+                .iov_base = const_cast<uint8_t*>(obegin),
+                .iov_len = body_size,
+            },
+        };
+        int rc = writev(handle, iov, 2);
+        if (!rc) {
+            PLOG(ERROR) << "Error sending SND message. " << rc;
+            return rc;
+        }
+
+        obegin += body_size;
+
+        rc = read(handle, &header, kHeaderSize);
+        if (!rc) {
+            PLOG(ERROR) << "Error reading ACK. " << rc;
+            return rc;
+        }
+
+        if (header.type != PacketType::ACK || header.remaining != oend - obegin) {
+            LOG(ERROR) << "malformed ACK";
+            return -1;
+        }
+    }
+
+    ssize_t remaining = 0;
+    auto begin = ibegin;
+    do {
+        PacketHeader header = {
+            .type = PacketType::RCV,
+            .remaining = 0,
+        };
+
+        iovec iov[] = {
+            {
+                .iov_base = &header,
+                .iov_len = kHeaderSize,
+            },
+            {
+                .iov_base = begin,
+                .iov_len = uint32_t(iend - begin),
+            },
+        };
+
+        ssize_t rc = writev(handle, iov, 1);
+        if (!rc) {
+            PLOG(ERROR) << "Error sending RCV message. " << rc;
+            return rc;
+        }
+
+        rc = readv(handle, iov, 2);
+        if (rc < 0) {
+            PLOG(ERROR) << "Error reading response. " << rc;
+            return rc;
+        }
+
+        uint32_t body_size = std::min(kPayloadSize, header.remaining);
+        if (body_size != rc - kHeaderSize) {
+            LOG(ERROR) << "Unexpected amount of data: " << rc;
+            return -1;
+        }
+
+        remaining = header.remaining - body_size;
+        begin += body_size;
+    } while (remaining);
+
+    return begin - ibegin;
+}
+
+TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
+    : handle_(kInvalidHandle) {
+    handle_ = tipc_connect(path.c_str(), appname.c_str());
+    if (handle_ == kInvalidHandle) {
+        LOG(ERROR) << AT << "failed to connect to Trusty TA \"" << appname << "\" using dev:"
+                   << "\"" << path << "\"";
+    }
+    LOG(INFO) << AT << "succeeded to connect to Trusty TA \"" << appname << "\"";
+}
+TrustyApp::~TrustyApp() {
+    if (handle_ != kInvalidHandle) {
+        tipc_close(handle_);
+    }
+    LOG(INFO) << "Done shutting down TrustyApp";
+}
+
+}  // namespace trusty
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyApp.h b/trusty/confirmationui/TrustyApp.h
new file mode 100644
index 0000000..05a25f6
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include <sys/stat.h>
+#include <teeui/msg_formatting.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#define AT __FILE__ ":" << __LINE__ << ": "
+
+namespace android {
+namespace trusty {
+
+using ::teeui::Message;
+using ::teeui::msg2tuple_t;
+using ::teeui::ReadStream;
+using ::teeui::WriteStream;
+
+#ifndef TEEUI_USE_STD_VECTOR
+/*
+ * TEEUI_USE_STD_VECTOR makes certain wire types like teeui::MsgString and
+ * teeui::MsgVector be aliases for std::vector. This is required for thread safe
+ * message serialization. Always compile this with -DTEEUI_USE_STD_VECTOR set in
+ * CFLAGS of the HAL service.
+ */
+#error "Must be compiled with -DTEEUI_USE_STD_VECTOR."
+#endif
+
+enum class TrustyAppError : int32_t {
+    OK,
+    ERROR = -1,
+    MSG_TOO_LONG = -2,
+};
+
+/*
+ * There is a hard limitation of 0x1800 bytes for the to-be-signed message size. The protocol
+ * overhead is limited, so that 0x2000 is a buffer size that will be sufficient in any benign
+ * mode of operation.
+ */
+static constexpr const size_t kSendBufferSize = 0x2000;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+                  uint8_t* iend);
+
+class TrustyApp {
+  private:
+    int handle_;
+    static constexpr const int kInvalidHandle = -1;
+    /*
+     * This mutex serializes communication with the trusted app, not handle_.
+     * Calling issueCmd during construction or deletion is undefined behavior.
+     */
+    std::mutex mutex_;
+
+  public:
+    TrustyApp(const std::string& path, const std::string& appname);
+    ~TrustyApp();
+
+    template <typename Request, typename Response, typename... T>
+    std::tuple<TrustyAppError, msg2tuple_t<Response>> issueCmd(const T&... args) {
+        std::lock_guard<std::mutex> lock(mutex_);
+
+        if (handle_ == kInvalidHandle) {
+            LOG(ERROR) << "TrustyApp not connected";
+            return {TrustyAppError::ERROR, {}};
+        }
+
+        uint8_t buffer[kSendBufferSize];
+        WriteStream out(buffer);
+
+        out = write(Request(), out, args...);
+        if (!out) {
+            LOG(ERROR) << AT << "send command failed: message formatting";
+            return {TrustyAppError::MSG_TOO_LONG, {}};
+        }
+
+        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+                            &buffer[kSendBufferSize]);
+        if (rc < 0) return {TrustyAppError::ERROR, {}};
+
+        ReadStream in(&buffer[0], rc);
+        auto result = read(Response(), in);
+        if (!std::get<0>(result)) {
+            LOG(ERROR) << "send command failed: message parsing";
+            return {TrustyAppError::ERROR, {}};
+        }
+
+        return {std::get<0>(result) ? TrustyAppError::OK : TrustyAppError::ERROR,
+                tuple_tail(std::move(result))};
+    }
+
+    template <typename Request, typename... T> TrustyAppError issueCmd(const T&... args) {
+        std::lock_guard<std::mutex> lock(mutex_);
+
+        if (handle_ == kInvalidHandle) {
+            LOG(ERROR) << "TrustyApp not connected";
+            return TrustyAppError::ERROR;
+        }
+
+        uint8_t buffer[kSendBufferSize];
+        WriteStream out(buffer);
+
+        out = write(Request(), out, args...);
+        if (!out) {
+            LOG(ERROR) << AT << "send command failed: message formatting";
+            return TrustyAppError::MSG_TOO_LONG;
+        }
+
+        auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+                            &buffer[kSendBufferSize]);
+        if (rc < 0) {
+            LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")";
+            return TrustyAppError::ERROR;
+        }
+
+        if (rc > 0) {
+            LOG(ERROR) << "Unexpected non zero length response";
+            return TrustyAppError::ERROR;
+        }
+        return TrustyAppError::OK;
+    }
+
+    operator bool() const { return handle_ != kInvalidHandle; }
+};
+
+}  // namespace trusty
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp
new file mode 100644
index 0000000..6b25893
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.cpp
@@ -0,0 +1,513 @@
+/*
+ *
+ * Copyright 2019, 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.
+ */
+
+#include "TrustyConfirmationUI.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <pthread.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <secure_input/secure_input_proto.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <teeui/msg_formatting.h>
+#include <teeui/utils.h>
+#include <time.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using namespace secure_input;
+
+using ::android::trusty::TrustyAppError;
+
+using ::teeui::AbortMsg;
+using ::teeui::DeliverTestCommandMessage;
+using ::teeui::DeliverTestCommandResponse;
+using ::teeui::FetchConfirmationResult;
+using ::teeui::MsgString;
+using ::teeui::MsgVector;
+using ::teeui::PromptUserConfirmationMsg;
+using ::teeui::PromptUserConfirmationResponse;
+using ::teeui::ResultMsg;
+
+using ::secure_input::createSecureInput;
+
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+using ::std::tie;
+
+using TeeuiRc = ::teeui::ResponseCode;
+
+constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+constexpr const char kConfirmationuiAppName[] = "com.android.trusty.confirmationui";
+
+namespace {
+
+class Finalize {
+  private:
+    std::function<void()> f_;
+
+  public:
+    Finalize(std::function<void()> f) : f_(f) {}
+    ~Finalize() {
+        if (f_) f_();
+    }
+    void release() { f_ = {}; }
+};
+
+ResponseCode convertRc(TeeuiRc trc) {
+    static_assert(
+        uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) &&
+            uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) &&
+            uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) &&
+            uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) &&
+            uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) &&
+            uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) &&
+            uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) &&
+            uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) &&
+            uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) &&
+            uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) &&
+            uint32_t(TeeuiRc::UIErrorMessageTooLong) ==
+                uint32_t(ResponseCode::UIErrorMessageTooLong) &&
+            uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) ==
+                uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding),
+        "teeui::ResponseCode and "
+        "::android::hardware::confirmationui::V1_0::Responsecude are out of "
+        "sync");
+    return ResponseCode(trc);
+}
+
+teeui::UIOption convertUIOption(UIOption uio) {
+    static_assert(uint32_t(UIOption::AccessibilityInverted) ==
+                          uint32_t(teeui::UIOption::AccessibilityInverted) &&
+                      uint32_t(UIOption::AccessibilityMagnified) ==
+                          uint32_t(teeui::UIOption::AccessibilityMagnified),
+                  "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
+                  "anre out of sync");
+    return teeui::UIOption(uio);
+}
+
+inline MsgString hidl2MsgString(const hidl_string& s) {
+    return {s.c_str(), s.c_str() + s.size()};
+}
+template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
+    return {v};
+}
+
+inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
+    MsgVector<teeui::UIOption> result(v.size());
+    for (unsigned int i = 0; i < v.size(); ++i) {
+        result[i] = convertUIOption(v[i]);
+    }
+    return result;
+}
+
+}  // namespace
+
+TrustyConfirmationUI::TrustyConfirmationUI()
+    : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {}
+
+TrustyConfirmationUI::~TrustyConfirmationUI() {
+    ListenerState state = listener_state_;
+    if (state == ListenerState::SetupDone || state == ListenerState::Interactive) {
+        abort();
+    }
+    if (state != ListenerState::None) {
+        callback_thread_.join();
+    }
+}
+
+std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>>
+TrustyConfirmationUI::promptUserConfirmation_(const MsgString& promptText,
+                                              const MsgVector<uint8_t>& extraData,
+                                              const MsgString& locale,
+                                              const MsgVector<teeui::UIOption>& uiOptions) {
+    std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+    /*
+     * This is the main listener thread function. The listener thread life cycle
+     * is equivalent to the life cycle of a single confirmation request. The life
+     * cycle is devided in four phases.
+     *  * The starting phase:
+     *    * The Trusted App gets loaded and/or the connection to it gets established.
+     *    * A connection to the secure input device is established.
+     *    * The prompt is initiated. This sends all information required by the
+     *      confirmation dialog to the TA. The dialog is not yet displayed.
+     *    * An event loop is created.
+     *      * The event loop listens for user input events, fetches them from the
+     *        secure input device, and delivers them to the TA.
+     *    * All evdev devices are grabbed to give confirmationui exclusive access
+     *      to user input.
+     *
+     * Note: During the starting phase the hwbinder service thread is blocked and
+     * waiting for possible Errors. If the setup phase concludes sucessfully, the
+     * hwbinder service thread gets unblocked and returns successfully. Errors
+     * that occur after the first phase are delivered by callback interface.
+     *
+     *  * The 2nd phase - non interactive phase
+     *    * The event loop thread is started.
+     *    * After a grace period:
+     *      * A handshake between the secure input device SecureInput and the TA
+     *        is performed.
+     *      * The input event handler are armed to process user input events.
+     *
+     *  * The 3rd phase - interactive phase
+     *    * We wait to any external event
+     *      * Abort
+     *      * Secure user input asserted
+     *      * Secure input delivered (for non interactive VTS testing)
+     *    * The result is fetched from the TA.
+     *
+     *  * The 4th phase - cleanup
+     *    The cleanup phase is given by the scope of automatic variables created
+     *    in this function. The cleanup commences in reverse order of their creation.
+     *    Here is a list of more complex items in the order in which they go out of
+     *    scope
+     *    * finalizeSecureTouch - signals and joins the secure touch thread.
+     *    * eventloop - signals and joins the event loop thread. The event
+     *      handlers also own all EventDev instances which ungrab the event devices.
+     *      When the eventloop goes out of scope the EventDevs get destroyed
+     *      relinquishing the exclusive hold on the event devices.
+     *    * finalizeConfirmationPrompt - calls abort on the TA, making sure a
+     *      pending operation gets canceled. If the prompt concluded successfully this
+     *      is a spurious call but semantically a no op.
+     *    * secureInput - shuts down the connection to the secure input device
+     *      SecureInput.
+     *    * app - disconnects the TA. Since app is a shared pointer this may not
+     *      unload the app here. It is possible that more instances of the shared
+     *      pointer are held in TrustyConfirmationUI::deliverSecureInputEvent and
+     *      TrustyConfirmationUI::abort. But these instances are extremely short lived
+     *      and it is safe if they are destroyed by either.
+     *    * stateLock - unlocks the listener_state_lock_ if it happens to be held
+     *      at the time of return.
+     */
+
+    std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>> result;
+    TeeuiRc& rc = std::get<TeeuiRc>(result);
+    rc = TeeuiRc::SystemError;
+
+    listener_state_ = ListenerState::Starting;
+
+    auto app = std::make_shared<TrustyApp>(kTrustyDeviceName, kConfirmationuiAppName);
+    if (!app) return result;  // TeeuiRc::SystemError
+
+    app_ = app;
+
+    auto hsBegin = [&]() -> std::tuple<TeeuiRc, Nonce> {
+        auto [error, result] =
+            app->issueCmd<secure_input::InputHandshake, secure_input::InputHandshakeResponse>();
+        auto& [rc, nCo] = result;
+
+        if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+            LOG(ERROR) << "Failed to begin secure input handshake (" << int32_t(error) << "/"
+                       << uint32_t(rc) << ")";
+            rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+        }
+        return result;
+    };
+
+    auto hsFinalize = [&](const Signature& sig, const Nonce& nCi) -> TeeuiRc {
+        auto [error, finalizeResponse] =
+            app->issueCmd<FinalizeInputSessionHandshake, FinalizeInputSessionHandshakeResponse>(
+                nCi, sig);
+        auto& [rc] = finalizeResponse;
+        if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+            LOG(ERROR) << "Failed to finalize secure input handshake (" << int32_t(error) << "/"
+                       << uint32_t(rc) << ")";
+            rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+        }
+        return rc;
+    };
+
+    auto deliverInput = [&](DTupKeyEvent event,
+                            const Signature& sig) -> std::tuple<TeeuiRc, InputResponse> {
+        auto [error, result] =
+            app->issueCmd<DeliverInputEvent, DeliverInputEventResponse>(event, sig);
+        auto& [rc, ir] = result;
+        if (error != TrustyAppError::OK) {
+            LOG(ERROR) << "Failed to deliver input command";
+            rc = TeeuiRc::SystemError;
+        }
+        return result;
+    };
+
+    std::atomic<TeeuiRc> eventRC = TeeuiRc::OperationPending;
+    auto inputResult = [&](TeeuiRc rc) {
+        TeeuiRc expected = TeeuiRc::OperationPending;
+        if (eventRC.compare_exchange_strong(expected, rc)) {
+            listener_state_condv_.notify_all();
+        }
+    };
+
+    // create Secure Input device.
+    auto secureInput = createSecureInput(hsBegin, hsFinalize, deliverInput, inputResult);
+    if (!secureInput || !(*secureInput)) {
+        LOG(ERROR) << "Failed to open secure input device";
+        return result;  // TeeuiRc::SystemError;
+    }
+
+    Finalize finalizeConfirmationPrompt([app] {
+        LOG(INFO) << "Calling abort for cleanup";
+        app->issueCmd<AbortMsg>();
+    });
+
+    // initiate prompt
+    LOG(INFO) << "Initiating prompt";
+    TrustyAppError error;
+    auto initResponse = std::tie(rc);
+    std::tie(error, initResponse) =
+        app->issueCmd<PromptUserConfirmationMsg, PromptUserConfirmationResponse>(
+            promptText, extraData, locale, uiOptions);
+    if (error == TrustyAppError::MSG_TOO_LONG) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: message too long";
+        rc = TeeuiRc::UIErrorMessageTooLong;
+        return result;
+    } else if (error != TrustyAppError::OK) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: " << int32_t(error);
+        return result;  // TeeuiRc::SystemError;
+    }
+    if (rc != TeeuiRc::OK) {
+        LOG(ERROR) << "PromptUserConfirmationMsg failed: " << uint32_t(rc);
+        return result;
+    }
+
+    LOG(INFO) << "Grabbing event devices";
+    EventLoop eventloop;
+    bool grabbed =
+        grabAllEvDevsAndRegisterCallbacks(&eventloop, [&](short flags, const EventDev& evDev) {
+            if (!(flags & POLLIN)) return;
+            secureInput->handleEvent(evDev);
+        });
+
+    if (!grabbed) {
+        rc = TeeuiRc::SystemError;
+        return result;
+    }
+
+    abort_called_ = false;
+    secureInputDelivered_ = false;
+
+    //  ############################## Start 2nd Phase #############################################
+    listener_state_ = ListenerState::SetupDone;
+    stateLock.unlock();
+    listener_state_condv_.notify_all();
+
+    if (!eventloop.start()) {
+        rc = TeeuiRc::SystemError;
+        return result;
+    }
+
+    stateLock.lock();
+
+    LOG(INFO) << "going to sleep for the grace period";
+    auto then = std::chrono::system_clock::now() +
+                std::chrono::milliseconds(kUserPreInputGracePeriodMillis) +
+                std::chrono::microseconds(50);
+    listener_state_condv_.wait_until(stateLock, then, [&]() { return abort_called_; });
+    LOG(INFO) << "waking up";
+
+    if (abort_called_) {
+        LOG(ERROR) << "Abort called";
+        result = {TeeuiRc::Aborted, {}, {}};
+        return result;
+    }
+
+    LOG(INFO) << "Arming event poller";
+    // tell the event poller to act on received input events from now on.
+    secureInput->start();
+
+    //  ############################## Start 3rd Phase - interactive phase #########################
+    LOG(INFO) << "Transition to Interactive";
+    listener_state_ = ListenerState::Interactive;
+    stateLock.unlock();
+    listener_state_condv_.notify_all();
+
+    stateLock.lock();
+    listener_state_condv_.wait(stateLock, [&]() {
+        return eventRC != TeeuiRc::OperationPending || abort_called_ || secureInputDelivered_;
+    });
+    LOG(INFO) << "Listener waking up";
+    if (abort_called_) {
+        LOG(ERROR) << "Abort called";
+        result = {TeeuiRc::Aborted, {}, {}};
+        return result;
+    }
+
+    if (!secureInputDelivered_) {
+        if (eventRC != TeeuiRc::OK) {
+            LOG(ERROR) << "Bad input response";
+            result = {eventRC, {}, {}};
+            return result;
+        }
+    }
+
+    stateLock.unlock();
+
+    LOG(INFO) << "Fetching Result";
+    std::tie(error, result) = app->issueCmd<FetchConfirmationResult, ResultMsg>();
+    LOG(INFO) << "Result yields " << int32_t(error) << "/" << uint32_t(rc);
+    if (error != TrustyAppError::OK) {
+        result = {TeeuiRc::SystemError, {}, {}};
+    }
+    return result;
+
+    //  ############################## Start 4th Phase - cleanup ##################################
+}
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+// follow.
+Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
+    const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+    const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+    const hidl_vec<UIOption>& uiOptions) {
+    std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
+    if (!stateLock.try_lock()) {
+        return ResponseCode::OperationPending;
+    }
+    switch (listener_state_) {
+    case ListenerState::None:
+        break;
+    case ListenerState::Starting:
+    case ListenerState::SetupDone:
+    case ListenerState::Interactive:
+        return ResponseCode::OperationPending;
+    case ListenerState::Terminating:
+        callback_thread_.join();
+        listener_state_ = ListenerState::None;
+        break;
+    default:
+        return ResponseCode::Unexpected;
+    }
+
+    assert(listener_state_ == ListenerState::None);
+
+    callback_thread_ = std::thread(
+        [this](sp<IConfirmationResultCallback> resultCB, hidl_string promptText,
+               hidl_vec<uint8_t> extraData, hidl_string locale, hidl_vec<UIOption> uiOptions) {
+            auto [trc, msg, token] =
+                promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData),
+                                        hidl2MsgString(locale), hidl2MsgVector(uiOptions));
+            bool do_callback = (listener_state_ == ListenerState::Interactive ||
+                                listener_state_ == ListenerState::SetupDone) &&
+                               resultCB;
+            prompt_result_ = convertRc(trc);
+            listener_state_ = ListenerState::Terminating;
+            if (do_callback) {
+                auto error = resultCB->result(prompt_result_, msg, token);
+                if (!error.isOk()) {
+                    LOG(ERROR) << "Result callback failed " << error.description();
+                }
+            } else {
+                listener_state_condv_.notify_all();
+            }
+        },
+        resultCB, promptText, extraData, locale, uiOptions);
+
+    listener_state_condv_.wait(stateLock, [this] {
+        return listener_state_ == ListenerState::SetupDone ||
+               listener_state_ == ListenerState::Interactive ||
+               listener_state_ == ListenerState::Terminating;
+    });
+    if (listener_state_ == ListenerState::Terminating) {
+        callback_thread_.join();
+        listener_state_ = ListenerState::None;
+        return prompt_result_;
+    }
+    return ResponseCode::OK;
+}
+
+Return<ResponseCode>
+TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+    ResponseCode rc = ResponseCode::Ignored;
+    {
+        /*
+         * deliverSecureInputEvent is only used by the VTS test to mock human input. A correct
+         * implementation responds with a mock confirmation token signed with a test key. The
+         * problem is that the non interactive grace period was not formalized in the HAL spec,
+         * so that the VTS test does not account for the grace period. (It probably should.)
+         * This means we can only pass the VTS test if we block until the grace period is over
+         * (SetupDone -> Interactive) before we deliver the input event.
+         *
+         * The true secure input is delivered by a different mechanism and gets ignored -
+         * not queued - until the grace period is over.
+         *
+         */
+        std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+        listener_state_condv_.wait(stateLock,
+                                   [this] { return listener_state_ != ListenerState::SetupDone; });
+
+        if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored;
+        auto sapp = app_.lock();
+        if (!sapp) return ResponseCode::Ignored;
+        auto [error, response] =
+            sapp->issueCmd<DeliverTestCommandMessage, DeliverTestCommandResponse>(
+                static_cast<teeui::TestModeCommands>(secureInputToken.challenge));
+        if (error != TrustyAppError::OK) return ResponseCode::SystemError;
+        auto& [trc] = response;
+        if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true;
+        rc = convertRc(trc);
+    }
+    if (secureInputDelivered_) listener_state_condv_.notify_all();
+    // VTS test expect an OK response if the event was successfully delivered.
+    // But since the TA returns the callback response now, we have to translate
+    // Canceled into OK. Canceled is only returned if the delivered event canceled
+    // the operation, which means that the event was successfully delivered. Thus
+    // we return OK.
+    if (rc == ResponseCode::Canceled) return ResponseCode::OK;
+    return rc;
+}
+
+Return<void> TrustyConfirmationUI::abort() {
+    {
+        std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+        if (listener_state_ == ListenerState::SetupDone ||
+            listener_state_ == ListenerState::Interactive) {
+            auto sapp = app_.lock();
+            if (sapp) sapp->issueCmd<AbortMsg>();
+            abort_called_ = true;
+        }
+    }
+    listener_state_condv_.notify_all();
+    return Void();
+}
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI() {
+    return new TrustyConfirmationUI();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.h b/trusty/confirmationui/TrustyConfirmationUI.h
new file mode 100644
index 0000000..3a7c7ef
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020, 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 ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <teeui/generic_messages.h>
+#include <thread>
+
+#include "TrustyApp.h"
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::trusty::TrustyApp;
+
+class TrustyConfirmationUI : public IConfirmationUI {
+  public:
+    TrustyConfirmationUI();
+    virtual ~TrustyConfirmationUI();
+    // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+    // follow.
+    Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+                                                const hidl_string& promptText,
+                                                const hidl_vec<uint8_t>& extraData,
+                                                const hidl_string& locale,
+                                                const hidl_vec<UIOption>& uiOptions) override;
+    Return<ResponseCode> deliverSecureInputEvent(
+        const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+    Return<void> abort() override;
+
+  private:
+    std::weak_ptr<TrustyApp> app_;
+    std::thread callback_thread_;
+
+    enum class ListenerState : uint32_t {
+        None,
+        Starting,
+        SetupDone,
+        Interactive,
+        Terminating,
+    };
+
+    /*
+     * listener_state is protected by listener_state_lock. It makes transitions between phases
+     * of the confirmation operation atomic.
+     * (See TrustyConfirmationUI.cpp#promptUserConfirmation_ for details about operation phases)
+     */
+    ListenerState listener_state_;
+    /*
+     * abort_called_ is also protected by listener_state_lock_ and indicates that the HAL user
+     * called abort.
+     */
+    bool abort_called_;
+    std::mutex listener_state_lock_;
+    std::condition_variable listener_state_condv_;
+    ResponseCode prompt_result_;
+    bool secureInputDelivered_;
+
+    std::tuple<teeui::ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>
+    promptUserConfirmation_(const teeui::MsgString& promptText,
+                            const teeui::MsgVector<uint8_t>& extraData,
+                            const teeui::MsgString& locale,
+                            const teeui::MsgVector<teeui::UIOption>& uiOptions);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
new file mode 100644
index 0000000..dc7a03b
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
@@ -0,0 +1,4 @@
+service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty
+    class hal
+    user nobody
+    group drmrpc input
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
new file mode 100644
index 0000000..9008b87
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.confirmationui</name>
+        <transport>hwbinder</transport>
+        <version>1.0</version>
+        <interface>
+        <name>IConfirmationUI</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/trusty/confirmationui/include/TrustyConfirmationuiHal.h b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
new file mode 100644
index 0000000..2ab9389
--- /dev/null
+++ b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI();
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp
new file mode 100644
index 0000000..dd7e84b
--- /dev/null
+++ b/trusty/confirmationui/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <TrustyConfirmationuiHal.h>
+
+using android::sp;
+using android::hardware::confirmationui::V1_0::implementation::createTrustyConfirmationUI;
+
+int main() {
+    ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
+    auto service = createTrustyConfirmationUI();
+    auto status = service->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for ConfirmationUI 1.0 (" << status << ")";
+        return -1;
+    }
+    ::android::hardware::joinRpcThreadpool();
+    return -1;
+}