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 
5 #include "device/fido/hid/fido_hid_message.h"
6 
7 #include "base/memory/ptr_util.h"
8 #include "base/numerics/safe_conversions.h"
9 #include "device/fido/fido_constants.h"
10 #include "device/fido/hid/fido_hid_packet.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace device {
15 
16 static const size_t kDefaultInitDataSize =
17     kHidMaxPacketSize - kHidInitPacketHeaderSize;
18 static const size_t kDefaultContinuationDataSize =
19     kHidMaxPacketSize - kHidContinuationPacketHeaderSize;
20 
21 /*
22  * U2f Init Packets are of the format:
23  * Byte 0:    0
24  * Byte 1-4:  Channel ID
25  * Byte 5:    Command byte
26  * Byte 6-7:  Big Endian size of data
27  * Byte 8-n:  Data block
28  *
29  * Remaining buffer is padded with 0
30  */
TEST(FidoHidMessageTest,TestPacketData)31 TEST(FidoHidMessageTest, TestPacketData) {
32   uint32_t channel_id = 0xF5060708;
33   std::vector<uint8_t> data{10, 11};
34   FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
35   auto init_packet =
36       std::make_unique<FidoHidInitPacket>(channel_id, cmd, data, data.size());
37   size_t index = 0;
38 
39   std::vector<uint8_t> serialized = init_packet->GetSerializedData();
40   EXPECT_EQ((channel_id >> 24) & 0xff, serialized[index++]);
41   EXPECT_EQ((channel_id >> 16) & 0xff, serialized[index++]);
42   EXPECT_EQ((channel_id >> 8) & 0xff, serialized[index++]);
43   EXPECT_EQ(channel_id & 0xff, serialized[index++]);
44   EXPECT_EQ(base::strict_cast<uint8_t>(cmd), serialized[index++] & 0x7f);
45 
46   EXPECT_EQ(data.size() >> 8, serialized[index++]);
47   EXPECT_EQ(data.size() & 0xff, serialized[index++]);
48   EXPECT_EQ(data[0], serialized[index++]);
49   EXPECT_EQ(data[1], serialized[index++]);
50   for (; index < serialized.size(); index++)
51     EXPECT_EQ(0, serialized[index]) << "mismatch at index " << index;
52 }
53 
TEST(FidoHidMessageTest,TestPacketConstructors)54 TEST(FidoHidMessageTest, TestPacketConstructors) {
55   uint32_t channel_id = 0x05060708;
56   std::vector<uint8_t> data{10, 11};
57   FidoHidDeviceCommand cmd = FidoHidDeviceCommand::kWink;
58   auto orig_packet =
59       std::make_unique<FidoHidInitPacket>(channel_id, cmd, data, data.size());
60 
61   size_t payload_length = static_cast<size_t>(orig_packet->payload_length());
62   std::vector<uint8_t> orig_data = orig_packet->GetSerializedData();
63 
64   auto reconstructed_packet =
65       FidoHidInitPacket::CreateFromSerializedData(orig_data, &payload_length);
66   EXPECT_EQ(orig_packet->command(), reconstructed_packet->command());
67   EXPECT_EQ(orig_packet->payload_length(),
68             reconstructed_packet->payload_length());
69   EXPECT_THAT(orig_packet->GetPacketPayload(),
70               ::testing::ContainerEq(reconstructed_packet->GetPacketPayload()));
71 
72   EXPECT_EQ(channel_id, reconstructed_packet->channel_id());
73 
74   ASSERT_EQ(orig_packet->GetSerializedData().size(),
75             reconstructed_packet->GetSerializedData().size());
76   for (size_t index = 0; index < orig_packet->GetSerializedData().size();
77        ++index) {
78     EXPECT_EQ(orig_packet->GetSerializedData()[index],
79               reconstructed_packet->GetSerializedData()[index])
80         << "mismatch at index " << index;
81   }
82 }
83 
TEST(FidoHidMessageTest,TestMaxLengthPacketConstructors)84 TEST(FidoHidMessageTest, TestMaxLengthPacketConstructors) {
85   uint32_t channel_id = 0xAAABACAD;
86   std::vector<uint8_t> data;
87   for (size_t i = 0; i < kHidMaxMessageSize; ++i)
88     data.push_back(static_cast<uint8_t>(i % 0xff));
89 
90   for (size_t report_size = kHidInitPacketHeaderSize + 1;
91        report_size <= kHidMaxPacketSize; report_size++) {
92     auto orig_msg = FidoHidMessage::Create(
93         channel_id, FidoHidDeviceCommand::kMsg, report_size, data);
94     ASSERT_TRUE(orig_msg);
95 
96     const auto& original_msg_packets = orig_msg->GetPacketsForTesting();
97     auto it = original_msg_packets.begin();
98     auto msg_data = (*it)->GetSerializedData();
99     auto new_msg = FidoHidMessage::CreateFromSerializedData(msg_data);
100     it++;
101 
102     for (; it != original_msg_packets.end(); ++it) {
103       msg_data = (*it)->GetSerializedData();
104       new_msg->AddContinuationPacket(msg_data);
105     }
106 
107     EXPECT_EQ(new_msg->NumPackets(), orig_msg->NumPackets());
108 
109     auto orig_it = original_msg_packets.begin();
110     const auto& new_msg_packets = new_msg->GetPacketsForTesting();
111     auto new_msg_it = new_msg_packets.begin();
112 
113     for (; orig_it != original_msg_packets.end() &&
114            new_msg_it != new_msg_packets.end();
115          ++orig_it, ++new_msg_it) {
116       EXPECT_THAT((*orig_it)->GetPacketPayload(),
117                   ::testing::ContainerEq((*new_msg_it)->GetPacketPayload()));
118 
119       EXPECT_EQ((*orig_it)->channel_id(), (*new_msg_it)->channel_id());
120 
121       ASSERT_EQ((*orig_it)->GetSerializedData().size(),
122                 (*new_msg_it)->GetSerializedData().size());
123       for (size_t index = 0; index < (*orig_it)->GetSerializedData().size();
124            ++index) {
125         EXPECT_EQ((*orig_it)->GetSerializedData()[index],
126                   (*new_msg_it)->GetSerializedData()[index])
127             << "mismatch at index " << index;
128       }
129     }
130 
131     EXPECT_TRUE(orig_it == original_msg_packets.end());
132     EXPECT_TRUE(new_msg_it == new_msg_packets.end());
133   }
134 }
135 
TEST(FidoHidMessageTest,TestMessagePartitoning)136 TEST(FidoHidMessageTest, TestMessagePartitoning) {
137   uint32_t channel_id = 0x01010203;
138   std::vector<uint8_t> data(kDefaultInitDataSize + 1);
139   auto two_packet_message = FidoHidMessage::Create(
140       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
141   ASSERT_TRUE(two_packet_message);
142   EXPECT_EQ(2U, two_packet_message->NumPackets());
143 
144   data.resize(kDefaultInitDataSize);
145   auto one_packet_message = FidoHidMessage::Create(
146       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
147   ASSERT_TRUE(one_packet_message);
148   EXPECT_EQ(1U, one_packet_message->NumPackets());
149 
150   data.resize(kDefaultInitDataSize + kDefaultContinuationDataSize + 1);
151   auto three_packet_message = FidoHidMessage::Create(
152       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
153   ASSERT_TRUE(three_packet_message);
154   EXPECT_EQ(3U, three_packet_message->NumPackets());
155 
156   // With the minimal report size, only a single byte of data will fit in an
157   // init message, followed by three bytes in each continuation message.
158   data.resize(1 + 3 + 3);
159   auto three_small_messages =
160       FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing,
161                              kHidInitPacketHeaderSize + 1, data);
162   ASSERT_TRUE(three_small_messages);
163   EXPECT_EQ(3U, three_small_messages->NumPackets());
164 }
165 
TEST(FidoHidMessageTest,TooLarge)166 TEST(FidoHidMessageTest, TooLarge) {
167   std::vector<uint8_t> data;
168 
169 #if DCHECK_IS_ON()
170 #define EXPECT_SIZE_FAILURE(x) EXPECT_DEATH_IF_SUPPORTED(x, "")
171 #else
172 #define EXPECT_SIZE_FAILURE(x) EXPECT_FALSE(x.has_value())
173 #endif
174 
175   // kHidInitPacketHeaderSize is too small a report size to be valid.
176   EXPECT_SIZE_FAILURE(FidoHidMessage::Create(kHidBroadcastChannel,
177                                              FidoHidDeviceCommand::kPing,
178                                              kHidInitPacketHeaderSize, data));
179 
180   // kHidMaxPacketSize + 1 is too large a report size.
181   EXPECT_SIZE_FAILURE(FidoHidMessage::Create(kHidBroadcastChannel,
182                                              FidoHidDeviceCommand::kPing,
183                                              kHidMaxPacketSize + 1, data));
184 
185 #undef EXPECT_SIZE_FAILURE
186 }
187 
TEST(FidoHidMessageTest,TestMaxSize)188 TEST(FidoHidMessageTest, TestMaxSize) {
189   uint32_t channel_id = 0x00010203;
190   std::vector<uint8_t> data(kHidMaxMessageSize + 1);
191   auto oversize_message = FidoHidMessage::Create(
192       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
193   EXPECT_FALSE(oversize_message);
194 }
195 
TEST(FidoHidMessageTest,TestDeconstruct)196 TEST(FidoHidMessageTest, TestDeconstruct) {
197   uint32_t channel_id = 0x0A0B0C0D;
198   std::vector<uint8_t> data(kHidMaxMessageSize, 0x7F);
199   auto filled_message = FidoHidMessage::Create(
200       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
201   ASSERT_TRUE(filled_message);
202   EXPECT_THAT(data,
203               ::testing::ContainerEq(filled_message->GetMessagePayload()));
204 }
205 
TEST(FidoHidMessageTest,TestDeserialize)206 TEST(FidoHidMessageTest, TestDeserialize) {
207   uint32_t channel_id = 0x0A0B0C0D;
208   std::vector<uint8_t> data(kHidMaxMessageSize);
209 
210   auto orig_message = FidoHidMessage::Create(
211       channel_id, FidoHidDeviceCommand::kPing, kHidMaxPacketSize, data);
212   ASSERT_TRUE(orig_message);
213 
214   base::circular_deque<std::vector<uint8_t>> orig_list;
215   auto buf = orig_message->PopNextPacket();
216   orig_list.push_back(buf);
217 
218   auto new_message = FidoHidMessage::CreateFromSerializedData(buf);
219   while (!new_message->MessageComplete()) {
220     buf = orig_message->PopNextPacket();
221     orig_list.push_back(buf);
222     new_message->AddContinuationPacket(buf);
223   }
224 
225   while (!(buf = new_message->PopNextPacket()).empty()) {
226     EXPECT_EQ(buf, orig_list.front());
227     orig_list.pop_front();
228   }
229 }
230 
231 }  // namespace device
232