First working version of the confirmationui HAL service

This implementation does not provide any security guaranties.
 * The input method (NotSoSecureInput) runs a crypto 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.
 * This implementation provides most of the functionality, but not the
   secure UI infrastructure required to run Android Protected
   Confirmation.

Bug: 146078942
Test: VtsHalConfirmationUIV1_0TargetTest
Change-Id: I14717b5fa4ef15db960cdd506b8c6fe5369aec8d
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