Moved confirmationui support library to libteeui

This patch moves functionality from the support library in
hardware/interfaces/confirmationui in libteeui.
* Move support library to the new namespace teeui
* Removed IntegerSequence and replaced it with std::index_sequence
* Remove dependency on HIDL types hidl_vec, hidl_string, and
  the Keymaster type HardwareAuthToken for the message passing between
  the TA and the HAL. To this end this patch introduces static_vec.h.
  static_vec is an alias for std::vector when compiled with
  -DTEEUI_USE_STD_VEC which it should always be compiled with in the
  context of the HAL service. Otherwise, it behaves like a span that
  does not own the underlying storage otherwise. This is the expected
  behavior when compiled in the context of the TA.
* Moved confirmationui HAL enums into the teeui namespace. It is now up to
  the HAL implementation to translate between the TA types and the hidl
  defined types.
* Separated the core logic for message formatting from the
  protocol (now generic_messages.h) and serialization functions
  for common types (now common_message_types.h).
* Add protocol specifiers to commands to allow easier extension of the
  protocols between the TA and HAL.
* NullOr was removed in favor of std::optional.

Test: keystore_cli_v2
      VtsHalConfirmationUIV1_0TargetTest
Bug: 111446692
Bug: 111451575
Change-Id: I8a498d49593b6e382c874d08f322f572c03ddcb8
diff --git a/libteeui/include/teeui/cbor.h b/libteeui/include/teeui/cbor.h
new file mode 100644
index 0000000..3b1320a
--- /dev/null
+++ b/libteeui/include/teeui/cbor.h
@@ -0,0 +1,296 @@
+/*
+ *
+ * Copyright 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 TEEUI_CBOR_H_
+#define TEEUI_CBOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace teeui {
+namespace cbor {
+
+template <typename In, typename Out> Out copy(In begin, In end, Out out) {
+    while (begin != end) {
+        *out++ = *begin++;
+    }
+    return out;
+}
+
+enum class Type : uint8_t {
+    NUMBER = 0,
+    NEGATIVE = 1,
+    BYTE_STRING = 2,
+    TEXT_STRING = 3,
+    ARRAY = 4,
+    MAP = 5,
+    TAG = 6,
+    FLOAT = 7,
+};
+
+enum class Error : uint32_t {
+    OK = 0,
+    OUT_OF_DATA = 1,
+    MALFORMED = 2,
+    MALFORMED_UTF8 = 3,
+};
+
+template <typename Key, typename Value> struct MapElement {
+    const Key& key_;
+    const Value& value_;
+    MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
+};
+
+template <typename... Elems> struct Array;
+
+template <typename Head, typename... Tail> struct Array<Head, Tail...> {
+    const Head& head_;
+    Array<Tail...> tail_;
+    Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <> struct Array<> {};
+
+struct TextStr {};
+struct ByteStr {};
+
+template <typename T, typename Variant> struct StringBuffer {
+    const T* data_;
+    size_t size_;
+    StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
+        static_assert(sizeof(T) == 1, "elements too large");
+    }
+    const T* data() const { return data_; }
+    size_t size() const { return size_; }
+};
+
+/**
+ * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
+ * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
+ * If the terminating 0 shall not be stripped use text_keep_last.
+ */
+template <size_t size> StringBuffer<char, TextStr> text(const char (&str)[size]) {
+    if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+/**
+ * As opposed to text(const char (&str)[size] this function does not strips the last character.
+ */
+template <size_t size> StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T> auto getData(const T& v) -> decltype(v.data()) {
+    return v.data();
+}
+
+template <typename T> auto getData(const T& v) -> decltype(v.c_str()) {
+    return v.c_str();
+}
+
+template <typename T>
+auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
+}
+
+inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T, size_t size> StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T> StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
+}
+
+template <typename... Elems> struct Map;
+
+template <typename HeadKey, typename HeadValue, typename... Tail>
+struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
+    const MapElement<HeadKey, HeadValue>& head_;
+    Map<Tail...> tail_;
+    Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
+        : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <> struct Map<> {};
+
+template <typename... Keys, typename... Values>
+Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
+    return Map<MapElement<Keys, Values>...>(elements...);
+}
+
+template <typename... Elements> Array<Elements...> arr(const Elements&... elements) {
+    return Array<Elements...>(elements...);
+}
+
+template <typename Key, typename Value> MapElement<Key, Value> pair(const Key& k, const Value& v) {
+    return MapElement<Key, Value>(k, v);
+}
+
+template <size_t size> struct getUnsignedType;
+
+template <> struct getUnsignedType<sizeof(uint8_t)> { using type = uint8_t; };
+template <> struct getUnsignedType<sizeof(uint16_t)> { using type = uint16_t; };
+template <> struct getUnsignedType<sizeof(uint32_t)> { using type = uint32_t; };
+template <> struct getUnsignedType<sizeof(uint64_t)> { using type = uint64_t; };
+
+template <size_t size> using Unsigned = typename getUnsignedType<size>::type;
+
+class WriteState {
+  public:
+    WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size, Error error)
+        : data_(buffer), size_(size), error_(error) {}
+    template <size_t size>
+    WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
+
+    WriteState& operator++() {
+        if (size_) {
+            ++data_;
+            --size_;
+        } else {
+            error_ = Error::OUT_OF_DATA;
+        }
+        return *this;
+    }
+    WriteState& operator+=(size_t offset) {
+        if (offset > size_) {
+            error_ = Error::OUT_OF_DATA;
+        } else {
+            data_ += offset;
+            size_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return error_ == Error::OK; }
+
+    uint8_t* data_;
+    size_t size_;
+    Error error_;
+};
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
+
+template <typename T> WriteState writeNumber(WriteState wState, const T& v) {
+    if (!wState) return wState;
+    if (v >= 0) {
+        return writeHeader(wState, Type::NUMBER, v);
+    } else {
+        return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
+    }
+}
+
+inline WriteState write(const WriteState& wState, const uint8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint64_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int64_t& v) {
+    return writeNumber(wState, v);
+}
+
+template <typename T> WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
+    wState = writeHeader(wState, Type::TEXT_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
+        wState.error_ = Error::MALFORMED_UTF8;
+    }
+    return wState;
+}
+
+template <typename T> WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
+    wState = writeHeader(wState, Type::BYTE_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    static_assert(sizeof(*v.data()) == 1, "elements too large");
+    copy(v.data(), v.data() + v.size(), buffer);
+    return wState;
+}
+
+template <template <typename...> class Arr>
+WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
+    return wState;
+}
+
+template <template <typename...> class Arr, typename Head, typename... Tail>
+WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
+    wState = write(wState, arr.head_);
+    return writeArrayHelper(wState, arr.tail_);
+}
+
+template <typename... Elems> WriteState write(WriteState wState, const Map<Elems...>& map) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::MAP, map.size());
+    return writeArrayHelper(wState, map);
+}
+
+template <typename... Elems> WriteState write(WriteState wState, const Array<Elems...>& arr) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::ARRAY, arr.size());
+    return writeArrayHelper(wState, arr);
+}
+
+template <typename Key, typename Value>
+WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
+    if (!wState) return wState;
+    wState = write(wState, element.key_);
+    return write(wState, element.value_);
+}
+
+template <typename Head, typename... Tail>
+WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
+    wState = write(wState, head);
+    return write(wState, tail...);
+}
+
+}  // namespace cbor
+}  // namespace teeui
+
+#endif  // TEEUI_CBOR_H_
diff --git a/libteeui/include/teeui/common_message_types.h b/libteeui/include/teeui/common_message_types.h
new file mode 100644
index 0000000..c9fb2a6
--- /dev/null
+++ b/libteeui/include/teeui/common_message_types.h
@@ -0,0 +1,178 @@
+/*
+ *
+ * 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.
+ */
+
+#ifndef TEEUI_COMMONMESSAGETYPES_H_
+#define TEEUI_COMMONMESSAGETYPES_H_
+
+#include <teeui/msg_formatting.h>
+
+#include <tuple>
+
+#include <stdint.h>
+
+#include <teeui/static_vec.h>
+
+namespace teeui {
+
+enum class UIOption : uint32_t;
+enum class ResponseCode : uint32_t;
+enum class MessageSize : uint32_t;
+enum class TestKeyBits : uint8_t;
+enum class TestModeCommands : uint64_t;
+
+enum class UIOption : uint32_t {
+    AccessibilityInverted = 0u,
+    AccessibilityMagnified = 1u,
+};
+
+enum class ResponseCode : uint32_t {
+    OK = 0u,
+    Canceled = 1u,
+    Aborted = 2u,
+    OperationPending = 3u,
+    Ignored = 4u,
+    SystemError = 5u,
+    Unimplemented = 6u,
+    Unexpected = 7u,
+    UIError = 0x10000,
+    UIErrorMissingGlyph,
+    UIErrorMessageTooLong,
+    UIErrorMalformedUTF8Encoding,
+};
+
+enum class MessageSize : uint32_t {
+    MAX = 6144u,
+};
+
+enum class TestKeyBits : uint8_t {
+    BYTE = 165,
+};
+
+enum class TestModeCommands : uint64_t {
+    OK_EVENT = 0ull,
+    CANCEL_EVENT = 1ull,
+};
+
+using MsgString = static_vec<const char>;
+template <typename T> using MsgVector = static_vec<T>;
+
+template <typename T> inline const uint8_t* copyField(T& field, const uint8_t*(&pos)) {
+    auto& s = bytesCast(field);
+    std::copy(pos, pos + sizeof(T), s);
+    return pos + sizeof(T);
+}
+
+template <typename T> inline uint8_t* copyField(const T& field, uint8_t*(&pos)) {
+    auto& s = bytesCast(field);
+    return std::copy(s, &s[sizeof(T)], pos);
+}
+
+/**
+ * This actually only reads in place if compiled without TEEUI_USE_STD_VECTOR. See static_vec.h
+ * If compiled with TEEUI_USE_STD_VECTOR MsgVector becomes std::vector and the data is actually
+ * copied.
+ */
+template <typename T> std::tuple<ReadStream, MsgVector<T>> readSimpleVecInPlace(ReadStream in) {
+    std::tuple<ReadStream, MsgVector<T>> result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(std::get<0>(result), pos, read_size) = read(in);
+    if (!std::get<0>(result) || read_size % sizeof(T)) {
+        std::get<0>(result).bad();
+        return result;
+    }
+    std::get<1>(result) =
+        MsgVector<T>(reinterpret_cast<T*>(const_cast<uint8_t*>(pos)),
+                     reinterpret_cast<T*>(const_cast<uint8_t*>(pos)) + (read_size / sizeof(T)));
+    return result;
+}
+
+template <typename T> WriteStream writeSimpleVec(WriteStream out, const MsgVector<T>& vec) {
+    return write(out, reinterpret_cast<const uint8_t*>(vec.data()), vec.size() * sizeof(T));
+}
+
+// ResponseCode
+inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
+    return readSimpleType<ResponseCode>(in);
+}
+inline WriteStream write(WriteStream out, const ResponseCode& v) {
+    return write(out, bytesCast(v));
+}
+
+// TestModeCommands
+inline std::tuple<ReadStream, TestModeCommands> read(Message<TestModeCommands>, ReadStream in) {
+    return readSimpleType<TestModeCommands>(in);
+}
+inline WriteStream write(WriteStream out, const TestModeCommands& v) {
+    return write(out, bytesCast(v));
+}
+
+namespace msg {
+
+// MsgVector<uint8_t>
+inline std::tuple<ReadStream, MsgVector<uint8_t>> read(Message<MsgVector<uint8_t>>, ReadStream in) {
+    return readSimpleVecInPlace<uint8_t>(in);
+}
+inline WriteStream write(WriteStream out, const MsgVector<uint8_t>& v) {
+    return writeSimpleVec(out, v);
+}
+
+// MsgString
+inline std::tuple<ReadStream, MsgString> read(Message<MsgString>, ReadStream in) {
+    return readSimpleVecInPlace<const char>(in);
+}
+inline WriteStream write(WriteStream out, const MsgString& v) {
+    return writeSimpleVec(out, v);
+}
+
+// MsgVector<UIOption>
+inline std::tuple<ReadStream, MsgVector<UIOption>> read(Message<MsgVector<UIOption>>,
+                                                        ReadStream in) {
+    return readSimpleVecInPlace<UIOption>(in);
+}
+inline WriteStream write(WriteStream out, const MsgVector<UIOption>& v) {
+    return writeSimpleVec(out, v);
+}
+
+}  //  namespace msg
+
+// teeui::Array<uint8_t, size>
+template <size_t size>
+inline std::tuple<teeui::ReadStream, teeui::Array<uint8_t, size>>
+read(teeui::Message<teeui::Array<uint8_t, size>>, teeui::ReadStream in) {
+    std::tuple<teeui::ReadStream, teeui::Array<uint8_t, size>> result;
+    teeui::ReadStream& in_ = std::get<0>(result);
+    auto& result_ = std::get<1>(result);
+    teeui::ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in_, pos, read_size) = read(in);
+    if (!in_) return result;
+    if (read_size != size) {
+        in_.bad();
+        return result;
+    }
+    std::copy(pos, pos + size, result_.data());
+    return result;
+}
+template <size_t size>
+inline teeui::WriteStream write(teeui::WriteStream out, const teeui::Array<uint8_t, size>& v) {
+    return write(out, v.data(), v.size());
+}
+
+}  // namespace teeui
+
+#endif  // TEEUI_COMMONMESSAGETYPES_H_
diff --git a/libteeui/include/teeui/generic_messages.h b/libteeui/include/teeui/generic_messages.h
new file mode 100644
index 0000000..90cc690
--- /dev/null
+++ b/libteeui/include/teeui/generic_messages.h
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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.
+ */
+
+#ifndef TEEUI_GENERICMESSAGES_H_
+#define TEEUI_GENERICMESSAGES_H_
+
+#include <limits>
+#include <tuple>
+
+#include <stdint.h>
+
+#include <teeui/common_message_types.h>
+#include <teeui/msg_formatting.h>
+
+namespace teeui {
+
+enum class Command : uint32_t {
+    Invalid,
+    PromptUserConfirmation,
+    FetchConfirmationResult,
+    DeliverTestCommand,
+    Abort,
+};
+
+using Protocol = uint32_t;
+
+template <Protocol Proto, typename CmdT, CmdT cmd> struct Cmd {};
+
+static constexpr const Protocol kProtoGeneric = 0;
+static constexpr const Protocol kProtoInvalid = std::numeric_limits<Protocol>::max();
+
+#define DECLARE_GENERIC_COMMAND(cmd) using Cmd##cmd = Cmd<kProtoGeneric, Command, Command::cmd>
+
+DECLARE_GENERIC_COMMAND(PromptUserConfirmation);
+DECLARE_GENERIC_COMMAND(FetchConfirmationResult);
+DECLARE_GENERIC_COMMAND(DeliverTestCommand);
+DECLARE_GENERIC_COMMAND(Abort);
+
+using PromptUserConfirmationMsg = Message<CmdPromptUserConfirmation, MsgString, MsgVector<uint8_t>,
+                                          MsgString, MsgVector<UIOption>>;
+using PromptUserConfirmationResponse = Message<ResponseCode>;
+using DeliverTestCommandMessage = Message<CmdDeliverTestCommand, TestModeCommands>;
+using DeliverTestCommandResponse = Message<ResponseCode>;
+using AbortMsg = Message<CmdAbort>;
+using ResultMsg = Message<ResponseCode, MsgVector<uint8_t>, MsgVector<uint8_t>>;
+using FetchConfirmationResult = Message<CmdFetchConfirmationResult>;
+
+template <uint32_t proto, typename CmdT, CmdT cmd>
+inline WriteStream write(WriteStream out, Cmd<proto, CmdT, cmd>) {
+    volatile Protocol* protoptr = reinterpret_cast<volatile Protocol*>(out.pos());
+    out += sizeof(Protocol);
+    if (out) *protoptr = proto;
+
+    volatile CmdT* cmdptr = reinterpret_cast<volatile CmdT*>(out.pos());
+    out += sizeof(CmdT);
+    if (out) *cmdptr = cmd;
+
+    return out;
+}
+
+template <typename CmdSpec, typename... Tail>
+WriteStream write(Message<CmdSpec, Tail...>, WriteStream out, const Tail&... tail) {
+    out = write(out, CmdSpec());
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Protocol proto, typename CmdT, CmdT cmd, typename... Fields>
+std::tuple<ReadStream, Fields...> read(Message<Cmd<proto, CmdT, cmd>, Fields...>, ReadStream in) {
+    return read(Message<Fields...>(), in);
+}
+
+template <Protocol proto, typename CmdT, CmdT cmd, typename... T>
+struct msg2tuple<Message<Cmd<proto, CmdT, cmd>, T...>> {
+    using type = std::tuple<T...>;
+};
+
+std::tuple<ReadStream, uint32_t> readU32(ReadStream in);
+
+template <typename CmdT, CmdT Invalid = CmdT::Invalid>
+std::tuple<ReadStream, CmdT> readCmd(ReadStream in) {
+    static_assert(sizeof(CmdT) == sizeof(uint32_t),
+                  "Can only be used with types the size of uint32_t");
+    auto [stream, value] = readU32(in);
+    if (stream) return {stream, CmdT(value)};
+    return {stream, Invalid};
+}
+
+template <typename CmdT, CmdT Invalid = CmdT::Invalid> CmdT peakCmd(ReadStream in) {
+    auto [_, cmd] = readCmd<CmdT>(in);
+    return cmd;
+}
+
+std::tuple<ReadStream, Command> readCommand(ReadStream in);
+Command peakCommand(ReadStream in);
+std::tuple<ReadStream, Protocol> readProtocol(ReadStream in);
+Protocol peakProtocol(ReadStream in);
+
+}  // namespace teeui
+
+#endif  // TEEUI_GENERICMESSAGES_H_
diff --git a/libteeui/include/teeui/generic_operation.h b/libteeui/include/teeui/generic_operation.h
new file mode 100644
index 0000000..e821e13
--- /dev/null
+++ b/libteeui/include/teeui/generic_operation.h
@@ -0,0 +1,281 @@
+/*
+ * Copyright 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 TEEUI_GENERICOPERATION_H_
+#define TEEUI_GENERICOPERATION_H_
+
+#include <teeui/cbor.h>
+#include <teeui/generic_messages.h>
+#include <teeui/msg_formatting.h>
+#include <teeui/utils.h>
+
+namespace teeui {
+
+inline bool hasOption(UIOption option, const MsgVector<UIOption>& uiOptions) {
+    for (auto& o : uiOptions) {
+        if (o == option) return true;
+    }
+    return false;
+}
+
+/**
+ * The generic Confirmation Operation:
+ *
+ * Derived needs to implement:
+ *   Derived::TimeStamp needs to be a timestamp type
+ *   Derived::now() needs to return a TimeStamp value denoting the current point in time.
+ *   Derived::hmac256 with the following prototype which computes the 32-byte HMAC-SHA256 over the
+ *   concatenation of all provided "buffers" keyed with "key".
+ *
+ *     optional<Hmac> HMacImplementation::hmac256(const AuthTokenKey& key,
+ *                                                std::initializer_list<ByteBufferProxy> buffers);
+ *
+ *   ResponseCode initHook();
+ *     Gets called on PromptUserConfirmation. If initHook returns anything but ResponseCode::OK,
+ *     The operation is not started and the result is returned to the HAL service.
+ *   void abortHook();
+ *     Gets called on Abort. Allows the implementation to perform cleanup.
+ *   void finalizeHook();
+ *     Gets called on FetchConfirmationResult.
+ *   ResponseCode testCommandHook(TestModeCommands testCmd);
+ *     Gets called on DeliverTestCommand and allows the implementation to react to test commands.
+ *
+ * And optionally:
+ *   WriteStream vendorCommandHook(ReadStream in, WriteStream out);
+ *
+ * The latter allows Implementations to implement custom protocol extensions.
+ *
+ */
+template <typename Derived, typename TimeStamp> class Operation {
+    using HMacer = HMac<Derived>;
+
+  public:
+    Operation()
+        : error_(ResponseCode::Ignored), formattedMessageLength_(0),
+          maginifiedViewRequested_(false), invertedColorModeRequested_(false),
+          languageIdLength_(0) {}
+
+    ResponseCode init(const MsgString& promptText, const MsgVector<uint8_t>& extraData,
+                      const MsgString& locale, const MsgVector<UIOption>& options) {
+        // An hmacKey needs to be installed before we can commence operation.
+        if (!hmacKey_) return ResponseCode::Unexpected;
+        if (error_ != ResponseCode::Ignored) return ResponseCode::OperationPending;
+        confirmationTokenScratchpad_ = {};
+
+        // We need to access the prompt text multiple times. Once for formatting the CBOR message
+        // and again for rendering the dialog. It is vital that the prompt does not change
+        // in the meantime. As of this point the prompt text is in a shared buffer and therefore
+        // susceptible to TOCTOU attacks. Note that promptText.size() resides on the stack and
+        // is safe to access multiple times. So now we copy the prompt string into the
+        // scratchpad promptStringBuffer_ from where we can format the CBOR message and then
+        // pass it to the renderer.
+        if (promptText.size() >= uint32_t(MessageSize::MAX))
+            return ResponseCode::UIErrorMessageTooLong;
+        auto pos = std::copy(promptText.begin(), promptText.end(), promptStringBuffer_);
+        *pos = 0;  // null-terminate the prompt for the renderer.
+
+        using namespace ::teeui::cbor;
+        using CborError = ::teeui::cbor::Error;
+        // Note the extra data is accessed only once for formatting the CBOR message. So it is safe
+        // to read it from the shared buffer directly. Anyway we don't trust or interpret the
+        // extra data in any way so all we do is take a snapshot and we don't care if it is
+        // modified concurrently.
+        auto state = write(WriteState(formattedMessageBuffer_),
+                           map(pair(text("prompt"), text(promptStringBuffer_, promptText.size())),
+                               pair(text("extra"), bytes(extraData))));
+        switch (state.error_) {
+        case CborError::OK:
+            break;
+        case CborError::OUT_OF_DATA:
+            return ResponseCode::UIErrorMessageTooLong;
+        case CborError::MALFORMED_UTF8:
+            return ResponseCode::UIErrorMalformedUTF8Encoding;
+        case CborError::MALFORMED:
+        default:
+            return ResponseCode::Unexpected;
+        }
+        formattedMessageLength_ = state.data_ - formattedMessageBuffer_;
+
+        if (locale.size() >= kMaxLocaleSize) return ResponseCode::UIErrorMessageTooLong;
+        pos = std::copy(locale.begin(), locale.end(), languageIdBuffer_);
+        *pos = 0;
+        languageIdLength_ = locale.size();
+
+        invertedColorModeRequested_ = hasOption(UIOption::AccessibilityInverted, options);
+        maginifiedViewRequested_ = hasOption(UIOption::AccessibilityMagnified, options);
+
+        // on success record the start time
+        startTime_ = Derived::now();
+        if (!startTime_.isOk()) {
+            return ResponseCode::SystemError;
+        }
+
+        auto rc = static_cast<Derived*>(this)->initHook();
+
+        if (rc == ResponseCode::OK) {
+            error_ = ResponseCode::OK;
+        }
+        return rc;
+    }
+
+    void setHmacKey(const AuthTokenKey& key) { hmacKey_ = key; }
+    optional<AuthTokenKey> hmacKey() const { return hmacKey_; }
+
+    void abort() {
+        if (isPending()) {
+            error_ = ResponseCode::Aborted;
+            static_cast<Derived*>(this)->abortHook();
+        }
+    }
+
+    void userCancel() {
+        if (isPending()) {
+            error_ = ResponseCode::Canceled;
+        }
+    }
+
+    std::tuple<ResponseCode, MsgVector<uint8_t>, MsgVector<uint8_t>> fetchConfirmationResult() {
+        std::tuple<ResponseCode, MsgVector<uint8_t>, MsgVector<uint8_t>> result;
+        auto& [rc, message, token] = result;
+        rc = error_;
+        if (error_ == ResponseCode::OK) {
+            message = {&formattedMessageBuffer_[0],
+                       &formattedMessageBuffer_[formattedMessageLength_]};
+            if (confirmationTokenScratchpad_) {
+                token = {confirmationTokenScratchpad_->begin(),
+                         confirmationTokenScratchpad_->end()};
+            }
+        }
+        error_ = ResponseCode::Ignored;
+        static_cast<Derived*>(this)->finalizeHook();
+        return result;
+    }
+
+    bool isPending() const { return error_ != ResponseCode::Ignored; }
+
+    const MsgString getPrompt() const {
+        return {&promptStringBuffer_[0], &promptStringBuffer_[strlen(promptStringBuffer_)]};
+    }
+
+    ResponseCode deliverTestCommand(TestModeCommands testCommand) {
+        constexpr const auto testKey = AuthTokenKey::fill(static_cast<uint8_t>(TestKeyBits::BYTE));
+        auto rc = static_cast<Derived*>(this)->testCommandHook(testCommand);
+        if (rc != ResponseCode::OK) return rc;
+        switch (testCommand) {
+        case TestModeCommands::OK_EVENT: {
+            if (isPending()) {
+                signConfirmation(testKey);
+                return ResponseCode::OK;
+            } else {
+                return ResponseCode::Ignored;
+            }
+        }
+        case TestModeCommands::CANCEL_EVENT: {
+            bool ignored = !isPending();
+            userCancel();
+            return ignored ? ResponseCode::Ignored : ResponseCode::OK;
+        }
+        default:
+            return ResponseCode::Ignored;
+        }
+    }
+
+    WriteStream dispatchCommandMessage(ReadStream in_, WriteStream out) {
+        auto [in, proto] = readProtocol(in_);
+        if (proto == kProtoGeneric) {
+            auto [in_cmd, cmd] = readCommand(in);
+            switch (cmd) {
+            case Command::PromptUserConfirmation:
+                return command(CmdPromptUserConfirmation(), in_cmd, out);
+            case Command::FetchConfirmationResult:
+                return command(CmdFetchConfirmationResult(), in_cmd, out);
+            case Command::DeliverTestCommand:
+                return command(CmdDeliverTestCommand(), in_cmd, out);
+            case Command::Abort:
+                return command(CmdAbort(), in_cmd, out);
+            default:
+                return write(Message<ResponseCode>(), out, ResponseCode::Unimplemented);
+            }
+        }
+        return static_cast<Derived*>(this)->extendedProtocolHook(proto, in, out);
+    }
+
+  protected:
+    /*
+     * The extendedProtocolHoock allows implementations to implement custom protocols on top of
+     * the default commands.
+     * This function is only called if "Derived" does not implement the extendedProtocolHoock
+     * and writes ResponseCode::Unimplemented to the response buffer.
+     */
+    inline WriteStream extendedProtocolHook(Protocol proto, ReadStream, WriteStream out) {
+        return write(Message<ResponseCode>(), out, ResponseCode::Unimplemented);
+    }
+
+  private:
+    WriteStream command(CmdPromptUserConfirmation, ReadStream in, WriteStream out) {
+        auto [in_, promt, extra, locale, options] = read(PromptUserConfirmationMsg(), in);
+        if (!in_) return write(PromptUserConfirmationResponse(), out, ResponseCode::SystemError);
+        auto rc = init(promt, extra, locale, options);
+        return write(PromptUserConfirmationResponse(), out, rc);
+    }
+    WriteStream command(CmdFetchConfirmationResult, ReadStream in, WriteStream out) {
+        auto [rc, message, token] = fetchConfirmationResult();
+        return write(ResultMsg(), out, rc, message, token);
+    }
+    WriteStream command(CmdDeliverTestCommand, ReadStream in, WriteStream out) {
+        auto [in_, token] = read(DeliverTestCommandMessage(), in);
+        if (!in_) return write(DeliverTestCommandResponse(), out, ResponseCode::SystemError);
+        auto rc = deliverTestCommand(token);
+        return write(DeliverTestCommandResponse(), out, rc);
+    }
+    WriteStream command(CmdAbort, ReadStream in, WriteStream out) {
+        abort();
+        return out;
+    }
+
+    MsgVector<uint8_t> getMessage() {
+        MsgVector<uint8_t> result;
+        if (error_ != ResponseCode::OK) return {};
+        return {&formattedMessageBuffer_[0], &formattedMessageBuffer_[formattedMessageLength_]};
+    }
+
+  protected:
+    void signConfirmation(const AuthTokenKey& key) {
+        if (error_ != ResponseCode::OK) return;
+        confirmationTokenScratchpad_ = HMacer::hmac256(key, "confirmation token", getMessage());
+        if (!confirmationTokenScratchpad_) {
+            error_ = ResponseCode::Unexpected;
+        }
+    }
+
+  protected:
+    ResponseCode error_ = ResponseCode::Ignored;
+    uint8_t formattedMessageBuffer_[uint32_t(MessageSize::MAX)];
+    size_t formattedMessageLength_ = 0;
+    char promptStringBuffer_[uint32_t(MessageSize::MAX)];
+    optional<Hmac> confirmationTokenScratchpad_;
+    TimeStamp startTime_;
+    optional<AuthTokenKey> hmacKey_;
+    bool maginifiedViewRequested_;
+    bool invertedColorModeRequested_;
+    constexpr static size_t kMaxLocaleSize = 64;
+    char languageIdBuffer_[kMaxLocaleSize];
+    size_t languageIdLength_;
+};
+
+}  // namespace teeui
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
diff --git a/libteeui/include/teeui/msg_formatting.h b/libteeui/include/teeui/msg_formatting.h
new file mode 100644
index 0000000..1644c2f
--- /dev/null
+++ b/libteeui/include/teeui/msg_formatting.h
@@ -0,0 +1,202 @@
+/*
+ *
+ * Copyright 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 TEEUI_MSG_FORMATTING_H_
+#define TEEUI_MSG_FORMATTING_H_
+
+#include <algorithm>
+#include <stddef.h>
+#include <stdint.h>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include <teeui/utils.h>
+
+namespace teeui {
+namespace msg {
+
+template <typename... fields> class Message {};
+
+template <size_t... idx, typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(std::index_sequence<idx...>,
+                                                              std::tuple<T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
+    return tuple_move_helper(std::make_index_sequence<sizeof...(T)>(), std::move(t));
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
+    return tuple_move_helper(std::make_index_sequence<sizeof...(T)>(), std::move(t));
+}
+
+void zero(volatile uint8_t* begin, const volatile uint8_t* end);
+
+template <typename T> class StreamState {
+  public:
+    static_assert(
+        sizeof(T) == 1,
+        "StreamState must be instantiated with 1 byte sized type, e.g., uint8_t or const uint8_t.");
+    using ptr_t = T*;
+    template <size_t size>
+    StreamState(T (&buffer)[size]) : begin_(&buffer[0]), end_(&buffer[size]), pos_(begin_) {}
+    StreamState(T* buffer, size_t size) : begin_(buffer), end_(buffer + size), pos_(begin_) {}
+    StreamState() : begin_(nullptr), end_(nullptr), pos_(nullptr) {}
+    StreamState& operator+=(size_t offset) {
+        auto good_ = pos_ != nullptr && pos_ + offset <= end_;
+        if (good_) {
+            pos_ += offset;
+        } else {
+            pos_ = nullptr;
+        }
+        return *this;
+    }
+
+    operator bool() const { return pos_ != nullptr; }
+    ptr_t pos() const { return pos_; };
+
+    template <typename U = T>
+    bool insertFieldSize(typename std::enable_if<!std::is_const<U>::value, uint32_t>::type size) {
+        // offset to the nearest n * 8 + 4 boundary from beginning of the buffer! (not memory).
+        uintptr_t pos = pos_ - begin_;
+        auto offset = (((pos + 11UL) & ~7UL) - 4UL) - pos;
+        if (*this += offset + sizeof(size)) {
+            // zero out the gaps
+            zero(pos_ - offset - sizeof(size), pos_ - sizeof(size));
+            *reinterpret_cast<uint32_t*>(pos_ - sizeof(size)) = size;
+            return true;
+        }
+        return false;
+    }
+
+    template <typename U = T>
+    typename std::enable_if<std::is_const<U>::value, uint32_t>::type extractFieldSize() {
+        // offset to the nearest n * 8 + 4 boundary from beginning of the buffer! (not memory).
+        uintptr_t pos = pos_ - begin_;
+        auto offset = (((pos + 11UL) & ~7UL) - 4UL) - pos;
+        if (*this += offset + sizeof(uint32_t)) {
+            return *reinterpret_cast<const uint32_t*>(pos_ - sizeof(uint32_t));
+        }
+        return 0;
+    }
+
+    void bad() { pos_ = nullptr; };
+
+  private:
+    ptr_t begin_;
+    ptr_t end_;
+    ptr_t pos_;
+};
+
+using WriteStream = StreamState<uint8_t>;
+using ReadStream = StreamState<const uint8_t>;
+
+inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
+//// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
+//// It is to accommodate the 4 byte size field which is then followed by 8byte aligned data.
+// template <typename T>
+// StreamState<T> unalign(StreamState<T> s) {
+//    auto result = s;
+//    auto offset = (((uintptr_t(s.pos_) + 11UL) & ~7UL) - 4UL) - uintptr_t(s.pos_);
+//    result += offset;
+//    // zero out the gaps when writing
+//    if (result) zero(s.pos_, result.pos_);
+//    return result;
+//}
+
+WriteStream write(WriteStream out, const uint8_t* buffer, uint32_t size);
+
+template <uint32_t size> WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
+    return write(out, v, size);
+}
+
+std::tuple<ReadStream, ReadStream::ptr_t, uint32_t> read(ReadStream in);
+
+template <typename T> std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
+    auto [in_, pos, size] = read(in);
+    T result = {};
+    if (in_ && size == sizeof(T))
+        result = *reinterpret_cast<const T*>(pos);
+    else
+        in_.bad();
+    return {in_, result};
+}
+
+inline WriteStream write(Message<>, WriteStream out) {
+    return out;
+}
+
+template <typename Head, typename... Tail>
+WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
+    out = write(out, head);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <typename... Msg> std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
+    return {in, [&in]() -> Msg {
+                Msg result;
+                std::tie(in, result) = read(Message<Msg>(), in);
+                return result;
+            }()...};
+}
+
+template <typename T> struct msg2tuple {};
+
+template <typename... T> struct msg2tuple<Message<T...>> { using type = std::tuple<T...>; };
+
+template <typename T> using msg2tuple_t = typename msg2tuple<T>::type;
+
+template <size_t first_idx, size_t... idx, typename HEAD, typename... T>
+std::tuple<T&&...> tuple_tail(std::index_sequence<first_idx, idx...>, std::tuple<HEAD, T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <size_t first_idx, size_t... idx, typename HEAD, typename... T>
+std::tuple<const T&...> tuple_tail(std::index_sequence<first_idx, idx...>,
+                                   const std::tuple<HEAD, T...>& t) {
+    return {std::get<idx>(t)...};
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
+    return tuple_tail(std::make_index_sequence<sizeof...(Tail) + 1>(), std::move(t));
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
+    return tuple_tail(std::make_index_sequence<sizeof...(Tail) + 1>(), t);
+}
+
+}  // namespace msg
+
+using msg::Message;
+using msg::msg2tuple;
+using msg::msg2tuple_t;
+using msg::read;
+using msg::readSimpleType;
+using msg::ReadStream;
+using msg::tuple_tail;
+using msg::write;
+using msg::WriteStream;
+
+}  // namespace teeui
+
+#endif  // TEEUI_MSG_FORMATTING_H_
diff --git a/libteeui/include/teeui/static_vec.h b/libteeui/include/teeui/static_vec.h
new file mode 100644
index 0000000..fb41935
--- /dev/null
+++ b/libteeui/include/teeui/static_vec.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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.
+ */
+
+#ifndef TEEUI_STATIC_VEC_H_
+#define TEEUI_STATIC_VEC_H_
+
+#include <stddef.h>  // for size_t
+
+#ifdef TEEUI_USE_STD_VECTOR
+#include <vector>
+#endif
+
+namespace teeui {
+
+/**
+ * teeui::static_vec leads a double life.
+ *
+ * When compiling with TEEUI_USE_STD_VECTOR it is just an alias for std::vector. HAL services using
+ * this library must use this option for safe handling of message buffers.
+ *
+ * When compiling without TEEUI_USE_STD_VECTOR this class works more like a span that does not
+ * actually own the buffer if wraps. This is the behavior expected by generic_operation.h, which
+ * is used inside a heap-less implementation of a confirmationui trusted app.
+ */
+#ifndef TEEUI_USE_STD_VECTOR
+template <typename T> class static_vec {
+  private:
+    T* data_;
+    size_t size_;
+
+  public:
+    static_vec() : data_(nullptr), size_(0) {}
+    static_vec(T* begin, T* end) : data_(begin), size_(end - begin) {}
+    template <size_t s> static_vec(T (&arr)[s]) : data_(&arr[0]), size_(s) {}
+    static_vec(const static_vec&) = default;
+    static_vec(static_vec&&) = default;
+    static_vec& operator=(const static_vec&) = default;
+    static_vec& operator=(static_vec&&) = default;
+
+    T* data() { return data_; }
+    const T* data() const { return data_; }
+    size_t size() const { return size_; }
+
+    T* begin() { return data_; }
+    T* end() { return data_ + size_; }
+    const T* begin() const { return data_; }
+    const T* end() const { return data_ + size_; }
+};
+#else
+template <typename T> using static_vec = std::vector<T>;
+#endif
+
+}  // namespace teeui
+
+#endif  // TEEUI_STATIC_VEC_H_
diff --git a/libteeui/include/teeui/utils.h b/libteeui/include/teeui/utils.h
index c6e5f6c..7e1b908 100644
--- a/libteeui/include/teeui/utils.h
+++ b/libteeui/include/teeui/utils.h
@@ -19,10 +19,12 @@
 #define TEEUI_LIBTEEUI_UTILS_H_
 
 #include <math.h>
+#include <stddef.h>
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <algorithm>
+#include <initializer_list>
 #include <optional>
 #include <tuple>
 #include <type_traits>
@@ -34,6 +36,135 @@
 
 using std::optional;
 
+template <typename T, size_t elements> class Array {
+    using array_type = T[elements];
+
+  public:
+    constexpr Array() : data_{} {}
+    constexpr Array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
+    constexpr Array(const std::initializer_list<uint8_t>& li) {
+        size_t i = 0;
+        for (auto& item : li) {
+            data_[i] = item;
+            ++i;
+            if (i == elements) break;
+        }
+        for (; i < elements; ++i) {
+            data_[i] = {};
+        }
+    }
+
+    T* data() { return data_; }
+    const T* data() const { return data_; }
+    constexpr size_t size() const { return elements; }
+
+    T* begin() { return data_; }
+    T* end() { return data_ + elements; }
+    const T* begin() const { return data_; }
+    const T* end() const { return data_ + elements; }
+
+    static constexpr Array fill(const T& v) {
+        Array result;
+        for (size_t i = 0; i < elements; ++i) {
+            result.data_[i] = v;
+        }
+        return result;
+    }
+
+  private:
+    array_type data_;
+};
+
+template <typename T> auto bytesCast(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+template <typename T> auto bytesCast(T& v) -> uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v);
+}
+
+class ByteBufferProxy {
+    template <typename T> struct has_data {
+        template <typename U> static int f(const U*, const void*) { return 0; }
+        template <typename U> static int* f(const U* u, decltype(u->data())) { return nullptr; }
+        static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value;
+    };
+
+  public:
+    template <typename T>
+    ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const char (&buffer)[size])
+        : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) {
+        static_assert(size > 0, "even an empty string must be 0-terminated");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
+
+    ByteBufferProxy() : data_(nullptr), size_(0) {}
+
+    const uint8_t* data() const { return data_; }
+    size_t size() const { return size_; }
+
+    const uint8_t* begin() const { return data_; }
+    const uint8_t* end() const { return data_ + size_; }
+
+  private:
+    const uint8_t* data_;
+    size_t size_;
+};
+
+constexpr const uint8_t kAuthTokenKeySize = 32;
+constexpr const uint8_t kHmacKeySize = kAuthTokenKeySize;
+using AuthTokenKey = Array<uint8_t, kAuthTokenKeySize>;
+using Hmac = AuthTokenKey;
+
+/**
+ * Implementer are expected to provide an implementation with the following prototype:
+ *  static optional<array<uint8_t, 32>> hmac256(const uint8_t key[32],
+ *                                     std::initializer_list<ByteBufferProxy> buffers);
+ */
+template <typename Impl> class HMac {
+  public:
+    template <typename... Data>
+    static optional<Hmac> hmac256(const AuthTokenKey& key, const Data&... data) {
+        return Impl::hmac256(key, {data...});
+    }
+};
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs);
+
+template <typename IntType, uint32_t byteOrder> struct choose_hton;
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+    inline static IntType hton(const IntType& value) {
+        IntType result = {};
+        const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+        unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+        for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+            *(outbytes++) = inbytes[i];
+        }
+        return result;
+    }
+};
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+    inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType> inline IntType hton(const IntType& value) {
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType> inline IntType ntoh(const IntType& value) {
+    // same operation as hton
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
 enum class Unit : uint8_t {
     PX,
     DP,
diff --git a/libteeui/src/cbor.cpp b/libteeui/src/cbor.cpp
new file mode 100644
index 0000000..48c461d
--- /dev/null
+++ b/libteeui/src/cbor.cpp
@@ -0,0 +1,124 @@
+/*
+ *
+ * Copyright 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.
+ */
+
+#include <teeui/cbor.h>
+
+namespace teeui {
+namespace cbor {
+
+namespace {
+
+inline uint8_t getByte(const uint64_t& v, const uint8_t index) {
+    return (v >> (index * 8)) & 0xff;
+}
+
+WriteState writeBytes(WriteState state, uint64_t value, uint8_t size) {
+    auto pos = state.data_;
+    if (!(state += size)) return state;
+    switch (size) {
+    case 8:
+        *pos++ = getByte(value, 7);
+        *pos++ = getByte(value, 6);
+        *pos++ = getByte(value, 5);
+        *pos++ = getByte(value, 4);
+        [[fallthrough]];
+    case 4:
+        *pos++ = getByte(value, 3);
+        *pos++ = getByte(value, 2);
+        [[fallthrough]];
+    case 2:
+        *pos++ = getByte(value, 1);
+        [[fallthrough]];
+    case 1:
+        *pos++ = getByte(value, 0);
+        break;
+    default:
+        state.error_ = Error::MALFORMED;
+    }
+    return state;
+}
+
+}  // anonymous namespace
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value) {
+    if (!wState) return wState;
+    uint8_t& header = *wState.data_;
+    if (!++wState) return wState;
+    header = static_cast<uint8_t>(type) << 5;
+    if (value < 24) {
+        header |= static_cast<uint8_t>(value);
+    } else if (value < 0x100) {
+        header |= 24;
+        wState = writeBytes(wState, value, 1);
+    } else if (value < 0x10000) {
+        header |= 25;
+        wState = writeBytes(wState, value, 2);
+    } else if (value < 0x100000000) {
+        header |= 26;
+        wState = writeBytes(wState, value, 4);
+    } else {
+        header |= 27;
+        wState = writeBytes(wState, value, 8);
+    }
+    return wState;
+}
+
+static size_t byteCount(char c) {
+    if ((0xc0 & c) == 0x80) {
+        return 0;  // this is a multibyte payload byte
+    } else if (0x80 & c) {
+        /*
+         * CLZ - count leading zeroes.
+         * __builtin_clz promotes the argument to unsigned int.
+         * We invert c to turn leading ones into leading zeroes.
+         * We subtract additional leading zeroes due to the type promotion from the result.
+         */
+        return __builtin_clz((unsigned char)(~c)) - (sizeof(unsigned int) * 8 - 8);
+    } else {
+        return 1;
+    }
+}
+
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out) {
+    while (begin != end) {
+        auto bc = byteCount(*begin);
+        // if the string ends in the middle of a multi byte char it is invalid
+        if (begin + bc > end) return false;
+        switch (bc) {
+        case 4:
+            if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+            [[fallthrough]];
+        case 3:
+            if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+            [[fallthrough]];
+        case 2:
+            if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+            [[fallthrough]];
+        case 1:
+            if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+            break;
+        default:
+            // case 0 means we encounted a payload byte when we expected a header.
+            // case > 4 is malformed.
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace cbor
+}  // namespace teeui
diff --git a/libteeui/src/generic_messages.cpp b/libteeui/src/generic_messages.cpp
new file mode 100644
index 0000000..e6da5e8
--- /dev/null
+++ b/libteeui/src/generic_messages.cpp
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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 <teeui/generic_messages.h>
+
+namespace teeui {
+
+std::tuple<ReadStream, uint32_t> readU32(ReadStream in) {
+    volatile const uint32_t* pos = reinterpret_cast<volatile const uint32_t*>(in.pos());
+    in += sizeof(uint32_t);
+    if (!in) return {in, 0};
+    return {in, *pos};
+}
+
+std::tuple<ReadStream, Command> readCommand(ReadStream in) {
+    return readCmd<Command>(in);
+}
+
+Command peakCommand(ReadStream in) {
+    auto [_, cmd] = readCommand(in);
+    return cmd;
+}
+
+std::tuple<ReadStream, Protocol> readProtocol(ReadStream in) {
+    return readCmd<Protocol, kProtoInvalid>(in);
+}
+
+Protocol peakProtocol(ReadStream in) {
+    auto [_, proto] = readProtocol(in);
+    return proto;
+}
+
+}  // namespace teeui
diff --git a/libteeui/src/msg_formatting.cpp b/libteeui/src/msg_formatting.cpp
new file mode 100644
index 0000000..b96cea4
--- /dev/null
+++ b/libteeui/src/msg_formatting.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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 <teeui/msg_formatting.h>
+
+namespace teeui {
+namespace msg {
+
+void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
+    while (begin != end) {
+        *begin++ = 0x0;
+    }
+}
+
+WriteStream write(WriteStream out, const uint8_t* buffer, uint32_t size) {
+    if (out.insertFieldSize(size)) {
+        auto pos = out.pos();
+        out += size;
+        if (out) {
+            std::copy(buffer, buffer + size, pos);
+        }
+    }
+    return out;
+}
+
+std::tuple<ReadStream, ReadStream::ptr_t, uint32_t> read(ReadStream in) {
+    auto size = in.extractFieldSize();
+    auto pos = in.pos();
+    in += size;
+    return {in, pos, size};
+}
+
+}  // namespace msg
+}  // namespace teeui
diff --git a/libteeui/src/utils.cpp b/libteeui/src/utils.cpp
index d094bf7..8e8c2ee 100644
--- a/libteeui/src/utils.cpp
+++ b/libteeui/src/utils.cpp
@@ -19,6 +19,17 @@
 
 namespace teeui {
 
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs) {
+    if (lhs.size() == rhs.size()) {
+        auto lhsi = lhs.begin();
+        auto rhsi = rhs.begin();
+        while (lhsi != lhs.end()) {
+            if (*lhsi++ != *rhsi++) return false;
+        }
+    }
+    return true;
+}
+
 constexpr const DefaultNumericType kEpsilon = 0.000001;
 constexpr const DefaultNumericType kHalfSqrt2 = 0.70710678118;