Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / device / usb / webusb_descriptors.cc
blob034a1197625f4b1f7823eefee3162e79ab345e13
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.
5 #include <iterator>
7 #include "base/logging.h"
8 #include "device/usb/webusb_descriptors.h"
10 namespace device {
12 namespace {
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;
19 const uint8_t kPlatformDevCapabilityType = 0x05;
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};
28 const uint8_t kDescriptorSetDescriptorType = 0x00;
29 const uint8_t kConfigurationSubsetDescriptorType = 0x01;
30 const uint8_t kFunctionSubsetDescriptorType = 0x02;
31 const uint8_t kUrlDescriptorType = 0x03;
33 bool ParseUrl(GURL* url,
34 std::vector<uint8_t>::const_iterator* it,
35 std::vector<uint8_t>::const_iterator end) {
36 // These conditions must be guaranteed by the caller.
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);
43 if (length == 2) {
44 return false;
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;
53 std::advance(*it, length);
54 return true;
57 bool ParseFunction(WebUsbFunctionSubset* function,
58 std::vector<uint8_t>::const_iterator* it,
59 std::vector<uint8_t>::const_iterator end) {
60 // These conditions must be guaranteed by the caller.
61 DCHECK(*it != end);
62 uint8_t length = (*it)[0];
63 DCHECK_LE(length, std::distance(*it, end));
64 DCHECK_GE(length, 2);
65 DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType);
67 if (length != 5) {
68 return false;
71 function->first_interface = (*it)[2];
73 // Validate the Function Subset header.
74 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
75 if (length > total_length || total_length > std::distance(*it, end)) {
76 return false;
79 end = *it + total_length;
80 std::advance(*it, length);
82 while (*it != end) {
83 uint8_t length = (*it)[0];
84 if (length < 2 || std::distance(*it, end) < length) {
85 return false;
88 uint8_t type = (*it)[1];
89 if (type == kUrlDescriptorType) {
90 GURL url;
91 if (!ParseUrl(&url, it, end)) {
92 return false;
94 function->origins.push_back(url.GetOrigin());
95 } else {
96 return false;
100 return true;
103 bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
104 std::vector<uint8_t>::const_iterator* it,
105 std::vector<uint8_t>::const_iterator end) {
106 // These conditions must be guaranteed by the caller.
107 DCHECK(*it != end);
108 uint8_t length = (*it)[0];
109 DCHECK_LE(length, std::distance(*it, end));
110 DCHECK_GE(length, 2);
111 DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType);
113 if (length != 5) {
114 return false;
117 configuration->configuration_value = (*it)[2];
119 // Validate the Configuration Subset header.
120 uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
121 if (length > total_length || total_length > std::distance(*it, end)) {
122 return false;
125 end = *it + total_length;
126 std::advance(*it, length);
128 while (*it != end) {
129 uint8_t length = (*it)[0];
130 if (length < 2 || std::distance(*it, end) < length) {
131 return false;
134 uint8_t type = (*it)[1];
135 if (type == kFunctionSubsetDescriptorType) {
136 WebUsbFunctionSubset function;
137 if (!ParseFunction(&function, it, end)) {
138 return false;
140 configuration->functions.push_back(function);
141 } else if (type == kUrlDescriptorType) {
142 GURL url;
143 if (!ParseUrl(&url, it, end)) {
144 return false;
146 configuration->origins.push_back(url.GetOrigin());
147 } else {
148 return false;
152 return true;
155 } // namespace
157 WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
159 WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
161 WebUsbConfigurationSubset::WebUsbConfigurationSubset()
162 : configuration_value(0) {}
164 WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
166 WebUsbDescriptorSet::WebUsbDescriptorSet() {}
168 WebUsbDescriptorSet::~WebUsbDescriptorSet() {}
170 bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) {
171 if (bytes.size() < 4) {
172 return false;
175 // Validate the descriptor set header.
176 uint16_t total_length = bytes[2] + (bytes[3] << 8);
177 if (bytes[0] != 4 || // bLength
178 bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType
179 4 > total_length || total_length > bytes.size()) { // wTotalLength
180 return false;
183 std::vector<uint8_t>::const_iterator it = bytes.begin();
184 std::vector<uint8_t>::const_iterator end = it + total_length;
185 std::advance(it, 4);
187 while (it != bytes.end()) {
188 uint8_t length = it[0];
189 if (length < 2 || std::distance(it, end) < length) {
190 return false;
193 uint8_t type = it[1];
194 if (type == kConfigurationSubsetDescriptorType) {
195 WebUsbConfigurationSubset configuration;
196 if (!ParseConfiguration(&configuration, &it, end)) {
197 return false;
199 configurations.push_back(configuration);
200 } else if (type == kUrlDescriptorType) {
201 GURL url;
202 if (!ParseUrl(&url, &it, end)) {
203 return false;
205 origins.push_back(url.GetOrigin());
206 } else {
207 return false;
211 return true;
214 WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
215 : version(0), vendor_code(0) {}
217 WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {}
219 bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
220 const std::vector<uint8_t>& bytes) {
221 if (bytes.size() < 5) {
222 // Too short for the BOS descriptor header.
223 return false;
226 // Validate the BOS descriptor, defined in Table 9-12 of the Universal Serial
227 // Bus 3.1 Specification, Revision 1.0.
228 uint16_t total_length = bytes[2] + (bytes[3] << 8);
229 if (bytes[0] != 5 || // bLength
230 bytes[1] != kBosDescriptorType || // bDescriptorType
231 5 > total_length || total_length > bytes.size()) { // wTotalLength
232 return false;
235 uint8_t num_device_caps = bytes[4];
236 std::vector<uint8_t>::const_iterator it = bytes.begin();
237 std::vector<uint8_t>::const_iterator end = it + total_length;
238 std::advance(it, 5);
240 uint8_t length = 0;
241 bool found_vendor_code = false;
242 for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
243 if (it == end) {
244 return false;
247 // Validate the Device Capability descriptor, defined in Table 9-13 of the
248 // Universal Serial Bus 3.1 Specification, Revision 1.0.
249 length = it[0];
250 if (length < 3 || std::distance(it, end) < length || // bLength
251 it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType
252 return false;
255 if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType
256 continue;
259 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
260 // Universal Serial Bus 3.1 Specification, Revision 1.0.
261 if (length < 20) {
262 // Platform capability descriptors must be at least 20 bytes.
263 return false;
266 if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) !=
267 0) { // PlatformCapabilityUUID
268 continue;
271 if (length < 23) {
272 // The WebUSB capability descriptor must be at least 23 bytes (to allow
273 // for future versions).
274 return false;
277 version = it[20] + (it[21] << 8); // bcdVersion
278 if (version < 0x0100) {
279 continue;
282 // Version 1.0 only defines a single field, bVendorCode.
283 vendor_code = it[22];
284 found_vendor_code = true;
287 return found_vendor_code;
290 bool ParseWebUsbUrlDescriptor(const std::vector<uint8_t>& bytes, GURL* output) {
291 if (bytes.size() < 2) {
292 return false;
294 uint8_t length = bytes[0];
295 if (length != bytes.size() || bytes[1] != kUrlDescriptorType) {
296 return false;
298 std::vector<uint8_t>::const_iterator it = bytes.begin();
299 return ParseUrl(output, &it, bytes.end());
302 } // namespace device