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

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: 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,
35 std::vector<uint8_t>::const_iterator end) {
36 uint8_t length = (*it)[0];
37 DCHECK_LE(length, std::distance(*it, end));
38 DCHECK_EQ((*it)[1], kUrlDescriptorType);
Ken Rockot(use gerrit already) 2015/08/04 00:59:02 If it is passed as 1 short of |end|, can't (*it)[1
Reilly Grant (use Gerrit) 2015/08/04 01:05:20 These properties should be guaranteed by the calle
39
40 const char* str = reinterpret_cast<const char*>(&(*it)[2]);
Ken Rockot(use gerrit already) 2015/08/04 00:59:02 As can (*it)[2]
41 *url = GURL(std::string(str, length - 2));
Ken Rockot(use gerrit already) 2015/08/04 00:59:02 length - 2 can underflow
42 if (!url->is_valid()) {
43 return false;
44 }
45
46 std::advance(*it, length);
47 return true;
48 }
49
50 bool ParseFunction(WebUsbFunctionSubset* function,
51 std::vector<uint8_t>::const_iterator* it,
52 std::vector<uint8_t>::const_iterator end) {
53 uint8_t length = (*it)[0];
54 DCHECK_LE(length, std::distance(*it, end));
55 DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType);
Ken Rockot(use gerrit already) 2015/08/04 00:59:02 same deal as above
56
57 if (length != 5) {
58 return false;
59 }
60
61 function->first_interface = (*it)[2];
62
63 // Validate the Function Subset header.
64 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
65 if (length > total_length || total_length > std::distance(*it, end)) {
66 return false;
67 }
68
69 end = *it + total_length;
70 std::advance(*it, length);
71
72 while (*it != end) {
73 uint8_t length = (*it)[0];
74 if (length < 2 || std::distance(*it, end) < length) {
75 return false;
76 }
77
78 uint8_t type = (*it)[1];
79 if (type == kUrlDescriptorType) {
80 GURL origin;
81 if (!ParseUrl(&origin, it, end)) {
82 return false;
83 }
84 function->origins.push_back(origin);
85 } else {
86 return false;
87 }
88 }
89
90 return true;
91 }
92
93 bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
94 std::vector<uint8_t>::const_iterator* it,
95 std::vector<uint8_t>::const_iterator end) {
96 uint8_t length = (*it)[0];
97 DCHECK_LE(length, std::distance(*it, end));
98 DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType);
99
100 if (length != 5) {
101 return false;
102 }
103
104 configuration->configuration_value = (*it)[2];
105
106 // Validate the Configuration Subset header.
107 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
108 if (length > total_length || total_length > std::distance(*it, end)) {
109 return false;
110 }
111
112 end = *it + total_length;
113 std::advance(*it, length);
114
115 while (*it != end) {
116 uint8_t length = (*it)[0];
117 if (length < 2 || std::distance(*it, end) < length) {
118 return false;
119 }
120
121 uint8_t type = (*it)[1];
122 if (type == kFunctionSubsetDescriptorType) {
123 WebUsbFunctionSubset function;
124 if (!ParseFunction(&function, it, end)) {
125 return false;
126 }
127 configuration->functions.push_back(function);
128 } else if (type == kUrlDescriptorType) {
129 GURL origin;
130 if (!ParseUrl(&origin, it, end)) {
131 return false;
132 }
133 configuration->origins.push_back(origin);
134 } else {
135 return false;
136 }
137 }
138
139 return true;
140 }
141
142 } // namespace
143
144 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
145
146 WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
147
148 WebUsbConfigurationSubset::WebUsbConfigurationSubset()
149 : configuration_value(0) {}
150
151 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
152
153 WebUsbDescriptorSet::WebUsbDescriptorSet() {}
154
155 WebUsbDescriptorSet::~WebUsbDescriptorSet() {}
156
157 bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) {
158 if (bytes.size() < 4) {
159 return false;
160 }
161
162 // Validate the descriptor set header.
163 uint16_t total_length = bytes[2] + (bytes[3] << 8);
164 if (bytes[0] != 4 || // bLength
165 bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType
166 4 > total_length || total_length > bytes.size()) { // wTotalLength
167 return false;
Ken Rockot(use gerrit already) 2015/08/04 00:59:02 Is it worth vlogging anything for some of these fa
Reilly Grant (use Gerrit) 2015/08/04 01:05:20 I had a bunch of VLOGs when I was developing but I
168 }
169
170 std::vector<uint8_t>::const_iterator it = bytes.begin();
171 std::vector<uint8_t>::const_iterator end = it + total_length;
172 std::advance(it, 4);
173
174 while (it != bytes.end()) {
175 uint8_t length = it[0];
176 if (length < 2 || std::distance(it, end) < length) {
177 return false;
178 }
179
180 uint8_t type = it[1];
181 if (type == kConfigurationSubsetDescriptorType) {
182 WebUsbConfigurationSubset configuration;
183 if (!ParseConfiguration(&configuration, &it, end)) {
184 return false;
185 }
186 configurations.push_back(configuration);
187 } else if (type == kUrlDescriptorType) {
188 GURL origin;
189 if (!ParseUrl(&origin, &it, end)) {
190 return false;
191 }
192 origins.push_back(origin);
193 } else {
194 return false;
195 }
196 }
197
198 return true;
199 }
200
201 WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
202 : version(0), vendor_code(0) {}
203
204 WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {}
205
206 bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
207 const std::vector<uint8_t>& bytes) {
208 if (bytes.size() < 5) {
209 // Too short for the BOS descriptor header.
210 return false;
211 }
212
213 // Validate the BOS descriptor, defined in Table 9-12 of the Universal Serial
214 // Bus 3.1 Specification, Revision 1.0.
215 uint16_t total_length = bytes[2] + (bytes[3] << 8);
216 if (bytes[0] != 5 || // bLength
217 bytes[1] != kBosDescriptorType || // bDescriptorType
218 5 > total_length || total_length > bytes.size()) { // wTotalLength
219 return false;
220 }
221
222 uint8_t num_device_caps = bytes[4];
223 std::vector<uint8_t>::const_iterator it = bytes.begin();
224 std::vector<uint8_t>::const_iterator end = it + total_length;
225 std::advance(it, 5);
226
227 uint8_t length = 0;
228 bool found_vendor_code = false;
229 for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
230 if (it == end) {
231 return false;
232 }
233
234 // Validate the Device Capability descriptor, defined in Table 9-13 of the
235 // Universal Serial Bus 3.1 Specification, Revision 1.0.
236 length = it[0];
237 if (length < 3 || std::distance(it, end) < length || // bLength
238 it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType
239 return false;
240 }
241
242 if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType
243 continue;
244 }
245
246 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
247 // Universal Serial Bus 3.1 Specification, Revision 1.0.
248 if (length < 20) {
249 // Platform capability descriptors must be at least 20 bytes.
250 return false;
251 }
252
253 if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) !=
254 0) { // PlatformCapabilityUUID
255 continue;
256 }
257
258 if (length < 23) {
259 // The WebUSB capability descriptor must be at least 23 bytes (to allow
260 // for future versions).
261 return false;
262 }
263
264 version = it[20] + (it[21] << 8); // bcdVersion
265 if (version < 0x0100) {
266 continue;
267 }
268
269 // Version 1.0 only defines a single field, bVendorCode.
270 vendor_code = it[22];
271 found_vendor_code = true;
272 }
273
274 return found_vendor_code;
275 }
276
277 } // 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