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 
31 namespace android {
32 namespace hardware {
33 namespace confirmationui {
34 namespace support {
35 
36 template <size_t... I>
37 class IntegerSequence {};
38 
39 namespace integer_sequence {
40 
41 template <typename Lhs, typename Rhs>
42 struct conc {};
43 
44 template <size_t... ILhs, size_t... IRhs>
45 struct conc<IntegerSequence<ILhs...>, IntegerSequence<IRhs...>> {
46     using type = IntegerSequence<ILhs..., IRhs...>;
47 };
48 
49 template <typename Lhs, typename Rhs>
50 using conc_t = typename conc<Lhs, Rhs>::type;
51 
52 template <size_t... n>
53 struct make {};
54 
55 template <size_t n>
56 struct make<n> {
57     using type = conc_t<typename make<n - 1>::type, IntegerSequence<n - 1>>;
58 };
59 template <size_t start, size_t n>
60 struct make<start, n> {
61     using type = conc_t<typename make<start, n - 1>::type, IntegerSequence<start + n - 1>>;
62 };
63 
64 template <size_t start>
65 struct make<start, start> {
66     using type = IntegerSequence<start>;
67 };
68 
69 template <>
70 struct make<0> {
71     using type = IntegerSequence<>;
72 };
73 
74 template <size_t... n>
75 using make_t = typename make<n...>::type;
76 
77 }  // namespace integer_sequence
78 
79 template <size_t... idx, typename... T>
80 std::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 
85 template <typename... T>
86 std::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 
90 template <typename... T>
91 std::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 
95 using ::android::hardware::confirmationui::V1_0::ResponseCode;
96 using ::android::hardware::confirmationui::V1_0::UIOption;
97 using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
98 using ::android::hardware::hidl_string;
99 using ::android::hardware::hidl_vec;
100 
101 template <typename... fields>
102 class Message {};
103 
104 enum class Command : uint32_t {
105     PromptUserConfirmation,
106     DeliverSecureInputEvent,
107     Abort,
108     Vendor,
109 };
110 
111 template <Command cmd>
112 struct Cmd {};
113 
114 #define DECLARE_COMMAND(cmd) using cmd##_t = Cmd<Command::cmd>
115 
116 DECLARE_COMMAND(PromptUserConfirmation);
117 DECLARE_COMMAND(DeliverSecureInputEvent);
118 DECLARE_COMMAND(Abort);
119 DECLARE_COMMAND(Vendor);
120 
121 using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
122                                           hidl_string, hidl_vec<UIOption>>;
123 using PromptUserConfirmationResponse = Message<ResponseCode>;
124 using DeliverSecureInputEventMsg = Message<DeliverSecureInputEvent_t, HardwareAuthToken>;
125 using DeliverSecureInputEventRespose = Message<ResponseCode>;
126 using AbortMsg = Message<Abort_t>;
127 using ResultMsg = Message<ResponseCode, hidl_vec<uint8_t>, hidl_vec<uint8_t>>;
128 
129 template <typename T>
130 struct 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 
161 using WriteStream = StreamState<uint8_t>;
162 using ReadStream = StreamState<const uint8_t>;
163 
164 inline void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
165     while (begin != end) {
166         *begin++ = 0xaa;
167     }
168 }
169 inline 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.
172 template <typename T>
173 StreamState<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 
189 inline 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 }
204 template <size_t size>
205 WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
206     return write(out, v, size);
207 }
208 
209 inline 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 
221 template <typename T>
222 std::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 
235 template <typename T>
236 std::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 
250 template <typename T>
251 WriteStream 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
256 constexpr 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 
262 template <typename T>
263 inline 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 }
268 inline 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 
289 template <typename T>
290 inline 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 
295 inline 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
310 inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
311     return readSimpleType<ResponseCode>(in);
312 }
313 inline WriteStream write(WriteStream out, const ResponseCode& v) {
314     return write(out, bytes_cast(v));
315 }
316 
317 // hidl_vec<uint8_t>
318 inline std::tuple<ReadStream, hidl_vec<uint8_t>> read(Message<hidl_vec<uint8_t>>, ReadStream in) {
319     return readSimpleHidlVecInPlace<uint8_t>(in);
320 }
321 inline WriteStream write(WriteStream out, const hidl_vec<uint8_t>& v) {
322     return writeSimpleHidlVec(out, v);
323 }
324 
325 // hidl_vec<UIOption>
326 inline std::tuple<ReadStream, hidl_vec<UIOption>> read(Message<hidl_vec<UIOption>>, ReadStream in) {
327     in = unalign(in);
328     return readSimpleHidlVecInPlace<UIOption>(in);
329 }
330 inline WriteStream write(WriteStream out, const hidl_vec<UIOption>& v) {
331     out = unalign(out);
332     return writeSimpleHidlVec(out, v);
333 }
334 
335 // hidl_string
336 inline 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 }
354 inline 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 
364 inline 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 }
372 template <Command cmd>
373 WriteStream write(WriteStream out, Cmd<cmd>) {
374     return write(out, cmd);
375 }
376 
377 inline 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 
384 template <Command cmd>
385 std::tuple<ReadStream, bool> read(Message<Cmd<cmd>>, ReadStream in) {
386     return read(in, cmd);
387 }
388 
389 inline WriteStream write(Message<>, WriteStream out) {
390     return out;
391 }
392 
393 template <typename Head, typename... Tail>
394 WriteStream 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 
399 template <Command cmd, typename... Tail>
400 WriteStream write(Message<Cmd<cmd>, Tail...>, WriteStream out, const Tail&... tail) {
401     out = write(out, cmd);
402     return write(Message<Tail...>(), out, tail...);
403 }
404 
405 template <Command cmd, typename HEAD, typename... Tail>
406 std::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 
424 template <typename... Msg>
425 std::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 
433 template <typename T>
434 struct msg2tuple {};
435 
436 template <typename... T>
437 struct msg2tuple<Message<T...>> {
438     using type = std::tuple<T...>;
439 };
440 template <Command cmd, typename... T>
441 struct msg2tuple<Message<Cmd<cmd>, T...>> {
442     using type = std::tuple<T...>;
443 };
444 
445 template <typename T>
446 using msg2tuple_t = typename msg2tuple<T>::type;
447 
448 template <size_t... idx, typename HEAD, typename... T>
449 std::tuple<T&&...> tuple_tail(IntegerSequence<idx...>, std::tuple<HEAD, T...>&& t) {
450     return {std::move(std::get<idx>(t))...};
451 }
452 
453 template <size_t... idx, typename HEAD, typename... T>
454 std::tuple<const T&...> tuple_tail(IntegerSequence<idx...>, const std::tuple<HEAD, T...>& t) {
455     return {std::get<idx>(t)...};
456 }
457 
458 template <typename HEAD, typename... Tail>
459 std::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 
463 template <typename HEAD, typename... Tail>
464 std::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