fido_hid_packet.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/hid/fido_hid_packet.h"
  5. #include <algorithm>
  6. #include <utility>
  7. #include "base/containers/contains.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/numerics/safe_conversions.h"
  10. namespace device {
  11. FidoHidPacket::FidoHidPacket(std::vector<uint8_t> data, uint32_t channel_id)
  12. : data_(std::move(data)), channel_id_(channel_id) {}
  13. FidoHidPacket::FidoHidPacket() = default;
  14. FidoHidPacket::~FidoHidPacket() = default;
  15. // static
  16. std::unique_ptr<FidoHidInitPacket> FidoHidInitPacket::CreateFromSerializedData(
  17. base::span<const uint8_t> serialized,
  18. size_t* remaining_size) {
  19. if (serialized.size() <= kHidInitPacketHeaderSize)
  20. return nullptr;
  21. size_t index = 0;
  22. auto channel_id = (serialized[index++] & 0xff) << 24;
  23. channel_id |= (serialized[index++] & 0xff) << 16;
  24. channel_id |= (serialized[index++] & 0xff) << 8;
  25. channel_id |= serialized[index++] & 0xff;
  26. auto command = static_cast<FidoHidDeviceCommand>(serialized[index++] & 0x7f);
  27. if (!base::Contains(GetFidoHidDeviceCommandList(), command))
  28. return nullptr;
  29. uint16_t payload_size = serialized[index++] << 8;
  30. payload_size |= serialized[index++];
  31. DCHECK_EQ(index, kHidInitPacketHeaderSize);
  32. // Check to see if payload is less than maximum size and padded with 0s.
  33. uint16_t data_size =
  34. std::min(payload_size, static_cast<uint16_t>(serialized.size() - index));
  35. // Update remaining size to determine the payload size of follow on packets.
  36. *remaining_size = payload_size - data_size;
  37. auto data = std::vector<uint8_t>(serialized.begin() + index,
  38. serialized.begin() + index + data_size);
  39. return std::make_unique<FidoHidInitPacket>(channel_id, command,
  40. std::move(data), payload_size);
  41. }
  42. // U2F Initialization packet is defined as:
  43. // Offset Length
  44. // 0 4 Channel ID
  45. // 4 1 Command ID
  46. // 5 1 High order packet payload size
  47. // 6 1 Low order packet payload size
  48. // 7 (s-7) Payload data
  49. FidoHidInitPacket::FidoHidInitPacket(uint32_t channel_id,
  50. FidoHidDeviceCommand cmd,
  51. std::vector<uint8_t> data,
  52. uint16_t payload_length)
  53. : FidoHidPacket(std::move(data), channel_id),
  54. command_(cmd),
  55. payload_length_(payload_length) {}
  56. FidoHidInitPacket::~FidoHidInitPacket() = default;
  57. std::vector<uint8_t> FidoHidInitPacket::GetSerializedData() const {
  58. std::vector<uint8_t> serialized;
  59. serialized.reserve(kHidMaxPacketSize);
  60. serialized.push_back((channel_id_ >> 24) & 0xff);
  61. serialized.push_back((channel_id_ >> 16) & 0xff);
  62. serialized.push_back((channel_id_ >> 8) & 0xff);
  63. serialized.push_back(channel_id_ & 0xff);
  64. serialized.push_back(base::strict_cast<uint8_t>(command_) | 0x80);
  65. serialized.push_back((payload_length_ >> 8) & 0xff);
  66. serialized.push_back(payload_length_ & 0xff);
  67. serialized.insert(serialized.end(), data_.begin(), data_.end());
  68. return serialized;
  69. }
  70. // static
  71. std::unique_ptr<FidoHidContinuationPacket>
  72. FidoHidContinuationPacket::CreateFromSerializedData(
  73. base::span<const uint8_t> serialized,
  74. size_t* remaining_size) {
  75. if (serialized.size() <= kHidContinuationPacketHeaderSize)
  76. return nullptr;
  77. size_t index = 0;
  78. auto channel_id = (serialized[index++] & 0xff) << 24;
  79. channel_id |= (serialized[index++] & 0xff) << 16;
  80. channel_id |= (serialized[index++] & 0xff) << 8;
  81. channel_id |= serialized[index++] & 0xff;
  82. auto sequence = serialized[index++];
  83. DCHECK_EQ(index, kHidContinuationPacketHeaderSize);
  84. // Check to see if packet payload is less than maximum size and padded with
  85. // 0s.
  86. size_t data_size = std::min(*remaining_size, serialized.size() - index);
  87. *remaining_size -= data_size;
  88. auto data = std::vector<uint8_t>(serialized.begin() + index,
  89. serialized.begin() + index + data_size);
  90. return std::make_unique<FidoHidContinuationPacket>(channel_id, sequence,
  91. std::move(data));
  92. }
  93. // U2F Continuation packet is defined as:
  94. // Offset Length
  95. // 0 4 Channel ID
  96. // 4 1 Packet sequence 0x00..0x7f
  97. // 5 (s-5) Payload data
  98. FidoHidContinuationPacket::FidoHidContinuationPacket(const uint32_t channel_id,
  99. const uint8_t sequence,
  100. std::vector<uint8_t> data)
  101. : FidoHidPacket(std::move(data), channel_id), sequence_(sequence) {}
  102. FidoHidContinuationPacket::~FidoHidContinuationPacket() = default;
  103. std::vector<uint8_t> FidoHidContinuationPacket::GetSerializedData() const {
  104. std::vector<uint8_t> serialized;
  105. serialized.reserve(kHidMaxPacketSize);
  106. serialized.push_back((channel_id_ >> 24) & 0xff);
  107. serialized.push_back((channel_id_ >> 16) & 0xff);
  108. serialized.push_back((channel_id_ >> 8) & 0xff);
  109. serialized.push_back(channel_id_ & 0xff);
  110. serialized.push_back(sequence_);
  111. serialized.insert(serialized.end(), data_.begin(), data_.end());
  112. return serialized;
  113. }
  114. } // namespace device