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

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

Issue 1646783002: Update webusb_descriptors.cc to parse the new WebUSB descriptors. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@io_buffer
Patch Set: Sometimes MSVC complains about passing size_type to BarrierClosure. Created 4 years, 10 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include <iterator> 7 #include <iterator>
8 #include <map>
9 #include <set>
8 10
11 #include "base/barrier_closure.h"
12 #include "base/bind.h"
13 #include "base/callback.h"
9 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "components/device_event_log/device_event_log.h"
16 #include "device/usb/usb_device_handle.h"
10 #include "device/usb/webusb_descriptors.h" 17 #include "device/usb/webusb_descriptors.h"
18 #include "net/base/io_buffer.h"
19
20 using net::IOBufferWithSize;
11 21
12 namespace device { 22 namespace device {
13 23
14 namespace { 24 namespace {
15 25
16 // These constants are defined by the Universal Serial Device 3.0 Specification 26 // These constants are defined by the Universal Serial Device 3.0 Specification
17 // Revision 1.0. 27 // Revision 1.0.
28 const uint8_t kGetDescriptorRequest = 0x06;
29
18 const uint8_t kBosDescriptorType = 0x0F; 30 const uint8_t kBosDescriptorType = 0x0F;
19 const uint8_t kDeviceCapabilityDescriptorType = 0x10; 31 const uint8_t kDeviceCapabilityDescriptorType = 0x10;
20 32
21 const uint8_t kPlatformDevCapabilityType = 0x05; 33 const uint8_t kPlatformDevCapabilityType = 0x05;
22 34
23 // These constants are defined by the WebUSB specification: 35 // These constants are defined by the WebUSB specification:
24 // http://wicg.github.io/webusb/ 36 // http://wicg.github.io/webusb/
37 const uint8_t kGetAllowedOriginsRequest = 0x01;
38 const uint8_t kGetUrlRequest = 0x02;
39
25 const uint8_t kWebUsbCapabilityUUID[16] = { 40 const uint8_t kWebUsbCapabilityUUID[16] = {
26 // Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}. 41 // Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}.
27 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 42 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
28 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65}; 43 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
29 44
30 const uint8_t kDescriptorSetDescriptorType = 0x00; 45 const int kControlTransferTimeout = 60000; // 1 minute
31 const uint8_t kConfigurationSubsetDescriptorType = 0x01; 46
32 const uint8_t kFunctionSubsetDescriptorType = 0x02; 47 using ReadWebUsbDescriptorsCallback =
33 const uint8_t kUrlDescriptorType = 0x03; 48 base::Callback<void(scoped_ptr<WebUsbAllowedOrigins> allowed_origins,
34 49 const GURL& landing_page)>;
35 bool ParseUrl(GURL* url, 50
36 std::vector<uint8_t>::const_iterator* it, 51 using ReadWebUsbAllowedOriginsCallback =
37 std::vector<uint8_t>::const_iterator end) { 52 base::Callback<void(scoped_ptr<WebUsbAllowedOrigins> allowed_origins)>;
38 // These conditions must be guaranteed by the caller. 53
39 DCHECK(*it != end); 54 // Parses a WebUSB Function Subset Header:
40 uint8_t length = (*it)[0]; 55 // http://wicg.github.io/webusb/#dfn-function-subset-header
41 DCHECK_LE(length, std::distance(*it, end)); 56 //
42 DCHECK_GE(length, 2); 57 // 0 1 2 3
43 DCHECK_EQ((*it)[1], kUrlDescriptorType); 58 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
44 59 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 if (length == 2) { 60 // | length | type | 1st interface | origin[0] |
46 return false; 61 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 } 62 // | origin[1] | ...
48 63 // +-+-+-+-+-+-+-+-+-+-+-+------
49 const char* str = reinterpret_cast<const char*>(&(*it)[2]);
50 *url = GURL(std::string(str, length - 2));
51 if (!url->is_valid()) {
52 return false;
53 }
54
55 std::advance(*it, length);
56 return true;
57 }
58
59 bool ParseFunction(WebUsbFunctionSubset* function, 64 bool ParseFunction(WebUsbFunctionSubset* function,
60 std::vector<uint8_t>::const_iterator* it, 65 std::vector<uint8_t>::const_iterator* it,
61 std::vector<uint8_t>::const_iterator end) { 66 std::vector<uint8_t>::const_iterator end) {
62 // These conditions must be guaranteed by the caller. 67 const uint8_t kDescriptorType = 0x02;
63 DCHECK(*it != end); 68 const uint8_t kDescriptorMinLength = 3;
69
70 // If this isn't the end of the buffer then there must be at least one byte
71 // available, the length of the descriptor.
72 if (*it == end)
73 return false;
64 uint8_t length = (*it)[0]; 74 uint8_t length = (*it)[0];
65 DCHECK_LE(length, std::distance(*it, end)); 75
66 DCHECK_GE(length, 2); 76 // Is this a valid Function Subset Header? It must be long enough, fit within
67 DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType); 77 // the buffer and have the right descriptor type.
68 78 if (length < kDescriptorMinLength || std::distance(*it, end) < length ||
69 if (length != 5) { 79 (*it)[1] != kDescriptorType) {
70 return false; 80 return false;
71 } 81 }
72 82
73 function->first_interface = (*it)[2]; 83 function->first_interface = (*it)[2];
74 84
75 // Validate the Function Subset header. 85 // Everything after the mandatory fields are origin indicies.
76 uint16_t total_length = (*it)[3] + ((*it)[4] << 8); 86 std::advance(*it, kDescriptorMinLength);
77 if (length > total_length || total_length > std::distance(*it, end)) { 87 uint8_t num_origins = length - kDescriptorMinLength;
78 return false; 88 function->origin_ids.reserve(num_origins);
79 } 89 for (size_t i = 0; i < num_origins; ++i) {
80 90 uint8_t index = *(*it)++;
81 end = *it + total_length; 91 if (index == 0)
82 std::advance(*it, length);
83
84 while (*it != end) {
85 uint8_t length = (*it)[0];
86 if (length < 2 || std::distance(*it, end) < length) {
87 return false; 92 return false;
88 } 93 function->origin_ids.push_back(index);
89
90 uint8_t type = (*it)[1];
91 if (type == kUrlDescriptorType) {
92 GURL url;
93 if (!ParseUrl(&url, it, end)) {
94 return false;
95 }
96 function->origins.push_back(url.GetOrigin());
97 } else {
98 return false;
99 }
100 } 94 }
101 95
102 return true; 96 return true;
103 } 97 }
104 98
99 // Parses a WebUSB Configuration Subset Header:
100 // http://wicg.github.io/webusb/#dfn-configuration-subset-header
101 //
102 // 0 1 2 3
103 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
104 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105 // | length | type | config value | num functions |
106 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 // | origin[0] | origin[1] | ...
108 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+------
105 bool ParseConfiguration(WebUsbConfigurationSubset* configuration, 109 bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
106 std::vector<uint8_t>::const_iterator* it, 110 std::vector<uint8_t>::const_iterator* it,
107 std::vector<uint8_t>::const_iterator end) { 111 std::vector<uint8_t>::const_iterator end) {
108 // These conditions must be guaranteed by the caller. 112 const uint8_t kDescriptorType = 0x01;
109 DCHECK(*it != end); 113 const uint8_t kDescriptorMinLength = 4;
114
115 // If this isn't the end of the buffer then there must be at least one byte
116 // available, the length of the descriptor.
117 if (*it == end)
118 return false;
110 uint8_t length = (*it)[0]; 119 uint8_t length = (*it)[0];
111 DCHECK_LE(length, std::distance(*it, end)); 120
112 DCHECK_GE(length, 2); 121 // Is this a valid Configuration Subset Header? It must be long enough, fit
113 DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType); 122 // within the buffer and have the right descriptor type.
114 123 if (length < kDescriptorMinLength || std::distance(*it, end) < length ||
115 if (length != 5) { 124 (*it)[1] != kDescriptorType) {
116 return false; 125 return false;
117 } 126 }
118 127
119 configuration->configuration_value = (*it)[2]; 128 configuration->configuration_value = (*it)[2];
120 129 uint8_t num_functions = (*it)[3];
121 // Validate the Configuration Subset header. 130
122 uint16_t total_length = (*it)[3] + ((*it)[4] << 8); 131 // The next |length - 4| bytes after the mandatory fields are origin indicies.
123 if (length > total_length || total_length > std::distance(*it, end)) { 132 std::advance(*it, kDescriptorMinLength);
124 return false; 133 uint8_t num_origins = length - kDescriptorMinLength;
125 } 134 configuration->origin_ids.reserve(num_origins);
126 135 for (size_t i = 0; i < num_origins; ++i) {
127 end = *it + total_length; 136 uint8_t index = *(*it)++;
128 std::advance(*it, length); 137 if (index == 0)
129
130 while (*it != end) {
131 uint8_t length = (*it)[0];
132 if (length < 2 || std::distance(*it, end) < length) {
133 return false; 138 return false;
139 configuration->origin_ids.push_back(index);
140 }
141
142 // |num_functions| function descriptors then follow the descriptor.
143 for (size_t i = 0; i < num_functions; ++i) {
144 WebUsbFunctionSubset function;
145 if (!ParseFunction(&function, it, end))
146 return false;
147 configuration->functions.push_back(function);
148 }
149
150 return true;
151 }
152
153 void OnDoneReadingUrls(scoped_ptr<WebUsbAllowedOrigins> allowed_origins,
154 uint8_t landing_page_id,
155 scoped_ptr<std::map<uint8_t, GURL>> url_map,
156 const ReadWebUsbDescriptorsCallback& callback) {
157 for (uint8_t origin_id : allowed_origins->origin_ids) {
158 const auto& it = url_map->find(origin_id);
159 if (it != url_map->end())
160 allowed_origins->origins.push_back(it->second.GetOrigin());
161 }
162
163 for (auto& configuration : allowed_origins->configurations) {
164 for (uint8_t origin_id : configuration.origin_ids) {
165 const auto& it = url_map->find(origin_id);
166 if (it != url_map->end())
167 configuration.origins.push_back(it->second.GetOrigin());
134 } 168 }
135 169
136 uint8_t type = (*it)[1]; 170 for (auto& function : configuration.functions) {
137 if (type == kFunctionSubsetDescriptorType) { 171 for (uint8_t origin_id : function.origin_ids) {
138 WebUsbFunctionSubset function; 172 const auto& it = url_map->find(origin_id);
139 if (!ParseFunction(&function, it, end)) { 173 if (it != url_map->end())
140 return false; 174 function.origins.push_back(it->second.GetOrigin());
141 } 175 }
142 configuration->functions.push_back(function);
143 } else if (type == kUrlDescriptorType) {
144 GURL url;
145 if (!ParseUrl(&url, it, end)) {
146 return false;
147 }
148 configuration->origins.push_back(url.GetOrigin());
149 } else {
150 return false;
151 } 176 }
152 } 177 }
153 178
154 return true; 179 GURL landing_page;
180 if (landing_page_id != 0)
181 landing_page = (*url_map)[landing_page_id];
182
183 callback.Run(std::move(allowed_origins), landing_page);
184 }
185
186 void OnReadUrlDescriptor(std::map<uint8_t, GURL>* url_map,
187 uint8_t index,
188 const base::Closure& callback,
189 UsbTransferStatus status,
190 scoped_refptr<net::IOBuffer> buffer,
191 size_t length) {
192 if (status != USB_TRANSFER_COMPLETED) {
193 USB_LOG(EVENT) << "Failed to read WebUSB URL descriptor: " << index;
194 callback.Run();
195 return;
196 }
197
198 GURL url;
199 if (ParseWebUsbUrlDescriptor(
200 std::vector<uint8_t>(buffer->data(), buffer->data() + length),
201 &url)) {
202 (*url_map)[index] = url;
203 }
204 callback.Run();
205 }
206
207 // Reads the descriptor with |index| from the device, adds the value to
208 // |url_map| and then runs |callback|.
209 void ReadUrlDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
210 uint8_t vendor_code,
211 std::map<uint8_t, GURL>* url_map,
212 uint8_t index,
213 const base::Closure& callback) {
214 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(255);
215 device_handle->ControlTransfer(
216 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
217 vendor_code, index, kGetUrlRequest, buffer, buffer->size(),
218 kControlTransferTimeout,
219 base::Bind(&OnReadUrlDescriptor, url_map, index, callback));
220 }
221
222 // Reads URL descriptors from the device so that it can fill |allowed_origins|
223 // with the GURLs matching the indicies already collected.
224 void ReadUrlDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
225 uint8_t vendor_code,
226 uint8_t landing_page_id,
227 const ReadWebUsbDescriptorsCallback& callback,
228 scoped_ptr<WebUsbAllowedOrigins> allowed_origins) {
229 if (!allowed_origins) {
230 callback.Run(nullptr, GURL());
231 return;
232 }
233
234 std::set<uint8_t> to_request;
235 if (landing_page_id != 0)
236 to_request.insert(landing_page_id);
237
238 to_request.insert(allowed_origins->origin_ids.begin(),
239 allowed_origins->origin_ids.end());
240 for (auto& config : allowed_origins->configurations) {
241 to_request.insert(config.origin_ids.begin(), config.origin_ids.end());
242 for (auto& function : config.functions) {
243 to_request.insert(function.origin_ids.begin(), function.origin_ids.end());
244 }
245 }
246
247 scoped_ptr<std::map<uint8_t, GURL>> url_map(new std::map<uint8_t, GURL>());
248 std::map<uint8_t, GURL>* url_map_ptr = url_map.get();
249 base::Closure barrier = base::BarrierClosure(
250 static_cast<int>(to_request.size()),
251 base::Bind(&OnDoneReadingUrls, base::Passed(&allowed_origins),
252 landing_page_id, base::Passed(&url_map), callback));
253
254 for (uint8_t index : to_request) {
255 ReadUrlDescriptor(device_handle, vendor_code, url_map_ptr, index, barrier);
256 }
257 }
258
259 void OnReadWebUsbAllowedOrigins(
260 const ReadWebUsbAllowedOriginsCallback& callback,
261 UsbTransferStatus status,
262 scoped_refptr<net::IOBuffer> buffer,
263 size_t length) {
264 if (status != USB_TRANSFER_COMPLETED) {
265 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins.";
266 callback.Run(nullptr);
267 return;
268 }
269
270 scoped_ptr<WebUsbAllowedOrigins> allowed_origins(new WebUsbAllowedOrigins());
271 if (allowed_origins->Parse(
272 std::vector<uint8_t>(buffer->data(), buffer->data() + length))) {
273 callback.Run(std::move(allowed_origins));
274 } else {
275 callback.Run(nullptr);
276 }
277 }
278
279 void OnReadWebUsbAllowedOriginsHeader(
280 scoped_refptr<UsbDeviceHandle> device_handle,
281 const ReadWebUsbAllowedOriginsCallback& callback,
282 uint8_t vendor_code,
283 UsbTransferStatus status,
284 scoped_refptr<net::IOBuffer> buffer,
285 size_t length) {
286 if (status != USB_TRANSFER_COMPLETED || length != 4) {
287 USB_LOG(EVENT) << "Failed to read WebUSB allowed origins header.";
288 callback.Run(nullptr);
289 return;
290 }
291
292 uint16_t new_length = buffer->data()[2] | (buffer->data()[3] << 8);
293 scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
294 device_handle->ControlTransfer(
295 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
296 vendor_code, 0, kGetAllowedOriginsRequest, new_buffer, new_buffer->size(),
297 kControlTransferTimeout,
298 base::Bind(&OnReadWebUsbAllowedOrigins, callback));
299 }
300
301 void ReadWebUsbAllowedOrigins(
302 scoped_refptr<UsbDeviceHandle> device_handle,
303 uint8_t vendor_code,
304 const ReadWebUsbAllowedOriginsCallback& callback) {
305 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(4);
306 device_handle->ControlTransfer(
307 USB_DIRECTION_INBOUND, UsbDeviceHandle::VENDOR, UsbDeviceHandle::DEVICE,
308 vendor_code, 0, kGetAllowedOriginsRequest, buffer, buffer->size(),
309 kControlTransferTimeout,
310 base::Bind(&OnReadWebUsbAllowedOriginsHeader, device_handle, callback,
311 vendor_code));
312 }
313
314 void OnReadBosDescriptor(scoped_refptr<UsbDeviceHandle> device_handle,
315 const ReadWebUsbDescriptorsCallback& callback,
316 UsbTransferStatus status,
317 scoped_refptr<net::IOBuffer> buffer,
318 size_t length) {
319 if (status != USB_TRANSFER_COMPLETED) {
320 USB_LOG(EVENT) << "Failed to read BOS descriptor.";
321 callback.Run(nullptr, GURL());
322 return;
323 }
324
325 WebUsbPlatformCapabilityDescriptor descriptor;
326 if (!descriptor.ParseFromBosDescriptor(
327 std::vector<uint8_t>(buffer->data(), buffer->data() + length))) {
328 callback.Run(nullptr, GURL());
329 return;
330 }
331
332 ReadWebUsbAllowedOrigins(
333 device_handle, descriptor.vendor_code,
334 base::Bind(&ReadUrlDescriptors, device_handle, descriptor.vendor_code,
335 descriptor.landing_page_id, callback));
336 }
337
338 void OnReadBosDescriptorHeader(scoped_refptr<UsbDeviceHandle> device_handle,
339 const ReadWebUsbDescriptorsCallback& callback,
340 UsbTransferStatus status,
341 scoped_refptr<net::IOBuffer> buffer,
342 size_t length) {
343 if (status != USB_TRANSFER_COMPLETED || length != 5) {
344 USB_LOG(EVENT) << "Failed to read BOS descriptor header.";
345 callback.Run(nullptr, GURL());
346 return;
347 }
348
349 uint16_t new_length = buffer->data()[2] | (buffer->data()[3] << 8);
350 scoped_refptr<IOBufferWithSize> new_buffer = new IOBufferWithSize(new_length);
351 device_handle->ControlTransfer(
352 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
353 kGetDescriptorRequest, kBosDescriptorType << 8, 0, new_buffer,
354 new_buffer->size(), kControlTransferTimeout,
355 base::Bind(&OnReadBosDescriptor, device_handle, callback));
155 } 356 }
156 357
157 } // namespace 358 } // namespace
158 359
159 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {} 360 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
160 361
161 WebUsbFunctionSubset::~WebUsbFunctionSubset() {} 362 WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
162 363
163 WebUsbConfigurationSubset::WebUsbConfigurationSubset() 364 WebUsbConfigurationSubset::WebUsbConfigurationSubset()
164 : configuration_value(0) {} 365 : configuration_value(0) {}
165 366
166 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {} 367 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
167 368
168 WebUsbDescriptorSet::WebUsbDescriptorSet() {} 369 WebUsbAllowedOrigins::WebUsbAllowedOrigins() {}
169 370
170 WebUsbDescriptorSet::~WebUsbDescriptorSet() {} 371 WebUsbAllowedOrigins::~WebUsbAllowedOrigins() {}
171 372
172 bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) { 373 // Parses a WebUSB Allowed Origins Header:
173 if (bytes.size() < 4) { 374 // http://wicg.github.io/webusb/#dfn-allowed-origins-header
375 //
376 // 0 1 2 3
377 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
378 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379 // | length | type | total length |
380 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
381 // | num configs | origin[0] | origin[1] | ...
382 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+------
383 bool WebUsbAllowedOrigins::Parse(const std::vector<uint8_t>& bytes) {
384 const uint8_t kDescriptorType = 0x00;
385 const uint8_t kDescriptorMinLength = 5;
386
387 // The buffer must be at least the length of this descriptor's mandatory
388 // fields.
389 if (bytes.size() < kDescriptorMinLength)
174 return false; 390 return false;
175 }
176 391
177 // Validate the descriptor set header. 392 // Validate that the length of this descriptor and the total length of the
393 // entire block of descriptors is consistent with the length of the buffer.
394 uint8_t length = bytes[0];
178 uint16_t total_length = bytes[2] + (bytes[3] << 8); 395 uint16_t total_length = bytes[2] + (bytes[3] << 8);
179 if (bytes[0] != 4 || // bLength 396 if (length < 5 || length > bytes.size() || // bLength
180 bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType 397 bytes[1] != kDescriptorType || // bDescriptorType
181 4 > total_length || total_length > bytes.size()) { // wTotalLength 398 total_length < length || total_length > bytes.size()) { // wTotalLength
182 return false; 399 return false;
183 } 400 }
184 401
185 std::vector<uint8_t>::const_iterator it = bytes.begin(); 402 std::vector<uint8_t>::const_iterator it = bytes.begin();
186 std::vector<uint8_t>::const_iterator end = it + total_length; 403 uint8_t num_configurations = bytes[4];
187 std::advance(it, 4);
188 404
189 while (it != bytes.end()) { 405 // The next |length - 5| bytes after the mandatory fields are origin indicies.
190 uint8_t length = it[0]; 406 std::advance(it, kDescriptorMinLength);
191 if (length < 2 || std::distance(it, end) < length) { 407 uint8_t num_origins = length - kDescriptorMinLength;
408 origin_ids.reserve(num_origins);
409 for (size_t i = 0; i < num_origins; ++i) {
410 uint8_t index = *it++;
411 if (index == 0)
192 return false; 412 return false;
193 } 413 origin_ids.push_back(index);
414 }
194 415
195 uint8_t type = it[1]; 416 // |num_configurations| configuration descriptors then follow the descriptor.
196 if (type == kConfigurationSubsetDescriptorType) { 417 for (size_t i = 0; i < num_configurations; ++i) {
197 WebUsbConfigurationSubset configuration; 418 WebUsbConfigurationSubset configuration;
198 if (!ParseConfiguration(&configuration, &it, end)) { 419 if (!ParseConfiguration(&configuration, &it, bytes.end()))
199 return false;
200 }
201 configurations.push_back(configuration);
202 } else if (type == kUrlDescriptorType) {
203 GURL url;
204 if (!ParseUrl(&url, &it, end)) {
205 return false;
206 }
207 origins.push_back(url.GetOrigin());
208 } else {
209 return false; 420 return false;
210 } 421 configurations.push_back(configuration);
211 } 422 }
212 423
213 return true; 424 return true;
214 } 425 }
215 426
216 WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor() 427 WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
217 : version(0), vendor_code(0) {} 428 : version(0), vendor_code(0) {}
218 429
219 WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {} 430 WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {}
220 431
(...skipping 12 matching lines...) Expand all
233 5 > total_length || total_length > bytes.size()) { // wTotalLength 444 5 > total_length || total_length > bytes.size()) { // wTotalLength
234 return false; 445 return false;
235 } 446 }
236 447
237 uint8_t num_device_caps = bytes[4]; 448 uint8_t num_device_caps = bytes[4];
238 std::vector<uint8_t>::const_iterator it = bytes.begin(); 449 std::vector<uint8_t>::const_iterator it = bytes.begin();
239 std::vector<uint8_t>::const_iterator end = it + total_length; 450 std::vector<uint8_t>::const_iterator end = it + total_length;
240 std::advance(it, 5); 451 std::advance(it, 5);
241 452
242 uint8_t length = 0; 453 uint8_t length = 0;
243 bool found_vendor_code = false;
244 for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) { 454 for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
245 if (it == end) { 455 if (it == end) {
246 return false; 456 return false;
247 } 457 }
248 458
249 // Validate the Device Capability descriptor, defined in Table 9-13 of the 459 // Validate the Device Capability descriptor, defined in Table 9-13 of the
250 // Universal Serial Bus 3.1 Specification, Revision 1.0. 460 // Universal Serial Bus 3.1 Specification, Revision 1.0.
251 length = it[0]; 461 length = it[0];
252 if (length < 3 || std::distance(it, end) < length || // bLength 462 if (length < 3 || std::distance(it, end) < length || // bLength
253 it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType 463 it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType
254 return false; 464 return false;
255 } 465 }
256 466
257 if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType 467 if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType
258 continue; 468 continue;
259 } 469 }
260 470
261 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the 471 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
262 // Universal Serial Bus 3.1 Specification, Revision 1.0. 472 // Universal Serial Bus 3.1 Specification, Revision 1.0.
263 if (length < 20) { 473 if (length < 20) {
264 // Platform capability descriptors must be at least 20 bytes. 474 // Platform capability descriptors must be at least 20 bytes.
265 return false; 475 return false;
266 } 476 }
267 477
268 if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) != 478 if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) !=
269 0) { // PlatformCapabilityUUID 479 0) { // PlatformCapabilityUUID
270 continue; 480 continue;
271 } 481 }
272 482
273 if (length < 23) { 483 if (length < 22) {
274 // The WebUSB capability descriptor must be at least 23 bytes (to allow 484 // The WebUSB capability descriptor must be at least 22 bytes (to allow
275 // for future versions). 485 // for future versions).
276 return false; 486 return false;
277 } 487 }
278 488
279 version = it[20] + (it[21] << 8); // bcdVersion 489 version = it[20] + (it[21] << 8); // bcdVersion
280 if (version < 0x0100) { 490 if (version < 0x0100) {
281 continue; 491 continue;
282 } 492 }
283 493
284 // Version 1.0 only defines a single field, bVendorCode. 494 // Version 1.0 defines two fields for a total length of 24 bytes.
495 if (length != 24) {
496 return false;
497 }
498
285 vendor_code = it[22]; 499 vendor_code = it[22];
286 found_vendor_code = true; 500 landing_page_id = it[23];
501 return true;
287 } 502 }
288 503
289 return found_vendor_code; 504 return false;
290 } 505 }
291 506
507 // Parses a WebUSB URL Descriptor:
508 // http://wicg.github.io/webusb/#dfn-url-descriptor
509 //
510 // 0 1 2 3
511 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
512 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513 // | length | type | prefix | data[0] |
514 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515 // | data[1] | ...
516 // +-+-+-+-+-+-+-+-+-+-+-+------
292 bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) { 517 bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) {
293 if (bytes.size() < 2) { 518 const uint8_t kDescriptorType = 0x03;
519 const uint8_t kDescriptorMinLength = 3;
520
521 if (bytes.size() < kDescriptorMinLength) {
294 return false; 522 return false;
295 } 523 }
524
525 // Validate that the length is consistent and fits within the buffer.
296 uint8_t length = bytes[0]; 526 uint8_t length = bytes[0];
297 if (length != bytes.size() || bytes[1] != kUrlDescriptorType) { 527 if (length < kDescriptorMinLength || length < bytes.size() ||
528 bytes[1] != kDescriptorType) {
298 return false; 529 return false;
299 } 530 }
300 std::vector<uint8_t>::const_iterator it = bytes.begin(); 531
301 return ParseUrl(output, &it, bytes.end()); 532 // Look up the URL prefix and append the rest of the data in the descriptor.
533 std::string url;
534 switch (bytes[2]) {
535 case 0:
536 url.append("http://");
537 break;
538 case 1:
539 url.append("https://");
540 break;
541 default:
542 return false;
543 }
544 url.append(reinterpret_cast<const char*>(bytes.data() + 3), length - 3);
545
546 *output = GURL(url);
547 if (!output->is_valid()) {
548 return false;
549 }
550
551 return true;
552 }
553
554 void ReadWebUsbDescriptors(scoped_refptr<UsbDeviceHandle> device_handle,
555 const ReadWebUsbDescriptorsCallback& callback) {
556 scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(5);
557 device_handle->ControlTransfer(
558 USB_DIRECTION_INBOUND, UsbDeviceHandle::STANDARD, UsbDeviceHandle::DEVICE,
559 kGetDescriptorRequest, kBosDescriptorType << 8, 0, buffer, buffer->size(),
560 kControlTransferTimeout,
561 base::Bind(&OnReadBosDescriptorHeader, device_handle, callback));
302 } 562 }
303 563
304 } // namespace device 564 } // 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