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

Unified 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: Comment tweaks. 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: device/usb/webusb_descriptors.cc
diff --git a/device/usb/webusb_descriptors.cc b/device/usb/webusb_descriptors.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f64b4db23e5da9b7f808a7f900d835d30471be98
--- /dev/null
+++ b/device/usb/webusb_descriptors.cc
@@ -0,0 +1,290 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <iterator>
+
+#include "base/logging.h"
+#include "device/usb/webusb_descriptors.h"
+
+namespace device {
+
+namespace {
+
+// These constants are defined by the Universal Serial Device 3.0 Specification
+// Revision 1.0.
+const uint8_t kBosDescriptorType = 0x0F;
+const uint8_t kDeviceCapabilityDescriptorType = 0x10;
+
+const uint8_t kPlatformDevCapabilityType = 0x05;
+
+// These constants are defined by the WebUSB specification:
+// http://reillyeon.github.io/webusb/
+const uint8_t kWebUsbCapabilityUUID[16] = {
+ // Little-endian encoding of {3408b638-09a9-47a0-8bfd-a0768815b665}.
+ 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,
+ 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65};
+
+const uint8_t kDescriptorSetDescriptorType = 0x00;
+const uint8_t kConfigurationSubsetDescriptorType = 0x01;
+const uint8_t kFunctionSubsetDescriptorType = 0x02;
+const uint8_t kUrlDescriptorType = 0x03;
+
+bool ParseUrl(GURL* url,
+ std::vector<uint8_t>::const_iterator* it,
+ std::vector<uint8_t>::const_iterator end) {
+ // These conditions must be guaranteed by the caller.
+ DCHECK(*it != end);
+ uint8_t length = (*it)[0];
+ DCHECK_LE(length, std::distance(*it, end));
+ DCHECK_GE(length, 2);
+ DCHECK_EQ((*it)[1], kUrlDescriptorType);
+
+ if (length == 2) {
+ return false;
+ }
+
+ const char* str = reinterpret_cast<const char*>(&(*it)[2]);
+ *url = GURL(std::string(str, length - 2));
+ if (!url->is_valid()) {
+ return false;
+ }
+
+ std::advance(*it, length);
+ return true;
+}
+
+bool ParseFunction(WebUsbFunctionSubset* function,
+ std::vector<uint8_t>::const_iterator* it,
+ std::vector<uint8_t>::const_iterator end) {
+ // These conditions must be guaranteed by the caller.
+ DCHECK(*it != end);
+ uint8_t length = (*it)[0];
+ DCHECK_LE(length, std::distance(*it, end));
+ DCHECK_GE(length, 2);
+ DCHECK_EQ((*it)[1], kFunctionSubsetDescriptorType);
+
+ if (length != 5) {
+ return false;
+ }
+
+ function->first_interface = (*it)[2];
+
+ // Validate the Function Subset header.
+ uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
+ if (length > total_length || total_length > std::distance(*it, end)) {
+ return false;
+ }
+
+ end = *it + total_length;
+ std::advance(*it, length);
+
+ while (*it != end) {
+ uint8_t length = (*it)[0];
+ if (length < 2 || std::distance(*it, end) < length) {
+ return false;
+ }
+
+ uint8_t type = (*it)[1];
+ if (type == kUrlDescriptorType) {
+ GURL origin;
+ if (!ParseUrl(&origin, it, end)) {
+ return false;
+ }
+ function->origins.push_back(origin);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ParseConfiguration(WebUsbConfigurationSubset* configuration,
+ std::vector<uint8_t>::const_iterator* it,
+ std::vector<uint8_t>::const_iterator end) {
+ // These conditions must be guaranteed by the caller.
+ DCHECK(*it != end);
+ uint8_t length = (*it)[0];
+ DCHECK_LE(length, std::distance(*it, end));
+ DCHECK_GE(length, 2);
+ DCHECK_EQ((*it)[1], kConfigurationSubsetDescriptorType);
+
+ if (length != 5) {
+ return false;
+ }
+
+ configuration->configuration_value = (*it)[2];
+
+ // Validate the Configuration Subset header.
+ uint16_t total_length = (*it)[3] + ((*it)[4] << 8);
+ if (length > total_length || total_length > std::distance(*it, end)) {
+ return false;
+ }
+
+ end = *it + total_length;
+ std::advance(*it, length);
+
+ while (*it != end) {
+ uint8_t length = (*it)[0];
+ if (length < 2 || std::distance(*it, end) < length) {
+ return false;
+ }
+
+ uint8_t type = (*it)[1];
+ if (type == kFunctionSubsetDescriptorType) {
+ WebUsbFunctionSubset function;
+ if (!ParseFunction(&function, it, end)) {
+ return false;
+ }
+ configuration->functions.push_back(function);
+ } else if (type == kUrlDescriptorType) {
+ GURL origin;
+ if (!ParseUrl(&origin, it, end)) {
+ return false;
+ }
+ configuration->origins.push_back(origin);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+WebUsbFunctionSubset::WebUsbFunctionSubset() : first_interface(0) {}
+
+WebUsbFunctionSubset::~WebUsbFunctionSubset() {}
+
+WebUsbConfigurationSubset::WebUsbConfigurationSubset()
+ : configuration_value(0) {}
+
+WebUsbConfigurationSubset::~WebUsbConfigurationSubset() {}
+
+WebUsbDescriptorSet::WebUsbDescriptorSet() {}
+
+WebUsbDescriptorSet::~WebUsbDescriptorSet() {}
+
+bool WebUsbDescriptorSet::Parse(const std::vector<uint8_t>& bytes) {
+ if (bytes.size() < 4) {
+ return false;
+ }
+
+ // Validate the descriptor set header.
+ uint16_t total_length = bytes[2] + (bytes[3] << 8);
+ if (bytes[0] != 4 || // bLength
+ bytes[1] != kDescriptorSetDescriptorType || // bDescriptorType
+ 4 > total_length || total_length > bytes.size()) { // wTotalLength
+ return false;
+ }
+
+ std::vector<uint8_t>::const_iterator it = bytes.begin();
+ std::vector<uint8_t>::const_iterator end = it + total_length;
+ std::advance(it, 4);
+
+ while (it != bytes.end()) {
+ uint8_t length = it[0];
+ if (length < 2 || std::distance(it, end) < length) {
+ return false;
+ }
+
+ uint8_t type = it[1];
+ if (type == kConfigurationSubsetDescriptorType) {
+ WebUsbConfigurationSubset configuration;
+ if (!ParseConfiguration(&configuration, &it, end)) {
+ return false;
+ }
+ configurations.push_back(configuration);
+ } else if (type == kUrlDescriptorType) {
+ GURL origin;
+ if (!ParseUrl(&origin, &it, end)) {
+ return false;
+ }
+ origins.push_back(origin);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+WebUsbPlatformCapabilityDescriptor::WebUsbPlatformCapabilityDescriptor()
+ : version(0), vendor_code(0) {}
+
+WebUsbPlatformCapabilityDescriptor::~WebUsbPlatformCapabilityDescriptor() {}
+
+bool WebUsbPlatformCapabilityDescriptor::ParseFromBosDescriptor(
+ const std::vector<uint8_t>& bytes) {
+ if (bytes.size() < 5) {
+ // Too short for the BOS descriptor header.
+ return false;
+ }
+
+ // Validate the BOS descriptor, defined in Table 9-12 of the Universal Serial
+ // Bus 3.1 Specification, Revision 1.0.
+ uint16_t total_length = bytes[2] + (bytes[3] << 8);
+ if (bytes[0] != 5 || // bLength
+ bytes[1] != kBosDescriptorType || // bDescriptorType
+ 5 > total_length || total_length > bytes.size()) { // wTotalLength
+ return false;
+ }
+
+ uint8_t num_device_caps = bytes[4];
+ std::vector<uint8_t>::const_iterator it = bytes.begin();
+ std::vector<uint8_t>::const_iterator end = it + total_length;
+ std::advance(it, 5);
+
+ uint8_t length = 0;
+ bool found_vendor_code = false;
+ for (size_t i = 0; i < num_device_caps; ++i, std::advance(it, length)) {
+ if (it == end) {
+ return false;
+ }
+
+ // Validate the Device Capability descriptor, defined in Table 9-13 of the
+ // Universal Serial Bus 3.1 Specification, Revision 1.0.
+ length = it[0];
+ if (length < 3 || std::distance(it, end) < length || // bLength
+ it[1] != kDeviceCapabilityDescriptorType) { // bDescriptorType
+ return false;
+ }
+
+ if (it[2] != kPlatformDevCapabilityType) { // bDevCapabilityType
+ continue;
+ }
+
+ // Validate the Platform Capability Descriptor, defined in Table 9-18 of the
+ // Universal Serial Bus 3.1 Specification, Revision 1.0.
+ if (length < 20) {
+ // Platform capability descriptors must be at least 20 bytes.
+ return false;
+ }
+
+ if (memcmp(&it[4], kWebUsbCapabilityUUID, sizeof(kWebUsbCapabilityUUID)) !=
+ 0) { // PlatformCapabilityUUID
+ continue;
+ }
+
+ if (length < 23) {
+ // The WebUSB capability descriptor must be at least 23 bytes (to allow
+ // for future versions).
+ return false;
+ }
+
+ version = it[20] + (it[21] << 8); // bcdVersion
+ if (version < 0x0100) {
+ continue;
+ }
+
+ // Version 1.0 only defines a single field, bVendorCode.
+ vendor_code = it[22];
+ found_vendor_code = true;
+ }
+
+ return found_vendor_code;
+}
+
+} // namespace device
« 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