Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: device/usb/webusb_descriptors.cc

Issue 1256113006: Add utilities to parse WebUSB device descriptors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add DCHECKs and empty string test. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « device/usb/webusb_descriptors.h ('k') | device/usb/webusb_descriptors_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 <iterator>
6
7 #include "base/logging.h"
8 #include "device/usb/webusb_descriptors.h"
9
10 namespace device {
11
12 namespace {
13
14 // These constants are defined by the Universal Serial Device 3.0 Specification
15 // Revision 1.0.
16 const uint8_t kBosDescriptorType = 0x0F;
17 const uint8_t kDeviceCapabilityDescriptorType = 0x10;
18
19 const uint8_t kPlatformDevCapabilityType = 0x05;
20
21 // These constants are defined by the WebUSB specification:
22 // http://reillyeon.github.io/webusb/
23 const uint8_t kWebUsbCapabilityUUID[16] = {
24 // Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}.
25 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
26 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
27
28 const uint8_t kDescriptorSetDescriptorType = 0x00;
29 const uint8_t kConfigurationSubsetDescriptorType = 0x01;
30 const uint8_t kFunctionSubsetDescriptorType = 0x02;
31 const uint8_t kUrlDescriptorType = 0x03;
32
33 bool ParseUrl(GURL* url,
34 std::vector<uint8_t>::const_iterator* it,
Ken Rockot(use gerrit already) 2015/08/05 14:16:56 in these functions |it| is an input and output arg
Reilly Grant (use Gerrit) 2015/08/05 16:31:56 Considered. Passing end, begin is weirder than pas
35 std::vector<uint8_t>::const_iterator end) {
36 // These statements must be guaranteed by the caller.
Ken Rockot(use gerrit already) 2015/08/05 14:16:56 Suggestion: statements -> conditions?
Reilly Grant (use Gerrit) 2015/08/05 16:31:56 Done.
37 DCHECK(*it != end);
38 uint8_t length = (*it)[0];
39 DCHECK_LE(length, std::distance(*it, end));
40 DCHECK_GE(length, 2);
41 DCHECK_EQ((*it)[1], kUrlDescriptorType);
42
43 if (length == 2) {
44 return false;
45 }
46
47 const char* str = reinterpret_cast<const char*>(&(*it)[2]);
48 *url = GURL(std::string(str, length - 2));
49 if (!url->is_valid()) {
50 return false;
51 }
52
53 std::advance(*it, length);
54 return true;
55 }
56
57 bool ParseFunction(WebUsbFunctionSubset* function,
58 std::vector<uint8_t>::const_iterator* it,
59 std::vector<uint8_t>::const_iterator end) {
60 DCHECK(*it != end);
61 uint8_t length = (*it)[0];
62 DCHECK_LE(length, std::distance(*it, end));
63 DCHECK_GE(length, 2);
64 DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType);
65
66 if (length != 5) {
67 return false;
68 }
69
70 function->first_interface = (*it)[2];
71
72 // Validate the Function Subset header.
73 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
74 if (length > total_length || total_length > std::distance(*it, end)) {
75 return false;
76 }
77
78 end = *it + total_length;
79 std::advance(*it, length);
80
81 while (*it != end) {
82 uint8_t length = (*it)[0];
83 if (length < 2 || std::distance(*it, end) < length) {
84 return false;
85 }
86
87 uint8_t type = (*it)[1];
88 if (type == kUrlDescriptorType) {
89 GURL origin;
90 if (!ParseUrl(&origin, it, end)) {
91 return false;
92 }
93 function->origins.push_back(origin);
94 } else {
95 return false;
96 }
97 }
98
99 return true;
100 }
101
102 bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
103 std::vector<uint8_t>::const_iterator* it,
104 std::vector<uint8_t>::const_iterator end) {
105 DCHECK(*it != end);
106 uint8_t length = (*it)[0];
107 DCHECK_LE(length, std::distance(*it, end));
108 DCHECK_GE(length, 2);
109 DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType);
110
111 if (length != 5) {
112 return false;
113 }
114
115 configuration->configuration_value = (*it)[2];
116
117 // Validate the Configuration Subset header.
118 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
119 if (length > total_length || total_length > std::distance(*it, end)) {
120 return false;
121 }
122
123 end = *it + total_length;
124 std::advance(*it, length);
125
126 while (*it != end) {
127 uint8_t length = (*it)[0];
128 if (length < 2 || std::distance(*it, end) < length) {
129 return false;
130 }
131
132 uint8_t type = (*it)[1];
133 if (type == kFunctionSubsetDescriptorType) {
134 WebUsbFunctionSubset function;
135 if (!ParseFunction(&function, it, end)) {
136 return false;
137 }
138 configuration->functions.push_back(function);
139 } else if (type == kUrlDescriptorType) {
140 GURL origin;
141 if (!ParseUrl(&origin, it, end)) {
142 return false;
143 }
144 configuration->origins.push_back(origin);
145 } else {
146 return false;
147 }
148 }
149
150 return true;
151 }
152
153 } // namespace
154
155 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
156
157 WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
158
159 WebUsbConfigurationSubset::WebUsbConfigurationSubset()
160 : configuration_value(0) {}
161
162 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
163
164 WebUsbDescriptorSet::WebUsbDescriptorSet() {}
165
166 WebUsbDescriptorSet::~WebUsbDescriptorSet() {}
167
168 bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) {
169 if (bytes.size() < 4) {
170 return false;
171 }
172
173 // Validate the descriptor set header.
174 uint16_t total_length = bytes[2] + (bytes[3] << 8);
175 if (bytes[0] != 4 || // bLength
176 bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType
177 4 > total_length || total_length > bytes.size()) { // wTotalLength
178 return false;
179 }
180
181 std::vector<uint8_t>::const_iterator it = bytes.begin();
182 std::vector<uint8_t>::const_iterator end = it + total_length;
183 std::advance(it, 4);
184
185 while (it != bytes.end()) {
186 uint8_t length = it[0];
187 if (length < 2 || std::distance(it, end) < length) {
188 return false;
189 }
190
191 uint8_t type = it[1];
192 if (type == kConfigurationSubsetDescriptorType) {
193 WebUsbConfigurationSubset configuration;
194 if (!ParseConfiguration(&configuration, &it, end)) {
195 return false;
196 }
197 configurations.push_back(configuration);
198 } else if (type == kUrlDescriptorType) {
199 GURL origin;
200 if (!ParseUrl(&origin, &it, end)) {
201 return false;
202 }
203 origins.push_back(origin);
204 } else {
205 return false;
206 }
207 }
208
209 return true;
210 }
211
212 WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
213 : version(0), vendor_code(0) {}
214
215 WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {}
216
217 bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
218 const std::vector<uint8_t>& bytes) {
219 if (bytes.size() < 5) {
220 // Too short for the BOS descriptor header.
221 return false;
222 }
223
224 // Validate the BOS descriptor, defined in Table 9-12 of the Universal Serial
225 // Bus 3.1 Specification, Revision 1.0.
226 uint16_t total_length = bytes[2] + (bytes[3] << 8);
227 if (bytes[0] != 5 || // bLength
228 bytes[1] != kBosDescriptorType || // bDescriptorType
229 5 > total_length || total_length > bytes.size()) { // wTotalLength
230 return false;
231 }
232
233 uint8_t num_device_caps = bytes[4];
234 std::vector<uint8_t>::const_iterator it = bytes.begin();
235 std::vector<uint8_t>::const_iterator end = it + total_length;
236 std::advance(it, 5);
237
238 uint8_t length = 0;
239 bool found_vendor_code = false;
240 for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
241 if (it == end) {
242 return false;
243 }
244
245 // Validate the Device Capability descriptor, defined in Table 9-13 of the
246 // Universal Serial Bus 3.1 Specification, Revision 1.0.
247 length = it[0];
248 if (length < 3 || std::distance(it, end) < length || // bLength
249 it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType
250 return false;
251 }
252
253 if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType
254 continue;
255 }
256
257 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
258 // Universal Serial Bus 3.1 Specification, Revision 1.0.
259 if (length < 20) {
260 // Platform capability descriptors must be at least 20 bytes.
261 return false;
262 }
263
264 if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) !=
265 0) { // PlatformCapabilityUUID
266 continue;
267 }
268
269 if (length < 23) {
270 // The WebUSB capability descriptor must be at least 23 bytes (to allow
271 // for future versions).
272 return false;
273 }
274
275 version = it[20] + (it[21] << 8); // bcdVersion
276 if (version < 0x0100) {
277 continue;
278 }
279
280 // Version 1.0 only defines a single field, bVendorCode.
281 vendor_code = it[22];
282 found_vendor_code = true;
283 }
284
285 return found_vendor_code;
286 }
287
288 } // namespace device
OLDNEW
« no previous file with comments | « device/usb/webusb_descriptors.h ('k') | device/usb/webusb_descriptors_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698