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/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