1/*
2**
3** Copyright 2017, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#ifndef CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
19#define CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
20
21#include <android/hardware/confirmationui/1.0/types.h>
22#include <android/hardware/keymaster/4.0/types.h>
23#include <stddef.h>
24#include <stdint.h>
25#include <algorithm>
26#include <tuple>
27#include <type_traits>
28
29#include <android/hardware/confirmationui/support/confirmationui_utils.h>
30
31namespace android {
32namespace hardware {
33namespace confirmationui {
34namespace support {
35
36template <size_t... I>
37class IntegerSequence {};
38
39namespace integer_sequence {
40
41template <typename Lhs, typename Rhs>
42struct conc {};
43
44template <size_t... ILhs, size_t... IRhs>
45struct conc<IntegerSequence<ILhs...>, IntegerSequence<IRhs...>> {
46    using type = IntegerSequence<ILhs..., IRhs...>;
47};
48
49template <typename Lhs, typename Rhs>
50using conc_t = typename conc<Lhs, Rhs>::type;
51
52template <size_t... n>
53struct make {};
54
55template <size_t n>
56struct make<n> {
57    using type = conc_t<typename make<n - 1>::type, IntegerSequence<n - 1>>;
58};
59template <size_t start, size_t n>
60struct make<start, n> {
61    using type = conc_t<typename make<start, n - 1>::type, IntegerSequence<start + n - 1>>;
62};
63
64template <size_t start>
65struct make<start, start> {
66    using type = IntegerSequence<start>;
67};
68
69template <>
70struct make<0> {
71    using type = IntegerSequence<>;
72};
73
74template <size_t... n>
75using make_t = typename make<n...>::type;
76
77}  // namespace integer_sequence
78
79template <size_t... idx, typename... T>
80std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(IntegerSequence<idx...>,
81                                                              std::tuple<T...>&& t) {
82    return {std::move(std::get<idx>(t))...};
83}
84
85template <typename... T>
86std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
87    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
88}
89
90template <typename... T>
91std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
92    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
93}
94
95using ::android::hardware::confirmationui::V1_0::ResponseCode;
96using ::android::hardware::confirmationui::V1_0::UIOption;
97using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
98using ::android::hardware::hidl_string;
99using ::android::hardware::hidl_vec;
100
101template <typename... fields>
102class Message {};
103
104enum class Command : uint32_t {
105    PromptUserConfirmation,
106    DeliverSecureInputEvent,
107    Abort,
108    Vendor,
109};
110
111template <Command cmd>
112struct Cmd {};
113
114#define DECLARE_COMMAND(cmd) using cmd##_t = Cmd<Command::cmd>
115
116DECLARE_COMMAND(PromptUserConfirmation);
117DECLARE_COMMAND(DeliverSecureInputEvent);
118DECLARE_COMMAND(Abort);
119DECLARE_COMMAND(Vendor);
120
121using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
122                                          hidl_string, hidl_vec<UIOption>>;
123using PromptUserConfirmationResponse = Message<ResponseCode>;
124using DeliverSecureInputEventMsg = Message<DeliverSecureInputEvent_t, HardwareAuthToken>;
125using DeliverSecureInputEventRespose = Message<ResponseCode>;
126using AbortMsg = Message<Abort_t>;
127using ResultMsg = Message<ResponseCode, hidl_vec<uint8_t>, hidl_vec<uint8_t>>;
128
129template <typename T>
130struct StreamState {
131    using ptr_t = volatile T*;
132    volatile T* pos_;
133    size_t bytes_left_;
134    bool good_;
135    template <size_t size>
136    StreamState(T (&buffer)[size]) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
137    StreamState(T* buffer, size_t size) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
138    StreamState() : pos_(nullptr), bytes_left_(0), good_(false) {}
139    StreamState& operator++() {
140        if (good_ && bytes_left_) {
141            ++pos_;
142            --bytes_left_;
143        } else {
144            good_ = false;
145        }
146        return *this;
147    }
148    StreamState& operator+=(size_t offset) {
149        if (!good_ || offset > bytes_left_) {
150            good_ = false;
151        } else {
152            pos_ += offset;
153            bytes_left_ -= offset;
154        }
155        return *this;
156    }
157    operator bool() const { return good_; }
158    volatile T* pos() const { return pos_; };
159};
160
161using WriteStream = StreamState<uint8_t>;
162using ReadStream = StreamState<const uint8_t>;
163
164inline void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
165    while (begin != end) {
166        *begin++ = 0xaa;
167    }
168}
169inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
170// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
171// It is to accommodate the 4 byte size field which is then followed by 8byte aligned data.
172template <typename T>
173StreamState<T> unalign(StreamState<T> s) {
174    uint8_t unalignment = uintptr_t(s.pos_) & 0x3;
175    auto pos = s.pos_;
176    if (unalignment) {
177        s += 4 - unalignment;
178    }
179    // now s.pos_ is aligned on a 4byte boundary
180    if ((uintptr_t(s.pos_) & 0x4) == 0) {
181        // if we are 8byte aligned add 4
182        s += 4;
183    }
184    // zero out the gaps when writing
185    zero(pos, s.pos_);
186    return s;
187}
188
189inline WriteStream write(WriteStream out, const uint8_t* buffer, size_t size) {
190    auto pos = out.pos();
191    uint32_t v = size;
192    out += 4 + size;
193    if (out) {
194        if (size != v) {
195            out.good_ = false;
196            return out;
197        }
198        auto& s = bytes_cast(v);
199        pos = std::copy(s, s + 4, pos);
200        std::copy(buffer, buffer + size, pos);
201    }
202    return out;
203}
204template <size_t size>
205WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
206    return write(out, v, size);
207}
208
209inline std::tuple<ReadStream, ReadStream::ptr_t, size_t> read(ReadStream in) {
210    auto pos = in.pos();
211    in += 4;
212    if (!in) return {in, nullptr, 0};
213    uint32_t size;
214    std::copy(pos, pos + 4, bytes_cast(size));
215    pos = in.pos();
216    in += size;
217    if (!in) return {in, nullptr, 0};
218    return {in, pos, size};
219}
220
221template <typename T>
222std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
223    T result;
224    ReadStream::ptr_t pos = nullptr;
225    size_t read_size = 0;
226    std::tie(in, pos, read_size) = read(in);
227    if (!in || read_size != sizeof(T)) {
228        in.good_ = false;
229        return {in, {}};
230    }
231    std::copy(pos, pos + sizeof(T), bytes_cast(result));
232    return {in, std::move(result)};
233}
234
235template <typename T>
236std::tuple<ReadStream, hidl_vec<T>> readSimpleHidlVecInPlace(ReadStream in) {
237    std::tuple<ReadStream, hidl_vec<T>> result;
238    ReadStream::ptr_t pos = nullptr;
239    size_t read_size = 0;
240    std::tie(std::get<0>(result), pos, read_size) = read(in);
241    if (!std::get<0>(result) || read_size % sizeof(T)) {
242        std::get<0>(result).good_ = false;
243        return result;
244    }
245    std::get<1>(result).setToExternal(reinterpret_cast<T*>(const_cast<uint8_t*>(pos)),
246                                      read_size / sizeof(T));
247    return result;
248}
249
250template <typename T>
251WriteStream writeSimpleHidlVec(WriteStream out, const hidl_vec<T>& vec) {
252    return write(out, reinterpret_cast<const uint8_t*>(vec.data()), vec.size() * sizeof(T));
253}
254
255// HardwareAuthToken
256constexpr size_t hatSizeNoMac() {
257    HardwareAuthToken* hat = nullptr;
258    return sizeof hat->challenge + sizeof hat->userId + sizeof hat->authenticatorId +
259           sizeof hat->authenticatorType + sizeof hat->timestamp;
260}
261
262template <typename T>
263inline volatile const uint8_t* copyField(T& field, volatile const uint8_t*(&pos)) {
264    auto& s = bytes_cast(field);
265    std::copy(pos, pos + sizeof(T), s);
266    return pos + sizeof(T);
267}
268inline std::tuple<ReadStream, HardwareAuthToken> read(Message<HardwareAuthToken>, ReadStream in_) {
269    std::tuple<ReadStream, HardwareAuthToken> result;
270    ReadStream& in = std::get<0>(result) = in_;
271    auto& hat = std::get<1>(result);
272    constexpr size_t hatSize = hatSizeNoMac();
273    ReadStream::ptr_t pos = nullptr;
274    size_t read_size = 0;
275    std::tie(in, pos, read_size) = read(in);
276    if (!in || read_size != hatSize) {
277        in.good_ = false;
278        return result;
279    }
280    pos = copyField(hat.challenge, pos);
281    pos = copyField(hat.userId, pos);
282    pos = copyField(hat.authenticatorId, pos);
283    pos = copyField(hat.authenticatorType, pos);
284    pos = copyField(hat.timestamp, pos);
285    std::tie(in, hat.mac) = readSimpleHidlVecInPlace<uint8_t>(in);
286    return result;
287}
288
289template <typename T>
290inline volatile uint8_t* copyField(const T& field, volatile uint8_t*(&pos)) {
291    auto& s = bytes_cast(field);
292    return std::copy(s, &s[sizeof(T)], pos);
293}
294
295inline WriteStream write(WriteStream out, const HardwareAuthToken& v) {
296    auto pos = out.pos();
297    uint32_t size_field = hatSizeNoMac();
298    out += 4 + size_field;
299    if (!out) return out;
300    pos = copyField(size_field, pos);
301    pos = copyField(v.challenge, pos);
302    pos = copyField(v.userId, pos);
303    pos = copyField(v.authenticatorId, pos);
304    pos = copyField(v.authenticatorType, pos);
305    pos = copyField(v.timestamp, pos);
306    return writeSimpleHidlVec(out, v.mac);
307}
308
309// ResponseCode
310inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
311    return readSimpleType<ResponseCode>(in);
312}
313inline WriteStream write(WriteStream out, const ResponseCode& v) {
314    return write(out, bytes_cast(v));
315}
316
317// hidl_vec<uint8_t>
318inline std::tuple<ReadStream, hidl_vec<uint8_t>> read(Message<hidl_vec<uint8_t>>, ReadStream in) {
319    return readSimpleHidlVecInPlace<uint8_t>(in);
320}
321inline WriteStream write(WriteStream out, const hidl_vec<uint8_t>& v) {
322    return writeSimpleHidlVec(out, v);
323}
324
325// hidl_vec<UIOption>
326inline std::tuple<ReadStream, hidl_vec<UIOption>> read(Message<hidl_vec<UIOption>>, ReadStream in) {
327    in = unalign(in);
328    return readSimpleHidlVecInPlace<UIOption>(in);
329}
330inline WriteStream write(WriteStream out, const hidl_vec<UIOption>& v) {
331    out = unalign(out);
332    return writeSimpleHidlVec(out, v);
333}
334
335// hidl_string
336inline std::tuple<ReadStream, hidl_string> read(Message<hidl_string>, ReadStream in) {
337    std::tuple<ReadStream, hidl_string> result;
338    ReadStream& in_ = std::get<0>(result);
339    hidl_string& result_ = std::get<1>(result);
340    ReadStream::ptr_t pos = nullptr;
341    size_t read_size = 0;
342    std::tie(in_, pos, read_size) = read(in);
343    auto terminating_zero = in_.pos();
344    ++in_;  // skip the terminating zero. Does nothing if the stream was already bad
345    if (!in_) return result;
346    if (*terminating_zero) {
347        in_.good_ = false;
348        return result;
349    }
350    result_.setToExternal(reinterpret_cast<const char*>(const_cast<const uint8_t*>(pos)),
351                          read_size);
352    return result;
353}
354inline WriteStream write(WriteStream out, const hidl_string& v) {
355    out = write(out, reinterpret_cast<const uint8_t*>(v.c_str()), v.size());
356    auto terminating_zero = out.pos();
357    ++out;
358    if (out) {
359        *terminating_zero = 0;
360    }
361    return out;
362}
363
364inline WriteStream write(WriteStream out, Command cmd) {
365    volatile Command* pos = reinterpret_cast<volatile Command*>(out.pos_);
366    out += sizeof(Command);
367    if (out) {
368        *pos = cmd;
369    }
370    return out;
371}
372template <Command cmd>
373WriteStream write(WriteStream out, Cmd<cmd>) {
374    return write(out, cmd);
375}
376
377inline std::tuple<ReadStream, bool> read(ReadStream in, Command cmd) {
378    volatile const Command* pos = reinterpret_cast<volatile const Command*>(in.pos_);
379    in += sizeof(Command);
380    if (!in) return {in, false};
381    return {in, *pos == cmd};
382}
383
384template <Command cmd>
385std::tuple<ReadStream, bool> read(Message<Cmd<cmd>>, ReadStream in) {
386    return read(in, cmd);
387}
388
389inline WriteStream write(Message<>, WriteStream out) {
390    return out;
391}
392
393template <typename Head, typename... Tail>
394WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
395    out = write(out, head);
396    return write(Message<Tail...>(), out, tail...);
397}
398
399template <Command cmd, typename... Tail>
400WriteStream write(Message<Cmd<cmd>, Tail...>, WriteStream out, const Tail&... tail) {
401    out = write(out, cmd);
402    return write(Message<Tail...>(), out, tail...);
403}
404
405template <Command cmd, typename HEAD, typename... Tail>
406std::tuple<ReadStream, bool, HEAD, Tail...> read(Message<Cmd<cmd>, HEAD, Tail...>, ReadStream in) {
407    bool command_matches;
408    std::tie(in, command_matches) = read(in, cmd);
409    if (!command_matches) return {in, false, HEAD(), Tail()...};
410
411    return {in, true,
412            [&]() -> HEAD {
413                HEAD result;
414                std::tie(in, result) = read(Message<HEAD>(), in);
415                return result;
416            }(),
417            [&]() -> Tail {
418                Tail result;
419                std::tie(in, result) = read(Message<Tail>(), in);
420                return result;
421            }()...};
422}
423
424template <typename... Msg>
425std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
426    return {in, [&in]() -> Msg {
427                Msg result;
428                std::tie(in, result) = read(Message<Msg>(), in);
429                return result;
430            }()...};
431}
432
433template <typename T>
434struct msg2tuple {};
435
436template <typename... T>
437struct msg2tuple<Message<T...>> {
438    using type = std::tuple<T...>;
439};
440template <Command cmd, typename... T>
441struct msg2tuple<Message<Cmd<cmd>, T...>> {
442    using type = std::tuple<T...>;
443};
444
445template <typename T>
446using msg2tuple_t = typename msg2tuple<T>::type;
447
448template <size_t... idx, typename HEAD, typename... T>
449std::tuple<T&&...> tuple_tail(IntegerSequence<idx...>, std::tuple<HEAD, T...>&& t) {
450    return {std::move(std::get<idx>(t))...};
451}
452
453template <size_t... idx, typename HEAD, typename... T>
454std::tuple<const T&...> tuple_tail(IntegerSequence<idx...>, const std::tuple<HEAD, T...>& t) {
455    return {std::get<idx>(t)...};
456}
457
458template <typename HEAD, typename... Tail>
459std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
460    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), std::move(t));
461}
462
463template <typename HEAD, typename... Tail>
464std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
465    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), t);
466}
467
468}  // namespace support
469}  // namespace confirmationui
470}  // namespace hardware
471}  // namespace android
472
473#endif  // CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
474