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