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.
7 #include "base/logging.h"
8 #include "device/usb/webusb_descriptors.h"
14 // These constants are defined by the Universal Serial Device 3.0 Specification
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.
38 uint8_t length
= (*it
)[0];
39 DCHECK_LE(length
, std::distance(*it
, end
));
41 DCHECK_EQ((*it
)[1], kUrlDescriptorType
);
47 const char* str
= reinterpret_cast<const char*>(&(*it
)[2]);
48 *url
= GURL(std::string(str
, length
- 2));
49 if (!url
->is_valid()) {
53 std::advance(*it
, length
);
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.
62 uint8_t length
= (*it
)[0];
63 DCHECK_LE(length
, std::distance(*it
, end
));
65 DCHECK_EQ((*it
)[1], kFunctionSubsetDescriptorType
);
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
)) {
79 end
= *it
+ total_length
;
80 std::advance(*it
, length
);
83 uint8_t length
= (*it
)[0];
84 if (length
< 2 || std::distance(*it
, end
) < length
) {
88 uint8_t type
= (*it
)[1];
89 if (type
== kUrlDescriptorType
) {
91 if (!ParseUrl(&url
, it
, end
)) {
94 function
->origins
.push_back(url
.GetOrigin());
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.
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
);
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
)) {
125 end
= *it
+ total_length
;
126 std::advance(*it
, length
);
129 uint8_t length
= (*it
)[0];
130 if (length
< 2 || std::distance(*it
, end
) < length
) {
134 uint8_t type
= (*it
)[1];
135 if (type
== kFunctionSubsetDescriptorType
) {
136 WebUsbFunctionSubset function
;
137 if (!ParseFunction(&function
, it
, end
)) {
140 configuration
->functions
.push_back(function
);
141 } else if (type
== kUrlDescriptorType
) {
143 if (!ParseUrl(&url
, it
, end
)) {
146 configuration
->origins
.push_back(url
.GetOrigin());
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) {
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
183 std::vector
<uint8_t>::const_iterator it
= bytes
.begin();
184 std::vector
<uint8_t>::const_iterator end
= it
+ total_length
;
187 while (it
!= bytes
.end()) {
188 uint8_t length
= it
[0];
189 if (length
< 2 || std::distance(it
, end
) < length
) {
193 uint8_t type
= it
[1];
194 if (type
== kConfigurationSubsetDescriptorType
) {
195 WebUsbConfigurationSubset configuration
;
196 if (!ParseConfiguration(&configuration
, &it
, end
)) {
199 configurations
.push_back(configuration
);
200 } else if (type
== kUrlDescriptorType
) {
202 if (!ParseUrl(&url
, &it
, end
)) {
205 origins
.push_back(url
.GetOrigin());
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.
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
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
;
241 bool found_vendor_code
= false;
242 for (size_t i
= 0; i
< num_device_caps
; ++i
, std::advance(it
, length
)) {
247 // Validate the Device Capability descriptor, defined in Table 9-13 of the
248 // Universal Serial Bus 3.1 Specification, Revision 1.0.
250 if (length
< 3 || std::distance(it
, end
) < length
|| // bLength
251 it
[1] != kDeviceCapabilityDescriptorType
) { // bDescriptorType
255 if (it
[2] != kPlatformDevCapabilityType
) { // bDevCapabilityType
259 // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
260 // Universal Serial Bus 3.1 Specification, Revision 1.0.
262 // Platform capability descriptors must be at least 20 bytes.
266 if (memcmp(&it
[4], kWebUsbCapabilityUUID
, sizeof(kWebUsbCapabilityUUID
)) !=
267 0) { // PlatformCapabilityUUID
272 // The WebUSB capability descriptor must be at least 23 bytes (to allow
273 // for future versions).
277 version
= it
[20] + (it
[21] << 8); // bcdVersion
278 if (version
< 0x0100) {
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) {
294 uint8_t length
= bytes
[0];
295 if (length
!= bytes
.size() || bytes
[1] != kUrlDescriptorType
) {
298 std::vector
<uint8_t>::const_iterator it
= bytes
.begin();
299 return ParseUrl(output
, &it
, bytes
.end());
302 } // namespace device