summaryrefslogtreecommitdiff
path: root/chromium/device
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/device
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/device')
-rw-r--r--chromium/device/BUILD.gn7
-rw-r--r--chromium/device/OWNERS2
-rw-r--r--chromium/device/base/device_monitor_linux.cc2
-rw-r--r--chromium/device/bluetooth/BUILD.gn2
-rw-r--r--chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java18
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter.h8
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_factory_wrapper.cc4
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.h31
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.mm67
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm211
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_unittest.cc2
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.cc20
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.h3
-rw-r--r--chromium/device/bluetooth/bluetooth_device_unittest.cc56
-rw-r--r--chromium/device/bluetooth/bluetooth_device_winrt.cc75
-rw-r--r--chromium/device/bluetooth/bluetooth_device_winrt.h13
-rw-r--r--chromium/device/bluetooth/bluetooth_low_energy_device_mac.h3
-rw-r--r--chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm19
-rw-r--r--chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.h94
-rw-r--r--chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm153
-rw-r--r--chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc2
-rw-r--r--chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc2
-rw-r--r--chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc2
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc14
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h4
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc54
-rw-r--r--chromium/device/bluetooth/cast/OWNERS3
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc83
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_adapter_client.h28
-rw-r--r--chromium/device/bluetooth/dbus/bluez_dbus_manager.cc2
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc16
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h7
-rw-r--r--chromium/device/bluetooth/strings/BUILD.gn11
-rw-r--r--chromium/device/fido/BUILD.gn27
-rw-r--r--chromium/device/fido/DEPS1
-rw-r--r--chromium/device/fido/OWNERS23
-rw-r--r--chromium/device/fido/attestation_object.cc37
-rw-r--r--chromium/device/fido/attestation_object.h12
-rw-r--r--chromium/device/fido/attestation_statement.cc4
-rw-r--r--chromium/device/fido/attestation_statement.h6
-rw-r--r--chromium/device/fido/attestation_statement_formats.cc36
-rw-r--r--chromium/device/fido/attestation_statement_formats.h6
-rw-r--r--chromium/device/fido/attestation_statement_formats_unittest.cc20
-rw-r--r--chromium/device/fido/attested_credential_data.cc26
-rw-r--r--chromium/device/fido/attested_credential_data.h8
-rw-r--r--chromium/device/fido/authenticator_data.cc50
-rw-r--r--chromium/device/fido/authenticator_data.h13
-rw-r--r--chromium/device/fido/authenticator_get_assertion_response.cc18
-rw-r--r--chromium/device/fido/authenticator_get_info_response.cc14
-rw-r--r--chromium/device/fido/authenticator_make_credential_response.cc9
-rw-r--r--chromium/device/fido/authenticator_make_credential_response.h22
-rw-r--r--chromium/device/fido/authenticator_selection_criteria.cc4
-rw-r--r--chromium/device/fido/authenticator_selection_criteria.h14
-rw-r--r--chromium/device/fido/authenticator_supported_options.cc13
-rw-r--r--chromium/device/fido/authenticator_supported_options.h9
-rw-r--r--chromium/device/fido/ble/fido_ble_connection_unittest.cc2
-rw-r--r--chromium/device/fido/ble/fido_ble_device.cc23
-rw-r--r--chromium/device/fido/ble/fido_ble_device.h2
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery.cc96
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery.h26
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery_base.cc20
-rw-r--r--chromium/device/fido/ble/fido_ble_discovery_unittest.cc251
-rw-r--r--chromium/device/fido/ble/fido_ble_frames_unittest.cc9
-rw-r--r--chromium/device/fido/ble_adapter_manager_unittest.cc3
-rw-r--r--chromium/device/fido/cable/fido_cable_device_unittest.cc3
-rw-r--r--chromium/device/fido/cable/fido_cable_discovery_unittest.cc10
-rw-r--r--chromium/device/fido/cable/fido_cable_handshake_handler.cc17
-rw-r--r--chromium/device/fido/cable/fido_cable_handshake_handler_unittest.cc12
-rw-r--r--chromium/device/fido/ctap_get_assertion_request.cc169
-rw-r--r--chromium/device/fido/ctap_get_assertion_request.h29
-rw-r--r--chromium/device/fido/ctap_make_credential_request.cc212
-rw-r--r--chromium/device/fido/ctap_make_credential_request.h53
-rw-r--r--chromium/device/fido/ctap_request_unittest.cc75
-rw-r--r--chromium/device/fido/ctap_response_fuzzer.cc4
-rw-r--r--chromium/device/fido/ctap_response_unittest.cc73
-rw-r--r--chromium/device/fido/device_response_converter.cc15
-rw-r--r--chromium/device/fido/ec_public_key.cc16
-rw-r--r--chromium/device/fido/fake_fido_discovery.cc2
-rw-r--r--chromium/device/fido/fake_fido_discovery.h4
-rw-r--r--chromium/device/fido/fake_fido_discovery_unittest.cc7
-rw-r--r--chromium/device/fido/features.cc30
-rw-r--r--chromium/device/fido/features.h28
-rw-r--r--chromium/device/fido/fido_authenticator.h14
-rw-r--r--chromium/device/fido/fido_constants.cc5
-rw-r--r--chromium/device/fido/fido_constants.h29
-rw-r--r--chromium/device/fido/fido_device.cc4
-rw-r--r--chromium/device/fido/fido_device.h1
-rw-r--r--chromium/device/fido/fido_device_authenticator.cc73
-rw-r--r--chromium/device/fido/fido_device_authenticator.h11
-rw-r--r--chromium/device/fido/fido_device_discovery.cc124
-rw-r--r--chromium/device/fido/fido_device_discovery.h76
-rw-r--r--chromium/device/fido/fido_device_discovery_unittest.cc7
-rw-r--r--chromium/device/fido/fido_discovery_base.h10
-rw-r--r--chromium/device/fido/fido_discovery_factory.cc158
-rw-r--r--chromium/device/fido/fido_discovery_factory.h109
-rw-r--r--chromium/device/fido/fido_parsing_utils.h15
-rw-r--r--chromium/device/fido/fido_parsing_utils_unittest.cc112
-rw-r--r--chromium/device/fido/fido_request_handler.h8
-rw-r--r--chromium/device/fido/fido_request_handler_base.cc74
-rw-r--r--chromium/device/fido/fido_request_handler_base.h27
-rw-r--r--chromium/device/fido/fido_request_handler_unittest.cc61
-rw-r--r--chromium/device/fido/fido_test_data.h292
-rw-r--r--chromium/device/fido/get_assertion_handler_unittest.cc92
-rw-r--r--chromium/device/fido/get_assertion_request_handler.cc66
-rw-r--r--chromium/device/fido/get_assertion_request_handler.h7
-rw-r--r--chromium/device/fido/get_assertion_task_unittest.cc27
-rw-r--r--chromium/device/fido/hid/fake_hid_impl_for_testing.cc29
-rw-r--r--chromium/device/fido/hid/fake_hid_impl_for_testing.h24
-rw-r--r--chromium/device/fido/hid/fido_hid_device.cc3
-rw-r--r--chromium/device/fido/hid/fido_hid_discovery_unittest.cc58
-rw-r--r--chromium/device/fido/mac/OWNERS5
-rw-r--r--chromium/device/fido/mac/authenticator.h5
-rw-r--r--chromium/device/fido/mac/authenticator.mm12
-rw-r--r--chromium/device/fido/mac/browsing_data_deletion_unittest.mm4
-rw-r--r--chromium/device/fido/mac/credential_metadata.cc27
-rw-r--r--chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm6
-rw-r--r--chromium/device/fido/mac/make_credential_operation_unittest_mac.mm4
-rw-r--r--chromium/device/fido/mac/util.mm17
-rw-r--r--chromium/device/fido/make_credential_handler_unittest.cc55
-rw-r--r--chromium/device/fido/make_credential_request_handler.cc73
-rw-r--r--chromium/device/fido/make_credential_request_handler.h7
-rw-r--r--chromium/device/fido/make_credential_task.cc14
-rw-r--r--chromium/device/fido/make_credential_task_unittest.cc33
-rw-r--r--chromium/device/fido/mock_fido_discovery_observer.h4
-rw-r--r--chromium/device/fido/opaque_attestation_statement.cc22
-rw-r--r--chromium/device/fido/opaque_attestation_statement.h8
-rw-r--r--chromium/device/fido/public_key_credential_descriptor.cc21
-rw-r--r--chromium/device/fido/public_key_credential_descriptor.h6
-rw-r--r--chromium/device/fido/public_key_credential_params.cc15
-rw-r--r--chromium/device/fido/public_key_credential_params.h6
-rw-r--r--chromium/device/fido/public_key_credential_rp_entity.cc14
-rw-r--r--chromium/device/fido/public_key_credential_rp_entity.h6
-rw-r--r--chromium/device/fido/public_key_credential_user_entity.cc19
-rw-r--r--chromium/device/fido/public_key_credential_user_entity.h6
-rw-r--r--chromium/device/fido/scoped_virtual_fido_device.cc3
-rw-r--r--chromium/device/fido/scoped_virtual_fido_device.h4
-rw-r--r--chromium/device/fido/u2f_command_constructor.cc3
-rw-r--r--chromium/device/fido/u2f_command_constructor_unittest.cc11
-rw-r--r--chromium/device/fido/u2f_register_operation_unittest.cc2
-rw-r--r--chromium/device/fido/u2f_sign_operation_unittest.cc8
-rw-r--r--chromium/device/fido/virtual_ctap2_device.cc349
-rw-r--r--chromium/device/fido/virtual_ctap2_device.h23
-rw-r--r--chromium/device/fido/virtual_fido_device.cc10
-rw-r--r--chromium/device/fido/virtual_fido_device.h5
-rw-r--r--chromium/device/fido/win/authenticator.cc294
-rw-r--r--chromium/device/fido/win/authenticator.h72
-rw-r--r--chromium/device/fido/win/discovery.cc36
-rw-r--r--chromium/device/fido/win/discovery.h37
-rw-r--r--chromium/device/fido/win/fake_webauthn_api.cc71
-rw-r--r--chromium/device/fido/win/fake_webauthn_api.h70
-rw-r--r--chromium/device/fido/win/type_conversions.cc229
-rw-r--r--chromium/device/fido/win/type_conversions.h54
-rw-r--r--chromium/device/fido/win/webauthn_api.cc348
-rw-r--r--chromium/device/fido/win/webauthn_api.h116
-rw-r--r--chromium/device/gamepad/gamepad_provider.cc8
-rw-r--r--chromium/device/udev_linux/udev_watcher.cc4
-rw-r--r--chromium/device/usb/OWNERS2
-rw-r--r--chromium/device/usb/mojo/device_impl.cc11
-rw-r--r--chromium/device/usb/mojo/device_impl.h2
-rw-r--r--chromium/device/usb/mojo/device_manager_impl.cc18
-rw-r--r--chromium/device/usb/mojo/device_manager_impl.h4
-rw-r--r--chromium/device/usb/mojo/type_converters.cc1
-rw-r--r--chromium/device/usb/public/cpp/BUILD.gn1
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device.cc11
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device.h2
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device_info.cc16
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device_info.h7
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device_manager.cc7
-rw-r--r--chromium/device/usb/public/cpp/fake_usb_device_manager.h3
-rw-r--r--chromium/device/usb/public/mojom/BUILD.gn3
-rw-r--r--chromium/device/usb/public/mojom/device.mojom2
-rw-r--r--chromium/device/usb/public/mojom/device_manager.mojom5
-rw-r--r--chromium/device/usb/usb_device_handle_win.cc130
-rw-r--r--chromium/device/usb/usb_device_handle_win.h17
-rw-r--r--chromium/device/vr/BUILD.gn2
-rw-r--r--chromium/device/vr/PRESUBMIT.py24
-rw-r--r--chromium/device/vr/android/gvr/gvr_delegate_provider.h3
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.cc151
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.h12
-rw-r--r--chromium/device/vr/android/gvr/vr_module_delegate.cc28
-rw-r--r--chromium/device/vr/android/gvr/vr_module_delegate.h38
-rw-r--r--chromium/device/vr/oculus/oculus_device.cc2
-rw-r--r--chromium/device/vr/oculus/oculus_device.h2
-rw-r--r--chromium/device/vr/oculus/oculus_render_loop.cc9
-rw-r--r--chromium/device/vr/oculus/oculus_render_loop.h3
-rw-r--r--chromium/device/vr/openvr/openvr_device.cc2
-rw-r--r--chromium/device/vr/openvr/openvr_device.h2
-rw-r--r--chromium/device/vr/openvr/openvr_render_loop.cc24
-rw-r--r--chromium/device/vr/openvr/openvr_render_loop.h3
-rw-r--r--chromium/device/vr/orientation/orientation_device.cc2
-rw-r--r--chromium/device/vr/orientation/orientation_device.h2
-rw-r--r--chromium/device/vr/orientation/orientation_device_provider_unittest.cc5
-rw-r--r--chromium/device/vr/orientation/orientation_device_unittest.cc4
-rw-r--r--chromium/device/vr/public/mojom/isolated_xr_service.mojom4
-rw-r--r--chromium/device/vr/public/mojom/vr_service.mojom37
-rw-r--r--chromium/device/vr/vr_device_base.cc25
-rw-r--r--chromium/device/vr/vr_device_base.h9
-rw-r--r--chromium/device/vr/vr_device_base_unittest.cc6
-rw-r--r--chromium/device/vr/vr_display_impl.cc19
-rw-r--r--chromium/device/vr/vr_display_impl.h8
-rw-r--r--chromium/device/vr/vr_display_impl_unittest.cc2
201 files changed, 5088 insertions, 1825 deletions
diff --git a/chromium/device/BUILD.gn b/chromium/device/BUILD.gn
index 7edaa8891cd..fa1385f0e15 100644
--- a/chromium/device/BUILD.gn
+++ b/chromium/device/BUILD.gn
@@ -106,6 +106,13 @@ test("device_unittests") {
"test/run_all_unittests.cc",
]
+ if (is_fuchsia) {
+ sources += [
+ "bluetooth/test/bluetooth_test_fuchsia.cc",
+ "bluetooth/test/bluetooth_test_fuchsia.h",
+ ]
+ }
+
deps = [
"//base/test:test_support",
"//base/third_party/dynamic_annotations:dynamic_annotations",
diff --git a/chromium/device/OWNERS b/chromium/device/OWNERS
index 2d212568dac..a0f1773a4f8 100644
--- a/chromium/device/OWNERS
+++ b/chromium/device/OWNERS
@@ -1,5 +1,5 @@
reillyg@chromium.org
-rockot@chromium.org
+rockot@google.com
per-file BUILD.gn=*
diff --git a/chromium/device/base/device_monitor_linux.cc b/chromium/device/base/device_monitor_linux.cc
index d65d3e60293..1218bb1aeaa 100644
--- a/chromium/device/base/device_monitor_linux.cc
+++ b/chromium/device/base/device_monitor_linux.cc
@@ -84,6 +84,7 @@ void DeviceMonitorLinux::RemoveObserver(Observer* observer) {
void DeviceMonitorLinux::Enumerate(const EnumerateCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get()));
if (!enumerate) {
@@ -114,6 +115,7 @@ DeviceMonitorLinux::~DeviceMonitorLinux() {
void DeviceMonitorLinux::OnMonitorCanReadWithoutBlocking() {
DCHECK(thread_checker_.CalledOnValidThread());
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
ScopedUdevDevicePtr device(udev_monitor_receive_device(monitor_.get()));
if (!device)
return;
diff --git a/chromium/device/bluetooth/BUILD.gn b/chromium/device/bluetooth/BUILD.gn
index 96e66736e90..851b4f384f2 100644
--- a/chromium/device/bluetooth/BUILD.gn
+++ b/chromium/device/bluetooth/BUILD.gn
@@ -156,6 +156,8 @@ component("bluetooth") {
"bluetooth_low_energy_defs_win.h",
"bluetooth_low_energy_device_mac.h",
"bluetooth_low_energy_device_mac.mm",
+ "bluetooth_low_energy_device_watcher_mac.h",
+ "bluetooth_low_energy_device_watcher_mac.mm",
"bluetooth_low_energy_discovery_manager_mac.h",
"bluetooth_low_energy_discovery_manager_mac.mm",
"bluetooth_low_energy_peripheral_delegate.h",
diff --git a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
index 43d3f744cfe..da726ec8d0e 100644
--- a/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
+++ b/chromium/device/bluetooth/android/java/src/org/chromium/device/bluetooth/ChromeBluetoothDevice.java
@@ -131,12 +131,12 @@ final class ChromeBluetoothDevice {
@Override
public void run() {
if (newState == android.bluetooth.BluetoothProfile.STATE_CONNECTED) {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onConnectionStateChange.Status.Connected",
status);
mBluetoothGatt.discoverServices();
} else if (newState == android.bluetooth.BluetoothProfile.STATE_DISCONNECTED) {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onConnectionStateChange.Status.Disconnected",
status);
if (mBluetoothGatt != null) {
@@ -144,7 +144,7 @@ final class ChromeBluetoothDevice {
mBluetoothGatt = null;
}
} else {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onConnectionStateChange.Status.InvalidState",
status);
}
@@ -167,13 +167,13 @@ final class ChromeBluetoothDevice {
// When the device disconnects it deletes
// mBluetoothGatt, so we need to check it's not null.
if (mBluetoothGatt == null) {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onServicesDiscovered.Status."
+ "Disconnected",
status);
return;
}
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onServicesDiscovered.Status.Connected",
status);
@@ -231,7 +231,7 @@ final class ChromeBluetoothDevice {
// when the event races object destruction.
Log.v(TAG, "onCharacteristicRead when chromeCharacteristic == null.");
} else {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onCharacteristicRead.Status", status);
chromeCharacteristic.onCharacteristicRead(status);
}
@@ -253,7 +253,7 @@ final class ChromeBluetoothDevice {
// when the event races object destruction.
Log.v(TAG, "onCharacteristicWrite when chromeCharacteristic == null.");
} else {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onCharacteristicWrite.Status", status);
chromeCharacteristic.onCharacteristicWrite(status);
}
@@ -274,7 +274,7 @@ final class ChromeBluetoothDevice {
// when the event races object destruction.
Log.v(TAG, "onDescriptorRead when chromeDescriptor == null.");
} else {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onDescriptorRead.Status", status);
chromeDescriptor.onDescriptorRead(status);
}
@@ -295,7 +295,7 @@ final class ChromeBluetoothDevice {
// when the event races object destruction.
Log.v(TAG, "onDescriptorWrite when chromeDescriptor == null.");
} else {
- RecordHistogram.recordSparseSlowlyHistogram(
+ RecordHistogram.recordSparseHistogram(
"Bluetooth.Web.Android.onDescriptorWrite.Status", status);
chromeDescriptor.onDescriptorWrite(status);
}
diff --git a/chromium/device/bluetooth/bluetooth_adapter.h b/chromium/device/bluetooth/bluetooth_adapter.h
index a67ca355555..c0de60694fd 100644
--- a/chromium/device/bluetooth/bluetooth_adapter.h
+++ b/chromium/device/bluetooth/bluetooth_adapter.h
@@ -89,6 +89,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
// |device| changes:
// * GetAddress()
// * GetAppearance()
+ // * GetName() (Chrome OS and Windows only)
// * GetBluetoothClass()
// * GetInquiryRSSI()
// * GetInquiryTxPower()
@@ -151,6 +152,13 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
BluetoothDevice* device,
int16_t rssi,
const std::vector<uint8_t>& eir) {}
+
+ // This function is implemented for ChromeOS only.
+ // Called when |device|'s state has changed from connected to not connected
+ // or vice versa.
+ virtual void DeviceConnectedStateChanged(BluetoothAdapter* adapter,
+ BluetoothDevice* device,
+ bool is_now_connected) {}
#endif
// Called when the device |device| is removed from the adapter |adapter|,
diff --git a/chromium/device/bluetooth/bluetooth_adapter_factory_wrapper.cc b/chromium/device/bluetooth/bluetooth_adapter_factory_wrapper.cc
index bb06297d163..c1756cb4617 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_factory_wrapper.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_factory_wrapper.cc
@@ -16,7 +16,7 @@
namespace {
static base::LazyInstance<device::BluetoothAdapterFactoryWrapper>::Leaky
- g_singleton = LAZY_INSTANCE_INITIALIZER;
+ g_bluetooth_adapter_factory_wrapper_singleton = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -32,7 +32,7 @@ BluetoothAdapterFactoryWrapper::~BluetoothAdapterFactoryWrapper() {
// static
BluetoothAdapterFactoryWrapper& BluetoothAdapterFactoryWrapper::Get() {
- return g_singleton.Get();
+ return g_bluetooth_adapter_factory_wrapper_singleton.Get();
}
bool BluetoothAdapterFactoryWrapper::IsLowEnergySupported() {
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.h b/chromium/device/bluetooth/bluetooth_adapter_mac.h
index 3c13e213006..f5280d6f0bd 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.h
@@ -7,8 +7,10 @@
#include <IOKit/IOReturn.h>
+#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include "base/containers/hash_tables.h"
@@ -23,6 +25,7 @@
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h"
#include "device/bluetooth/bluetooth_low_energy_device_mac.h"
+#include "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
#include "device/bluetooth/bluetooth_low_energy_discovery_manager_mac.h"
#include "device/bluetooth/bluetooth_uuid.h"
@@ -120,12 +123,21 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterMac
void DidFailToConnectPeripheral(CBPeripheral* peripheral, NSError* error);
void DidDisconnectPeripheral(CBPeripheral* peripheral, NSError* error);
+ bool IsBluetoothLowEnergyDeviceSystemPaired(
+ base::StringPiece device_identifier) const;
+
protected:
+ using GetDevicePairedStatusCallback =
+ base::RepeatingCallback<bool(const std::string& address)>;
+
// BluetoothAdapter override:
bool SetPoweredImpl(bool powered) override;
void RemovePairingDelegateInternal(
device::BluetoothDevice::PairingDelegate* pairing_delegate) override;
+ void UpdateKnownLowEnergyDevices(
+ std::map<std::string, std::string> updated_low_energy_device_info);
+
private:
// Struct bundling information about the state of the HostController.
struct HostControllerState {
@@ -165,6 +177,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterMac
void SetPowerStateFunctionForTesting(
SetControllerPowerStateFunction power_state_function);
+ // Allow the mocking out of BluetoothLowEnergyDeviceWatcher for testing.
+ void SetLowEnergyDeviceWatcherForTesting(
+ scoped_refptr<BluetoothLowEnergyDeviceWatcherMac> watcher);
+
+ // Allow the mocking of out GetDevicePairedStatusCallback for testing.
+ void SetGetDevicePairedStatusCallbackForTesting(
+ GetDevicePairedStatusCallback callback);
+
// The length of time that must elapse since the last Inquiry response (on
// Classic devices) or call to BluetoothLowEnergyDevice::Update() (on Low
// Energy) before a discovered device is considered to be no longer available.
@@ -284,6 +304,17 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterMac
base::scoped_nsobject<BluetoothLowEnergyPeripheralManagerDelegate>
low_energy_peripheral_manager_delegate_;
+ GetDevicePairedStatusCallback device_paired_status_callback_;
+
+ // Watches system file /Library/Preferences/com.apple.Bluetooth.plist to
+ // obtain information about system paired bluetooth devices.
+ scoped_refptr<BluetoothLowEnergyDeviceWatcherMac>
+ bluetooth_low_energy_device_watcher_;
+
+ // Map of UUID formatted device identifiers of paired Bluetooth devices and
+ // corresponding device address.
+ std::map<std::string, std::string> low_energy_devices_info_;
+
base::WeakPtrFactory<BluetoothAdapterMac> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterMac);
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.mm b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
index 24a63be8a4b..fafb98764b5 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
@@ -21,7 +21,9 @@
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
+#include "base/task/task_traits.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "device/bluetooth/bluetooth_adapter_mac_metrics.h"
@@ -31,6 +33,7 @@
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_discovery_session_outcome.h"
#include "device/bluetooth/bluetooth_low_energy_central_manager_delegate.h"
+#include "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
#include "device/bluetooth/bluetooth_low_energy_peripheral_manager_delegate.h"
#include "device/bluetooth/bluetooth_socket_mac.h"
@@ -53,6 +56,12 @@ namespace {
// The frequency with which to poll the adapter for updates.
const int kPollIntervalMs = 500;
+bool IsDeviceSystemPaired(const std::string& device_address) {
+ IOBluetoothDevice* device = [IOBluetoothDevice
+ deviceWithAddressString:base::SysUTF8ToNSString(device_address)];
+ return device && [device isPaired];
+}
+
} // namespace
namespace device {
@@ -125,6 +134,8 @@ BluetoothAdapterMac::BluetoothAdapterMac()
should_update_name_(true),
classic_discovery_manager_(
BluetoothDiscoveryManagerMac::CreateClassic(this)),
+ device_paired_status_callback_(
+ base::BindRepeating(&IsDeviceSystemPaired)),
weak_ptr_factory_(this) {
if (IsLowEnergyAvailable()) {
low_energy_discovery_manager_.reset(
@@ -339,6 +350,28 @@ BluetoothAdapterMac::GetHostControllerState() {
return state;
}
+void BluetoothAdapterMac::UpdateKnownLowEnergyDevices(
+ std::map<std::string, std::string> updated_low_energy_devices_info) {
+ std::map<std::string, std::string> changed_devices;
+ // Notify DeviceChanged() to devices that have been newly paired as well as to
+ // devices that have been removed from the pairing list.
+ std::set_symmetric_difference(
+ updated_low_energy_devices_info.begin(),
+ updated_low_energy_devices_info.end(), low_energy_devices_info_.begin(),
+ low_energy_devices_info_.end(),
+ std::inserter(changed_devices, changed_devices.end()));
+
+ low_energy_devices_info_ = std::move(updated_low_energy_devices_info);
+ for (const auto& info : changed_devices) {
+ auto it = devices_.find(
+ BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(info.first));
+ if (it == devices_.end())
+ continue;
+
+ NotifyDeviceChanged(it->second.get());
+ }
+}
+
void BluetoothAdapterMac::SetCentralManagerForTesting(
CBCentralManager* central_manager) {
CHECK(BluetoothAdapterMac::IsLowEnergyAvailable());
@@ -366,6 +399,19 @@ void BluetoothAdapterMac::SetPowerStateFunctionForTesting(
power_state_function_ = std::move(power_state_function);
}
+void BluetoothAdapterMac::SetLowEnergyDeviceWatcherForTesting(
+ scoped_refptr<BluetoothLowEnergyDeviceWatcherMac>
+ bluetooth_low_energy_device_watcher) {
+ bluetooth_low_energy_device_watcher_ =
+ std::move(bluetooth_low_energy_device_watcher);
+ bluetooth_low_energy_device_watcher_->Init();
+}
+
+void BluetoothAdapterMac::SetGetDevicePairedStatusCallbackForTesting(
+ GetDevicePairedStatusCallback device_paired_status_callback) {
+ device_paired_status_callback_ = std::move(device_paired_status_callback);
+}
+
void BluetoothAdapterMac::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
@@ -496,6 +542,16 @@ void BluetoothAdapterMac::Init() {
low_energy_advertisement_manager_->Init(ui_task_runner_,
low_energy_peripheral_manager_);
PollAdapter();
+
+ // To obtain list of low energy devices known to the system, we need to parse
+ // and watch system property list file for paired device addresses.
+ bluetooth_low_energy_device_watcher_ =
+ BluetoothLowEnergyDeviceWatcherMac::CreateAndStartWatching(
+ ui_task_runner_,
+ base::BindRepeating(&BluetoothAdapterMac::UpdateKnownLowEnergyDevices,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ bluetooth_low_energy_device_watcher_->ReadBluetoothPropertyListFile();
}
void BluetoothAdapterMac::InitForTest(
@@ -795,6 +851,17 @@ void BluetoothAdapterMac::DidDisconnectPeripheral(CBPeripheral* peripheral,
device_mac->DidDisconnectPeripheral(error);
}
+bool BluetoothAdapterMac::IsBluetoothLowEnergyDeviceSystemPaired(
+ base::StringPiece device_identifier) const {
+ auto it = std::find_if(
+ low_energy_devices_info_.begin(), low_energy_devices_info_.end(),
+ [&](const auto& info) { return info.first == device_identifier; });
+ if (it == low_energy_devices_info_.end())
+ return false;
+
+ return device_paired_status_callback_.Run(it->second);
+}
+
BluetoothLowEnergyDeviceMac*
BluetoothAdapterMac::GetBluetoothLowEnergyDeviceMac(CBPeripheral* peripheral) {
std::string device_address =
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm b/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
index 05d44819034..3a5aca107ae 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac_unittest.mm
@@ -9,9 +9,15 @@
#include <memory>
#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter.h"
@@ -19,6 +25,7 @@
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_discovery_session_outcome.h"
#import "device/bluetooth/bluetooth_low_energy_device_mac.h"
+#include "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
#import "device/bluetooth/test/mock_bluetooth_cbperipheral_mac.h"
#import "device/bluetooth/test/mock_bluetooth_central_manager_mac.h"
#import "device/bluetooth/test/test_bluetooth_adapter_observer.h"
@@ -38,16 +45,71 @@ void IOBluetoothPreferenceSetControllerPowerState(int state);
}
namespace {
+
+const char kTestPropertyListFileName[] = "test_property_list_file.plist";
+
// |kTestHashAddress| is the hash corresponding to identifier |kTestNSUUID|.
const char kTestNSUUID[] = "00000000-1111-2222-3333-444444444444";
const char kTestHashAddress[] = "D1:6F:E3:22:FD:5B";
const int kTestRssi = 0;
+
+NSDictionary* CreateTestPropertyListData() {
+ return @{
+ @"CoreBluetoothCache" : @{
+ @"00000000-1111-2222-3333-444444444444" : @{
+ @"DeviceAddress" : @"22-22-22-22-22-22",
+ @"DeviceAddressType" : @1,
+ @"ServiceChangedHandle" : @3,
+ @"ServiceChangeSubscribed" : @0,
+ @"ServiceDiscoveryComplete" : @0
+ }
+ }
+ };
+}
+
+bool IsTestDeviceSystemPaired(const std::string& address) {
+ return true;
+}
+
} // namespace
namespace device {
class BluetoothAdapterMacTest : public testing::Test {
public:
+ class FakeBluetoothLowEnergyDeviceWatcherMac
+ : public BluetoothLowEnergyDeviceWatcherMac {
+ public:
+ FakeBluetoothLowEnergyDeviceWatcherMac(
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner,
+ LowEnergyDeviceListUpdatedCallback callback)
+ : BluetoothLowEnergyDeviceWatcherMac(ui_thread_task_runner, callback),
+ weak_ptr_factory_(this) {}
+
+ void SimulatePropertyListFileChanged(
+ const base::FilePath& path,
+ const std::string& changed_file_content) {
+ auto expected_file_size = changed_file_content.length();
+ ASSERT_EQ(static_cast<int>(expected_file_size),
+ base::WriteFile(path, changed_file_content.data(),
+ expected_file_size));
+ OnPropertyListFileChangedOnFileThread(path, false /* error */);
+ }
+
+ private:
+ ~FakeBluetoothLowEnergyDeviceWatcherMac() override = default;
+
+ void Init() override { ReadBluetoothPropertyListFile(); }
+
+ void ReadBluetoothPropertyListFile() override {
+ low_energy_device_list_updated_callback().Run(
+ ParseBluetoothDevicePropertyListData(CreateTestPropertyListData()));
+ }
+
+ base::WeakPtrFactory<FakeBluetoothLowEnergyDeviceWatcherMac>
+ weak_ptr_factory_;
+ };
+
BluetoothAdapterMacTest()
: ui_task_runner_(new base::TestSimpleTaskRunner()),
adapter_(new BluetoothAdapterMac()),
@@ -55,9 +117,25 @@ class BluetoothAdapterMacTest : public testing::Test {
observer_(adapter_),
callback_count_(0),
error_callback_count_(0) {
+ adapter_mac_->SetGetDevicePairedStatusCallbackForTesting(
+ base::BindRepeating(&IsTestDeviceSystemPaired));
adapter_mac_->InitForTest(ui_task_runner_);
+ fake_low_energy_device_watcher_ =
+ base::MakeRefCounted<FakeBluetoothLowEnergyDeviceWatcherMac>(
+ ui_task_runner_,
+ base::BindRepeating(
+ &BluetoothAdapterMac::UpdateKnownLowEnergyDevices,
+ adapter_mac_->weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ test_property_list_file_path_ =
+ temp_dir_.GetPath().AppendASCII(kTestPropertyListFileName);
}
+ void TearDown() override { scoped_task_environment_.RunUntilIdle(); }
+
// Helper methods for setup and access to BluetoothAdapterMacTest's members.
void PollAdapter() { adapter_mac_->PollAdapter(); }
@@ -141,6 +219,11 @@ class BluetoothAdapterMacTest : public testing::Test {
int NumDiscoverySessions() { return adapter_mac_->num_discovery_sessions_; }
+ void SetFakeLowEnergyDeviceWatcher() {
+ adapter_mac_->SetLowEnergyDeviceWatcherForTesting(
+ fake_low_energy_device_watcher_);
+ }
+
// Generic callbacks.
void Callback() { ++callback_count_; }
void ErrorCallback() { ++error_callback_count_; }
@@ -149,9 +232,12 @@ class BluetoothAdapterMacTest : public testing::Test {
}
protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_;
scoped_refptr<BluetoothAdapter> adapter_;
BluetoothAdapterMac* adapter_mac_;
+ scoped_refptr<FakeBluetoothLowEnergyDeviceWatcherMac>
+ fake_low_energy_device_watcher_;
TestBluetoothAdapterObserver observer_;
// Owned by |adapter_mac_|.
@@ -159,6 +245,8 @@ class BluetoothAdapterMacTest : public testing::Test {
int callback_count_;
int error_callback_count_;
+ base::ScopedTempDir temp_dir_;
+ base::FilePath test_property_list_file_path_;
};
// Test if private IOBluetooth APIs are callable on all supported macOS
@@ -314,4 +402,127 @@ TEST_F(BluetoothAdapterMacTest, LowEnergyDeviceUpdatedNewDevice) {
EXPECT_TRUE(DevicePresent(mock_peripheral));
}
+TEST_F(BluetoothAdapterMacTest, GetSystemPairedLowEnergyDevice) {
+ SetFakeLowEnergyDeviceWatcher();
+ ui_task_runner_->RunUntilIdle();
+ EXPECT_TRUE(
+ adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(kTestNSUUID));
+}
+
+TEST_F(BluetoothAdapterMacTest, GetNewlyPairedLowEnergyDevice) {
+ constexpr char kPropertyListFileContentWithAddedDevice[] =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+ "<plist version=\"1.0\">"
+ "<dict>"
+ " <key>CoreBluetoothCache</key>"
+ " <dict> "
+ " <key>E7F8589A-A7D9-4B94-9A08-D89076A159F4</key>"
+ " <dict> "
+ " <key>DeviceAddress</key>"
+ " <string>11-11-11-11-11-11</string>"
+ " <key>DeviceAddressType</key>"
+ " <integer>1</integer>"
+ " <key>ServiceChangedHandle</key>"
+ " <integer>3</integer>"
+ " <key>ServiceChangeSubscribed</key>"
+ " <integer>0</integer>"
+ " <key>ServiceDiscoveryComplete</key>"
+ " <integer>0</integer>"
+ " </dict>"
+ " <key>00000000-1111-2222-3333-444444444444</key>"
+ " <dict> "
+ " <key>DeviceAddress</key>"
+ " <string>22-22-22-22-22-22</string>"
+ " <key>DeviceAddressType</key>"
+ " <integer>1</integer>"
+ " <key>ServiceChangedHandle</key>"
+ " <integer>3</integer>"
+ " <key>ServiceChangeSubscribed</key>"
+ " <integer>0</integer>"
+ " <key>ServiceDiscoveryComplete</key>"
+ " <integer>0</integer>"
+ " </dict>"
+
+ " </dict>"
+ "</dict>"
+ "</plist>";
+
+ const char kTestAddedDeviceNSUUID[] = "E7F8589A-A7D9-4B94-9A08-D89076A159F4";
+
+ ASSERT_TRUE(SetMockCentralManager(CBCentralManagerStatePoweredOn));
+
+ base::scoped_nsobject<CBPeripheral> mock_peripheral_one(
+ CreateMockPeripheral(kTestNSUUID));
+ ASSERT_TRUE(mock_peripheral_one);
+
+ LowEnergyDeviceUpdated(
+ mock_peripheral_one,
+ base::scoped_nsobject<NSDictionary>(AdvertisementData()), kTestRssi);
+
+ base::scoped_nsobject<CBPeripheral> mock_peripheral_two(
+ CreateMockPeripheral(kTestAddedDeviceNSUUID));
+ ASSERT_TRUE(mock_peripheral_two);
+
+ LowEnergyDeviceUpdated(
+ mock_peripheral_two,
+ base::scoped_nsobject<NSDictionary>(AdvertisementData()), kTestRssi);
+ observer_.Reset();
+
+ // BluetoothAdapterMac only notifies observers of changed devices detected by
+ // BluetoothLowEnergyDeviceWatcherMac if the device has been already known to
+ // the system(i.e. the changed device is in BluetoothAdatper::devices_). As
+ // so, add mock devices prior to setting BluetoothLowenergyDeviceWatcherMac.
+ SetFakeLowEnergyDeviceWatcher();
+
+ EXPECT_EQ(1, observer_.device_changed_count());
+ observer_.Reset();
+
+ fake_low_energy_device_watcher_->SimulatePropertyListFileChanged(
+ test_property_list_file_path_, kPropertyListFileContentWithAddedDevice);
+ ui_task_runner_->RunUntilIdle();
+ EXPECT_EQ(1, observer_.device_changed_count());
+ EXPECT_TRUE(adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(
+ kTestAddedDeviceNSUUID));
+}
+
+TEST_F(BluetoothAdapterMacTest, NotifyObserverWhenDeviceIsUnpaired) {
+ constexpr char kPropertyListFileContentWithRemovedDevice[] =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+ "<plist version=\"1.0\">"
+ "<dict>"
+ " <key>CoreBluetoothCache</key>"
+ " <dict> "
+ " </dict>"
+ "</dict>"
+ "</plist>";
+
+ if (!SetMockCentralManager(CBCentralManagerStatePoweredOn))
+ return;
+
+ base::scoped_nsobject<CBPeripheral> mock_peripheral(
+ CreateMockPeripheral(kTestNSUUID));
+ if (!mock_peripheral)
+ return;
+
+ LowEnergyDeviceUpdated(
+ mock_peripheral, base::scoped_nsobject<NSDictionary>(AdvertisementData()),
+ kTestRssi);
+ observer_.Reset();
+
+ SetFakeLowEnergyDeviceWatcher();
+ EXPECT_EQ(1, observer_.device_changed_count());
+ observer_.Reset();
+
+ fake_low_energy_device_watcher_->SimulatePropertyListFileChanged(
+ test_property_list_file_path_, kPropertyListFileContentWithRemovedDevice);
+ ui_task_runner_->RunUntilIdle();
+ EXPECT_EQ(1, observer_.device_changed_count());
+ EXPECT_FALSE(
+ adapter_mac_->IsBluetoothLowEnergyDeviceSystemPaired(kTestNSUUID));
+}
+
} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
index 274ca34a628..25c725679d5 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -39,6 +39,8 @@
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
using device::BluetoothDevice;
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
index f53da79c97d..1052a6a8aaf 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -421,9 +421,8 @@ ComPtr<IBluetoothLEAdvertisement> GetAdvertisement(
return advertisement;
}
-base::Optional<std::string> GetDeviceName(
- IBluetoothLEAdvertisementReceivedEventArgs* received) {
- ComPtr<IBluetoothLEAdvertisement> advertisement = GetAdvertisement(received);
+base::Optional<std::string> ExtractDeviceName(
+ IBluetoothLEAdvertisement* advertisement) {
if (!advertisement)
return base::nullopt;
@@ -435,6 +434,10 @@ base::Optional<std::string> GetDeviceName(
return base::nullopt;
}
+ // Return early otherwise ScopedHString will create an empty string.
+ if (!local_name)
+ return base::nullopt;
+
return base::win::ScopedHString(local_name).GetAsUTF8();
}
@@ -449,6 +452,8 @@ void ExtractAndUpdateAdvertisementData(
}
ComPtr<IBluetoothLEAdvertisement> advertisement = GetAdvertisement(received);
+ static_cast<BluetoothDeviceWinrt*>(device)->UpdateLocalName(
+ ExtractDeviceName(advertisement.Get()));
device->UpdateAdvertisementData(rssi, ExtractFlags(advertisement.Get()),
ExtractAdvertisedUUIDs(advertisement.Get()),
ExtractTxPower(advertisement.Get()),
@@ -871,10 +876,8 @@ BluetoothAdapterWinrt::CreateAdvertisement() const {
}
std::unique_ptr<BluetoothDeviceWinrt> BluetoothAdapterWinrt::CreateDevice(
- uint64_t raw_address,
- base::Optional<std::string> local_name) {
- return std::make_unique<BluetoothDeviceWinrt>(this, raw_address,
- std::move(local_name));
+ uint64_t raw_address) {
+ return std::make_unique<BluetoothDeviceWinrt>(this, raw_address);
}
void BluetoothAdapterWinrt::OnGetDefaultAdapter(
@@ -1144,8 +1147,7 @@ void BluetoothAdapterWinrt::OnAdvertisementReceived(
if (is_new_device) {
bool was_inserted = false;
std::tie(it, was_inserted) = devices_.emplace(
- std::move(bluetooth_address),
- CreateDevice(raw_bluetooth_address, GetDeviceName(received)));
+ std::move(bluetooth_address), CreateDevice(raw_bluetooth_address));
DCHECK(was_inserted);
}
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.h b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
index 25611d511da..3daa169f8cf 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_winrt.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
@@ -117,8 +117,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
const;
virtual std::unique_ptr<BluetoothDeviceWinrt> CreateDevice(
- uint64_t raw_address,
- base::Optional<std::string> local_name);
+ uint64_t raw_address);
private:
void OnGetDefaultAdapter(
diff --git a/chromium/device/bluetooth/bluetooth_device_unittest.cc b/chromium/device/bluetooth/bluetooth_device_unittest.cc
index a443aeffba4..4e1d05c0804 100644
--- a/chromium/device/bluetooth/bluetooth_device_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_device_unittest.cc
@@ -26,6 +26,8 @@
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
namespace device {
@@ -291,6 +293,30 @@ TEST_F(BluetoothTest, LowEnergyDeviceProperties) {
base::ContainsKey(uuids, BluetoothUUID(kTestUUIDGenericAttribute)));
}
+// Verifies that the device name can be populated by later advertisement
+// packets and is persistent.
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrt, LowEnergyDeviceNameDelayed) {
+#else
+// This test does not yet pass on any other platform.
+TEST_F(BluetoothTest, DISABLED_LowEnergyDeviceNameDelayed) {
+#endif
+ if (!PlatformSupportsLowEnergy()) {
+ LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+ return;
+ }
+ InitWithFakeAdapter();
+ StartLowEnergyDiscoverySession();
+ BluetoothDevice* device = SimulateLowEnergyDevice(3);
+ ASSERT_TRUE(device);
+ // GetName() returns a base::Optional<std:string> however some backends still
+ // return an empty string rather than nullopt when no name is available.
+ EXPECT_TRUE(!device->GetName().has_value() || device->GetName()->empty());
+
+ SimulateLowEnergyDevice(1);
+ EXPECT_EQ(base::UTF8ToUTF16(kTestDeviceName), device->GetNameForDisplay());
+}
+
// Device with no advertised Service UUIDs.
#if defined(OS_WIN)
TEST_P(BluetoothTestWinrt, LowEnergyDeviceNoUUIDs) {
@@ -2128,4 +2154,34 @@ TEST_F(BluetoothTest, MAYBE_GetPrimaryServicesByUUID) {
}
}
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrtOnly, GattConnectedNameChange) {
+#else
+// The SimulateGattNameChange() function is not yet available on other
+// platforms.
+TEST_F(BluetoothTest, DISABLED_GattConnectedNameChange) {
+#endif
+ if (!PlatformSupportsLowEnergy()) {
+ LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+ return;
+ }
+ InitWithFakeAdapter();
+
+ StartLowEnergyDiscoverySession();
+ BluetoothDevice* device = SimulateLowEnergyDevice(3);
+ device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED),
+ GetConnectErrorCallback(Call::NOT_EXPECTED));
+ SimulateGattConnection(device);
+ base::RunLoop().RunUntilIdle();
+ // GetName() returns a base::Optional<std:string> however some backends still
+ // return an empty string rather than nullopt when no name is available.
+ EXPECT_TRUE(!device->GetName() || device->GetName()->empty());
+
+ TestBluetoothAdapterObserver observer(adapter_);
+ SimulateGattNameChange(device, kTestDeviceName);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1, observer.device_changed_count());
+ EXPECT_EQ(base::UTF8ToUTF16(kTestDeviceName), device->GetNameForDisplay());
+}
+
} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.cc b/chromium/device/bluetooth/bluetooth_device_winrt.cc
index 0313a90e235..da92568c452 100644
--- a/chromium/device/bluetooth/bluetooth_device_winrt.cc
+++ b/chromium/device/bluetooth/bluetooth_device_winrt.cc
@@ -136,24 +136,27 @@ void RemoveGattServicesChangedHandler(IBluetoothLEDevice* ble_device,
}
}
+void RemoveNameChangedHandler(IBluetoothLEDevice* ble_device,
+ EventRegistrationToken token) {
+ HRESULT hr = ble_device->remove_NameChanged(token);
+ if (FAILED(hr)) {
+ VLOG(2) << "Removing NameChanged Handler failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+}
+
} // namespace
-BluetoothDeviceWinrt::BluetoothDeviceWinrt(
- BluetoothAdapterWinrt* adapter,
- uint64_t raw_address,
- base::Optional<std::string> local_name)
+BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
+ uint64_t raw_address)
: BluetoothDevice(adapter),
raw_address_(raw_address),
address_(CanonicalizeAddress(raw_address)),
- local_name_(std::move(local_name)),
weak_ptr_factory_(this) {}
BluetoothDeviceWinrt::~BluetoothDeviceWinrt() {
CloseDevice(ble_device_);
- if (!connection_changed_token_)
- return;
-
- RemoveConnectionStatusHandler(ble_device_.Get(), *connection_changed_token_);
+ ClearEventRegistrations();
}
uint32_t BluetoothDeviceWinrt::GetBluetoothClass() const {
@@ -202,6 +205,10 @@ base::Optional<std::string> BluetoothDeviceWinrt::GetName() const {
return local_name_;
}
+ // Prefer returning |local_name_| over an empty string.
+ if (!name)
+ return local_name_;
+
return base::win::ScopedHString(name).GetAsUTF8();
}
@@ -404,6 +411,14 @@ std::string BluetoothDeviceWinrt::CanonicalizeAddress(uint64_t address) {
return bluetooth_address;
}
+void BluetoothDeviceWinrt::UpdateLocalName(
+ base::Optional<std::string> local_name) {
+ if (!local_name)
+ return;
+
+ local_name_ = std::move(local_name);
+}
+
void BluetoothDeviceWinrt::CreateGattConnectionImpl() {
ComPtr<IBluetoothLEDeviceStatics> device_statics;
HRESULT hr = GetBluetoothLEDeviceStaticsActivationFactory(&device_statics);
@@ -482,15 +497,12 @@ void BluetoothDeviceWinrt::OnFromBluetoothAddress(
return;
}
- if (connection_changed_token_) {
- // As we are about to replace |ble_device_| with |ble_device| we will also
- // unregister the existing event handler and add a new one to the new
- // device.
- RemoveConnectionStatusHandler(ble_device_.Get(),
- *connection_changed_token_);
- }
+ // As we are about to replace |ble_device_| with |ble_device| existing event
+ // handlers need to be unregistered. New ones will be added below.
+ ClearEventRegistrations();
ble_device_ = std::move(ble_device);
+
connection_changed_token_ = AddTypedEventHandler(
ble_device_.Get(), &IBluetoothLEDevice::add_ConnectionStatusChanged,
base::BindRepeating(&BluetoothDeviceWinrt::OnConnectionStatusChanged,
@@ -503,11 +515,6 @@ void BluetoothDeviceWinrt::OnFromBluetoothAddress(
if (IsGattConnected())
DidConnectGatt();
- if (gatt_services_changed_token_) {
- RemoveGattServicesChangedHandler(ble_device_.Get(),
- *gatt_services_changed_token_);
- }
-
gatt_services_changed_token_ = AddTypedEventHandler(
ble_device_.Get(), &IBluetoothLEDevice::add_GattServicesChanged,
base::BindRepeating(&BluetoothDeviceWinrt::OnGattServicesChanged,
@@ -520,6 +527,11 @@ void BluetoothDeviceWinrt::OnFromBluetoothAddress(
gatt_discoverer_->StartGattDiscovery(
base::BindOnce(&BluetoothDeviceWinrt::OnGattDiscoveryComplete,
weak_ptr_factory_.GetWeakPtr()));
+
+ name_changed_token_ = AddTypedEventHandler(
+ ble_device_.Get(), &IBluetoothLEDevice::add_NameChanged,
+ base::BindRepeating(&BluetoothDeviceWinrt::OnNameChanged,
+ weak_ptr_factory_.GetWeakPtr()));
}
void BluetoothDeviceWinrt::OnConnectionStatusChanged(
@@ -554,6 +566,12 @@ void BluetoothDeviceWinrt::OnGattServicesChanged(IBluetoothLEDevice* ble_device,
}
}
+void BluetoothDeviceWinrt::OnNameChanged(IBluetoothLEDevice* ble_device,
+ IInspectable* object) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ adapter_->NotifyDeviceChanged(this);
+}
+
void BluetoothDeviceWinrt::OnGattDiscoveryComplete(bool success) {
if (!success) {
if (!IsGattConnected())
@@ -600,4 +618,19 @@ void BluetoothDeviceWinrt::ClearGattServices() {
SetGattServicesDiscoveryComplete(false);
}
+void BluetoothDeviceWinrt::ClearEventRegistrations() {
+ if (connection_changed_token_) {
+ RemoveConnectionStatusHandler(ble_device_.Get(),
+ *connection_changed_token_);
+ }
+
+ if (gatt_services_changed_token_) {
+ RemoveGattServicesChangedHandler(ble_device_.Get(),
+ *gatt_services_changed_token_);
+ }
+
+ if (name_changed_token_)
+ RemoveNameChangedHandler(ble_device_.Get(), *name_changed_token_);
+}
+
} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.h b/chromium/device/bluetooth/bluetooth_device_winrt.h
index 93644ab66cd..c7fe84aad23 100644
--- a/chromium/device/bluetooth/bluetooth_device_winrt.h
+++ b/chromium/device/bluetooth/bluetooth_device_winrt.h
@@ -37,9 +37,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
static constexpr uint8_t k32BitServiceDataSection = 0x20;
static constexpr uint8_t k128BitServiceDataSection = 0x21;
- BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter,
- uint64_t raw_address,
- base::Optional<std::string> local_name);
+ BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter, uint64_t raw_address);
~BluetoothDeviceWinrt() override;
// BluetoothDevice:
@@ -91,6 +89,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
// each 'X' is a hex digit.
static std::string CanonicalizeAddress(uint64_t address);
+ // Called by BluetoothAdapterWinrt when an advertisement packet is received.
+ void UpdateLocalName(base::Optional<std::string> local_name);
+
protected:
// BluetoothDevice:
void CreateGattConnectionImpl() override;
@@ -117,9 +118,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice* ble_device,
IInspectable* object);
+ void OnNameChanged(
+ ABI::Windows::Devices::Bluetooth::IBluetoothLEDevice* ble_device,
+ IInspectable* object);
+
void OnGattDiscoveryComplete(bool success);
void ClearGattServices();
+ void ClearEventRegistrations();
uint64_t raw_address_;
std::string address_;
@@ -131,6 +137,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
base::Optional<EventRegistrationToken> connection_changed_token_;
base::Optional<EventRegistrationToken> gatt_services_changed_token_;
+ base::Optional<EventRegistrationToken> name_changed_token_;
THREAD_CHECKER(thread_checker_);
diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.h b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.h
index b6b6e59fe69..15b98aa4880 100644
--- a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.h
+++ b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.h
@@ -105,6 +105,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyDeviceMac
// we switch to using bluetooth identifiers throughout Chrome.
// http://crbug.com/507824
static std::string GetPeripheralHashAddress(CBPeripheral* peripheral);
+ static std::string GetPeripheralHashAddress(
+ base::StringPiece device_identifier);
private:
friend class BluetoothAdapterMac;
@@ -125,6 +127,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyDeviceMac
// Returns the Bluetooth adapter.
BluetoothAdapterMac* GetMacAdapter();
+ BluetoothAdapterMac* GetMacAdapter() const;
// Returns the CoreBluetooth Peripheral.
CBPeripheral* GetPeripheral();
diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm
index a65d9fe3932..8d9df355abc 100644
--- a/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm
+++ b/chromium/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -103,7 +103,7 @@ base::Optional<std::string> BluetoothLowEnergyDeviceMac::GetName() const {
}
bool BluetoothLowEnergyDeviceMac::IsPaired() const {
- return false;
+ return GetMacAdapter()->IsBluetoothLowEnergyDeviceSystemPaired(identifier_);
}
bool BluetoothLowEnergyDeviceMac::IsConnected() const {
@@ -409,12 +409,17 @@ std::string BluetoothLowEnergyDeviceMac::GetPeripheralIdentifier(
// static
std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(
CBPeripheral* peripheral) {
+ return GetPeripheralHashAddress(GetPeripheralIdentifier(peripheral));
+}
+
+// static
+std::string BluetoothLowEnergyDeviceMac::GetPeripheralHashAddress(
+ base::StringPiece device_identifier) {
const size_t kCanonicalAddressNumberOfBytes = 6;
char raw[kCanonicalAddressNumberOfBytes];
- crypto::SHA256HashString(GetPeripheralIdentifier(peripheral), raw,
- sizeof(raw));
- std::string hash = base::HexEncode(raw, sizeof(raw));
- return BluetoothDevice::CanonicalizeAddress(hash);
+ crypto::SHA256HashString(device_identifier, raw, sizeof(raw));
+ return BluetoothDevice::CanonicalizeAddress(
+ base::HexEncode(raw, sizeof(raw)));
}
void BluetoothLowEnergyDeviceMac::DidConnectPeripheral() {
@@ -463,6 +468,10 @@ BluetoothAdapterMac* BluetoothLowEnergyDeviceMac::GetMacAdapter() {
return static_cast<BluetoothAdapterMac*>(this->adapter_);
}
+BluetoothAdapterMac* BluetoothLowEnergyDeviceMac::GetMacAdapter() const {
+ return static_cast<BluetoothAdapterMac*>(this->adapter_);
+}
+
CBPeripheral* BluetoothLowEnergyDeviceMac::GetPeripheral() {
return peripheral_;
}
diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.h b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.h
new file mode 100644
index 00000000000..51cd3f96070
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.h
@@ -0,0 +1,94 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_DEVICE_WATCHER_MAC_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_DEVICE_WATCHER_MAC_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "base/task/post_task.h"
+#include "device/bluetooth/bluetooth_export.h"
+
+@class NSDictionary;
+
+namespace device {
+
+// Manages watching and reading system bluetooth property list file in
+// background thread to obtain a list of known Bluetooth low energy devices.
+class DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyDeviceWatcherMac
+ : public base::RefCountedThreadSafe<BluetoothLowEnergyDeviceWatcherMac> {
+ public:
+ using LowEnergyDeviceListUpdatedCallback =
+ base::RepeatingCallback<void(std::map<std::string, std::string>)>;
+
+ static scoped_refptr<BluetoothLowEnergyDeviceWatcherMac>
+ CreateAndStartWatching(
+ scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner,
+ LowEnergyDeviceListUpdatedCallback
+ update_low_energy_device_list_callback);
+
+ BluetoothLowEnergyDeviceWatcherMac(
+ scoped_refptr<base::SequencedTaskRunner> main_thread_task_runner,
+ LowEnergyDeviceListUpdatedCallback
+ update_low_energy_device_list_callback);
+
+ protected:
+ virtual ~BluetoothLowEnergyDeviceWatcherMac();
+
+ // Read system bluetooth property list file for change and fetches
+ // identifier and device address of system paired bluetooth devices.
+ void OnPropertyListFileChangedOnFileThread(const base::FilePath& path,
+ bool error);
+
+ // Overriden in tests.
+ virtual void Init();
+ virtual void ReadBluetoothPropertyListFile();
+
+ std::map<std::string, std::string> ParseBluetoothDevicePropertyListData(
+ NSDictionary* data);
+
+ LowEnergyDeviceListUpdatedCallback low_energy_device_list_updated_callback() {
+ return low_energy_device_list_updated_callback_;
+ }
+
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner() {
+ return ui_thread_task_runner_;
+ }
+
+ private:
+ friend class BluetoothAdapterMac;
+ friend class base::RefCountedThreadSafe<BluetoothLowEnergyDeviceWatcherMac>;
+
+ void AddBluetoothPropertyListFileWatcher();
+
+ static const base::FilePath& BluetoothPlistFilePath();
+
+ // Thread runner to watch, read, and parse bluetooth property list file.
+ scoped_refptr<base::SequencedTaskRunner> file_thread_task_runner_ =
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner_;
+ LowEnergyDeviceListUpdatedCallback low_energy_device_list_updated_callback_;
+ std::unique_ptr<base::FilePathWatcher> property_list_watcher_ =
+ std::make_unique<base::FilePathWatcher>();
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyDeviceWatcherMac);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_DEVICE_WATCHER_MAC_H_
diff --git a/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm
new file mode 100644
index 00000000000..955d36777f8
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_low_energy_device_watcher_mac.mm
@@ -0,0 +1,153 @@
+// Copyright 2018 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 "device/bluetooth/bluetooth_low_energy_device_watcher_mac.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/task/task_traits.h"
+#include "device/bluetooth/bluetooth_adapter_mac.h"
+
+namespace device {
+
+namespace {
+
+constexpr char kBluetoothPlistFilePath[] =
+ "/Library/Preferences/com.apple.Bluetooth.plist";
+
+} // namespace
+
+// static
+scoped_refptr<BluetoothLowEnergyDeviceWatcherMac>
+BluetoothLowEnergyDeviceWatcherMac::CreateAndStartWatching(
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner,
+ LowEnergyDeviceListUpdatedCallback
+ low_energy_device_list_updated_callback) {
+ auto watcher = base::MakeRefCounted<BluetoothLowEnergyDeviceWatcherMac>(
+ std::move(ui_thread_task_runner),
+ std::move(low_energy_device_list_updated_callback));
+ watcher->Init();
+ return watcher;
+}
+
+BluetoothLowEnergyDeviceWatcherMac::BluetoothLowEnergyDeviceWatcherMac(
+ scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner,
+ LowEnergyDeviceListUpdatedCallback low_energy_device_list_updated_callback)
+ : ui_thread_task_runner_(std::move(ui_thread_task_runner)),
+ low_energy_device_list_updated_callback_(
+ std::move(low_energy_device_list_updated_callback)) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+BluetoothLowEnergyDeviceWatcherMac::~BluetoothLowEnergyDeviceWatcherMac() {
+ file_thread_task_runner_->DeleteSoon(FROM_HERE,
+ property_list_watcher_.release());
+}
+
+void BluetoothLowEnergyDeviceWatcherMac::OnPropertyListFileChangedOnFileThread(
+ const base::FilePath& path,
+ bool error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (error) {
+ LOG(WARNING) << "Failed to read com.apple.Bluetooth.plist.";
+ return;
+ }
+
+ // Bluetooth property list file is expected to have the following format:
+ //
+ // "CoreBluetoothCache" => {
+ // "E7F8589A-A7D9-4B94-9A08-D89076A159F4" => {
+ // "DeviceAddress" => "11-11-11-11-11-11"
+ // "DeviceAddressType" => 1
+ // "ServiceChangedHandle" => 3
+ // "ServiceChangedSubscribed" => 0
+ // "ServiceDiscoveryComplete" => 0
+ // }
+ // "D3CAC59E-C501-4599-97DA-2DF491544EEE" => {
+ // "DeviceAddress" => "22-22-22-22-22-22"
+ // "DeviceAddressType" => 1
+ // "ServiceChangedHandle" => 3
+ // "ServiceChangedSubscribed" => 0
+ // "ServiceDiscoveryComplete" => 0
+ // }
+ // }
+ NSString* plist_file_path = base::SysUTF8ToNSString(path.value());
+ NSDictionary* bluetooth_info_dictionary =
+ [NSDictionary dictionaryWithContentsOfFile:plist_file_path];
+
+ // |bluetooth_info_dictionary| is nil if there was an error reading the file
+ // or if the content of the read file cannot be represented by a dictionary.
+ if (!bluetooth_info_dictionary)
+ return;
+
+ auto parsed_data =
+ ParseBluetoothDevicePropertyListData(bluetooth_info_dictionary);
+ ui_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(low_energy_device_list_updated_callback_,
+ std::move(parsed_data)));
+}
+
+void BluetoothLowEnergyDeviceWatcherMac::Init() {
+ file_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&BluetoothLowEnergyDeviceWatcherMac::
+ AddBluetoothPropertyListFileWatcher,
+ this));
+}
+
+void BluetoothLowEnergyDeviceWatcherMac::ReadBluetoothPropertyListFile() {
+ file_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&BluetoothLowEnergyDeviceWatcherMac::
+ OnPropertyListFileChangedOnFileThread,
+ this, BluetoothPlistFilePath(), false /* error */));
+}
+
+std::map<std::string, std::string>
+BluetoothLowEnergyDeviceWatcherMac::ParseBluetoothDevicePropertyListData(
+ NSDictionary* data) {
+ std::map<std::string, std::string> updated_low_energy_devices_info;
+ NSDictionary* low_energy_devices_info = data[@"CoreBluetoothCache"];
+ if (!low_energy_devices_info)
+ return updated_low_energy_devices_info;
+
+ for (NSString* identifier in low_energy_devices_info) {
+ NSDictionary* device_info = low_energy_devices_info[identifier];
+ if (!device_info)
+ continue;
+
+ NSString* raw_device_address = device_info[@"DeviceAddress"];
+ if (!raw_device_address)
+ continue;
+
+ NSString* formatted_device_address =
+ [raw_device_address stringByReplacingOccurrencesOfString:@"-"
+ withString:@":"];
+ updated_low_energy_devices_info[base::SysNSStringToUTF8(identifier)] =
+ base::SysNSStringToUTF8(formatted_device_address);
+ }
+
+ return updated_low_energy_devices_info;
+}
+
+// static
+const base::FilePath&
+BluetoothLowEnergyDeviceWatcherMac::BluetoothPlistFilePath() {
+ static const base::FilePath file_path(kBluetoothPlistFilePath);
+ return file_path;
+}
+
+void BluetoothLowEnergyDeviceWatcherMac::AddBluetoothPropertyListFileWatcher() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ property_list_watcher_->Watch(
+ BluetoothPlistFilePath(), false /* recursive */,
+ base::BindRepeating(&BluetoothLowEnergyDeviceWatcherMac::
+ OnPropertyListFileChangedOnFileThread,
+ this));
+}
+
+} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
index e6c286b2d5e..0f388cdabfa 100644
--- a/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
@@ -25,6 +25,8 @@
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
namespace device {
diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc
index 3c3e5d0726d..95f3d222208 100644
--- a/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_remote_gatt_descriptor_unittest.cc
@@ -18,6 +18,8 @@
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
namespace device {
diff --git a/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc b/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc
index 9574c4dd0cc..9969ed56bf8 100644
--- a/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_remote_gatt_service_unittest.cc
@@ -19,6 +19,8 @@
#include "device/bluetooth/test/bluetooth_test_cast.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
namespace device {
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index 81427385990..e570b92f0f4 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -690,6 +690,10 @@ void BluetoothAdapterBlueZ::DevicePropertyChanged(
NotifyDeviceAdvertisementReceived(device_bluez, properties->rssi.value(),
properties->eir.value());
+ if (property_name == properties->connected.name())
+ NotifyDeviceConnectedStateChanged(device_bluez,
+ properties->connected.value());
+
if (property_name == properties->services_resolved.name() &&
properties->services_resolved.value()) {
device_bluez->UpdateGattServices(object_path);
@@ -1152,6 +1156,16 @@ void BluetoothAdapterBlueZ::NotifyDeviceAdvertisementReceived(
observer.DeviceAdvertisementReceived(this, device, rssi, eir);
}
+void BluetoothAdapterBlueZ::NotifyDeviceConnectedStateChanged(
+ BluetoothDeviceBlueZ* device,
+ bool is_now_connected) {
+ DCHECK_EQ(device->adapter_, this);
+ DCHECK_EQ(device->IsConnected(), is_now_connected);
+
+ for (auto& observer : observers_)
+ observer.DeviceConnectedStateChanged(this, device, is_now_connected);
+}
+
void BluetoothAdapterBlueZ::UseProfile(
const BluetoothUUID& uuid,
const dbus::ObjectPath& device_path,
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
index 7c1cc85f0e3..ef5205c3f8e 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -172,6 +172,10 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
int16_t rssi,
const std::vector<uint8_t>& eir);
+ // Announce to observers that |device| has changed its connected state.
+ void NotifyDeviceConnectedStateChanged(BluetoothDeviceBlueZ* device,
+ bool is_now_connected);
+
// Returns the object path of the adapter.
const dbus::ObjectPath& object_path() const { return object_path_; }
diff --git a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index 3e36926a2ac..f3cf5d3b299 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -224,7 +225,7 @@ class BluetoothBlueZTest : public testing::Test {
// without using this function.
void DiscoverDevice(const std::string& address) {
ASSERT_TRUE(adapter_.get() != nullptr);
- ASSERT_TRUE(base::MessageLoop::current() != nullptr);
+ ASSERT_TRUE(base::MessageLoopCurrent::IsSet());
fake_bluetooth_device_client_->SetSimulationIntervalMs(10);
TestBluetoothAdapterObserver observer(adapter_);
@@ -981,10 +982,11 @@ TEST_F(BluetoothBlueZTest, UnexpectedChangesDuringMultipleDiscoverySessions) {
// bluez::FakeBluetoothAdapterClient's count should be only 1 and a single
// call to
// bluez::FakeBluetoothAdapterClient::StopDiscovery should work.
- fake_bluetooth_adapter_client_->StopDiscovery(
+ fake_bluetooth_adapter_client_->BluetoothAdapterClient::StopDiscovery(
dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
- GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
- base::Unretained(this)));
+ GetCallback(),
+ base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
+ base::Unretained(this)));
base::RunLoop().Run();
EXPECT_EQ(2, observer.discovering_changed_count());
EXPECT_EQ(4, callback_count_);
@@ -1090,10 +1092,11 @@ TEST_F(BluetoothBlueZTest, UnexpectedChangesDuringMultipleDiscoverySessions) {
// Stop discovery via D-Bus. The fake client's reference count will drop but
// the discovery state won't change since our BluetoothAdapter also just
// requested it via D-Bus.
- fake_bluetooth_adapter_client_->StopDiscovery(
+ fake_bluetooth_adapter_client_->BluetoothAdapterClient::StopDiscovery(
dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
- GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
- base::Unretained(this)));
+ GetCallback(),
+ base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
+ base::Unretained(this)));
base::RunLoop().Run();
EXPECT_EQ(5, observer.discovering_changed_count());
EXPECT_EQ(10, callback_count_);
@@ -1168,10 +1171,11 @@ TEST_F(BluetoothBlueZTest, InvalidatedDiscoverySessions) {
// should become inactive, but more importantly, we shouldn't run into any
// memory errors as the sessions that we explicitly deleted should get
// cleaned up.
- fake_bluetooth_adapter_client_->StopDiscovery(
+ fake_bluetooth_adapter_client_->BluetoothAdapterClient::StopDiscovery(
dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
- GetCallback(), base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
- base::Unretained(this)));
+ GetCallback(),
+ base::Bind(&BluetoothBlueZTest::DBusErrorCallback,
+ base::Unretained(this)));
base::RunLoop().Run();
EXPECT_EQ(2, observer.discovering_changed_count());
EXPECT_EQ(4, callback_count_);
@@ -2434,6 +2438,36 @@ TEST_F(BluetoothBlueZTest, DeviceAdvertisementReceived) {
EXPECT_EQ(1, observer.device_advertisement_received_count());
EXPECT_EQ(eir, observer.device_eir());
}
+
+TEST_F(BluetoothBlueZTest, DeviceConnectedStateChanged) {
+ GetAdapter();
+
+ fake_bluetooth_device_client_->CreateDevice(
+ dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+ BluetoothDevice* device =
+ adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress);
+ ASSERT_TRUE(device);
+
+ // Install an observer; expect DeviceConnectedStateChanged method to be
+ // called.
+ TestBluetoothAdapterObserver observer(adapter_);
+
+ bluez::FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+
+ // The device starts out disconnected.
+ EXPECT_FALSE(device->IsConnected());
+
+ properties->connected.ReplaceValue(true);
+ EXPECT_EQ(1u, observer.device_connected_state_changed_values().size());
+ EXPECT_TRUE(observer.device_connected_state_changed_values()[0]);
+
+ properties->connected.ReplaceValue(false);
+ EXPECT_EQ(2u, observer.device_connected_state_changed_values().size());
+ EXPECT_FALSE(observer.device_connected_state_changed_values()[1]);
+}
#endif
TEST_F(BluetoothBlueZTest, DeviceUuidsChanged) {
diff --git a/chromium/device/bluetooth/cast/OWNERS b/chromium/device/bluetooth/cast/OWNERS
index 999dc46f8d1..e3a9c035733 100644
--- a/chromium/device/bluetooth/cast/OWNERS
+++ b/chromium/device/bluetooth/cast/OWNERS
@@ -1,2 +1 @@
-slan@chromium.org
-bcf@chromium.org
+halliwell@chromium.org
diff --git a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
index 2829a2d045d..d0b09b2fb53 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
+++ b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
@@ -5,6 +5,7 @@
#include "device/bluetooth/dbus/bluetooth_adapter_client.h"
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/callback.h"
@@ -95,6 +96,31 @@ void WriteAttribute(dbus::MessageWriter* writer,
writer->CloseContainer(&struct_writer);
}
+BluetoothAdapterClient::Error ErrorResponseToError(
+ dbus::ErrorResponse* response) {
+ BluetoothAdapterClient::Error error(BluetoothAdapterClient::kNoResponseError,
+ "");
+ if (response) {
+ dbus::MessageReader reader(response);
+ error.name = response->GetErrorName();
+ reader.PopString(&error.message);
+ }
+
+ return error;
+}
+
+void OnResponseAdapter(
+ const base::Closure& callback,
+ BluetoothAdapterClient::ErrorCallback error_callback,
+ const base::Optional<BluetoothAdapterClient::Error>& error) {
+ if (!error) {
+ callback.Run();
+ return;
+ }
+
+ std::move(error_callback).Run(error->name, error->message);
+}
+
} // namespace
BluetoothAdapterClient::DiscoveryFilter::DiscoveryFilter() = default;
@@ -124,6 +150,10 @@ void BluetoothAdapterClient::DiscoveryFilter::CopyFrom(
uuids.reset();
}
+BluetoothAdapterClient::Error::Error(const std::string& name,
+ const std::string& message)
+ : name(name), message(message) {}
+
const char BluetoothAdapterClient::kNoResponseError[] =
"org.chromium.Error.NoResponse";
const char BluetoothAdapterClient::kUnknownAdapterError[] =
@@ -206,48 +236,40 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
// BluetoothAdapterClient override.
void StartDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) override {
+ ResponseCallback callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStartDiscovery);
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- std::move(error_callback).Run(kUnknownAdapterError, "");
+ std::move(callback).Run(Error(kUnknownAdapterError, ""));
return;
}
- object_proxy->CallMethodWithErrorCallback(
+ object_proxy->CallMethodWithErrorResponse(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
- weak_ptr_factory_.GetWeakPtr(), callback),
- base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(error_callback)));
+ base::BindOnce(&BluetoothAdapterClientImpl::OnResponse,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
// BluetoothAdapterClient override.
void StopDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) override {
+ ResponseCallback callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery);
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- std::move(error_callback).Run(kUnknownAdapterError, "");
+ std::move(callback).Run(Error(kUnknownAdapterError, ""));
return;
}
- object_proxy->CallMethodWithErrorCallback(
+ object_proxy->CallMethodWithErrorResponse(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
- weak_ptr_factory_.GetWeakPtr(), callback),
- base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(error_callback)));
+ base::BindOnce(&BluetoothAdapterClientImpl::OnResponse,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
// BluetoothAdapterClient override.
@@ -541,6 +563,17 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
std::move(error_callback).Run(error_name, error_message);
}
+ void OnResponse(ResponseCallback callback,
+ dbus::Response* response,
+ dbus::ErrorResponse* error_response) {
+ if (response) {
+ std::move(callback).Run(base::nullopt);
+ return;
+ }
+
+ std::move(callback).Run(ErrorResponseToError(error_response));
+ }
+
dbus::ObjectManager* object_manager_;
// List of observers interested in event notifications from us.
@@ -563,4 +596,18 @@ BluetoothAdapterClient* BluetoothAdapterClient::Create() {
return new BluetoothAdapterClientImpl;
}
+void BluetoothAdapterClient::StartDiscovery(const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ ErrorCallback error_callback) {
+ StartDiscovery(object_path, base::BindOnce(&OnResponseAdapter, callback,
+ std::move(error_callback)));
+}
+
+void BluetoothAdapterClient::StopDiscovery(const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ ErrorCallback error_callback) {
+ StopDiscovery(object_path, base::BindOnce(&OnResponseAdapter, callback,
+ std::move(error_callback)));
+}
+
} // namespace bluez
diff --git a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
index 03ff66d74f9..2415c80f5ac 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
+++ b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
@@ -12,6 +12,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "dbus/object_path.h"
#include "dbus/property.h"
#include "device/bluetooth/bluetooth_export.h"
@@ -47,6 +48,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
DISALLOW_COPY_AND_ASSIGN(DiscoveryFilter);
};
+ // Represent an error sent through DBus.
+ struct Error {
+ Error(const std::string& name, const std::string& message);
+
+ std::string name;
+ std::string message;
+ };
+
// Structure of properties associated with bluetooth adapters.
struct Properties : public dbus::PropertySet {
// The Bluetooth device address of the adapter. Read-only.
@@ -147,16 +156,27 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
const std::string& error_message)>
ErrorCallback;
+ // Callback used by adapter methods to indicate that a response was
+ // received with an optional Error in case an error occurred.
+ using ResponseCallback =
+ base::OnceCallback<void(const base::Optional<Error>&)>;
+
// Starts a device discovery on the adapter with object path |object_path|.
virtual void StartDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) = 0;
+ ResponseCallback callback) = 0;
+ // DEPRECATED: Use StartDiscovery() above.
+ void StartDiscovery(const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ ErrorCallback error_callback);
// Cancels any previous device discovery on the adapter with object path
// |object_path|.
virtual void StopDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) = 0;
+ ResponseCallback callback) = 0;
+ // DEPRECATED: Use StopDiscovery() above.
+ void StopDiscovery(const dbus::ObjectPath& object_path,
+ const base::Closure& callback,
+ ErrorCallback error_callback);
// Pauses all discovery sessions.
virtual void PauseDiscovery(const dbus::ObjectPath& object_path,
diff --git a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
index 4ae5de84dcc..c5683311d77 100644
--- a/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
+++ b/chromium/device/bluetooth/dbus/bluez_dbus_manager.cc
@@ -10,7 +10,7 @@
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
-#include "base/sys_info.h"
+#include "base/system/sys_info.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "dbus/bus.h"
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
index 573019b5028..9865d675651 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
@@ -134,18 +134,17 @@ FakeBluetoothAdapterClient::GetProperties(const dbus::ObjectPath& object_path) {
void FakeBluetoothAdapterClient::StartDiscovery(
const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) {
+ ResponseCallback callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
PostDelayedTask(
- base::BindOnce(std::move(error_callback), kNoResponseError, ""));
+ base::BindOnce(std::move(callback), Error(kNoResponseError, "")));
return;
}
++discovering_count_;
VLOG(1) << "StartDiscovery: " << object_path.value() << ", "
<< "count is now " << discovering_count_;
- PostDelayedTask(callback);
+ PostDelayedTask(base::BindOnce(std::move(callback), base::nullopt));
if (discovering_count_ == 1) {
properties_->discovering.ReplaceValue(true);
@@ -159,25 +158,24 @@ void FakeBluetoothAdapterClient::StartDiscovery(
void FakeBluetoothAdapterClient::StopDiscovery(
const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) {
+ ResponseCallback callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
PostDelayedTask(
- base::BindOnce(std::move(error_callback), kNoResponseError, ""));
+ base::BindOnce(std::move(callback), Error(kNoResponseError, "")));
return;
}
if (!discovering_count_) {
LOG(WARNING) << "StopDiscovery called when not discovering";
PostDelayedTask(
- base::BindOnce(std::move(error_callback), kNoResponseError, ""));
+ base::BindOnce(std::move(callback), Error(kNoResponseError, "")));
return;
}
--discovering_count_;
VLOG(1) << "StopDiscovery: " << object_path.value() << ", "
<< "count is now " << discovering_count_;
- PostDelayedTask(callback);
+ PostDelayedTask(base::BindOnce(std::move(callback), base::nullopt));
if (discovering_count_ == 0) {
FakeBluetoothDeviceClient* device_client =
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
index 59adc334a6a..c971c7a9362 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
@@ -5,6 +5,7 @@
#ifndef DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_ADAPTER_CLIENT_H_
#define DEVICE_BLUETOOTH_DBUS_FAKE_BLUETOOTH_ADAPTER_CLIENT_H_
+#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -49,11 +50,9 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothAdapterClient
std::vector<dbus::ObjectPath> GetAdapters() override;
Properties* GetProperties(const dbus::ObjectPath& object_path) override;
void StartDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) override;
+ ResponseCallback callback) override;
void StopDiscovery(const dbus::ObjectPath& object_path,
- const base::Closure& callback,
- ErrorCallback error_callback) override;
+ ResponseCallback callback) override;
void PauseDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
ErrorCallback error_callback) override;
diff --git a/chromium/device/bluetooth/strings/BUILD.gn b/chromium/device/bluetooth/strings/BUILD.gn
index 6eaeb0ce90b..7102935a46b 100644
--- a/chromium/device/bluetooth/strings/BUILD.gn
+++ b/chromium/device/bluetooth/strings/BUILD.gn
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//tools/grit/grit_rule.gni")
+import("//tools/grit/repack.gni")
grit("strings") {
source = "../bluetooth_strings.grd"
@@ -64,3 +65,13 @@ grit("strings") {
"bluetooth_strings_zh-TW.pak",
]
}
+
+repack("bluetooth_test_strings") {
+ sources = [
+ "$root_gen_dir/device/bluetooth/strings/bluetooth_strings_en-US.pak",
+ ]
+ output = "$root_out_dir/bluetooth_test_strings.pak"
+ deps = [
+ ":strings",
+ ]
+}
diff --git a/chromium/device/fido/BUILD.gn b/chromium/device/fido/BUILD.gn
index b1cbe9983ff..8572852222f 100644
--- a/chromium/device/fido/BUILD.gn
+++ b/chromium/device/fido/BUILD.gn
@@ -64,6 +64,8 @@ component("fido") {
"device_response_converter.h",
"ec_public_key.cc",
"ec_public_key.h",
+ "features.cc",
+ "features.h",
"fido_authenticator.h",
"fido_constants.cc",
"fido_constants.h",
@@ -75,6 +77,8 @@ component("fido") {
"fido_device_discovery.h",
"fido_discovery_base.cc",
"fido_discovery_base.h",
+ "fido_discovery_factory.cc",
+ "fido_discovery_factory.h",
"fido_parsing_utils.cc",
"fido_parsing_utils.h",
"fido_request_handler.h",
@@ -138,6 +142,7 @@ component("fido") {
"//services/service_manager/public/cpp",
"//services/service_manager/public/mojom",
"//third_party/boringssl",
+ "//third_party/microsoft_webauthn",
"//ui/base",
]
@@ -193,6 +198,19 @@ component("fido") {
"Security.framework",
]
}
+
+ if (is_win) {
+ sources += [
+ "win/authenticator.cc",
+ "win/authenticator.h",
+ "win/discovery.cc",
+ "win/discovery.h",
+ "win/type_conversions.cc",
+ "win/type_conversions.h",
+ "win/webauthn_api.cc",
+ "win/webauthn_api.h",
+ ]
+ }
}
source_set("mocks") {
@@ -280,6 +298,8 @@ source_set("test_support") {
"//device/fido",
"//mojo/public/cpp/bindings",
"//services/device/public/mojom",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/mojom",
"//testing/gmock",
"//testing/gtest",
]
@@ -302,4 +322,11 @@ source_set("test_support") {
"mac/scoped_touch_id_test_environment.mm",
]
}
+
+ if (is_win) {
+ sources += [
+ "win/fake_webauthn_api.cc",
+ "win/fake_webauthn_api.h",
+ ]
+ }
}
diff --git a/chromium/device/fido/DEPS b/chromium/device/fido/DEPS
index 3d3a449eff9..18edc13fd28 100644
--- a/chromium/device/fido/DEPS
+++ b/chromium/device/fido/DEPS
@@ -6,4 +6,5 @@ include_rules = [
"+net/cert",
"+ui/base/l10n",
"+third_party/boringssl/src/include",
+ "+third_party/microsoft_webauthn",
]
diff --git a/chromium/device/fido/OWNERS b/chromium/device/fido/OWNERS
index 48920ce5d4d..6e1ff3c9d85 100644
--- a/chromium/device/fido/OWNERS
+++ b/chromium/device/fido/OWNERS
@@ -1,8 +1,23 @@
-reillyg@chromium.org
-jdoerrie@chromium.org
-engedy@chromium.org
+# Webauthn OWNERS
+
+# General, esp chrome/ UI and Android integration.
kpaulhamus@chromium.org
+
+# General, esp U2F and CTAP2 code.
hongjunchoi@chromium.org
-# TEAM: security-dev@chromium.org
+# TouchID, Windows Hello.
+martinkr@chromium.org
+
+# Bluetooth.
+jdoerrie@chromium.org
+
+# Attestation and legacy U2F implementation.
+agl@chromium.org
+
+# Emeritus; for occasional reviews, esp those in the depths of view & frame
+# lifetimes.
+engedy@chromium.org
+
+# TEAM: identity-dev@chromium.org
# COMPONENT: Blink>WebAuthentication
diff --git a/chromium/device/fido/attestation_object.cc b/chromium/device/fido/attestation_object.cc
index 217ee4d6c33..552223aa14f 100644
--- a/chromium/device/fido/attestation_object.cc
+++ b/chromium/device/fido/attestation_object.cc
@@ -6,8 +6,8 @@
#include <utility>
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "device/fido/attestation_statement.h"
#include "device/fido/fido_constants.h"
@@ -29,17 +29,22 @@ std::vector<uint8_t> AttestationObject::GetCredentialId() const {
return authenticator_data_.GetCredentialId();
}
-void AttestationObject::EraseAttestationStatement() {
+void AttestationObject::EraseAttestationStatement(
+ AttestationObject::AAGUID erase_aaguid) {
attestation_statement_ = std::make_unique<NoneAttestationStatement>();
- authenticator_data_.DeleteDeviceAaguid();
+ if (erase_aaguid == AAGUID::kErase) {
+ authenticator_data_.DeleteDeviceAaguid();
+ }
// Attested credential data is optional section within authenticator data. But
// if present, the first 16 bytes of it represents a device AAGUID which must
-// be set to zeros for none attestation statement format.
+// be set to zeros for none attestation statement format, unless explicitly
+// requested otherwise (we make an exception for platform authenticators).
#if DCHECK_IS_ON()
if (!authenticator_data_.attested_data())
return;
- DCHECK(authenticator_data_.attested_data()->IsAaguidZero());
+ DCHECK(erase_aaguid == AAGUID::kInclude ||
+ authenticator_data_.attested_data()->IsAaguidZero());
#endif
}
@@ -59,24 +64,24 @@ bool AttestationObject::IsAttestationCertificateInappropriatelyIdentifying() {
}
std::vector<uint8_t> AttestationObject::SerializeToCBOREncodedBytes() const {
- cbor::CBORValue::MapValue map;
- map[cbor::CBORValue(kFormatKey)] =
- cbor::CBORValue(attestation_statement_->format_name());
- map[cbor::CBORValue(kAuthDataKey)] =
- cbor::CBORValue(authenticator_data_.SerializeToByteArray());
- map[cbor::CBORValue(kAttestationStatementKey)] =
- cbor::CBORValue(attestation_statement_->GetAsCBORMap());
- return cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)))
+ cbor::Value::MapValue map;
+ map[cbor::Value(kFormatKey)] =
+ cbor::Value(attestation_statement_->format_name());
+ map[cbor::Value(kAuthDataKey)] =
+ cbor::Value(authenticator_data_.SerializeToByteArray());
+ map[cbor::Value(kAttestationStatementKey)] =
+ cbor::Value(attestation_statement_->GetAsCBORMap());
+ return cbor::Writer::Write(cbor::Value(std::move(map)))
.value_or(std::vector<uint8_t>());
}
std::vector<uint8_t> SerializeToCtapStyleCborEncodedBytes(
const AttestationObject& object) {
- cbor::CBORValue::MapValue map;
+ cbor::Value::MapValue map;
map.emplace(1, object.attestation_statement().format_name());
map.emplace(2, object.authenticator_data().SerializeToByteArray());
map.emplace(3, object.attestation_statement().GetAsCBORMap());
- auto encoded_bytes = cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+ auto encoded_bytes = cbor::Writer::Write(cbor::Value(std::move(map)));
DCHECK(encoded_bytes);
return std::move(*encoded_bytes);
}
diff --git a/chromium/device/fido/attestation_object.h b/chromium/device/fido/attestation_object.h
index 36f463d8493..2eba61f5fce 100644
--- a/chromium/device/fido/attestation_object.h
+++ b/chromium/device/fido/attestation_object.h
@@ -36,10 +36,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AttestationObject {
std::vector<uint8_t> GetCredentialId() const;
- // Replaces the attestation statement with a “none” attestation and replaces
- // device AAGUID with zero bytes as specified for step 20.3 in
+ enum class AAGUID {
+ kErase,
+ kInclude,
+ };
+
+ // Replaces the attestation statement with a “none” attestation, and replaces
+ // device AAGUID with zero bytes (unless |erase_aaguid| is kInclude) as
+ // specified for step 20.3 in
// https://w3c.github.io/webauthn/#createCredential.
- void EraseAttestationStatement();
+ void EraseAttestationStatement(AAGUID erase_aaguid);
// Returns true if the attestation is a "self" attestation, i.e. is just the
// private key signing itself to show that it is fresh. See
diff --git a/chromium/device/fido/attestation_statement.cc b/chromium/device/fido/attestation_statement.cc
index 04c96b5300c..44bc680e62c 100644
--- a/chromium/device/fido/attestation_statement.cc
+++ b/chromium/device/fido/attestation_statement.cc
@@ -35,8 +35,8 @@ NoneAttestationStatement::GetLeafCertificate() const {
return base::nullopt;
}
-cbor::CBORValue::MapValue NoneAttestationStatement::GetAsCBORMap() const {
- return cbor::CBORValue::MapValue();
+cbor::Value::MapValue NoneAttestationStatement::GetAsCBORMap() const {
+ return cbor::Value::MapValue();
}
} // namespace device
diff --git a/chromium/device/fido/attestation_statement.h b/chromium/device/fido/attestation_statement.h
index cf5421317c5..2119f430ccf 100644
--- a/chromium/device/fido/attestation_statement.h
+++ b/chromium/device/fido/attestation_statement.h
@@ -11,7 +11,7 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
namespace device {
@@ -31,7 +31,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AttestationStatement {
// https://www.w3.org/TR/2017/WD-webauthn-20170505/#defined-attestation-formats
// This is not a CBOR-encoded byte array, but the map that will be
// nested within another CBOR object and encoded then.
- virtual cbor::CBORValue::MapValue GetAsCBORMap() const = 0;
+ virtual cbor::Value::MapValue GetAsCBORMap() const = 0;
// Returns true if the attestation is a "self" attestation, i.e. is just the
// private key signing itself to show that it is fresh.
@@ -68,7 +68,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) NoneAttestationStatement
bool IsSelfAttestation() override;
bool IsAttestationCertificateInappropriatelyIdentifying() override;
- cbor::CBORValue::MapValue GetAsCBORMap() const override;
+ cbor::Value::MapValue GetAsCBORMap() const override;
base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
private:
diff --git a/chromium/device/fido/attestation_statement_formats.cc b/chromium/device/fido/attestation_statement_formats.cc
index ae9310300e8..dfa057b6286 100644
--- a/chromium/device/fido/attestation_statement_formats.cc
+++ b/chromium/device/fido/attestation_statement_formats.cc
@@ -119,18 +119,18 @@ FidoAttestationStatement::FidoAttestationStatement(
FidoAttestationStatement::~FidoAttestationStatement() = default;
-cbor::CBORValue::MapValue FidoAttestationStatement::GetAsCBORMap() const {
- cbor::CBORValue::MapValue attestation_statement_map;
- attestation_statement_map[cbor::CBORValue(kSignatureKey)] =
- cbor::CBORValue(signature_);
+cbor::Value::MapValue FidoAttestationStatement::GetAsCBORMap() const {
+ cbor::Value::MapValue attestation_statement_map;
+ attestation_statement_map[cbor::Value(kSignatureKey)] =
+ cbor::Value(signature_);
- std::vector<cbor::CBORValue> certificate_array;
+ std::vector<cbor::Value> certificate_array;
for (const auto& cert : x509_certificates_) {
- certificate_array.push_back(cbor::CBORValue(cert));
+ certificate_array.push_back(cbor::Value(cert));
}
- attestation_statement_map[cbor::CBORValue(kX509CertKey)] =
- cbor::CBORValue(std::move(certificate_array));
+ attestation_statement_map[cbor::Value(kX509CertKey)] =
+ cbor::Value(std::move(certificate_array));
return attestation_statement_map;
}
@@ -174,22 +174,22 @@ PackedAttestationStatement::PackedAttestationStatement(
PackedAttestationStatement::~PackedAttestationStatement() = default;
-cbor::CBORValue::MapValue PackedAttestationStatement::GetAsCBORMap() const {
- cbor::CBORValue::MapValue attestation_statement_map;
+cbor::Value::MapValue PackedAttestationStatement::GetAsCBORMap() const {
+ cbor::Value::MapValue attestation_statement_map;
// alg
- attestation_statement_map[cbor::CBORValue(kAlgorithmKey)] =
- cbor::CBORValue(static_cast<int>(algorithm_));
+ attestation_statement_map[cbor::Value(kAlgorithmKey)] =
+ cbor::Value(static_cast<int>(algorithm_));
// sig
- attestation_statement_map[cbor::CBORValue(kSignatureKey)] =
- cbor::CBORValue(signature_);
+ attestation_statement_map[cbor::Value(kSignatureKey)] =
+ cbor::Value(signature_);
// x5c (optional)
if (!x509_certificates_.empty()) {
- std::vector<cbor::CBORValue> certificate_array;
+ std::vector<cbor::Value> certificate_array;
for (const auto& cert : x509_certificates_) {
- certificate_array.push_back(cbor::CBORValue(cert));
+ certificate_array.push_back(cbor::Value(cert));
}
- attestation_statement_map[cbor::CBORValue(kX509CertKey)] =
- cbor::CBORValue(std::move(certificate_array));
+ attestation_statement_map[cbor::Value(kX509CertKey)] =
+ cbor::Value(std::move(certificate_array));
}
return attestation_statement_map;
}
diff --git a/chromium/device/fido/attestation_statement_formats.h b/chromium/device/fido/attestation_statement_formats.h
index 2db98ddd686..3bb9137936e 100644
--- a/chromium/device/fido/attestation_statement_formats.h
+++ b/chromium/device/fido/attestation_statement_formats.h
@@ -12,7 +12,7 @@
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/macros.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "device/fido/attestation_statement.h"
#include "device/fido/fido_constants.h"
@@ -30,7 +30,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoAttestationStatement
~FidoAttestationStatement() override;
// AttestationStatement
- cbor::CBORValue::MapValue GetAsCBORMap() const override;
+ cbor::Value::MapValue GetAsCBORMap() const override;
bool IsSelfAttestation() override;
bool IsAttestationCertificateInappropriatelyIdentifying() override;
base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
@@ -57,7 +57,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PackedAttestationStatement
~PackedAttestationStatement() override;
// AttestationStatement
- cbor::CBORValue::MapValue GetAsCBORMap() const override;
+ cbor::Value::MapValue GetAsCBORMap() const override;
bool IsSelfAttestation() override;
bool IsAttestationCertificateInappropriatelyIdentifying() override;
base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
diff --git a/chromium/device/fido/attestation_statement_formats_unittest.cc b/chromium/device/fido/attestation_statement_formats_unittest.cc
index 4bed60bd605..8db6090672e 100644
--- a/chromium/device/fido/attestation_statement_formats_unittest.cc
+++ b/chromium/device/fido/attestation_statement_formats_unittest.cc
@@ -4,8 +4,8 @@
#include <vector>
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/writer.h"
#include "device/fido/attestation_statement_formats.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
@@ -83,17 +83,17 @@ constexpr uint8_t kCertificates[] = {
TEST(PackedAttestationStatementTest, CBOR) {
EXPECT_THAT(
- *cbor::CBORWriter::Write(
- cbor::CBORValue(PackedAttestationStatement(
- CoseAlgorithmIdentifier::kCoseEs256,
- fido_parsing_utils::Materialize(kSignature),
- {fido_parsing_utils::Materialize(kCertificates)})
- .GetAsCBORMap())),
+ *cbor::Writer::Write(
+ cbor::Value(PackedAttestationStatement(
+ CoseAlgorithmIdentifier::kCoseEs256,
+ fido_parsing_utils::Materialize(kSignature),
+ {fido_parsing_utils::Materialize(kCertificates)})
+ .GetAsCBORMap())),
testing::ElementsAreArray(test_data::kPackedAttestationStatementCBOR));
}
TEST(PackedAttestationStatementTest, CBOR_NoCerts) {
- EXPECT_THAT(*cbor::CBORWriter::Write(cbor::CBORValue(
+ EXPECT_THAT(*cbor::Writer::Write(cbor::Value(
PackedAttestationStatement(
CoseAlgorithmIdentifier::kCoseEs256,
fido_parsing_utils::Materialize(kSignature), {})
@@ -104,7 +104,7 @@ TEST(PackedAttestationStatementTest, CBOR_NoCerts) {
TEST(OpaqueAttestationStatementTest, GetLeafCertificate) {
auto attestation_map =
- cbor::CBORReader::Read(test_data::kPackedAttestationStatementCBOR);
+ cbor::Reader::Read(test_data::kPackedAttestationStatementCBOR);
ASSERT_TRUE(attestation_map);
OpaqueAttestationStatement statement("packed", std::move(*attestation_map));
EXPECT_FALSE(statement.IsSelfAttestation());
diff --git a/chromium/device/fido/attested_credential_data.cc b/chromium/device/fido/attested_credential_data.cc
index 5b93d8cd8d9..7f59a16bb7d 100644
--- a/chromium/device/fido/attested_credential_data.cc
+++ b/chromium/device/fido/attested_credential_data.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/numerics/safe_math.h"
+#include "components/cbor/reader.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/opaque_public_key.h"
@@ -16,8 +17,8 @@
namespace device {
// static
-base::Optional<AttestedCredentialData>
-AttestedCredentialData::DecodeFromCtapResponse(
+base::Optional<std::pair<AttestedCredentialData, base::span<const uint8_t>>>
+AttestedCredentialData::ConsumeFromCtapResponse(
base::span<const uint8_t> buffer) {
if (buffer.size() < kAaguidLength)
return base::nullopt;
@@ -40,11 +41,22 @@ AttestedCredentialData::DecodeFromCtapResponse(
auto credential_id = buffer.first(credential_id_length);
buffer = buffer.subspan(credential_id_length);
- auto credential_public_key_data = std::make_unique<OpaquePublicKey>(buffer);
-
- return AttestedCredentialData(aaguid, credential_id_length_span,
- fido_parsing_utils::Materialize(credential_id),
- std::move(credential_public_key_data));
+ // The public key is a CBOR map and is thus variable length. Therefore the
+ // CBOR parser needs to be invoked to find its length, even though the result
+ // is discarded.
+ size_t bytes_read;
+ if (!cbor::Reader::Read(buffer, &bytes_read)) {
+ return base::nullopt;
+ }
+ auto credential_public_key_data =
+ std::make_unique<OpaquePublicKey>(buffer.first(bytes_read));
+ buffer = buffer.subspan(bytes_read);
+
+ return std::make_pair(
+ AttestedCredentialData(aaguid, credential_id_length_span,
+ fido_parsing_utils::Materialize(credential_id),
+ std::move(credential_public_key_data)),
+ buffer);
}
// static
diff --git a/chromium/device/fido/attested_credential_data.h b/chromium/device/fido/attested_credential_data.h
index 73ed9f5e00a..61cf0fd956b 100644
--- a/chromium/device/fido/attested_credential_data.h
+++ b/chromium/device/fido/attested_credential_data.h
@@ -23,8 +23,12 @@ class PublicKey;
// https://www.w3.org/TR/2017/WD-webauthn-20170505/#sec-attestation-data
class COMPONENT_EXPORT(DEVICE_FIDO) AttestedCredentialData {
public:
- static base::Optional<AttestedCredentialData> DecodeFromCtapResponse(
- base::span<const uint8_t> buffer);
+ // Parses an |AttestedCredentialData| from a prefix of |*buffer|. Returns
+ // nullopt on error, or else the parse return and a (possibly empty) suffix of
+ // |buffer| that was not parsed.
+ static base::Optional<
+ std::pair<AttestedCredentialData, base::span<const uint8_t>>>
+ ConsumeFromCtapResponse(base::span<const uint8_t> buffer);
static base::Optional<AttestedCredentialData> CreateFromU2fRegisterResponse(
base::span<const uint8_t> u2f_data,
diff --git a/chromium/device/fido/authenticator_data.cc b/chromium/device/fido/authenticator_data.cc
index 32a105f5af2..104967a476d 100644
--- a/chromium/device/fido/authenticator_data.cc
+++ b/chromium/device/fido/authenticator_data.cc
@@ -6,6 +6,8 @@
#include <utility>
+#include "components/cbor/reader.h"
+#include "components/cbor/writer.h"
#include "device/fido/attested_credential_data.h"
#include "device/fido/fido_parsing_utils.h"
@@ -27,24 +29,51 @@ base::Optional<AuthenticatorData> AuthenticatorData::DecodeAuthenticatorData(
uint8_t flag_byte = auth_data[kRpIdHashLength];
auto counter =
auth_data.subspan<kRpIdHashLength + kFlagsLength, kSignCounterLength>();
- auto attested_credential_data =
- AttestedCredentialData::DecodeFromCtapResponse(
- auth_data.subspan(kAttestedCredentialDataOffset));
+
+ auth_data = auth_data.subspan(kAttestedCredentialDataOffset);
+ base::Optional<AttestedCredentialData> attested_credential_data;
+ if (flag_byte & static_cast<uint8_t>(Flag::kAttestation)) {
+ auto maybe_result =
+ AttestedCredentialData::ConsumeFromCtapResponse(auth_data);
+ if (!maybe_result) {
+ return base::nullopt;
+ }
+ std::tie(attested_credential_data, auth_data) = std::move(*maybe_result);
+ }
+
+ base::Optional<cbor::Value> extensions;
+ if (flag_byte & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) {
+ extensions = cbor::Reader::Read(auth_data);
+ if (!extensions || !extensions->is_map()) {
+ return base::nullopt;
+ }
+ } else if (!auth_data.empty()) {
+ return base::nullopt;
+ }
return AuthenticatorData(application_parameter, flag_byte, counter,
- std::move(attested_credential_data));
+ std::move(attested_credential_data),
+ std::move(extensions));
}
AuthenticatorData::AuthenticatorData(
base::span<const uint8_t, kRpIdHashLength> application_parameter,
uint8_t flags,
base::span<const uint8_t, kSignCounterLength> counter,
- base::Optional<AttestedCredentialData> data)
+ base::Optional<AttestedCredentialData> data,
+ base::Optional<cbor::Value> extensions)
: application_parameter_(
fido_parsing_utils::Materialize(application_parameter)),
flags_(flags),
counter_(fido_parsing_utils::Materialize(counter)),
- attested_data_(std::move(data)) {}
+ attested_data_(std::move(data)),
+ extensions_(std::move(extensions)) {
+ DCHECK(!extensions_ || extensions_->is_map());
+ DCHECK_EQ((flags_ & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) != 0,
+ !!extensions_);
+ DCHECK_EQ(((flags_ & static_cast<uint8_t>(Flag::kAttestation)) != 0),
+ !!attested_data_);
+}
AuthenticatorData::AuthenticatorData(AuthenticatorData&& other) = default;
AuthenticatorData& AuthenticatorData::operator=(AuthenticatorData&& other) =
@@ -64,12 +93,21 @@ std::vector<uint8_t> AuthenticatorData::SerializeToByteArray() const {
fido_parsing_utils::Append(&authenticator_data, application_parameter_);
authenticator_data.insert(authenticator_data.end(), flags_);
fido_parsing_utils::Append(&authenticator_data, counter_);
+
if (attested_data_) {
// Attestations are returned in registration responses but not in assertion
// responses.
fido_parsing_utils::Append(&authenticator_data,
attested_data_->SerializeAsBytes());
}
+
+ if (extensions_) {
+ const auto maybe_extensions = cbor::Writer::Write(*extensions_);
+ if (maybe_extensions) {
+ fido_parsing_utils::Append(&authenticator_data, *maybe_extensions);
+ }
+ }
+
return authenticator_data;
}
diff --git a/chromium/device/fido/authenticator_data.h b/chromium/device/fido/authenticator_data.h
index e4e9e565833..3f4f440ab5a 100644
--- a/chromium/device/fido/authenticator_data.h
+++ b/chromium/device/fido/authenticator_data.h
@@ -16,6 +16,7 @@
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
+#include "components/cbor/values.h"
#include "device/fido/attested_credential_data.h"
#include "device/fido/fido_constants.h"
@@ -34,11 +35,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorData {
static base::Optional<AuthenticatorData> DecodeAuthenticatorData(
base::span<const uint8_t> auth_data);
+ // The attested credential |data| must be specified iff |flags| have
+ // kAttestation set; and |extensions| must be specified iff |flags| have
+ // kExtensionDataIncluded set.
AuthenticatorData(
base::span<const uint8_t, kRpIdHashLength> application_parameter,
uint8_t flags,
base::span<const uint8_t, kSignCounterLength> counter,
- base::Optional<AttestedCredentialData> data);
+ base::Optional<AttestedCredentialData> data,
+ base::Optional<cbor::Value> extensions = base::nullopt);
// Moveable.
AuthenticatorData(AuthenticatorData&& other);
@@ -65,6 +70,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorData {
return attested_data_;
}
+ // If a value is returned then the result of calling |is_map()| on it can be
+ // assumed to be true.
+ const base::Optional<cbor::Value>& extensions() const { return extensions_; }
+
const std::array<uint8_t, kRpIdHashLength>& application_parameter() const {
return application_parameter_;
}
@@ -105,6 +114,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorData {
// Signature counter, 32-bit unsigned big-endian integer.
std::array<uint8_t, kSignCounterLength> counter_;
base::Optional<AttestedCredentialData> attested_data_;
+ // If |extensions_| has a value, then it will be a CBOR map.
+ base::Optional<cbor::Value> extensions_;
DISALLOW_COPY_AND_ASSIGN(AuthenticatorData);
};
diff --git a/chromium/device/fido/authenticator_get_assertion_response.cc b/chromium/device/fido/authenticator_get_assertion_response.cc
index a02868d4413..44d304bc796 100644
--- a/chromium/device/fido/authenticator_get_assertion_response.cc
+++ b/chromium/device/fido/authenticator_get_assertion_response.cc
@@ -7,8 +7,8 @@
#include <utility>
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "device/fido/authenticator_data.h"
#include "device/fido/fido_parsing_utils.h"
@@ -36,9 +36,15 @@ AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
if (key_handle.empty())
return base::nullopt;
- auto flags = u2f_data.subspan<kFlagIndex, kFlagLength>();
+ auto flags = u2f_data.subspan<kFlagIndex, kFlagLength>()[0];
+ if (flags &
+ (static_cast<uint8_t>(AuthenticatorData::Flag::kExtensionDataIncluded) |
+ static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation))) {
+ // U2F responses cannot assert CTAP2 features.
+ return base::nullopt;
+ }
auto counter = u2f_data.subspan<kCounterIndex, kCounterLength>();
- AuthenticatorData authenticator_data(relying_party_id_hash, flags[0], counter,
+ AuthenticatorData authenticator_data(relying_party_id_hash, flags, counter,
base::nullopt);
auto signature =
@@ -93,7 +99,7 @@ AuthenticatorGetAssertionResponse::SetNumCredentials(uint8_t num_credentials) {
std::vector<uint8_t> GetSerializedCtapDeviceResponse(
const AuthenticatorGetAssertionResponse& response) {
- cbor::CBORValue::MapValue response_map;
+ cbor::Value::MapValue response_map;
if (response.credential())
response_map.emplace(1, response.credential()->ConvertToCBOR());
@@ -106,7 +112,7 @@ std::vector<uint8_t> GetSerializedCtapDeviceResponse(
// Multiple account selection is not supported.
response_map.emplace(5, 1);
auto encoded_response =
- cbor::CBORWriter::Write(cbor::CBORValue(std::move(response_map)));
+ cbor::Writer::Write(cbor::Value(std::move(response_map)));
DCHECK(encoded_response);
return *encoded_response;
}
diff --git a/chromium/device/fido/authenticator_get_info_response.cc b/chromium/device/fido/authenticator_get_info_response.cc
index 37de6493c09..d5f63d4f7c0 100644
--- a/chromium/device/fido/authenticator_get_info_response.cc
+++ b/chromium/device/fido/authenticator_get_info_response.cc
@@ -6,8 +6,8 @@
#include <utility>
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -15,8 +15,8 @@ namespace device {
namespace {
template <typename Container>
-cbor::CBORValue::ArrayValue ToArrayValue(const Container& container) {
- cbor::CBORValue::ArrayValue value;
+cbor::Value::ArrayValue ToArrayValue(const Container& container) {
+ cbor::Value::ArrayValue value;
value.reserve(container.size());
for (const auto& item : container)
value.emplace_back(item);
@@ -65,12 +65,12 @@ AuthenticatorGetInfoResponse& AuthenticatorGetInfoResponse::SetOptions(
std::vector<uint8_t> EncodeToCBOR(
const AuthenticatorGetInfoResponse& response) {
- cbor::CBORValue::ArrayValue version_array;
+ cbor::Value::ArrayValue version_array;
for (const auto& version : response.versions()) {
version_array.emplace_back(version == ProtocolVersion::kCtap ? kCtap2Version
: kU2fVersion);
}
- cbor::CBORValue::MapValue device_info_map;
+ cbor::Value::MapValue device_info_map;
device_info_map.emplace(1, std::move(version_array));
if (response.extensions())
@@ -89,7 +89,7 @@ std::vector<uint8_t> EncodeToCBOR(
}
auto encoded_bytes =
- cbor::CBORWriter::Write(cbor::CBORValue(std::move(device_info_map)));
+ cbor::Writer::Write(cbor::Value(std::move(device_info_map)));
DCHECK(encoded_bytes);
return *encoded_bytes;
}
diff --git a/chromium/device/fido/authenticator_make_credential_response.cc b/chromium/device/fido/authenticator_make_credential_response.cc
index 7efafaf1724..2559a51b9c4 100644
--- a/chromium/device/fido/authenticator_make_credential_response.cc
+++ b/chromium/device/fido/authenticator_make_credential_response.cc
@@ -18,7 +18,7 @@ namespace device {
// static
base::Optional<AuthenticatorMakeCredentialResponse>
AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
- FidoTransportProtocol transport_used,
+ base::Optional<FidoTransportProtocol> transport_used,
base::span<const uint8_t, kRpIdHashLength> relying_party_id_hash,
base::span<const uint8_t> u2f_data) {
auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
@@ -58,7 +58,7 @@ AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
}
AuthenticatorMakeCredentialResponse::AuthenticatorMakeCredentialResponse(
- FidoTransportProtocol transport_used,
+ base::Optional<FidoTransportProtocol> transport_used,
AttestationObject attestation_object)
: ResponseData(attestation_object.GetCredentialId()),
attestation_object_(std::move(attestation_object)),
@@ -78,8 +78,9 @@ AuthenticatorMakeCredentialResponse::GetCBOREncodedAttestationObject() const {
return attestation_object_.SerializeToCBOREncodedBytes();
}
-void AuthenticatorMakeCredentialResponse::EraseAttestationStatement() {
- attestation_object_.EraseAttestationStatement();
+void AuthenticatorMakeCredentialResponse::EraseAttestationStatement(
+ AttestationObject::AAGUID erase_aaguid) {
+ attestation_object_.EraseAttestationStatement(erase_aaguid);
}
bool AuthenticatorMakeCredentialResponse::IsSelfAttestation() {
diff --git a/chromium/device/fido/authenticator_make_credential_response.h b/chromium/device/fido/authenticator_make_credential_response.h
index 0f9c581c80c..e55193dd807 100644
--- a/chromium/device/fido/authenticator_make_credential_response.h
+++ b/chromium/device/fido/authenticator_make_credential_response.h
@@ -30,12 +30,13 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorMakeCredentialResponse
public:
static base::Optional<AuthenticatorMakeCredentialResponse>
CreateFromU2fRegisterResponse(
- FidoTransportProtocol transport_used,
+ base::Optional<FidoTransportProtocol> transport_used,
base::span<const uint8_t, kRpIdHashLength> relying_party_id_hash,
base::span<const uint8_t> u2f_data);
- AuthenticatorMakeCredentialResponse(FidoTransportProtocol transport_used,
- AttestationObject attestation_object);
+ AuthenticatorMakeCredentialResponse(
+ base::Optional<FidoTransportProtocol> transport_used,
+ AttestationObject attestation_object);
AuthenticatorMakeCredentialResponse(
AuthenticatorMakeCredentialResponse&& that);
AuthenticatorMakeCredentialResponse& operator=(
@@ -44,10 +45,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorMakeCredentialResponse
std::vector<uint8_t> GetCBOREncodedAttestationObject() const;
- // Replaces the attestation statement with a “none” attestation and removes
- // AAGUID from authenticator data section.
+ // Replaces the attestation statement with a “none” attestation, and removes
+ // AAGUID from authenticator data section unless |preserve_aaguid| is true.
// https://w3c.github.io/webauthn/#createCredential
- void EraseAttestationStatement();
+ void EraseAttestationStatement(AttestationObject::AAGUID erase_aaguid);
// Returns true if the attestation is a "self" attestation, i.e. is just the
// private key signing itself to show that it is fresh and the AAGUID is zero.
@@ -66,13 +67,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorMakeCredentialResponse
return attestation_object_;
}
- FidoTransportProtocol transport_used() const { return transport_used_; }
+ base::Optional<FidoTransportProtocol> transport_used() const {
+ return transport_used_;
+ }
private:
AttestationObject attestation_object_;
- // Contains the transport used to register the credential in this case.
- FidoTransportProtocol transport_used_;
+ // Contains the transport used to register the credential in this case. It is
+ // nullopt for cases where we cannot determine the transport (Windows).
+ base::Optional<FidoTransportProtocol> transport_used_;
DISALLOW_COPY_AND_ASSIGN(AuthenticatorMakeCredentialResponse);
};
diff --git a/chromium/device/fido/authenticator_selection_criteria.cc b/chromium/device/fido/authenticator_selection_criteria.cc
index 598f9d93fce..7229f566c2f 100644
--- a/chromium/device/fido/authenticator_selection_criteria.cc
+++ b/chromium/device/fido/authenticator_selection_criteria.cc
@@ -9,10 +9,10 @@ namespace device {
AuthenticatorSelectionCriteria::AuthenticatorSelectionCriteria() = default;
AuthenticatorSelectionCriteria::AuthenticatorSelectionCriteria(
- AuthenticatorAttachment authenticator_attachement,
+ AuthenticatorAttachment authenticator_attachment,
bool require_resident_key,
UserVerificationRequirement user_verification_requirement)
- : authenticator_attachement_(authenticator_attachement),
+ : authenticator_attachment_(authenticator_attachment),
require_resident_key_(require_resident_key),
user_verification_requirement_(user_verification_requirement) {}
diff --git a/chromium/device/fido/authenticator_selection_criteria.h b/chromium/device/fido/authenticator_selection_criteria.h
index 82d22d075ae..e3841ba05f3 100644
--- a/chromium/device/fido/authenticator_selection_criteria.h
+++ b/chromium/device/fido/authenticator_selection_criteria.h
@@ -15,15 +15,9 @@ namespace device {
// https://w3c.github.io/webauthn/#authenticatorSelection
class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorSelectionCriteria {
public:
- enum class AuthenticatorAttachment {
- kAny,
- kPlatform,
- kCrossPlatform,
- };
-
AuthenticatorSelectionCriteria();
AuthenticatorSelectionCriteria(
- AuthenticatorAttachment authenticator_attachement,
+ AuthenticatorAttachment authenticator_attachment,
bool require_resident_key,
UserVerificationRequirement user_verification_requirement);
AuthenticatorSelectionCriteria(const AuthenticatorSelectionCriteria& other);
@@ -34,8 +28,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorSelectionCriteria {
AuthenticatorSelectionCriteria&& other);
~AuthenticatorSelectionCriteria();
- AuthenticatorAttachment authenticator_attachement() const {
- return authenticator_attachement_;
+ AuthenticatorAttachment authenticator_attachment() const {
+ return authenticator_attachment_;
}
bool require_resident_key() const { return require_resident_key_; }
@@ -45,7 +39,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorSelectionCriteria {
}
private:
- AuthenticatorAttachment authenticator_attachement_ =
+ AuthenticatorAttachment authenticator_attachment_ =
AuthenticatorAttachment::kAny;
bool require_resident_key_ = false;
UserVerificationRequirement user_verification_requirement_ =
diff --git a/chromium/device/fido/authenticator_supported_options.cc b/chromium/device/fido/authenticator_supported_options.cc
index af08a3c6e70..819bd6afeb4 100644
--- a/chromium/device/fido/authenticator_supported_options.cc
+++ b/chromium/device/fido/authenticator_supported_options.cc
@@ -11,13 +11,14 @@
namespace device {
AuthenticatorSupportedOptions::AuthenticatorSupportedOptions() = default;
-
+AuthenticatorSupportedOptions::AuthenticatorSupportedOptions(
+ const AuthenticatorSupportedOptions& other) = default;
AuthenticatorSupportedOptions::AuthenticatorSupportedOptions(
AuthenticatorSupportedOptions&& other) = default;
-
+AuthenticatorSupportedOptions& AuthenticatorSupportedOptions::operator=(
+ const AuthenticatorSupportedOptions& other) = default;
AuthenticatorSupportedOptions& AuthenticatorSupportedOptions::operator=(
AuthenticatorSupportedOptions&& other) = default;
-
AuthenticatorSupportedOptions::~AuthenticatorSupportedOptions() = default;
AuthenticatorSupportedOptions&
@@ -54,8 +55,8 @@ AuthenticatorSupportedOptions::SetIsPlatformDevice(bool is_platform_device) {
return *this;
}
-cbor::CBORValue ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
- cbor::CBORValue::MapValue option_map;
+cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
+ cbor::Value::MapValue option_map;
option_map.emplace(kResidentKeyMapKey, options.supports_resident_key());
option_map.emplace(kUserPresenceMapKey, options.user_presence_required());
option_map.emplace(kPlatformDeviceMapKey, options.is_platform_device());
@@ -88,7 +89,7 @@ cbor::CBORValue ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
break;
}
- return cbor::CBORValue(std::move(option_map));
+ return cbor::Value(std::move(option_map));
}
} // namespace device
diff --git a/chromium/device/fido/authenticator_supported_options.h b/chromium/device/fido/authenticator_supported_options.h
index 0c6bed03f05..0d8fe25c1bf 100644
--- a/chromium/device/fido/authenticator_supported_options.h
+++ b/chromium/device/fido/authenticator_supported_options.h
@@ -8,7 +8,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
namespace device {
@@ -33,8 +33,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorSupportedOptions {
};
AuthenticatorSupportedOptions();
+ AuthenticatorSupportedOptions(const AuthenticatorSupportedOptions& other);
AuthenticatorSupportedOptions(AuthenticatorSupportedOptions&& other);
AuthenticatorSupportedOptions& operator=(
+ const AuthenticatorSupportedOptions& other);
+ AuthenticatorSupportedOptions& operator=(
AuthenticatorSupportedOptions&& other);
~AuthenticatorSupportedOptions();
@@ -74,12 +77,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorSupportedOptions {
// optional if client pin capability is not supported by the authenticator.
ClientPinAvailability client_pin_availability_ =
ClientPinAvailability::kNotSupported;
-
- DISALLOW_COPY_AND_ASSIGN(AuthenticatorSupportedOptions);
};
COMPONENT_EXPORT(DEVICE_FIDO)
-cbor::CBORValue ConvertToCBOR(const AuthenticatorSupportedOptions& options);
+cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options);
} // namespace device
diff --git a/chromium/device/fido/ble/fido_ble_connection_unittest.cc b/chromium/device/fido/ble/fido_ble_connection_unittest.cc
index 507297fb88b..e04c24fa05c 100644
--- a/chromium/device/fido/ble/fido_ble_connection_unittest.cc
+++ b/chromium/device/fido/ble/fido_ble_connection_unittest.cc
@@ -36,6 +36,8 @@
#include "device/bluetooth/test/bluetooth_test_win.h"
#elif defined(OS_CHROMEOS) || defined(OS_LINUX)
#include "device/bluetooth/test/bluetooth_test_bluez.h"
+#elif defined(OS_FUCHSIA)
+#include "device/bluetooth/test/bluetooth_test_fuchsia.h"
#endif
namespace device {
diff --git a/chromium/device/fido/ble/fido_ble_device.cc b/chromium/device/fido/ble/fido_ble_device.cc
index 5ea6e1e6b78..da6a3a1e58d 100644
--- a/chromium/device/fido/ble/fido_ble_device.cc
+++ b/chromium/device/fido/ble/fido_ble_device.cc
@@ -21,7 +21,7 @@ FidoBleDevice::FidoBleDevice(BluetoothAdapter* adapter, std::string address)
connection_ = std::make_unique<FidoBleConnection>(
adapter, std::move(address),
base::BindRepeating(&FidoBleDevice::OnStatusMessage,
- base::Unretained(this)));
+ weak_factory_.GetWeakPtr()));
}
FidoBleDevice::FidoBleDevice(std::unique_ptr<FidoBleConnection> connection)
@@ -36,7 +36,7 @@ void FidoBleDevice::Connect() {
StartTimeout();
state_ = State::kBusy;
connection_->Connect(
- base::BindOnce(&FidoBleDevice::OnConnected, base::Unretained(this)));
+ base::BindOnce(&FidoBleDevice::OnConnected, weak_factory_.GetWeakPtr()));
}
void FidoBleDevice::SendPing(std::vector<uint8_t> data,
@@ -108,9 +108,17 @@ bool FidoBleDevice::IsInPairingMode() const {
static_cast<int>(FidoServiceDataFlags::kPairingMode)) != 0;
}
+bool FidoBleDevice::IsPaired() const {
+ const BluetoothDevice* const ble_device = connection_->GetBleDevice();
+ if (!ble_device)
+ return false;
+
+ return ble_device->IsPaired();
+}
+
FidoBleConnection::ReadCallback FidoBleDevice::GetReadCallbackForTesting() {
return base::BindRepeating(&FidoBleDevice::OnStatusMessage,
- base::Unretained(this));
+ weak_factory_.GetWeakPtr());
}
void FidoBleDevice::DeviceTransact(std::vector<uint8_t> command,
@@ -148,8 +156,9 @@ void FidoBleDevice::Transition() {
case State::kConnected:
StartTimeout();
state_ = State::kBusy;
- connection_->ReadControlPointLength(base::BindOnce(
- &FidoBleDevice::OnReadControlPointLength, base::Unretained(this)));
+ connection_->ReadControlPointLength(
+ base::BindOnce(&FidoBleDevice::OnReadControlPointLength,
+ weak_factory_.GetWeakPtr()));
break;
case State::kReady:
if (!pending_frames_.empty()) {
@@ -215,8 +224,8 @@ void FidoBleDevice::SendRequestFrame(FidoBleFrame frame,
transaction_.emplace(connection_.get(), control_point_length_);
transaction_->WriteRequestFrame(
std::move(frame),
- base::BindOnce(&FidoBleDevice::OnResponseFrame, base::Unretained(this),
- std::move(callback)));
+ base::BindOnce(&FidoBleDevice::OnResponseFrame,
+ weak_factory_.GetWeakPtr(), std::move(callback)));
}
void FidoBleDevice::StartTimeout() {
diff --git a/chromium/device/fido/ble/fido_ble_device.h b/chromium/device/fido/ble/fido_ble_device.h
index e8636206767..26a37104189 100644
--- a/chromium/device/fido/ble/fido_ble_device.h
+++ b/chromium/device/fido/ble/fido_ble_device.h
@@ -50,6 +50,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDevice : public FidoDevice {
// mode by investigating the advertisement payload.
bool IsInPairingMode() const override;
+ bool IsPaired() const override;
+
FidoBleConnection::ReadCallback GetReadCallbackForTesting();
protected:
diff --git a/chromium/device/fido/ble/fido_ble_discovery.cc b/chromium/device/fido/ble/fido_ble_discovery.cc
index 4a6ade31391..36e8e950319 100644
--- a/chromium/device/fido/ble/fido_ble_discovery.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/time/time.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_common.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
@@ -15,6 +16,7 @@
#include "device/fido/ble/fido_ble_device.h"
#include "device/fido/ble/fido_ble_uuids.h"
#include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_constants.h"
#include "device/fido/fido_device_authenticator.h"
namespace device {
@@ -38,9 +40,11 @@ void FidoBleDiscovery::OnSetPowered() {
for (BluetoothDevice* device : adapter()->GetDevices()) {
if (!CheckForExcludedDeviceAndCacheAddress(device) &&
base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
- VLOG(2) << "U2F BLE device: " << device->GetAddress();
- AddDevice(
- std::make_unique<FidoBleDevice>(adapter(), device->GetAddress()));
+ const auto& device_address = device->GetAddress();
+ VLOG(2) << "FIDO BLE device: " << device_address;
+ AddDevice(std::make_unique<FidoBleDevice>(adapter(), device_address));
+ CheckAndRecordDevicePairingModeOnDiscovery(
+ FidoBleDevice::GetId(device_address));
}
}
@@ -62,8 +66,11 @@ void FidoBleDiscovery::DeviceAdded(BluetoothAdapter* adapter,
BluetoothDevice* device) {
if (!CheckForExcludedDeviceAndCacheAddress(device) &&
base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
- VLOG(2) << "Discovered U2F BLE device: " << device->GetAddress();
- AddDevice(std::make_unique<FidoBleDevice>(adapter, device->GetAddress()));
+ const auto& device_address = device->GetAddress();
+ VLOG(2) << "Discovered FIDO BLE device: " << device_address;
+ AddDevice(std::make_unique<FidoBleDevice>(adapter, device_address));
+ CheckAndRecordDevicePairingModeOnDiscovery(
+ FidoBleDevice::GetId(device_address));
}
}
@@ -74,29 +81,29 @@ void FidoBleDiscovery::DeviceChanged(BluetoothAdapter* adapter,
return;
}
- const auto device_id = FidoBleDevice::GetId(device->GetAddress());
- auto* authenticator = GetAuthenticator(device_id);
+ auto authenticator_id = FidoBleDevice::GetId(device->GetAddress());
+ auto* authenticator = GetAuthenticator(authenticator_id);
if (!authenticator) {
- VLOG(2) << "Discovered U2F service on existing BLE device: "
+ VLOG(2) << "Discovered FIDO service on existing BLE device: "
<< device->GetAddress();
AddDevice(std::make_unique<FidoBleDevice>(adapter, device->GetAddress()));
+ CheckAndRecordDevicePairingModeOnDiscovery(std::move(authenticator_id));
return;
}
- // Our model of FIDO BLE security key assumes that if BLE device is in pairing
- // mode long enough time without pairing attempt, the device stops advertising
- // and BluetoothAdapter::DeviceRemoved() is invoked instead of returning back
- // to regular "non-pairing" mode. As so, we only notify observer when
- // |fido_device| goes into pairing mode.
- if (observer() && authenticator->device()->IsInPairingMode())
- observer()->AuthenticatorPairingModeChanged(this, device_id);
+ if (authenticator->device()->IsInPairingMode()) {
+ RecordDevicePairingStatus(std::move(authenticator_id),
+ PairingModeChangeType::kUnobserved);
+ }
}
void FidoBleDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
BluetoothDevice* device) {
if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
- VLOG(2) << "U2F BLE device removed: " << device->GetAddress();
- RemoveDevice(FidoBleDevice::GetId(device->GetAddress()));
+ VLOG(2) << "FIDO BLE device removed: " << device->GetAddress();
+ auto device_id = FidoBleDevice::GetId(device->GetAddress());
+ RemoveDevice(device_id);
+ RemoveDeviceFromPairingTracker(device_id);
}
}
@@ -120,8 +127,17 @@ void FidoBleDiscovery::DeviceAddressChanged(BluetoothAdapter* adapter,
VLOG(2) << "Discovered FIDO BLE device address change from old address : "
<< old_address << " to new address : " << device->GetAddress();
- authenticators_.emplace(new_device_id, std::move(it->second));
- authenticators_.erase(it);
+
+ auto change_map_keys = [&](auto* map) {
+ auto it = map->find(previous_device_id);
+ if (it != map->end()) {
+ map->emplace(new_device_id, std::move(it->second));
+ map->erase(it);
+ }
+ };
+
+ change_map_keys(&authenticators_);
+ change_map_keys(&pairing_mode_device_tracker_);
if (observer()) {
observer()->AuthenticatorIdChanged(this, previous_device_id,
@@ -151,4 +167,46 @@ bool FidoBleDiscovery::CheckForExcludedDeviceAndCacheAddress(
return false;
}
+void FidoBleDiscovery::CheckAndRecordDevicePairingModeOnDiscovery(
+ std::string authenticator_id) {
+ auto* authenticator = GetAuthenticator(authenticator_id);
+ DCHECK(authenticator);
+ if (authenticator->device()->IsInPairingMode()) {
+ RecordDevicePairingStatus(std::move(authenticator_id),
+ PairingModeChangeType::kObserved);
+ }
+}
+
+void FidoBleDiscovery::RecordDevicePairingStatus(std::string device_id,
+ PairingModeChangeType type) {
+ auto it = pairing_mode_device_tracker_.find(device_id);
+ if (it != pairing_mode_device_tracker_.end()) {
+ it->second->Reset();
+ return;
+ }
+
+ if (observer() && type == PairingModeChangeType::kUnobserved) {
+ observer()->AuthenticatorPairingModeChanged(this, device_id,
+ true /* is_in_pairing_mode */);
+ }
+
+ auto pairing_mode_timer = std::make_unique<base::OneShotTimer>();
+ pairing_mode_timer->Start(
+ FROM_HERE, kBleDevicePairingModeWaitingInterval,
+ base::BindOnce(&FidoBleDiscovery::RemoveDeviceFromPairingTracker,
+ weak_factory_.GetWeakPtr(), device_id));
+ pairing_mode_device_tracker_.emplace(std::move(device_id),
+ std::move(pairing_mode_timer));
+}
+
+void FidoBleDiscovery::RemoveDeviceFromPairingTracker(
+ const std::string& device_id) {
+ // Destroying the timer stops the timer scheduled task.
+ pairing_mode_device_tracker_.erase(device_id);
+ if (observer()) {
+ observer()->AuthenticatorPairingModeChanged(this, device_id,
+ false /* is_in_pairing_mode */);
+ }
+}
+
} // namespace device
diff --git a/chromium/device/fido/ble/fido_ble_discovery.h b/chromium/device/fido/ble/fido_ble_discovery.h
index 0b03b863233..f786fc06ee5 100644
--- a/chromium/device/fido/ble/fido_ble_discovery.h
+++ b/chromium/device/fido/ble/fido_ble_discovery.h
@@ -5,6 +5,8 @@
#ifndef DEVICE_FIDO_BLE_FIDO_BLE_DISCOVERY_H_
#define DEVICE_FIDO_BLE_FIDO_BLE_DISCOVERY_H_
+#include <functional>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -12,6 +14,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
#include "device/fido/ble/fido_ble_discovery_base.h"
namespace device {
@@ -26,6 +29,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
~FidoBleDiscovery() override;
private:
+ FRIEND_TEST_ALL_PREFIXES(FidoBleDiscoveryTest,
+ DiscoveryNotifiesObserverWhenDeviceInPairingMode);
+ FRIEND_TEST_ALL_PREFIXES(FidoBleDiscoveryTest,
+ DiscoveryNotifiesObserverWhenDeviceInNonPairingMode);
+
+ enum class PairingModeChangeType {
+ kUnobserved,
+ kObserved,
+ };
+
static const BluetoothUUID& FidoServiceUUID();
// FidoBleDiscoveryBase:
@@ -46,7 +59,20 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
// to |blacklisted_cable_device_addresses_|.
bool CheckForExcludedDeviceAndCacheAddress(const BluetoothDevice* device);
+ void CheckAndRecordDevicePairingModeOnDiscovery(std::string authenticator_id);
+
+ // If |device_id| does not exist in |pairing_mode_device_tracker_|, add
+ // |device_id| to the map and start a timer. If the map element already
+ // exists, restart the timer.
+ void RecordDevicePairingStatus(std::string device_id,
+ PairingModeChangeType type);
+ void RemoveDeviceFromPairingTracker(const std::string& device_id);
+
std::set<std::string> excluded_cable_device_addresses_;
+
+ // Maps Bluetooth FIDO authenticators that are known to be in pairing mode.
+ std::map<std::string, std::unique_ptr<base::OneShotTimer>>
+ pairing_mode_device_tracker_;
base::WeakPtrFactory<FidoBleDiscovery> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoBleDiscovery);
diff --git a/chromium/device/fido/ble/fido_ble_discovery_base.cc b/chromium/device/fido/ble/fido_ble_discovery_base.cc
index 240513c74c3..19c24c12d08 100644
--- a/chromium/device/fido/ble/fido_ble_discovery_base.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery_base.cc
@@ -83,23 +83,9 @@ void FidoBleDiscoveryBase::OnGetAdapter(
}
void FidoBleDiscoveryBase::StartInternal() {
- auto& factory = BluetoothAdapterFactory::Get();
- auto callback = base::BindOnce(&FidoBleDiscoveryBase::OnGetAdapter,
- weak_factory_.GetWeakPtr());
-#if defined(OS_MACOSX)
- // BluetoothAdapter may invoke the callback synchronously on Mac, but
- // StartInternal() never wants to invoke to NotifyDiscoveryStarted()
- // immediately, so ensure there is at least post-task at this bottleneck.
- // See: https://crbug.com/823686.
- callback = base::BindOnce(
- [](BluetoothAdapterFactory::AdapterCallback callback,
- scoped_refptr<BluetoothAdapter> adapter) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), adapter));
- },
- base::AdaptCallbackForRepeating(std::move(callback)));
-#endif // defined(OS_MACOSX)
- factory.GetAdapter(base::AdaptCallbackForRepeating(std::move(callback)));
+ BluetoothAdapterFactory::Get().GetAdapter(
+ base::AdaptCallbackForRepeating(base::BindOnce(
+ &FidoBleDiscoveryBase::OnGetAdapter, weak_factory_.GetWeakPtr())));
}
} // namespace device
diff --git a/chromium/device/fido/ble/fido_ble_discovery_unittest.cc b/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
index 48533cc9e47..77f823433ef 100644
--- a/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
+++ b/chromium/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -9,6 +9,8 @@
#include "base/bind.h"
#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
#include "build/build_config.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/bluetooth_test.h"
@@ -36,7 +38,9 @@ namespace device {
namespace {
using ::testing::_;
+using ::testing::Return;
using TestMockDevice = ::testing::NiceMock<MockBluetoothDevice>;
+using NiceMockBluetoothAdapter = ::testing::NiceMock<MockBluetoothAdapter>;
constexpr char kDeviceName[] = "device_name";
constexpr char kDeviceAddress[] = "device_address";
@@ -54,48 +58,92 @@ MATCHER_P(IdMatches, id, "") {
} // namespace
-TEST_F(BluetoothTest, FidoBleDiscoveryNotifyObserverWhenAdapterNotPresent) {
- FidoBleDiscovery discovery;
- MockFidoDiscoveryObserver observer;
- discovery.set_observer(&observer);
- auto mock_adapter =
- base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
- EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(false));
- EXPECT_CALL(*mock_adapter, SetPowered).Times(0);
- BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
- discovery.Start();
+class FidoBleDiscoveryTest : public ::testing::Test {
+ public:
+ FidoBleDiscoveryTest() { discovery_.set_observer(&observer_); }
+
+ std::unique_ptr<TestMockDevice> CreateMockFidoDevice() {
+ DCHECK(adapter_);
+ auto mock_device = std::make_unique<TestMockDevice>(
+ adapter_.get(), 0 /* bluetooth_class */, kDeviceName, kDeviceAddress,
+ false /* paired */, false /* connected */);
+ EXPECT_CALL(*mock_device, GetUUIDs)
+ .WillRepeatedly(Return(
+ std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)}));
+ EXPECT_CALL(*mock_device, GetAddress)
+ .WillRepeatedly(Return(kDeviceAddress));
+
+ EXPECT_CALL(*adapter(), GetDevice(kDeviceAddress))
+ .WillRepeatedly(Return(mock_device.get()));
+
+ return mock_device;
+ }
+
+ void SetDeviceInPairingMode(TestMockDevice* device) {
+ // Update device advertisement data so that it represents BLE device in
+ // pairing mode.
+ DCHECK(adapter_);
+ device->UpdateAdvertisementData(
+ 0 /* rssi */, 1 << kLeLimitedDiscoverableModeBit,
+ std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)},
+ base::nullopt /* tx_power */, BluetoothDevice::ServiceDataMap(),
+ BluetoothDevice::ManufacturerDataMap());
+ adapter_->NotifyDeviceChanged(device);
+ }
+
+ void SetMockBluetoothAdapter() {
+ adapter_ = base::MakeRefCounted<NiceMockBluetoothAdapter>();
+ BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
+ }
+
+ FidoBleDiscovery* discovery() { return &discovery_; }
+ MockFidoDiscoveryObserver* observer() { return &observer_; }
+ MockBluetoothAdapter* adapter() {
+ DCHECK(adapter_);
+ return adapter_.get();
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_{
+ base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
+
+ private:
+ FidoBleDiscovery discovery_;
+ MockFidoDiscoveryObserver observer_;
+ scoped_refptr<MockBluetoothAdapter> adapter_;
+};
+
+TEST_F(FidoBleDiscoveryTest,
+ FidoBleDiscoveryNotifyObserverWhenAdapterNotPresent) {
+ SetMockBluetoothAdapter();
+ EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(false));
+ EXPECT_CALL(*adapter(), SetPowered).Times(0);
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false));
+ discovery()->Start();
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
}
-TEST_F(BluetoothTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
- FidoBleDiscovery discovery;
- MockFidoDiscoveryObserver observer;
- discovery.set_observer(&observer);
- auto mock_adapter =
- base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
- EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
- EXPECT_CALL(*mock_adapter, IsPowered()).WillOnce(::testing::Return(false));
+TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
+ SetMockBluetoothAdapter();
+ EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ EXPECT_CALL(*adapter(), IsPowered()).WillOnce(Return(false));
// After BluetoothAdapter is powered on, we expect that discovery session
// starts again.
- EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw);
- BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
- discovery.Start();
- mock_adapter->NotifyAdapterPoweredChanged(true);
+ EXPECT_CALL(*adapter(), StartDiscoverySessionWithFilterRaw);
+ discovery()->Start();
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
+ adapter()->NotifyAdapterPoweredChanged(true);
}
-TEST_F(BluetoothTest, FidoBleDiscoveryNoAdapter) {
+TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryNoAdapter) {
// We purposefully construct a temporary and provide no fake adapter,
// simulating cases where the discovery is destroyed before obtaining a handle
// to an adapter. This should be handled gracefully and not result in a crash.
- FidoBleDiscovery discovery;
-
// We don't expect any calls to the notification methods.
- MockFidoDiscoveryObserver observer;
- discovery.set_observer(&observer);
- EXPECT_CALL(observer, DiscoveryStarted(&discovery, _)).Times(0);
- EXPECT_CALL(observer, AuthenticatorAdded(&discovery, _)).Times(0);
- EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, _)).Times(0);
+ EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), _)).Times(0);
+ EXPECT_CALL(*observer(), AuthenticatorAdded(discovery(), _)).Times(0);
+ EXPECT_CALL(*observer(), AuthenticatorRemoved(discovery(), _)).Times(0);
}
TEST_F(BluetoothTest, FidoBleDiscoveryFindsKnownDevice) {
@@ -250,84 +298,101 @@ TEST_F(BluetoothTest, FidoBleDiscoveryRejectsCableDevice) {
SimulateLowEnergyDevice(7);
}
-TEST_F(BluetoothTest, DiscoveryDoesNotAddDuplicateDeviceOnAddressChanged) {
- using TestMockDevice = ::testing::NiceMock<MockBluetoothDevice>;
-
- MockFidoDiscoveryObserver observer;
- FidoBleDiscovery discovery;
- discovery.set_observer(&observer);
-
- auto mock_adapter =
- base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
- EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
-
- auto mock_device = std::make_unique<TestMockDevice>(
- mock_adapter.get(), 0 /* bluetooth_class */, kDeviceName, kDeviceAddress,
- false /* paired */, false /* connected */);
-
- EXPECT_CALL(*mock_device.get(), GetUUIDs)
- .WillRepeatedly(::testing::Return(
- std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)}));
+TEST_F(FidoBleDiscoveryTest,
+ DiscoveryDoesNotAddDuplicateDeviceOnAddressChanged) {
+ SetMockBluetoothAdapter();
+ EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ auto mock_device = CreateMockFidoDevice();
- BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter.get());
- EXPECT_CALL(observer, AuthenticatorIdChanged(&discovery, kAuthenticatorId,
- kAuthenticatorChangedId));
- discovery.Start();
+ EXPECT_CALL(*observer(), AuthenticatorIdChanged(discovery(), kAuthenticatorId,
+ kAuthenticatorChangedId));
+ discovery()->Start();
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
- EXPECT_CALL(*mock_device.get(), GetAddress)
- .WillRepeatedly(::testing::Return(kDeviceAddress));
- mock_adapter->NotifyDeviceChanged(mock_device.get());
+ adapter()->NotifyDeviceChanged(mock_device.get());
ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_device.get()));
EXPECT_CALL(*mock_device.get(), GetAddress)
- .WillRepeatedly(::testing::Return(kDeviceChangedAddress));
- for (auto& observer : mock_adapter->GetObservers()) {
- observer.DeviceAddressChanged(mock_adapter.get(), mock_device.get(),
- kDeviceAddress);
+ .WillRepeatedly(Return(kDeviceChangedAddress));
+ for (auto& observer : adapter()->GetObservers()) {
+ observer.DeviceAddressChanged(adapter(), mock_device.get(), kDeviceAddress);
}
- mock_adapter->NotifyDeviceChanged(mock_device.get());
+ adapter()->NotifyDeviceChanged(mock_device.get());
- EXPECT_EQ(1u, discovery.GetAuthenticatorsForTesting().size());
- EXPECT_TRUE(discovery.GetAuthenticatorForTesting(kAuthenticatorChangedId));
+ EXPECT_EQ(1u, discovery()->GetAuthenticatorsForTesting().size());
+ EXPECT_TRUE(discovery()->GetAuthenticatorForTesting(kAuthenticatorChangedId));
}
-TEST_F(BluetoothTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) {
- FidoBleDiscovery discovery;
- MockFidoDiscoveryObserver observer;
- discovery.set_observer(&observer);
+TEST_F(FidoBleDiscoveryTest, DiscoveryNotifiesObserverWhenDeviceInPairingMode) {
+ SetMockBluetoothAdapter();
+ EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ auto mock_device = CreateMockFidoDevice();
- auto mock_adapter =
- base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
- EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
+ const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
+ discovery()->Start();
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
+
+ ::testing::InSequence sequence;
+ EXPECT_CALL(*observer(),
+ AuthenticatorAdded(discovery(), IdMatches(kDeviceAddress)));
+ adapter()->NotifyDeviceChanged(mock_device.get());
+
+ EXPECT_CALL(*observer(),
+ AuthenticatorPairingModeChanged(discovery(), device_id, true));
+ SetDeviceInPairingMode(mock_device.get());
+ auto it = discovery()->pairing_mode_device_tracker_.find(device_id);
+ EXPECT_TRUE(it != discovery()->pairing_mode_device_tracker_.end());
+ EXPECT_TRUE(it->second->IsRunning());
+}
- auto mock_device = std::make_unique<TestMockDevice>(
- mock_adapter.get(), 0 /* bluetooth_class */, kDeviceName, kDeviceAddress,
- false /* paired */, false /* connected */);
- EXPECT_CALL(*mock_device.get(), GetUUIDs)
- .WillRepeatedly(::testing::Return(
- std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)}));
- EXPECT_CALL(*mock_adapter, GetDevice(kDeviceAddress))
- .WillRepeatedly(::testing::Return(mock_device.get()));
+TEST_F(FidoBleDiscoveryTest,
+ DiscoveryNotifiesObserverWhenDeviceInNonPairingMode) {
+ SetMockBluetoothAdapter();
+ EXPECT_CALL(*adapter(), IsPresent()).WillOnce(Return(true));
+ auto mock_device = CreateMockFidoDevice();
- BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter.get());
const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
- discovery.Start();
+ discovery()->Start();
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
::testing::InSequence sequence;
- EXPECT_CALL(observer,
- AuthenticatorAdded(&discovery, IdMatches(kDeviceAddress)));
- mock_adapter->NotifyDeviceChanged(mock_device.get());
-
- EXPECT_CALL(observer, AuthenticatorPairingModeChanged(&discovery, _));
- // Update device advertisement data so that it represents BLE device in
- // pairing mode.
- mock_device->UpdateAdvertisementData(
- 0 /* rssi */, 1 << kLeLimitedDiscoverableModeBit,
- std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)},
- base::nullopt /* tx_power */, BluetoothDevice::ServiceDataMap(),
- BluetoothDevice::ManufacturerDataMap());
- mock_adapter->NotifyDeviceChanged(mock_device.get());
+ EXPECT_CALL(*observer(),
+ AuthenticatorAdded(discovery(), IdMatches(kDeviceAddress)));
+ adapter()->NotifyDeviceChanged(mock_device.get());
+
+ EXPECT_CALL(*observer(),
+ AuthenticatorPairingModeChanged(discovery(), device_id, true));
+
+ SetDeviceInPairingMode(mock_device.get());
+ auto it = discovery()->pairing_mode_device_tracker_.find(device_id);
+ ASSERT_TRUE(it != discovery()->pairing_mode_device_tracker_.end());
+ EXPECT_TRUE(it->second->IsRunning());
+
+ // Simulates BLE device sending advertisement packet after some interval.
+ // Since device did not advertise that it is in pairing mode for longer than 3
+ // seconds, we expect that the discovery should
+ // 1) First set the device to be in non-pairing mode and notify the
+ // observer.
+ // 2) When advertisement packet arrives after delay, device is re-set to
+ // pairing mode and observer is notified.
+ // 3) When timer completes due to FastForwardUntilNoTasksRemain(),
+ // authenticator is re-set to non-pairing mode.
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(observer()));
+ EXPECT_CALL(*observer(),
+ AuthenticatorPairingModeChanged(discovery(), device_id, false));
+ EXPECT_CALL(*observer(),
+ AuthenticatorPairingModeChanged(discovery(), device_id, true));
+ EXPECT_CALL(*observer(),
+ AuthenticatorPairingModeChanged(discovery(), device_id, false));
+
+ scoped_task_environment_.GetMainThreadTaskRunner().get()->PostDelayedTask(
+ FROM_HERE, base::BindLambdaForTesting([&, this] {
+ adapter()->NotifyDeviceChanged(mock_device.get());
+ }),
+ base::TimeDelta::FromSeconds(4));
+
+ scoped_task_environment_.FastForwardUntilNoTasksRemain();
}
} // namespace device
diff --git a/chromium/device/fido/ble/fido_ble_frames_unittest.cc b/chromium/device/fido/ble/fido_ble_frames_unittest.cc
index 2d20c8d5370..ba9c4bdae3e 100644
--- a/chromium/device/fido/ble/fido_ble_frames_unittest.cc
+++ b/chromium/device/fido/ble/fido_ble_frames_unittest.cc
@@ -4,6 +4,7 @@
#include "device/fido/ble/fido_ble_frames.h"
+#include <algorithm>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,7 +39,9 @@ TEST(FidoBleFramesTest, InitializationFragment) {
FidoBleFrameInitializationFragment::Parse(buffer, &parsed_fragment));
EXPECT_EQ(kDataLength, parsed_fragment.data_length());
- EXPECT_EQ(base::make_span(data), parsed_fragment.fragment());
+ EXPECT_TRUE(std::equal(data.begin(), data.end(),
+ parsed_fragment.fragment().begin(),
+ parsed_fragment.fragment().end()));
EXPECT_EQ(FidoBleDeviceCommand::kMsg, parsed_fragment.command());
}
@@ -58,7 +61,9 @@ TEST(FidoBleFramesTest, ContinuationFragment) {
ASSERT_TRUE(
FidoBleFrameContinuationFragment::Parse(buffer, &parsed_fragment));
- EXPECT_EQ(base::make_span(data), parsed_fragment.fragment());
+ EXPECT_TRUE(std::equal(data.begin(), data.end(),
+ parsed_fragment.fragment().begin(),
+ parsed_fragment.fragment().end()));
EXPECT_EQ(kSequence, parsed_fragment.sequence());
}
diff --git a/chromium/device/fido/ble_adapter_manager_unittest.cc b/chromium/device/fido/ble_adapter_manager_unittest.cc
index c09e20377b7..eb6ef23b620 100644
--- a/chromium/device/fido/ble_adapter_manager_unittest.cc
+++ b/chromium/device/fido/ble_adapter_manager_unittest.cc
@@ -47,7 +47,8 @@ class MockTransportAvailabilityObserver
MOCK_METHOD2(FidoAuthenticatorIdChanged,
void(base::StringPiece old_authenticator_id,
std::string new_authenticator_id));
- MOCK_METHOD1(FidoAuthenticatorPairingModeChanged, void(base::StringPiece));
+ MOCK_METHOD2(FidoAuthenticatorPairingModeChanged,
+ void(base::StringPiece, bool));
private:
DISALLOW_COPY_AND_ASSIGN(MockTransportAvailabilityObserver);
diff --git a/chromium/device/fido/cable/fido_cable_device_unittest.cc b/chromium/device/fido/cable/fido_cable_device_unittest.cc
index e99e691a8d1..5d4a9e29316 100644
--- a/chromium/device/fido/cable/fido_cable_device_unittest.cc
+++ b/chromium/device/fido/cable/fido_cable_device_unittest.cc
@@ -267,8 +267,7 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnUnexpectedCounter) {
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
- .WillOnce(Invoke([this, kIncorrectAuthenticatorCounter](const auto& data,
- auto* cb) {
+ .WillOnce(Invoke([this](const auto& data, auto* cb) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(*cb), true));
diff --git a/chromium/device/fido/cable/fido_cable_discovery_unittest.cc b/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
index 814033e0733..138f23379b3 100644
--- a/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
+++ b/chromium/device/fido/cable/fido_cable_discovery_unittest.cc
@@ -116,8 +116,9 @@ MATCHER_P2(IsAdvertisementContent,
manufacturer_data_payload[1] == 0x15 && // Manufacturer Data Type
manufacturer_data_payload[2] == 0x20 && // Cable Flags
manufacturer_data_payload[3] == kTestCableVersionNumber &&
- base::make_span(manufacturer_data_payload).subspan(4) ==
- expected_client_eid;
+ std::equal(manufacturer_data_payload.begin() + 4,
+ manufacturer_data_payload.end(),
+ expected_client_eid.begin(), expected_client_eid.end());
#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
const auto service_data = arg->service_data();
@@ -131,7 +132,8 @@ MATCHER_P2(IsAdvertisementContent,
return (service_data_value[0] >> 5 & 1) &&
service_data_value[1] == kTestCableVersionNumber &&
service_data_value.size() == 18u &&
- base::make_span(service_data_value).subspan(2) == expected_client_eid;
+ std::equal(service_data_value.begin() + 2, service_data_value.end(),
+ expected_client_eid.begin(), expected_client_eid.end());
#endif
@@ -239,7 +241,7 @@ class CableMockAdapter : public MockBluetoothAdapter {
void ExpectDiscoveryWithScanCallback() {
EXPECT_CALL(*this, StartDiscoverySessionWithFilterRaw(_, _, _))
.WillOnce(::testing::WithArg<1>(
- [this](const auto& callback) { callback.Run(nullptr); }));
+ [](const auto& callback) { callback.Run(nullptr); }));
}
void ExpectDiscoveryWithScanCallback(
diff --git a/chromium/device/fido/cable/fido_cable_handshake_handler.cc b/chromium/device/fido/cable/fido_cable_handshake_handler.cc
index a227377a096..8c6e6fc2c86 100644
--- a/chromium/device/fido/cable/fido_cable_handshake_handler.cc
+++ b/chromium/device/fido/cable/fido_cable_handshake_handler.cc
@@ -9,9 +9,9 @@
#include "base/containers/span.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "crypto/hkdf.h"
#include "crypto/hmac.h"
#include "crypto/random.h"
@@ -44,10 +44,10 @@ std::string GenerateKey(base::StringPiece secret,
base::Optional<std::array<uint8_t, kClientHelloMessageSize>>
ConstructHandshakeMessage(base::StringPiece handshake_key,
base::span<const uint8_t, 16> client_random_nonce) {
- cbor::CBORValue::MapValue map;
+ cbor::Value::MapValue map;
map.emplace(0, kCableClientHelloMessage);
map.emplace(1, client_random_nonce);
- auto client_hello = cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+ auto client_hello = cbor::Writer::Write(cbor::Value(std::move(map)));
DCHECK(client_hello);
crypto::HMAC hmac(crypto::HMAC::SHA256);
@@ -125,15 +125,14 @@ bool FidoCableHandshakeHandler::ValidateAuthenticatorHandshakeMessage(
return false;
}
- const auto authenticator_hello_cbor =
- cbor::CBORReader::Read(authenticator_hello);
+ const auto authenticator_hello_cbor = cbor::Reader::Read(authenticator_hello);
if (!authenticator_hello_cbor || !authenticator_hello_cbor->is_map() ||
authenticator_hello_cbor->GetMap().size() != 2) {
return false;
}
const auto authenticator_hello_msg =
- authenticator_hello_cbor->GetMap().find(cbor::CBORValue(0));
+ authenticator_hello_cbor->GetMap().find(cbor::Value(0));
if (authenticator_hello_msg == authenticator_hello_cbor->GetMap().end() ||
!authenticator_hello_msg->second.is_string() ||
authenticator_hello_msg->second.GetString() !=
@@ -142,7 +141,7 @@ bool FidoCableHandshakeHandler::ValidateAuthenticatorHandshakeMessage(
}
const auto authenticator_random_nonce =
- authenticator_hello_cbor->GetMap().find(cbor::CBORValue(1));
+ authenticator_hello_cbor->GetMap().find(cbor::Value(1));
if (authenticator_random_nonce == authenticator_hello_cbor->GetMap().end() ||
!authenticator_random_nonce->second.is_bytestring() ||
authenticator_random_nonce->second.GetBytestring().size() != 16) {
diff --git a/chromium/device/fido/cable/fido_cable_handshake_handler_unittest.cc b/chromium/device/fido/cable/fido_cable_handshake_handler_unittest.cc
index 49ea55d3169..7c2117a4662 100644
--- a/chromium/device/fido/cable/fido_cable_handshake_handler_unittest.cc
+++ b/chromium/device/fido/cable/fido_cable_handshake_handler_unittest.cc
@@ -13,9 +13,9 @@
#include "base/optional.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "crypto/hkdf.h"
#include "crypto/hmac.h"
#include "device/bluetooth/test/bluetooth_test.h"
@@ -208,13 +208,13 @@ class FakeCableAuthenticator {
return false;
}
- const auto& client_hello_cbor = cbor::CBORReader::Read(client_hello);
+ const auto& client_hello_cbor = cbor::Reader::Read(client_hello);
if (!client_hello_cbor)
return false;
const auto& message_map = client_hello_cbor->GetMap();
- auto hello_message_it = message_map.find(cbor::CBORValue(0));
- auto client_random_nonce_it = message_map.find(cbor::CBORValue(1));
+ auto hello_message_it = message_map.find(cbor::Value(0));
+ auto client_random_nonce_it = message_map.find(cbor::Value(1));
if (hello_message_it == message_map.end() ||
client_random_nonce_it == message_map.end())
return false;
diff --git a/chromium/device/fido/ctap_get_assertion_request.cc b/chromium/device/fido/ctap_get_assertion_request.cc
index 64285cb5565..b2912a2be03 100644
--- a/chromium/device/fido/ctap_get_assertion_request.cc
+++ b/chromium/device/fido/ctap_get_assertion_request.cc
@@ -9,47 +9,18 @@
#include <utility>
#include "base/numerics/safe_conversions.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/writer.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
-namespace {
-
-bool AreGetAssertionRequestMapKeysCorrect(
- const cbor::CBORValue::MapValue& request_map) {
- return std::all_of(request_map.begin(), request_map.end(),
- [](const auto& param) {
- if (!param.first.is_integer())
- return false;
-
- const auto& key = param.first.GetInteger();
- return (key <= 7u || key >= 1u);
- });
-}
-
-bool IsGetAssertionOptionMapFormatCorrect(
- const cbor::CBORValue::MapValue& option_map) {
- return std::all_of(
- option_map.begin(), option_map.end(), [](const auto& param) {
- if (!param.first.is_string())
- return false;
-
- const auto& key = param.first.GetString();
- return (key == kUserPresenceMapKey || key == kUserVerificationMapKey) &&
- param.second.is_bool();
- });
-}
-
-} // namespace
-
-CtapGetAssertionRequest::CtapGetAssertionRequest(
- std::string rp_id,
- base::span<const uint8_t, kClientDataHashLength> client_data_hash)
+CtapGetAssertionRequest::CtapGetAssertionRequest(std::string rp_id,
+ std::string client_data_json)
: rp_id_(std::move(rp_id)),
- client_data_hash_(fido_parsing_utils::Materialize(client_data_hash)) {}
+ client_data_json_(std::move(client_data_json)),
+ client_data_hash_(
+ fido_parsing_utils::CreateSHA256Hash(client_data_json_)) {}
CtapGetAssertionRequest::CtapGetAssertionRequest(
const CtapGetAssertionRequest& that) = default;
@@ -66,46 +37,44 @@ CtapGetAssertionRequest& CtapGetAssertionRequest::operator=(
CtapGetAssertionRequest::~CtapGetAssertionRequest() = default;
std::vector<uint8_t> CtapGetAssertionRequest::EncodeAsCBOR() const {
- cbor::CBORValue::MapValue cbor_map;
- cbor_map[cbor::CBORValue(1)] = cbor::CBORValue(rp_id_);
- cbor_map[cbor::CBORValue(2)] = cbor::CBORValue(client_data_hash_);
+ cbor::Value::MapValue cbor_map;
+ cbor_map[cbor::Value(1)] = cbor::Value(rp_id_);
+ cbor_map[cbor::Value(2)] = cbor::Value(client_data_hash_);
if (allow_list_) {
- cbor::CBORValue::ArrayValue allow_list_array;
+ cbor::Value::ArrayValue allow_list_array;
for (const auto& descriptor : *allow_list_) {
allow_list_array.push_back(descriptor.ConvertToCBOR());
}
- cbor_map[cbor::CBORValue(3)] = cbor::CBORValue(std::move(allow_list_array));
+ cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array));
}
if (pin_auth_) {
- cbor_map[cbor::CBORValue(6)] = cbor::CBORValue(*pin_auth_);
+ cbor_map[cbor::Value(6)] = cbor::Value(*pin_auth_);
}
if (pin_protocol_) {
- cbor_map[cbor::CBORValue(7)] = cbor::CBORValue(*pin_protocol_);
+ cbor_map[cbor::Value(7)] = cbor::Value(*pin_protocol_);
}
- cbor::CBORValue::MapValue option_map;
+ cbor::Value::MapValue option_map;
// User presence is required by default.
if (!user_presence_required_) {
- option_map[cbor::CBORValue(kUserPresenceMapKey)] =
- cbor::CBORValue(user_presence_required_);
+ option_map[cbor::Value(kUserPresenceMapKey)] =
+ cbor::Value(user_presence_required_);
}
// User verification is not required by default.
if (user_verification_ == UserVerificationRequirement::kRequired) {
- option_map[cbor::CBORValue(kUserVerificationMapKey)] =
- cbor::CBORValue(true);
+ option_map[cbor::Value(kUserVerificationMapKey)] = cbor::Value(true);
}
if (!option_map.empty()) {
- cbor_map[cbor::CBORValue(5)] = cbor::CBORValue(std::move(option_map));
+ cbor_map[cbor::Value(5)] = cbor::Value(std::move(option_map));
}
- auto serialized_param =
- cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_map)));
+ auto serialized_param = cbor::Writer::Write(cbor::Value(std::move(cbor_map)));
DCHECK(serialized_param);
std::vector<uint8_t> cbor_request({base::strict_cast<uint8_t>(
@@ -151,106 +120,20 @@ CtapGetAssertionRequest& CtapGetAssertionRequest::SetCableExtension(
return *this;
}
-CtapGetAssertionRequest&
-CtapGetAssertionRequest::SetAlternativeApplicationParameter(
- base::span<const uint8_t, kRpIdHashLength>
- alternative_application_parameter) {
+CtapGetAssertionRequest& CtapGetAssertionRequest::SetAppId(std::string app_id) {
+ app_id_ = std::move(app_id);
alternative_application_parameter_ =
- fido_parsing_utils::Materialize(alternative_application_parameter);
+ std::array<uint8_t, crypto::kSHA256Length>();
+ crypto::SHA256HashString(*app_id_, alternative_application_parameter_->data(),
+ alternative_application_parameter_->size());
return *this;
}
bool CtapGetAssertionRequest::CheckResponseRpIdHash(
const std::array<uint8_t, kRpIdHashLength>& response_rp_id_hash) {
return response_rp_id_hash == fido_parsing_utils::CreateSHA256Hash(rp_id_) ||
- (alternative_application_parameter_ &&
- response_rp_id_hash == *alternative_application_parameter_);
-}
-
-base::Optional<CtapGetAssertionRequest> ParseCtapGetAssertionRequest(
- base::span<const uint8_t> request_bytes) {
- const auto& cbor_request = cbor::CBORReader::Read(request_bytes);
- if (!cbor_request || !cbor_request->is_map())
- return base::nullopt;
-
- const auto& request_map = cbor_request->GetMap();
- if (!AreGetAssertionRequestMapKeysCorrect(request_map))
- return base::nullopt;
-
- const auto rp_id_it = request_map.find(cbor::CBORValue(1));
- if (rp_id_it == request_map.end() || !rp_id_it->second.is_string())
- return base::nullopt;
-
- const auto client_data_hash_it = request_map.find(cbor::CBORValue(2));
- if (client_data_hash_it == request_map.end() ||
- !client_data_hash_it->second.is_bytestring())
- return base::nullopt;
-
- const auto client_data_hash =
- base::make_span(client_data_hash_it->second.GetBytestring())
- .subspan<0, kClientDataHashLength>();
- CtapGetAssertionRequest request(rp_id_it->second.GetString(),
- client_data_hash);
-
- const auto allow_list_it = request_map.find(cbor::CBORValue(3));
- if (allow_list_it != request_map.end()) {
- if (!allow_list_it->second.is_array())
- return base::nullopt;
-
- const auto& credential_descriptors = allow_list_it->second.GetArray();
- std::vector<PublicKeyCredentialDescriptor> allow_list;
- for (const auto& credential_descriptor : credential_descriptors) {
- auto allowed_credential =
- PublicKeyCredentialDescriptor::CreateFromCBORValue(
- credential_descriptor);
- if (!allowed_credential)
- return base::nullopt;
-
- allow_list.push_back(std::move(*allowed_credential));
- }
- request.SetAllowList(std::move(allow_list));
- }
-
- const auto option_it = request_map.find(cbor::CBORValue(5));
- if (option_it != request_map.end()) {
- if (!option_it->second.is_map())
- return base::nullopt;
-
- const auto& option_map = option_it->second.GetMap();
- if (!IsGetAssertionOptionMapFormatCorrect(option_map))
- return base::nullopt;
-
- const auto user_presence_option =
- option_map.find(cbor::CBORValue(kUserPresenceMapKey));
- if (user_presence_option != option_map.end())
- request.SetUserPresenceRequired(user_presence_option->second.GetBool());
-
- const auto uv_option =
- option_map.find(cbor::CBORValue(kUserVerificationMapKey));
- if (uv_option != option_map.end())
- request.SetUserVerification(
- uv_option->second.GetBool()
- ? UserVerificationRequirement::kRequired
- : UserVerificationRequirement::kPreferred);
- }
-
- const auto pin_auth_it = request_map.find(cbor::CBORValue(6));
- if (pin_auth_it != request_map.end()) {
- if (!pin_auth_it->second.is_bytestring())
- return base::nullopt;
- request.SetPinAuth(pin_auth_it->second.GetBytestring());
- }
-
- const auto pin_protocol_it = request_map.find(cbor::CBORValue(7));
- if (pin_protocol_it != request_map.end()) {
- if (!pin_protocol_it->second.is_unsigned() ||
- pin_protocol_it->second.GetUnsigned() >
- std::numeric_limits<uint8_t>::max())
- return base::nullopt;
- request.SetPinProtocol(pin_auth_it->second.GetUnsigned());
- }
-
- return request;
+ (app_id_ &&
+ response_rp_id_hash == *alternative_application_parameter());
}
} // namespace device
diff --git a/chromium/device/fido/ctap_get_assertion_request.h b/chromium/device/fido/ctap_get_assertion_request.h
index 4264606d9bb..84982ee3858 100644
--- a/chromium/device/fido/ctap_get_assertion_request.h
+++ b/chromium/device/fido/ctap_get_assertion_request.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <array>
#include <string>
#include <vector>
@@ -14,6 +15,7 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "crypto/sha2.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_constants.h"
#include "device/fido/public_key_credential_descriptor.h"
@@ -25,9 +27,9 @@ namespace device {
// https://fidoalliance.org/specs/fido-v2.0-rd-20161004/fido-client-to-authenticator-protocol-v2.0-rd-20161004.html#authenticatorgetassertion
class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
public:
- CtapGetAssertionRequest(
- std::string rp_id,
- base::span<const uint8_t, kClientDataHashLength> client_data_hash);
+ using ClientDataHash = std::array<uint8_t, kClientDataHashLength>;
+
+ CtapGetAssertionRequest(std::string rp_id, std::string client_data_json);
CtapGetAssertionRequest(const CtapGetAssertionRequest& that);
CtapGetAssertionRequest(CtapGetAssertionRequest&& that);
CtapGetAssertionRequest& operator=(const CtapGetAssertionRequest& other);
@@ -48,9 +50,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
CtapGetAssertionRequest& SetPinProtocol(uint8_t pin_protocol);
CtapGetAssertionRequest& SetCableExtension(
std::vector<CableDiscoveryData> cable_extension);
- CtapGetAssertionRequest& SetAlternativeApplicationParameter(
- base::span<const uint8_t, kRpIdHashLength>
- alternative_application_parameter);
+ CtapGetAssertionRequest& SetAppId(std::string app_id);
// Return true if the given RP ID hash from a response is valid for this
// request.
@@ -58,6 +58,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
const std::array<uint8_t, kRpIdHashLength>& response_rp_id_hash);
const std::string& rp_id() const { return rp_id_; }
+ const std::string& client_data_json() const { return client_data_json_; }
const std::array<uint8_t, kClientDataHashLength>& client_data_hash() const {
return client_data_hash_;
}
@@ -85,9 +86,16 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
alternative_application_parameter() const {
return alternative_application_parameter_;
}
+ const base::Optional<std::string>& app_id() const { return app_id_; }
+
+ bool is_incognito_mode() const { return is_incognito_mode_; }
+ void set_is_incognito_mode(bool is_incognito_mode) {
+ is_incognito_mode_ = is_incognito_mode;
+ }
private:
std::string rp_id_;
+ std::string client_data_json_;
std::array<uint8_t, kClientDataHashLength> client_data_hash_;
UserVerificationRequirement user_verification_ =
UserVerificationRequirement::kPreferred;
@@ -97,13 +105,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
base::Optional<std::vector<uint8_t>> pin_auth_;
base::Optional<uint8_t> pin_protocol_;
base::Optional<std::vector<CableDiscoveryData>> cable_extension_;
- base::Optional<std::array<uint8_t, kRpIdHashLength>>
+ base::Optional<std::string> app_id_;
+ base::Optional<std::array<uint8_t, crypto::kSHA256Length>>
alternative_application_parameter_;
-};
-COMPONENT_EXPORT(DEVICE_FIDO)
-base::Optional<CtapGetAssertionRequest> ParseCtapGetAssertionRequest(
- base::span<const uint8_t> request_bytes);
+ bool is_incognito_mode_ = false;
+};
} // namespace device
diff --git a/chromium/device/fido/ctap_make_credential_request.cc b/chromium/device/fido/ctap_make_credential_request.cc
index 5300df4a4f3..256aa28ccaf 100644
--- a/chromium/device/fido/ctap_make_credential_request.cc
+++ b/chromium/device/fido/ctap_make_credential_request.cc
@@ -9,48 +9,20 @@
#include <utility>
#include "base/numerics/safe_conversions.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/writer.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
-namespace {
-
-bool AreMakeCredentialRequestMapKeysCorrect(
- const cbor::CBORValue::MapValue& request_map) {
- return std::all_of(request_map.begin(), request_map.end(),
- [](const auto& param) {
- if (!param.first.is_integer())
- return false;
-
- const auto& key = param.first.GetInteger();
- return (key <= 9u && key >= 1u);
- });
-}
-
-bool IsMakeCredentialOptionMapFormatCorrect(
- const cbor::CBORValue::MapValue& option_map) {
- return std::all_of(
- option_map.begin(), option_map.end(), [](const auto& param) {
- if (!param.first.is_string())
- return false;
-
- const auto& key = param.first.GetString();
- return ((key == kResidentKeyMapKey || key == kUserVerificationMapKey) &&
- param.second.is_bool());
- });
-}
-
-} // namespace
-
CtapMakeCredentialRequest::CtapMakeCredentialRequest(
- base::span<const uint8_t, kClientDataHashLength> client_data_hash,
+ std::string client_data_json,
PublicKeyCredentialRpEntity rp,
PublicKeyCredentialUserEntity user,
PublicKeyCredentialParams public_key_credential_params)
- : client_data_hash_(fido_parsing_utils::Materialize(client_data_hash)),
+ : client_data_json_(std::move(client_data_json)),
+ client_data_hash_(
+ fido_parsing_utils::CreateSHA256Hash(client_data_json_)),
rp_(std::move(rp)),
user_(std::move(user)),
public_key_credential_params_(std::move(public_key_credential_params)) {}
@@ -70,47 +42,51 @@ CtapMakeCredentialRequest& CtapMakeCredentialRequest::operator=(
CtapMakeCredentialRequest::~CtapMakeCredentialRequest() = default;
std::vector<uint8_t> CtapMakeCredentialRequest::EncodeAsCBOR() const {
- cbor::CBORValue::MapValue cbor_map;
- cbor_map[cbor::CBORValue(1)] = cbor::CBORValue(client_data_hash_);
- cbor_map[cbor::CBORValue(2)] = rp_.ConvertToCBOR();
- cbor_map[cbor::CBORValue(3)] = user_.ConvertToCBOR();
- cbor_map[cbor::CBORValue(4)] = public_key_credential_params_.ConvertToCBOR();
+ cbor::Value::MapValue cbor_map;
+ cbor_map[cbor::Value(1)] = cbor::Value(client_data_hash_);
+ cbor_map[cbor::Value(2)] = rp_.ConvertToCBOR();
+ cbor_map[cbor::Value(3)] = user_.ConvertToCBOR();
+ cbor_map[cbor::Value(4)] = public_key_credential_params_.ConvertToCBOR();
if (exclude_list_) {
- cbor::CBORValue::ArrayValue exclude_list_array;
+ cbor::Value::ArrayValue exclude_list_array;
for (const auto& descriptor : *exclude_list_) {
exclude_list_array.push_back(descriptor.ConvertToCBOR());
}
- cbor_map[cbor::CBORValue(5)] =
- cbor::CBORValue(std::move(exclude_list_array));
+ cbor_map[cbor::Value(5)] = cbor::Value(std::move(exclude_list_array));
+ }
+
+ if (hmac_secret_) {
+ cbor::Value::MapValue extensions;
+ extensions[cbor::Value(kExtensionHmacSecret)] = cbor::Value(true);
+ cbor_map[cbor::Value(6)] = cbor::Value(std::move(extensions));
}
+
if (pin_auth_) {
- cbor_map[cbor::CBORValue(8)] = cbor::CBORValue(*pin_auth_);
+ cbor_map[cbor::Value(8)] = cbor::Value(*pin_auth_);
}
if (pin_protocol_) {
- cbor_map[cbor::CBORValue(9)] = cbor::CBORValue(*pin_protocol_);
+ cbor_map[cbor::Value(9)] = cbor::Value(*pin_protocol_);
}
- cbor::CBORValue::MapValue option_map;
+ cbor::Value::MapValue option_map;
- // Resident keys are not supported by default.
- if (resident_key_supported_) {
- option_map[cbor::CBORValue(kResidentKeyMapKey)] =
- cbor::CBORValue(resident_key_supported_);
+ // Resident keys are not required by default.
+ if (resident_key_required_) {
+ option_map[cbor::Value(kResidentKeyMapKey)] =
+ cbor::Value(resident_key_required_);
}
// User verification is not required by default.
- if (user_verification_required_) {
- option_map[cbor::CBORValue(kUserVerificationMapKey)] =
- cbor::CBORValue(user_verification_required_);
+ if (user_verification_ == UserVerificationRequirement::kRequired) {
+ option_map[cbor::Value(kUserVerificationMapKey)] = cbor::Value(true);
}
if (!option_map.empty()) {
- cbor_map[cbor::CBORValue(7)] = cbor::CBORValue(std::move(option_map));
+ cbor_map[cbor::Value(7)] = cbor::Value(std::move(option_map));
}
- auto serialized_param =
- cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_map)));
+ auto serialized_param = cbor::Writer::Write(cbor::Value(std::move(cbor_map)));
DCHECK(serialized_param);
std::vector<uint8_t> cbor_request({base::strict_cast<uint8_t>(
@@ -121,15 +97,21 @@ std::vector<uint8_t> CtapMakeCredentialRequest::EncodeAsCBOR() const {
}
CtapMakeCredentialRequest&
-CtapMakeCredentialRequest::SetUserVerificationRequired(
- bool user_verification_required) {
- user_verification_required_ = user_verification_required;
+CtapMakeCredentialRequest::SetAuthenticatorAttachment(
+ AuthenticatorAttachment authenticator_attachment) {
+ authenticator_attachment_ = authenticator_attachment;
return *this;
}
-CtapMakeCredentialRequest& CtapMakeCredentialRequest::SetResidentKeySupported(
- bool resident_key_supported) {
- resident_key_supported_ = resident_key_supported;
+CtapMakeCredentialRequest& CtapMakeCredentialRequest::SetUserVerification(
+ UserVerificationRequirement user_verification) {
+ user_verification_ = user_verification;
+ return *this;
+}
+
+CtapMakeCredentialRequest& CtapMakeCredentialRequest::SetResidentKeyRequired(
+ bool resident_key_required) {
+ resident_key_required_ = resident_key_required;
return *this;
}
@@ -158,112 +140,10 @@ CtapMakeCredentialRequest::SetIsIndividualAttestation(
return *this;
}
-base::Optional<CtapMakeCredentialRequest> ParseCtapMakeCredentialRequest(
- base::span<const uint8_t> request_bytes) {
- const auto& cbor_request = cbor::CBORReader::Read(request_bytes);
- if (!cbor_request || !cbor_request->is_map())
- return base::nullopt;
-
- const auto& request_map = cbor_request->GetMap();
- if (!AreMakeCredentialRequestMapKeysCorrect(request_map))
- return base::nullopt;
-
- const auto client_data_hash_it = request_map.find(cbor::CBORValue(1));
- if (client_data_hash_it == request_map.end() ||
- !client_data_hash_it->second.is_bytestring())
- return base::nullopt;
-
- const auto client_data_hash =
- base::make_span(client_data_hash_it->second.GetBytestring())
- .subspan<0, kClientDataHashLength>();
-
- const auto rp_entity_it = request_map.find(cbor::CBORValue(2));
- if (rp_entity_it == request_map.end() || !rp_entity_it->second.is_map())
- return base::nullopt;
-
- auto rp_entity =
- PublicKeyCredentialRpEntity::CreateFromCBORValue(rp_entity_it->second);
- if (!rp_entity)
- return base::nullopt;
-
- const auto user_entity_it = request_map.find(cbor::CBORValue(3));
- if (user_entity_it == request_map.end() || !user_entity_it->second.is_map())
- return base::nullopt;
-
- auto user_entity = PublicKeyCredentialUserEntity::CreateFromCBORValue(
- user_entity_it->second);
- if (!user_entity)
- return base::nullopt;
-
- const auto credential_params_it = request_map.find(cbor::CBORValue(4));
- if (credential_params_it == request_map.end())
- return base::nullopt;
-
- auto credential_params = PublicKeyCredentialParams::CreateFromCBORValue(
- credential_params_it->second);
- if (!credential_params)
- return base::nullopt;
-
- CtapMakeCredentialRequest request(client_data_hash, std::move(*rp_entity),
- std::move(*user_entity),
- std::move(*credential_params));
-
- const auto exclude_list_it = request_map.find(cbor::CBORValue(5));
- if (exclude_list_it != request_map.end()) {
- if (!exclude_list_it->second.is_array())
- return base::nullopt;
-
- const auto& credential_descriptors = exclude_list_it->second.GetArray();
- std::vector<PublicKeyCredentialDescriptor> exclude_list;
- for (const auto& credential_descriptor : credential_descriptors) {
- auto excluded_credential =
- PublicKeyCredentialDescriptor::CreateFromCBORValue(
- credential_descriptor);
- if (!excluded_credential)
- return base::nullopt;
-
- exclude_list.push_back(std::move(*excluded_credential));
- }
- request.SetExcludeList(std::move(exclude_list));
- }
-
- const auto option_it = request_map.find(cbor::CBORValue(7));
- if (option_it != request_map.end()) {
- if (!option_it->second.is_map())
- return base::nullopt;
-
- const auto& option_map = option_it->second.GetMap();
- if (!IsMakeCredentialOptionMapFormatCorrect(option_map))
- return base::nullopt;
-
- const auto resident_key_option =
- option_map.find(cbor::CBORValue(kResidentKeyMapKey));
- if (resident_key_option != option_map.end())
- request.SetResidentKeySupported(resident_key_option->second.GetBool());
-
- const auto uv_option =
- option_map.find(cbor::CBORValue(kUserVerificationMapKey));
- if (uv_option != option_map.end())
- request.SetUserVerificationRequired(uv_option->second.GetBool());
- }
-
- const auto pin_auth_it = request_map.find(cbor::CBORValue(8));
- if (pin_auth_it != request_map.end()) {
- if (!pin_auth_it->second.is_bytestring())
- return base::nullopt;
- request.SetPinAuth(pin_auth_it->second.GetBytestring());
- }
-
- const auto pin_protocol_it = request_map.find(cbor::CBORValue(9));
- if (pin_protocol_it != request_map.end()) {
- if (!pin_protocol_it->second.is_unsigned() ||
- pin_protocol_it->second.GetUnsigned() >
- std::numeric_limits<uint8_t>::max())
- return base::nullopt;
- request.SetPinProtocol(pin_auth_it->second.GetUnsigned());
- }
-
- return request;
+CtapMakeCredentialRequest& CtapMakeCredentialRequest::SetHmacSecret(
+ bool hmac_secret) {
+ hmac_secret_ = hmac_secret;
+ return *this;
}
} // namespace device
diff --git a/chromium/device/fido/ctap_make_credential_request.h b/chromium/device/fido/ctap_make_credential_request.h
index 3b434915529..d639b0ada8f 100644
--- a/chromium/device/fido/ctap_make_credential_request.h
+++ b/chromium/device/fido/ctap_make_credential_request.h
@@ -15,6 +15,7 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "device/fido/fido_constants.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_params.h"
#include "device/fido/public_key_credential_rp_entity.h"
@@ -27,8 +28,10 @@ namespace device {
// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
class COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
public:
+ using ClientDataHash = std::array<uint8_t, kClientDataHashLength>;
+
CtapMakeCredentialRequest(
- base::span<const uint8_t, kClientDataHashLength> client_data_hash,
+ std::string client_data_json,
PublicKeyCredentialRpEntity rp,
PublicKeyCredentialUserEntity user,
PublicKeyCredentialParams public_key_credential_params);
@@ -43,16 +46,20 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
// https://drafts.fidoalliance.org/fido-2/latest/fido-client-to-authenticator-protocol-v2.0-wd-20180305.html#authenticatorMakeCredential
std::vector<uint8_t> EncodeAsCBOR() const;
- CtapMakeCredentialRequest& SetUserVerificationRequired(
- bool user_verfication_required);
- CtapMakeCredentialRequest& SetResidentKeySupported(bool resident_key);
+ CtapMakeCredentialRequest& SetAuthenticatorAttachment(
+ AuthenticatorAttachment authenticator_attachment);
+ CtapMakeCredentialRequest& SetUserVerification(
+ UserVerificationRequirement user_verification);
+ CtapMakeCredentialRequest& SetResidentKeyRequired(bool resident_key);
CtapMakeCredentialRequest& SetExcludeList(
std::vector<PublicKeyCredentialDescriptor> exclude_list);
CtapMakeCredentialRequest& SetPinAuth(std::vector<uint8_t> pin_auth);
CtapMakeCredentialRequest& SetPinProtocol(uint8_t pin_protocol);
CtapMakeCredentialRequest& SetIsIndividualAttestation(
bool is_individual_attestation);
+ CtapMakeCredentialRequest& SetHmacSecret(bool hmac_secret);
+ const std::string& client_data_json() const { return client_data_json_; }
const std::array<uint8_t, kClientDataHashLength>& client_data_hash() const {
return client_data_hash_;
}
@@ -61,11 +68,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
const PublicKeyCredentialParams& public_key_credential_params() const {
return public_key_credential_params_;
}
- bool user_verification_required() const {
- return user_verification_required_;
+ UserVerificationRequirement user_verification() const {
+ return user_verification_;
+ }
+ AuthenticatorAttachment authenticator_attachment() const {
+ return authenticator_attachment_;
}
- bool resident_key_supported() const { return resident_key_supported_; }
+ bool resident_key_required() const { return resident_key_required_; }
bool is_individual_attestation() const { return is_individual_attestation_; }
+ bool hmac_secret() const { return hmac_secret_; }
const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
exclude_list() const {
return exclude_list_;
@@ -74,24 +85,40 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
return pin_auth_;
}
+ void set_is_u2f_only(bool is_u2f_only) { is_u2f_only_ = is_u2f_only; }
+ bool is_u2f_only() { return is_u2f_only_; }
+
+ bool is_incognito_mode() const { return is_incognito_mode_; }
+ void set_is_incognito_mode(bool is_incognito_mode) {
+ is_incognito_mode_ = is_incognito_mode;
+ }
+
private:
+ std::string client_data_json_;
std::array<uint8_t, kClientDataHashLength> client_data_hash_;
PublicKeyCredentialRpEntity rp_;
PublicKeyCredentialUserEntity user_;
PublicKeyCredentialParams public_key_credential_params_;
- bool user_verification_required_ = false;
- bool resident_key_supported_ = false;
+ UserVerificationRequirement user_verification_ =
+ UserVerificationRequirement::kPreferred;
+ AuthenticatorAttachment authenticator_attachment_ =
+ AuthenticatorAttachment::kAny;
+ bool resident_key_required_ = false;
bool is_individual_attestation_ = false;
+ // hmac_secret_ indicates whether the "hmac-secret" extension should be
+ // asserted to CTAP2 authenticators.
+ bool hmac_secret_ = false;
+
+ // If true, instruct the request handler only to dispatch this request via
+ // U2F.
+ bool is_u2f_only_ = false;
+ bool is_incognito_mode_ = false;
base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list_;
base::Optional<std::vector<uint8_t>> pin_auth_;
base::Optional<uint8_t> pin_protocol_;
};
-COMPONENT_EXPORT(DEVICE_FIDO)
-base::Optional<CtapMakeCredentialRequest> ParseCtapMakeCredentialRequest(
- base::span<const uint8_t> request_bytes);
-
} // namespace device
#endif // DEVICE_FIDO_CTAP_MAKE_CREDENTIAL_REQUEST_H_
diff --git a/chromium/device/fido/ctap_request_unittest.cc b/chromium/device/fido/ctap_request_unittest.cc
index 2599eca7c9b..83a0c13c0b6 100644
--- a/chromium/device/fido/ctap_request_unittest.cc
+++ b/chromium/device/fido/ctap_request_unittest.cc
@@ -8,6 +8,7 @@
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
+#include "device/fido/virtual_ctap2_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,19 +27,20 @@ TEST(CTAPRequestTest, TestConstructMakeCredentialRequestParam) {
.SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
CtapMakeCredentialRequest make_credential_param(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams({{CredentialType::kPublicKey, 7},
{CredentialType::kPublicKey, 257}}));
- auto serialized_data = make_credential_param.SetResidentKeySupported(true)
- .SetUserVerificationRequired(true)
- .EncodeAsCBOR();
+ auto serialized_data =
+ make_credential_param.SetResidentKeyRequired(true)
+ .SetUserVerification(UserVerificationRequirement::kRequired)
+ .EncodeAsCBOR();
EXPECT_THAT(serialized_data, ::testing::ElementsAreArray(
test_data::kCtapMakeCredentialRequest));
}
TEST(CTAPRequestTest, TestConstructGetAssertionRequest) {
CtapGetAssertionRequest get_assertion_req("acme.com",
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
std::vector<PublicKeyCredentialDescriptor> allowed_list;
allowed_list.push_back(PublicKeyCredentialDescriptor(
@@ -80,39 +82,42 @@ TEST(CTAPRequestTest, TestConstructCtapAuthenticatorRequestParam) {
::testing::ElementsAre(kSerializedResetCmd));
}
-TEST(CTAPRequestTest, ParseMakeCredentialRequestForVirtualCtapKey) {
- const auto request = ParseCtapMakeCredentialRequest(
+TEST(VirtualCtap2DeviceTest, ParseMakeCredentialRequestForVirtualCtapKey) {
+ const auto request_and_hash = ParseCtapMakeCredentialRequest(
base::make_span(test_data::kCtapMakeCredentialRequest).subspan(1));
- ASSERT_TRUE(request);
- EXPECT_THAT(request->client_data_hash(),
+ ASSERT_TRUE(request_and_hash);
+ auto request = std::get<0>(*request_and_hash);
+ auto client_data_hash = std::get<1>(*request_and_hash);
+ EXPECT_THAT(client_data_hash,
::testing::ElementsAreArray(test_data::kClientDataHash));
- EXPECT_EQ(test_data::kRelyingPartyId, request->rp().rp_id());
- EXPECT_EQ("Acme", request->rp().rp_name());
- EXPECT_THAT(request->user().user_id(),
+ EXPECT_EQ(test_data::kRelyingPartyId, request.rp().rp_id());
+ EXPECT_EQ("Acme", request.rp().rp_name());
+ EXPECT_THAT(request.user().user_id(),
::testing::ElementsAreArray(test_data::kUserId));
- ASSERT_TRUE(request->user().user_name());
- EXPECT_EQ("johnpsmith@example.com", *request->user().user_name());
- ASSERT_TRUE(request->user().user_display_name());
- EXPECT_EQ("John P. Smith", *request->user().user_display_name());
- ASSERT_TRUE(request->user().user_icon_url());
+ ASSERT_TRUE(request.user().user_name());
+ EXPECT_EQ("johnpsmith@example.com", *request.user().user_name());
+ ASSERT_TRUE(request.user().user_display_name());
+ EXPECT_EQ("John P. Smith", *request.user().user_display_name());
+ ASSERT_TRUE(request.user().user_icon_url());
EXPECT_EQ("https://pics.acme.com/00/p/aBjjjpqPb.png",
- request->user().user_icon_url()->spec());
- ASSERT_EQ(2u, request->public_key_credential_params()
+ request.user().user_icon_url()->spec());
+ ASSERT_EQ(2u, request.public_key_credential_params()
.public_key_credential_params()
.size());
- EXPECT_EQ(7, request->public_key_credential_params()
+ EXPECT_EQ(7, request.public_key_credential_params()
.public_key_credential_params()
.at(0)
.algorithm);
- EXPECT_EQ(257, request->public_key_credential_params()
+ EXPECT_EQ(257, request.public_key_credential_params()
.public_key_credential_params()
.at(1)
.algorithm);
- EXPECT_TRUE(request->user_verification_required());
- EXPECT_TRUE(request->resident_key_supported());
+ EXPECT_EQ(UserVerificationRequirement::kRequired,
+ request.user_verification());
+ EXPECT_TRUE(request.resident_key_required());
}
-TEST(CTAPRequestTest, ParseGetAssertionRequestForVirtualCtapKey) {
+TEST(VirtualCtap2DeviceTest, ParseGetAssertionRequestForVirtualCtapKey) {
constexpr uint8_t kAllowedCredentialOne[] = {
0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94,
0x2f, 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b,
@@ -127,22 +132,24 @@ TEST(CTAPRequestTest, ParseGetAssertionRequestForVirtualCtapKey) {
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
- const auto request = ParseCtapGetAssertionRequest(
+ auto request_and_hash = ParseCtapGetAssertionRequest(
base::make_span(test_data::kTestComplexCtapGetAssertionRequest)
.subspan(1));
- ASSERT_TRUE(request);
- EXPECT_THAT(request->client_data_hash(),
+ ASSERT_TRUE(request_and_hash);
+ auto request = std::get<0>(*request_and_hash);
+ auto client_data_hash = std::get<1>(*request_and_hash);
+ EXPECT_THAT(client_data_hash,
::testing::ElementsAreArray(test_data::kClientDataHash));
- EXPECT_EQ(test_data::kRelyingPartyId, request->rp_id());
+ EXPECT_EQ(test_data::kRelyingPartyId, request.rp_id());
EXPECT_EQ(UserVerificationRequirement::kRequired,
- request->user_verification());
- EXPECT_FALSE(request->user_presence_required());
- ASSERT_TRUE(request->allow_list());
- ASSERT_EQ(2u, request->allow_list()->size());
+ request.user_verification());
+ EXPECT_FALSE(request.user_presence_required());
+ ASSERT_TRUE(request.allow_list());
+ ASSERT_EQ(2u, request.allow_list()->size());
- EXPECT_THAT(request->allow_list()->at(0).id(),
+ EXPECT_THAT(request.allow_list()->at(0).id(),
::testing::ElementsAreArray(kAllowedCredentialOne));
- EXPECT_THAT(request->allow_list()->at(1).id(),
+ EXPECT_THAT(request.allow_list()->at(1).id(),
::testing::ElementsAreArray(kAllowedCredentialTwo));
}
} // namespace device
diff --git a/chromium/device/fido/ctap_response_fuzzer.cc b/chromium/device/fido/ctap_response_fuzzer.cc
index 4f251e6795c..c3abf101dde 100644
--- a/chromium/device/fido/ctap_response_fuzzer.cc
+++ b/chromium/device/fido/ctap_response_fuzzer.cc
@@ -35,14 +35,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
auto response = device::ReadCTAPMakeCredentialResponse(
FidoTransportProtocol::kUsbHumanInterfaceDevice, input);
if (response)
- response->EraseAttestationStatement();
+ response->EraseAttestationStatement(AttestationObject::AAGUID::kErase);
response = device::AuthenticatorMakeCredentialResponse::
CreateFromU2fRegisterResponse(
FidoTransportProtocol::kUsbHumanInterfaceDevice,
relying_party_id_hash, input);
if (response)
- response->EraseAttestationStatement();
+ response->EraseAttestationStatement(AttestationObject::AAGUID::kErase);
device::ReadCTAPGetAssertionResponse(input);
std::vector<uint8_t> u2f_response_data(data, data + size);
diff --git a/chromium/device/fido/ctap_response_unittest.cc b/chromium/device/fido/ctap_response_unittest.cc
index a201c75d6ab..609965c945e 100644
--- a/chromium/device/fido/ctap_response_unittest.cc
+++ b/chromium/device/fido/ctap_response_unittest.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "device/fido/attestation_statement_formats.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
@@ -318,43 +318,43 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
FidoTransportProtocol::kUsbHumanInterfaceDevice,
test_data::kTestMakeCredentialResponse);
ASSERT_TRUE(make_credential_response);
- auto cbor_attestation_object = cbor::CBORReader::Read(
+ auto cbor_attestation_object = cbor::Reader::Read(
make_credential_response->GetCBOREncodedAttestationObject());
ASSERT_TRUE(cbor_attestation_object);
ASSERT_TRUE(cbor_attestation_object->is_map());
const auto& attestation_object_map = cbor_attestation_object->GetMap();
- auto it = attestation_object_map.find(cbor::CBORValue(kFormatKey));
+ auto it = attestation_object_map.find(cbor::Value(kFormatKey));
ASSERT_TRUE(it != attestation_object_map.end());
ASSERT_TRUE(it->second.is_string());
EXPECT_EQ(it->second.GetString(), "packed");
- it = attestation_object_map.find(cbor::CBORValue(kAuthDataKey));
+ it = attestation_object_map.find(cbor::Value(kAuthDataKey));
ASSERT_TRUE(it != attestation_object_map.end());
ASSERT_TRUE(it->second.is_bytestring());
EXPECT_THAT(
it->second.GetBytestring(),
::testing::ElementsAreArray(test_data::kCtap2MakeCredentialAuthData));
- it = attestation_object_map.find(cbor::CBORValue(kAttestationStatementKey));
+ it = attestation_object_map.find(cbor::Value(kAttestationStatementKey));
ASSERT_TRUE(it != attestation_object_map.end());
ASSERT_TRUE(it->second.is_map());
const auto& attestation_statement_map = it->second.GetMap();
- auto attStmt_it = attestation_statement_map.find(cbor::CBORValue("alg"));
+ auto attStmt_it = attestation_statement_map.find(cbor::Value("alg"));
ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
ASSERT_TRUE(attStmt_it->second.is_integer());
EXPECT_EQ(attStmt_it->second.GetInteger(), -7);
- attStmt_it = attestation_statement_map.find(cbor::CBORValue("sig"));
+ attStmt_it = attestation_statement_map.find(cbor::Value("sig"));
ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
ASSERT_TRUE(attStmt_it->second.is_bytestring());
EXPECT_THAT(
attStmt_it->second.GetBytestring(),
::testing::ElementsAreArray(test_data::kCtap2MakeCredentialSignature));
- attStmt_it = attestation_statement_map.find(cbor::CBORValue("x5c"));
+ attStmt_it = attestation_statement_map.find(cbor::Value("x5c"));
ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
const auto& certificate = attStmt_it->second;
ASSERT_TRUE(certificate.is_array());
@@ -373,7 +373,8 @@ TEST(CTAPResponseTest, TestMakeCredentialNoneAttestationResponse) {
FidoTransportProtocol::kUsbHumanInterfaceDevice,
test_data::kTestMakeCredentialResponse);
ASSERT_TRUE(make_credential_response);
- make_credential_response->EraseAttestationStatement();
+ make_credential_response->EraseAttestationStatement(
+ AttestationObject::AAGUID::kErase);
EXPECT_THAT(make_credential_response->GetCBOREncodedAttestationObject(),
::testing::ElementsAreArray(test_data::kNoneAttestationResponse));
}
@@ -425,8 +426,8 @@ TEST(CTAPResponseTest, TestParseU2fAttestationStatementCBOR) {
FidoAttestationStatement::CreateFromU2fRegisterResponse(
test_data::kTestU2fRegisterResponse);
ASSERT_TRUE(fido_attestation_statement);
- auto cbor = cbor::CBORWriter::Write(
- cbor::CBORValue(fido_attestation_statement->GetAsCBORMap()));
+ auto cbor = cbor::Writer::Write(
+ cbor::Value(fido_attestation_statement->GetAsCBORMap()));
ASSERT_TRUE(cbor);
EXPECT_THAT(*cbor, ::testing::ElementsAreArray(
test_data::kU2fAttestationStatementCBOR));
@@ -529,6 +530,21 @@ TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse) {
EXPECT_FALSE(response);
}
+TEST(CTAPResponseTest, TestParseU2fSignWithCTAP2Flags) {
+ std::vector<uint8_t> sign_response = GetTestSignResponse();
+ // Set two flags that should only be set in CTAP2 responses and expect parsing
+ // to fail.
+ sign_response[0] |=
+ static_cast<uint8_t>(AuthenticatorData::Flag::kExtensionDataIncluded);
+ sign_response[0] |=
+ static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
+
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ test_data::kApplicationParameter, sign_response,
+ GetTestCredentialRawIdBytes());
+ EXPECT_FALSE(response);
+}
+
TEST(CTAPResponseTest, TestParseU2fSignWithNullCorruptedCounter) {
// A sign response of less than 5 bytes.
auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
@@ -600,13 +616,24 @@ TEST(CTAPResponseTest, TestSerializeGetInfoResponse) {
TEST(CTAPResponseTest, TestSerializeMakeCredentialResponse) {
constexpr uint8_t kCoseEncodedPublicKey[] = {
- 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x65, 0x45, 0x53, 0x32, 0x35, 0x36, 0x61,
- 0x78, 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf,
- 0xa4, 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5,
- 0xe6, 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a, 0x61,
- 0x79, 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3,
- 0x21, 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd,
- 0x61, 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ // map(3)
+ 0xa3,
+ // "x"
+ 0x61, 0x78,
+ // byte(32)
+ 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4,
+ 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6,
+ 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
+ // "y"
+ 0x61, 0x79,
+ // byte(32)
+ 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21,
+ 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61,
+ 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ // "fmt"
+ 0x63, 0x61, 0x6c, 0x67,
+ // "ES256"
+ 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
};
const auto application_parameter =
@@ -631,11 +658,11 @@ TEST(CTAPResponseTest, TestSerializeMakeCredentialResponse) {
signature_counter,
std::move(attested_credential_data));
- cbor::CBORValue::MapValue attestation_map;
+ cbor::Value::MapValue attestation_map;
attestation_map.emplace("alg", -7);
attestation_map.emplace("sig", fido_parsing_utils::Materialize(
test_data::kCtap2MakeCredentialSignature));
- cbor::CBORValue::ArrayValue certificate_chain;
+ cbor::Value::ArrayValue certificate_chain;
certificate_chain.emplace_back(fido_parsing_utils::Materialize(
test_data::kCtap2MakeCredentialCertificate));
attestation_map.emplace("x5c", std::move(certificate_chain));
@@ -644,7 +671,7 @@ TEST(CTAPResponseTest, TestSerializeMakeCredentialResponse) {
AttestationObject(
std::move(authenticator_data),
std::make_unique<OpaqueAttestationStatement>(
- "packed", cbor::CBORValue(std::move(attestation_map)))));
+ "packed", cbor::Value(std::move(attestation_map)))));
EXPECT_THAT(
GetSerializedCtapDeviceResponse(response),
::testing::ElementsAreArray(
diff --git a/chromium/device/fido/device_response_converter.cc b/chromium/device/fido/device_response_converter.cc
index 4cfe62b173a..a31f7669639 100644
--- a/chromium/device/fido/device_response_converter.cc
+++ b/chromium/device/fido/device_response_converter.cc
@@ -12,8 +12,8 @@
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "base/stl_util.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/writer.h"
#include "device/fido/authenticator_data.h"
#include "device/fido/authenticator_supported_options.h"
#include "device/fido/fido_constants.h"
@@ -36,7 +36,7 @@ ProtocolVersion ConvertStringToProtocolVersion(base::StringPiece version) {
} // namespace
-using CBOR = cbor::CBORValue;
+using CBOR = cbor::Value;
CtapDeviceResponseCode GetResponseCode(base::span<const uint8_t> buffer) {
if (buffer.empty())
@@ -56,8 +56,7 @@ ReadCTAPMakeCredentialResponse(FidoTransportProtocol transport_used,
if (buffer.size() <= kResponseCodeLength)
return base::nullopt;
- base::Optional<CBOR> decoded_response =
- cbor::CBORReader::Read(buffer.subspan(1));
+ base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
if (!decoded_response || !decoded_response->is_map())
return base::nullopt;
@@ -92,8 +91,7 @@ base::Optional<AuthenticatorGetAssertionResponse> ReadCTAPGetAssertionResponse(
if (buffer.size() <= kResponseCodeLength)
return base::nullopt;
- base::Optional<CBOR> decoded_response =
- cbor::CBORReader::Read(buffer.subspan(1));
+ base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
if (!decoded_response || !decoded_response->is_map())
return base::nullopt;
@@ -151,8 +149,7 @@ base::Optional<AuthenticatorGetInfoResponse> ReadCTAPGetInfoResponse(
GetResponseCode(buffer) != CtapDeviceResponseCode::kSuccess)
return base::nullopt;
- base::Optional<CBOR> decoded_response =
- cbor::CBORReader::Read(buffer.subspan(1));
+ base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
if (!decoded_response || !decoded_response->is_map())
return base::nullopt;
diff --git a/chromium/device/fido/ec_public_key.cc b/chromium/device/fido/ec_public_key.cc
index effded9a490..207ae333a4b 100644
--- a/chromium/device/fido/ec_public_key.cc
+++ b/chromium/device/fido/ec_public_key.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/writer.h"
#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -65,13 +65,13 @@ ECPublicKey::ECPublicKey(std::string algorithm,
ECPublicKey::~ECPublicKey() = default;
std::vector<uint8_t> ECPublicKey::EncodeAsCOSEKey() const {
- cbor::CBORValue::MapValue map;
- map[cbor::CBORValue(1)] = cbor::CBORValue(2);
- map[cbor::CBORValue(3)] = cbor::CBORValue(-7);
- map[cbor::CBORValue(-1)] = cbor::CBORValue(1);
- map[cbor::CBORValue(-2)] = cbor::CBORValue(x_coordinate_);
- map[cbor::CBORValue(-3)] = cbor::CBORValue(y_coordinate_);
- return *cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+ cbor::Value::MapValue map;
+ map[cbor::Value(1)] = cbor::Value(2);
+ map[cbor::Value(3)] = cbor::Value(-7);
+ map[cbor::Value(-1)] = cbor::Value(1);
+ map[cbor::Value(-2)] = cbor::Value(x_coordinate_);
+ map[cbor::Value(-3)] = cbor::Value(y_coordinate_);
+ return *cbor::Writer::Write(cbor::Value(std::move(map)));
}
} // namespace device
diff --git a/chromium/device/fido/fake_fido_discovery.cc b/chromium/device/fido/fake_fido_discovery.cc
index 7e49f9a4a90..66b8fe4e4da 100644
--- a/chromium/device/fido/fake_fido_discovery.cc
+++ b/chromium/device/fido/fake_fido_discovery.cc
@@ -80,7 +80,7 @@ FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextCableDiscovery(
return next_cable_discovery_.get();
}
-std::unique_ptr<FidoDeviceDiscovery>
+std::unique_ptr<FidoDiscoveryBase>
ScopedFakeFidoDiscoveryFactory::CreateFidoDiscovery(
FidoTransportProtocol transport,
::service_manager::Connector* connector) {
diff --git a/chromium/device/fido/fake_fido_discovery.h b/chromium/device/fido/fake_fido_discovery.h
index 57a65b7b555..e83c91a7d99 100644
--- a/chromium/device/fido/fake_fido_discovery.h
+++ b/chromium/device/fido/fake_fido_discovery.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
-#include "device/fido/fido_device_discovery.h"
+#include "device/fido/fido_discovery_factory.h"
#include "device/fido/fido_transport_protocol.h"
namespace service_manager {
@@ -117,7 +117,7 @@ class ScopedFakeFidoDiscoveryFactory
StartMode mode = StartMode::kManual);
protected:
- std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery(
+ std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscovery(
FidoTransportProtocol transport,
::service_manager::Connector* connector) override;
diff --git a/chromium/device/fido/fake_fido_discovery_unittest.cc b/chromium/device/fido/fake_fido_discovery_unittest.cc
index 407d710a3d4..a17c20aea99 100644
--- a/chromium/device/fido/fake_fido_discovery_unittest.cc
+++ b/chromium/device/fido/fake_fido_discovery_unittest.cc
@@ -11,6 +11,7 @@
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
+#include "device/fido/fido_discovery_factory.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/mock_fido_discovery_observer.h"
@@ -150,7 +151,7 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest,
auto* injected_fake_discovery = factory.ForgeNextHidDiscovery();
ASSERT_EQ(FidoTransportProtocol::kUsbHumanInterfaceDevice,
injected_fake_discovery->transport());
- auto produced_discovery = FidoDeviceDiscovery::Create(
+ auto produced_discovery = FidoDiscoveryFactory::Create(
FidoTransportProtocol::kUsbHumanInterfaceDevice, nullptr);
EXPECT_TRUE(produced_discovery);
EXPECT_EQ(injected_fake_discovery, produced_discovery.get());
@@ -164,14 +165,14 @@ TEST_F(ScopedFakeFidoDiscoveryFactoryTest,
auto* injected_fake_discovery_1 = factory.ForgeNextBleDiscovery();
ASSERT_EQ(FidoTransportProtocol::kBluetoothLowEnergy,
injected_fake_discovery_1->transport());
- auto produced_discovery_1 = FidoDeviceDiscovery::Create(
+ auto produced_discovery_1 = FidoDiscoveryFactory::Create(
FidoTransportProtocol::kBluetoothLowEnergy, nullptr);
EXPECT_EQ(injected_fake_discovery_1, produced_discovery_1.get());
auto* injected_fake_discovery_2 = factory.ForgeNextBleDiscovery();
ASSERT_EQ(FidoTransportProtocol::kBluetoothLowEnergy,
injected_fake_discovery_2->transport());
- auto produced_discovery_2 = FidoDeviceDiscovery::Create(
+ auto produced_discovery_2 = FidoDiscoveryFactory::Create(
FidoTransportProtocol::kBluetoothLowEnergy, nullptr);
EXPECT_EQ(injected_fake_discovery_2, produced_discovery_2.get());
}
diff --git a/chromium/device/fido/features.cc b/chromium/device/fido/features.cc
new file mode 100644
index 00000000000..dad7f0d1335
--- /dev/null
+++ b/chromium/device/fido/features.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 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 "device/fido/features.h"
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace device {
+
+#if defined(OS_WIN)
+// Controls whether on Windows, U2F/CTAP2 requests are forwarded to the
+// native WebAuthentication API, where available.
+const base::Feature kWebAuthUseNativeWinApi{"WebAuthenticationUseNativeWinApi",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If true, the minimum API version check for integration with the native
+// Windows WebAuthentication API is disabled. This is an interim solution for
+// for manual testing while we await the release of a DLL that implements the
+// version check.
+const base::Feature kWebAuthDisableWinApiVersionCheckForTesting{
+ "WebAuthenticationDisableWinApiVersionCheckForTesting",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_WIN)
+
+extern const base::Feature kWebAuthProxyCryptotoken{
+ "WebAuthenticationProxyCryptotoken", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace device
diff --git a/chromium/device/fido/features.h b/chromium/device/fido/features.h
new file mode 100644
index 00000000000..dbcb880d0c6
--- /dev/null
+++ b/chromium/device/fido/features.h
@@ -0,0 +1,28 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_FEATURES_H_
+#define DEVICE_FIDO_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
+namespace device {
+
+#if defined(OS_WIN)
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const base::Feature kWebAuthUseNativeWinApi;
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const base::Feature kWebAuthDisableWinApiVersionCheckForTesting;
+#endif // defined(OS_WIN)
+
+// Controls the proxying of Cryptotoken requests through WebAuthn.
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const base::Feature kWebAuthProxyCryptotoken;
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FEATURES_H_
diff --git a/chromium/device/fido/fido_authenticator.h b/chromium/device/fido/fido_authenticator.h
index 4fb6b7bbcdc..6c00f3fbe2c 100644
--- a/chromium/device/fido/fido_authenticator.h
+++ b/chromium/device/fido/fido_authenticator.h
@@ -15,11 +15,11 @@
#include "base/strings/string16.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/authenticator_supported_options.h"
#include "device/fido/fido_transport_protocol.h"
namespace device {
-class AuthenticatorSupportedOptions;
class CtapGetAssertionRequest;
class CtapMakeCredentialRequest;
@@ -42,17 +42,19 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoAuthenticator {
// call is received, |callback| is invoked. Below MakeCredential() and
// GetAssertion() must only called after |callback| is invoked.
virtual void InitializeAuthenticator(base::OnceClosure callback) = 0;
- virtual void MakeCredential(
- CtapMakeCredentialRequest request,
- MakeCredentialCallback callback) = 0;
+ virtual void MakeCredential(CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) = 0;
virtual void GetAssertion(CtapGetAssertionRequest request,
GetAssertionCallback callback) = 0;
virtual void Cancel() = 0;
virtual std::string GetId() const = 0;
virtual base::string16 GetDisplayName() const = 0;
- virtual const AuthenticatorSupportedOptions& Options() const = 0;
- virtual FidoTransportProtocol AuthenticatorTransport() const = 0;
+ virtual const base::Optional<AuthenticatorSupportedOptions>& Options()
+ const = 0;
+ virtual base::Optional<FidoTransportProtocol> AuthenticatorTransport()
+ const = 0;
virtual bool IsInPairingMode() const = 0;
+ virtual bool IsPaired() const = 0;
virtual base::WeakPtr<FidoAuthenticator> GetWeakPtr() = 0;
private:
diff --git a/chromium/device/fido/fido_constants.cc b/chromium/device/fido/fido_constants.cc
index bae7c52d45e..8d477d2091a 100644
--- a/chromium/device/fido/fido_constants.cc
+++ b/chromium/device/fido/fido_constants.cc
@@ -77,4 +77,9 @@ const char kCableClientHelloMessage[] = "caBLE v1 client hello";
const char kCtap2Version[] = "FIDO_2_0";
const char kU2fVersion[] = "U2F_V2";
+const char kExtensionHmacSecret[] = "hmac-secret";
+
+const base::TimeDelta kBleDevicePairingModeWaitingInterval =
+ base::TimeDelta::FromSeconds(2);
+
} // namespace device
diff --git a/chromium/device/fido/fido_constants.h b/chromium/device/fido/fido_constants.h
index 2dc2a2136ac..e8723a7dd51 100644
--- a/chromium/device/fido/fido_constants.h
+++ b/chromium/device/fido/fido_constants.h
@@ -92,10 +92,8 @@ enum class CtapDeviceResponseCode : uint8_t {
kCtap1ErrChannelBusy = 0x06,
kCtap1ErrLockRequired = 0x0A,
kCtap1ErrInvalidChannel = 0x0B,
- kCtap2ErrCBORParsing = 0x10,
- kCtap2ErrUnexpectedType = 0x11,
+ kCtap2ErrCBORUnexpectedType = 0x11,
kCtap2ErrInvalidCBOR = 0x12,
- kCtap2ErrInvalidCBORType = 0x13,
kCtap2ErrMissingParameter = 0x14,
kCtap2ErrLimitExceeded = 0x15,
kCtap2ErrUnsupportedExtension = 0x16,
@@ -145,10 +143,8 @@ constexpr std::array<CtapDeviceResponseCode, 51> GetCtapResponseCodeList() {
CtapDeviceResponseCode::kCtap1ErrChannelBusy,
CtapDeviceResponseCode::kCtap1ErrLockRequired,
CtapDeviceResponseCode::kCtap1ErrInvalidChannel,
- CtapDeviceResponseCode::kCtap2ErrCBORParsing,
- CtapDeviceResponseCode::kCtap2ErrUnexpectedType,
+ CtapDeviceResponseCode::kCtap2ErrCBORUnexpectedType,
CtapDeviceResponseCode::kCtap2ErrInvalidCBOR,
- CtapDeviceResponseCode::kCtap2ErrInvalidCBORType,
CtapDeviceResponseCode::kCtap2ErrMissingParameter,
CtapDeviceResponseCode::kCtap2ErrLimitExceeded,
CtapDeviceResponseCode::kCtap2ErrUnsupportedExtension,
@@ -259,6 +255,16 @@ enum class U2fApduInstruction : uint8_t {
enum class CredentialType { kPublicKey };
+// Authenticator attachment constraint passed on from the relying party as a
+// parameter for AuthenticatorSelectionCriteria. |kAny| is equivalent to the
+// (optional) attachment field not being present.
+// https://w3c.github.io/webauthn/#attachment
+enum class AuthenticatorAttachment {
+ kAny,
+ kPlatform,
+ kCrossPlatform,
+};
+
// User verification constraint passed on from the relying party as a parameter
// for AuthenticatorSelectionCriteria and for CtapGetAssertion request.
// https://w3c.github.io/webauthn/#enumdef-userverificationrequirement
@@ -373,6 +379,17 @@ COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCableClientHelloMessage[];
COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCtap2Version[];
COMPONENT_EXPORT(DEVICE_FIDO) extern const char kU2fVersion[];
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kExtensionHmacSecret[];
+
+// Maximum number of seconds the browser waits for Bluetooth authenticator to
+// send packets that advertises that the device is in pairing mode before
+// setting pairing mode to false. The interval time is set to 2 seconds, which
+// is equivalent to the maximum Bluetooth error wait interval set by the CTAP
+// spec.
+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#BTCORE
+COMPONENT_EXPORT(DEVICE_FIDO)
+extern const base::TimeDelta kBleDevicePairingModeWaitingInterval;
+
} // namespace device
#endif // DEVICE_FIDO_FIDO_CONSTANTS_H_
diff --git a/chromium/device/fido/fido_device.cc b/chromium/device/fido/fido_device.cc
index edd97a2a2ed..b27a1e1bea9 100644
--- a/chromium/device/fido/fido_device.cc
+++ b/chromium/device/fido/fido_device.cc
@@ -27,6 +27,10 @@ bool FidoDevice::IsInPairingMode() const {
return false;
}
+bool FidoDevice::IsPaired() const {
+ return false;
+}
+
void FidoDevice::DiscoverSupportedProtocolAndDeviceInfo(
base::OnceClosure done) {
if (base::FeatureList::IsEnabled(kNewCtap2Device)) {
diff --git a/chromium/device/fido/fido_device.h b/chromium/device/fido/fido_device.h
index 5a8bb387085..e9ecfa77060 100644
--- a/chromium/device/fido/fido_device.h
+++ b/chromium/device/fido/fido_device.h
@@ -63,6 +63,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice {
virtual base::string16 GetDisplayName() const;
virtual FidoTransportProtocol DeviceTransport() const = 0;
virtual bool IsInPairingMode() const;
+ virtual bool IsPaired() const;
virtual base::WeakPtr<FidoDevice> GetWeakPtr() = 0;
// Sends a speculative AuthenticatorGetInfo request to determine whether the
diff --git a/chromium/device/fido/fido_device_authenticator.cc b/chromium/device/fido/fido_device_authenticator.cc
index f011e9ed46f..e68c7625994 100644
--- a/chromium/device/fido/fido_device_authenticator.cc
+++ b/chromium/device/fido/fido_device_authenticator.cc
@@ -27,8 +27,29 @@ void FidoDeviceAuthenticator::InitializeAuthenticator(
base::OnceClosure callback) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
- base::BindOnce(&FidoDevice::DiscoverSupportedProtocolAndDeviceInfo,
- device()->GetWeakPtr(), std::move(callback)));
+ base::BindOnce(
+ &FidoDevice::DiscoverSupportedProtocolAndDeviceInfo,
+ device()->GetWeakPtr(),
+ base::BindOnce(&FidoDeviceAuthenticator::InitializeAuthenticatorDone,
+ weak_factory_.GetWeakPtr(), std::move(callback))));
+}
+
+void FidoDeviceAuthenticator::InitializeAuthenticatorDone(
+ base::OnceClosure callback) {
+ DCHECK(!options_);
+ switch (device_->supported_protocol()) {
+ case ProtocolVersion::kU2f:
+ options_ = AuthenticatorSupportedOptions();
+ break;
+ case ProtocolVersion::kCtap:
+ DCHECK(device_->device_info()) << "uninitialized device";
+ options_ = device_->device_info()->options();
+ break;
+ case ProtocolVersion::kUnknown:
+ NOTREACHED() << "uninitialized device";
+ options_ = AuthenticatorSupportedOptions();
+ }
+ std::move(callback).Run();
}
void FidoDeviceAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
@@ -36,6 +57,18 @@ void FidoDeviceAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
DCHECK(!task_);
DCHECK(device_->SupportedProtocolIsInitialized())
<< "InitializeAuthenticator() must be called first.";
+ DCHECK(Options());
+
+ // Update the request to the "effective" user verification requirement.
+ // https://w3c.github.io/webauthn/#effective-user-verification-requirement-for-credential-creation
+ if (Options()->user_verification_availability() ==
+ AuthenticatorSupportedOptions::UserVerificationAvailability::
+ kSupportedAndConfigured) {
+ request.SetUserVerification(UserVerificationRequirement::kRequired);
+ } else {
+ request.SetUserVerification(UserVerificationRequirement::kDiscouraged);
+ }
+
// TODO(martinkr): Change FidoTasks to take all request parameters by const
// reference, so we can avoid copying these from the RequestHandler.
task_ = std::make_unique<MakeCredentialTask>(
@@ -44,8 +77,21 @@ void FidoDeviceAuthenticator::MakeCredential(CtapMakeCredentialRequest request,
void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request,
GetAssertionCallback callback) {
+ DCHECK(!task_);
DCHECK(device_->SupportedProtocolIsInitialized())
<< "InitializeAuthenticator() must be called first.";
+ DCHECK(Options());
+
+ // Update the request to the "effective" user verification requirement.
+ // https://w3c.github.io/webauthn/#effective-user-verification-requirement-for-assertion
+ if (Options()->user_verification_availability() ==
+ AuthenticatorSupportedOptions::UserVerificationAvailability::
+ kSupportedAndConfigured) {
+ request.SetUserVerification(UserVerificationRequirement::kRequired);
+ } else {
+ request.SetUserVerification(UserVerificationRequirement::kDiscouraged);
+ }
+
task_ = std::make_unique<GetAssertionTask>(device_.get(), std::move(request),
std::move(callback));
}
@@ -65,22 +111,13 @@ base::string16 FidoDeviceAuthenticator::GetDisplayName() const {
return device_->GetDisplayName();
}
-const AuthenticatorSupportedOptions& FidoDeviceAuthenticator::Options() const {
- static const AuthenticatorSupportedOptions default_options;
- switch (device_->supported_protocol()) {
- case ProtocolVersion::kU2f:
- return default_options;
- case ProtocolVersion::kCtap:
- DCHECK(device_->device_info()) << "uninitialized device";
- return device_->device_info()->options();
- case ProtocolVersion::kUnknown:
- NOTREACHED() << "uninitialized device";
- }
- NOTREACHED();
- return default_options;
+const base::Optional<AuthenticatorSupportedOptions>&
+FidoDeviceAuthenticator::Options() const {
+ return options_;
}
-FidoTransportProtocol FidoDeviceAuthenticator::AuthenticatorTransport() const {
+base::Optional<FidoTransportProtocol>
+FidoDeviceAuthenticator::AuthenticatorTransport() const {
return device_->DeviceTransport();
}
@@ -88,6 +125,10 @@ bool FidoDeviceAuthenticator::IsInPairingMode() const {
return device_->IsInPairingMode();
}
+bool FidoDeviceAuthenticator::IsPaired() const {
+ return device_->IsPaired();
+}
+
void FidoDeviceAuthenticator::SetTaskForTesting(
std::unique_ptr<FidoTask> task) {
task_ = std::move(task);
diff --git a/chromium/device/fido/fido_device_authenticator.h b/chromium/device/fido/fido_device_authenticator.h
index 06738e4b545..0d7e4fa8b00 100644
--- a/chromium/device/fido/fido_device_authenticator.h
+++ b/chromium/device/fido/fido_device_authenticator.h
@@ -41,12 +41,14 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
void Cancel() override;
std::string GetId() const override;
base::string16 GetDisplayName() const override;
- const AuthenticatorSupportedOptions& Options() const override;
- FidoTransportProtocol AuthenticatorTransport() const override;
+ const base::Optional<AuthenticatorSupportedOptions>& Options() const override;
+ base::Optional<FidoTransportProtocol> AuthenticatorTransport() const override;
bool IsInPairingMode() const override;
+ bool IsPaired() const override;
base::WeakPtr<FidoAuthenticator> GetWeakPtr() override;
FidoDevice* device() { return device_.get(); }
+ void SetTaskForTesting(std::unique_ptr<FidoTask> task);
protected:
void OnCtapMakeCredentialResponseReceived(
@@ -56,10 +58,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
GetAssertionCallback callback,
base::Optional<std::vector<uint8_t>> response_data);
- void SetTaskForTesting(std::unique_ptr<FidoTask> task);
-
private:
+ void InitializeAuthenticatorDone(base::OnceClosure callback);
+
const std::unique_ptr<FidoDevice> device_;
+ base::Optional<AuthenticatorSupportedOptions> options_;
std::unique_ptr<FidoTask> task_;
base::WeakPtrFactory<FidoDeviceAuthenticator> weak_factory_;
diff --git a/chromium/device/fido/fido_device_discovery.cc b/chromium/device/fido/fido_device_discovery.cc
index fe7fbe1af0a..5e18cff4e85 100644
--- a/chromium/device/fido/fido_device_discovery.cc
+++ b/chromium/device/fido/fido_device_discovery.cc
@@ -7,81 +7,15 @@
#include <utility>
#include "base/bind.h"
-#include "build/build_config.h"
-#include "device/fido/ble/fido_ble_discovery.h"
-#include "device/fido/cable/fido_cable_discovery.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_device_authenticator.h"
-// HID is not supported on Android.
-#if !defined(OS_ANDROID)
-#include "device/fido/hid/fido_hid_discovery.h"
-#endif // !defined(OS_ANDROID)
-
namespace device {
-namespace {
-
-std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscoveryImpl(
- FidoTransportProtocol transport,
- service_manager::Connector* connector) {
- switch (transport) {
- case FidoTransportProtocol::kUsbHumanInterfaceDevice:
-#if !defined(OS_ANDROID)
- DCHECK(connector);
- return std::make_unique<FidoHidDiscovery>(connector);
-#else
- NOTREACHED() << "USB HID not supported on Android.";
- return nullptr;
-#endif // !defined(OS_ANDROID)
- case FidoTransportProtocol::kBluetoothLowEnergy:
- return std::make_unique<FidoBleDiscovery>();
- case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
- NOTREACHED() << "Cable discovery is constructed using the dedicated "
- "factory method.";
- return nullptr;
- case FidoTransportProtocol::kNearFieldCommunication:
- // TODO(https://crbug.com/825949): Add NFC support.
- return nullptr;
- case FidoTransportProtocol::kInternal:
- NOTREACHED() << "Internal authenticators should be handled separately.";
- return nullptr;
- }
- NOTREACHED() << "Unhandled transport type";
- return nullptr;
-}
-
-std::unique_ptr<FidoDeviceDiscovery> CreateCableDiscoveryImpl(
- std::vector<CableDiscoveryData> cable_data) {
- return std::make_unique<FidoCableDiscovery>(std::move(cable_data));
-}
-
-} // namespace
-
FidoDeviceDiscovery::Observer::~Observer() = default;
-// static
-FidoDeviceDiscovery::FactoryFuncPtr FidoDeviceDiscovery::g_factory_func_ =
- &CreateFidoDiscoveryImpl;
-
-// static
-FidoDeviceDiscovery::CableFactoryFuncPtr
- FidoDeviceDiscovery::g_cable_factory_func_ = &CreateCableDiscoveryImpl;
-
-// static
-std::unique_ptr<FidoDeviceDiscovery> FidoDeviceDiscovery::Create(
- FidoTransportProtocol transport,
- service_manager::Connector* connector) {
- return (*g_factory_func_)(transport, connector);
-}
-
-// static
-std::unique_ptr<FidoDeviceDiscovery> FidoDeviceDiscovery::CreateCable(
- std::vector<CableDiscoveryData> cable_data) {
- return (*g_cable_factory_func_)(std::move(cable_data));
-}
-
FidoDeviceDiscovery::FidoDeviceDiscovery(FidoTransportProtocol transport)
: FidoDiscoveryBase(transport), weak_factory_(this) {}
@@ -90,10 +24,12 @@ FidoDeviceDiscovery::~FidoDeviceDiscovery() = default;
void FidoDeviceDiscovery::Start() {
DCHECK_EQ(state_, State::kIdle);
state_ = State::kStarting;
- // TODO(hongjunchoi): Fix so that NotifiyStarted() is never called
- // synchronously after StartInternal().
- // See: https://crbug.com/823686
- StartInternal();
+
+ // To ensure that that NotifiyStarted() is never invoked synchronously,
+ // post task asynchronously.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&FidoDeviceDiscovery::StartInternal,
+ weak_factory_.GetWeakPtr()));
}
void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) {
@@ -174,50 +110,4 @@ bool FidoDeviceDiscovery::RemoveDevice(base::StringPiece device_id) {
return true;
}
-// ScopedFidoDiscoveryFactory -------------------------------------------------
-
-namespace internal {
-
-ScopedFidoDiscoveryFactory::ScopedFidoDiscoveryFactory() {
- DCHECK(!g_current_factory);
- g_current_factory = this;
- original_factory_func_ =
- std::exchange(FidoDeviceDiscovery::g_factory_func_,
- &ForwardCreateFidoDiscoveryToCurrentFactory);
- original_cable_factory_func_ =
- std::exchange(FidoDeviceDiscovery::g_cable_factory_func_,
- &ForwardCreateCableDiscoveryToCurrentFactory);
-}
-
-ScopedFidoDiscoveryFactory::~ScopedFidoDiscoveryFactory() {
- g_current_factory = nullptr;
- FidoDeviceDiscovery::g_factory_func_ = original_factory_func_;
- FidoDeviceDiscovery::g_cable_factory_func_ = original_cable_factory_func_;
-}
-
-// static
-std::unique_ptr<FidoDeviceDiscovery>
-ScopedFidoDiscoveryFactory::ForwardCreateFidoDiscoveryToCurrentFactory(
- FidoTransportProtocol transport,
- ::service_manager::Connector* connector) {
- DCHECK(g_current_factory);
- return g_current_factory->CreateFidoDiscovery(transport, connector);
-}
-
-// static
-std::unique_ptr<FidoDeviceDiscovery>
-ScopedFidoDiscoveryFactory::ForwardCreateCableDiscoveryToCurrentFactory(
- std::vector<CableDiscoveryData> cable_data) {
- DCHECK(g_current_factory);
- g_current_factory->set_last_cable_data(std::move(cable_data));
- return g_current_factory->CreateFidoDiscovery(
- FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
- nullptr /* connector */);
-}
-
-// static
-ScopedFidoDiscoveryFactory* ScopedFidoDiscoveryFactory::g_current_factory =
- nullptr;
-
-} // namespace internal
} // namespace device
diff --git a/chromium/device/fido/fido_device_discovery.h b/chromium/device/fido/fido_device_discovery.h
index d5b844fac46..fd8037f023a 100644
--- a/chromium/device/fido/fido_device_discovery.h
+++ b/chromium/device/fido/fido_device_discovery.h
@@ -17,23 +17,14 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece.h"
-#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_transport_protocol.h"
-namespace service_manager {
-class Connector;
-}
-
namespace device {
class FidoDevice;
class FidoDeviceAuthenticator;
-namespace internal {
-class ScopedFidoDiscoveryFactory;
-}
-
class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery
: public FidoDiscoveryBase {
public:
@@ -43,18 +34,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery
kRunning,
};
- // Factory functions to construct an instance that discovers authenticators on
- // the given |transport| protocol. The first variant is for everything except
- // for cloud-assisted BLE which is handled by the second variant.
- //
- // FidoTransportProtocol::kUsbHumanInterfaceDevice requires specifying a valid
- // |connector| on Desktop, and is not valid on Android.
- static std::unique_ptr<FidoDeviceDiscovery> Create(
- FidoTransportProtocol transport,
- ::service_manager::Connector* connector);
- static std::unique_ptr<FidoDeviceDiscovery> CreateCable(
- std::vector<CableDiscoveryData> cable_data);
-
~FidoDeviceDiscovery() override;
bool is_start_requested() const { return state_ != State::kIdle; }
@@ -94,67 +73,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceDiscovery
authenticators_;
private:
- friend class internal::ScopedFidoDiscoveryFactory;
-
- // Factory function can be overridden by tests to construct fakes.
- using FactoryFuncPtr = decltype(&Create);
- using CableFactoryFuncPtr = decltype(&CreateCable);
- static FactoryFuncPtr g_factory_func_;
- static CableFactoryFuncPtr g_cable_factory_func_;
-
State state_ = State::kIdle;
base::WeakPtrFactory<FidoDeviceDiscovery> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoDeviceDiscovery);
};
-namespace internal {
-
-// Base class for a scoped override of FidoDeviceDiscovery::Create, used in unit
-// tests, layout tests, and when running with the Web Authn Testing API enabled.
-//
-// While there is a subclass instance in scope, calls to the factory method will
-// be hijacked such that the derived class's CreateFidoDiscovery method will be
-// invoked instead.
-class COMPONENT_EXPORT(DEVICE_FIDO) ScopedFidoDiscoveryFactory {
- public:
- // There should be at most one instance of any subclass in scope at a time.
- ScopedFidoDiscoveryFactory();
- virtual ~ScopedFidoDiscoveryFactory();
-
- const std::vector<CableDiscoveryData>& last_cable_data() const {
- return last_cable_data_;
- }
-
- protected:
- void set_last_cable_data(std::vector<CableDiscoveryData> cable_data) {
- last_cable_data_ = std::move(cable_data);
- }
-
- virtual std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery(
- FidoTransportProtocol transport,
- ::service_manager::Connector* connector) = 0;
-
- private:
- static std::unique_ptr<FidoDeviceDiscovery>
- ForwardCreateFidoDiscoveryToCurrentFactory(
- FidoTransportProtocol transport,
- ::service_manager::Connector* connector);
-
- static std::unique_ptr<FidoDeviceDiscovery>
- ForwardCreateCableDiscoveryToCurrentFactory(
- std::vector<CableDiscoveryData> cable_data);
-
- static ScopedFidoDiscoveryFactory* g_current_factory;
-
- FidoDeviceDiscovery::FactoryFuncPtr original_factory_func_;
- FidoDeviceDiscovery::CableFactoryFuncPtr original_cable_factory_func_;
- std::vector<CableDiscoveryData> last_cable_data_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedFidoDiscoveryFactory);
-};
-
-} // namespace internal
} // namespace device
#endif // DEVICE_FIDO_FIDO_DEVICE_DISCOVERY_H_
diff --git a/chromium/device/fido/fido_device_discovery_unittest.cc b/chromium/device/fido/fido_device_discovery_unittest.cc
index 9e984c94e4a..f4d092bba23 100644
--- a/chromium/device/fido/fido_device_discovery_unittest.cc
+++ b/chromium/device/fido/fido_device_discovery_unittest.cc
@@ -59,6 +59,8 @@ TEST(FidoDiscoveryTest, TestAddAndRemoveObserver) {
}
TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer);
@@ -68,6 +70,8 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
EXPECT_CALL(discovery, StartInternal());
discovery.Start();
+ scoped_task_environment_.RunUntilIdle();
+
EXPECT_TRUE(discovery.is_start_requested());
EXPECT_FALSE(discovery.is_running());
::testing::Mock::VerifyAndClearExpectations(&discovery);
@@ -80,11 +84,14 @@ TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
}
TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
MockFidoDiscoveryObserver observer;
discovery.set_observer(&observer);
discovery.Start();
+ scoped_task_environment_.RunUntilIdle();
EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
discovery.NotifyDiscoveryStarted(false);
diff --git a/chromium/device/fido/fido_discovery_base.h b/chromium/device/fido/fido_discovery_base.h
index 0ba4a6228ed..6fd43084880 100644
--- a/chromium/device/fido/fido_discovery_base.h
+++ b/chromium/device/fido/fido_discovery_base.h
@@ -41,11 +41,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryBase {
const std::string& previous_id,
std::string new_id) = 0;
- // Invoked when connected Bluetooth device advertises that it is in pairing
- // mode.
- virtual void AuthenticatorPairingModeChanged(
- FidoDiscoveryBase* discovery,
- const std::string& device_id) = 0;
+ // Invoked when connected Bluetooth device advertises that its pairing mode
+ // has changed.
+ virtual void AuthenticatorPairingModeChanged(FidoDiscoveryBase* discovery,
+ const std::string& device_id,
+ bool is_in_pairing_mode) = 0;
};
// Start authenticator discovery. The Observer must have been set before this
diff --git a/chromium/device/fido/fido_discovery_factory.cc b/chromium/device/fido/fido_discovery_factory.cc
new file mode 100644
index 00000000000..bcf26c59af4
--- /dev/null
+++ b/chromium/device/fido/fido_discovery_factory.cc
@@ -0,0 +1,158 @@
+// Copyright 2018 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 "device/fido/fido_discovery_factory.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "device/fido/ble/fido_ble_discovery.h"
+#include "device/fido/cable/fido_cable_discovery.h"
+#include "device/fido/features.h"
+#include "device/fido/fido_discovery_base.h"
+
+// HID is not supported on Android.
+#if !defined(OS_ANDROID)
+#include "device/fido/hid/fido_hid_discovery.h"
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_WIN)
+#include <Winuser.h>
+#include "device/fido/win/discovery.h"
+#include "device/fido/win/webauthn_api.h"
+#endif // defined(OS_WIN)
+
+namespace device {
+
+namespace {
+
+std::unique_ptr<FidoDiscoveryBase> CreateUsbFidoDiscovery(
+ service_manager::Connector* connector) {
+#if defined(OS_ANDROID)
+ NOTREACHED() << "USB HID not supported on Android.";
+ return nullptr;
+#else
+
+ DCHECK(connector);
+ return std::make_unique<FidoHidDiscovery>(connector);
+#endif // !defined(OS_ANDROID)
+}
+
+std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscoveryImpl(
+ FidoTransportProtocol transport,
+ service_manager::Connector* connector) {
+ switch (transport) {
+ case FidoTransportProtocol::kUsbHumanInterfaceDevice:
+ return CreateUsbFidoDiscovery(connector);
+ case FidoTransportProtocol::kBluetoothLowEnergy:
+ return std::make_unique<FidoBleDiscovery>();
+ case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
+ NOTREACHED() << "Cable discovery is constructed using the dedicated "
+ "factory method.";
+ return nullptr;
+ case FidoTransportProtocol::kNearFieldCommunication:
+ // TODO(https://crbug.com/825949): Add NFC support.
+ return nullptr;
+ case FidoTransportProtocol::kInternal:
+ NOTREACHED() << "Internal authenticators should be handled separately.";
+ return nullptr;
+ }
+ NOTREACHED() << "Unhandled transport type";
+ return nullptr;
+}
+
+std::unique_ptr<FidoDiscoveryBase> CreateCableDiscoveryImpl(
+ std::vector<CableDiscoveryData> cable_data) {
+ return std::make_unique<FidoCableDiscovery>(std::move(cable_data));
+}
+
+} // namespace
+
+// static
+FidoDiscoveryFactory::FactoryFuncPtr FidoDiscoveryFactory::g_factory_func_ =
+ &CreateFidoDiscoveryImpl;
+
+// static
+FidoDiscoveryFactory::CableFactoryFuncPtr
+ FidoDiscoveryFactory::g_cable_factory_func_ = &CreateCableDiscoveryImpl;
+
+// static
+std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create(
+ FidoTransportProtocol transport,
+ service_manager::Connector* connector) {
+ return (*g_factory_func_)(transport, connector);
+}
+
+// static
+std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::CreateCable(
+ std::vector<CableDiscoveryData> cable_data) {
+ return (*g_cable_factory_func_)(std::move(cable_data));
+}
+
+// static
+#if defined(OS_WIN)
+std::unique_ptr<FidoDiscoveryBase>
+FidoDiscoveryFactory::MaybeCreateWinWebAuthnApiDiscovery() {
+ if (!base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) ||
+ !WinWebAuthnApi::GetDefault()->IsAvailable()) {
+ return nullptr;
+ }
+ return std::make_unique<WinWebAuthnApiAuthenticatorDiscovery>(
+ WinWebAuthnApi::GetDefault(),
+ // TODO(martinkr): Inject the window from which the request
+ // originated. Windows uses this parameter to center the
+ // dialog over the parent. The dialog should be centered
+ // over the originating Chrome Window; the foreground window
+ // may have changed to something else since the request was
+ // issued.
+ GetForegroundWindow());
+}
+#endif // defined(OS_WIN)
+
+// ScopedFidoDiscoveryFactory -------------------------------------------------
+
+namespace internal {
+
+ScopedFidoDiscoveryFactory::ScopedFidoDiscoveryFactory() {
+ DCHECK(!g_current_factory);
+ g_current_factory = this;
+ original_factory_func_ =
+ std::exchange(FidoDiscoveryFactory::g_factory_func_,
+ &ForwardCreateFidoDiscoveryToCurrentFactory);
+ original_cable_factory_func_ =
+ std::exchange(FidoDiscoveryFactory::g_cable_factory_func_,
+ &ForwardCreateCableDiscoveryToCurrentFactory);
+}
+
+ScopedFidoDiscoveryFactory::~ScopedFidoDiscoveryFactory() {
+ g_current_factory = nullptr;
+ FidoDiscoveryFactory::g_factory_func_ = original_factory_func_;
+ FidoDiscoveryFactory::g_cable_factory_func_ = original_cable_factory_func_;
+}
+
+// static
+std::unique_ptr<FidoDiscoveryBase>
+ScopedFidoDiscoveryFactory::ForwardCreateFidoDiscoveryToCurrentFactory(
+ FidoTransportProtocol transport,
+ ::service_manager::Connector* connector) {
+ DCHECK(g_current_factory);
+ return g_current_factory->CreateFidoDiscovery(transport, connector);
+}
+
+// static
+std::unique_ptr<FidoDiscoveryBase>
+ScopedFidoDiscoveryFactory::ForwardCreateCableDiscoveryToCurrentFactory(
+ std::vector<CableDiscoveryData> cable_data) {
+ DCHECK(g_current_factory);
+ g_current_factory->set_last_cable_data(std::move(cable_data));
+ return g_current_factory->CreateFidoDiscovery(
+ FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy,
+ nullptr /* connector */);
+}
+
+// static
+ScopedFidoDiscoveryFactory* ScopedFidoDiscoveryFactory::g_current_factory =
+ nullptr;
+
+} // namespace internal
+} // namespace device
diff --git a/chromium/device/fido/fido_discovery_factory.h b/chromium/device/fido/fido_discovery_factory.h
new file mode 100644
index 00000000000..cc21790622c
--- /dev/null
+++ b/chromium/device/fido/fido_discovery_factory.h
@@ -0,0 +1,109 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_FIDO_DISCOVERY_FACTORY_H_
+#define DEVICE_FIDO_FIDO_DISCOVERY_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/component_export.h"
+#include "build/build_config.h"
+#include "device/fido/cable/cable_discovery_data.h"
+#include "device/fido/fido_device_discovery.h"
+#include "device/fido/fido_discovery_base.h"
+#include "device/fido/fido_transport_protocol.h"
+
+namespace service_manager {
+class Connector;
+}
+
+namespace device {
+
+namespace internal {
+class ScopedFidoDiscoveryFactory;
+}
+
+// FidoDiscoveryFactory offers methods to construct instances of
+// FidoDiscoveryBase for a given |transport| protocol.
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory {
+ public:
+ // Instantiates a FidoDiscoveryBase for all protocols except caBLE and
+ // internal/platform.
+ //
+ // FidoTransportProtocol::kUsbHumanInterfaceDevice requires specifying a
+ // valid |connector| on Desktop, and is not valid on Android.
+ static std::unique_ptr<FidoDiscoveryBase> Create(
+ FidoTransportProtocol transport,
+ ::service_manager::Connector* connector);
+ // Instantiates a FidoDiscovery for caBLE.
+ static std::unique_ptr<FidoDiscoveryBase> CreateCable(
+ std::vector<CableDiscoveryData> cable_data);
+#if defined(OS_WIN)
+ // Instantiates a FidoDiscovery for the native Windows WebAuthn
+ // API where available. Returns nullptr otherwise.
+ static std::unique_ptr<FidoDiscoveryBase>
+ MaybeCreateWinWebAuthnApiDiscovery();
+#endif // defined(OS_WIN)
+
+ private:
+ friend class internal::ScopedFidoDiscoveryFactory;
+
+ // Factory function can be overridden by tests to construct fakes.
+ using FactoryFuncPtr = decltype(&Create);
+ using CableFactoryFuncPtr = decltype(&CreateCable);
+ static FactoryFuncPtr g_factory_func_;
+ static CableFactoryFuncPtr g_cable_factory_func_;
+};
+
+namespace internal {
+// Base class for a scoped override of FidoDiscoveryFactory::Create, used in
+// unit tests, layout tests, and when running with the Web Authn Testing API
+// enabled.
+//
+// While there is a subclass instance in scope, calls to the factory method will
+// be hijacked such that the derived class's CreateFidoDiscovery method will be
+// invoked instead.
+class COMPONENT_EXPORT(DEVICE_FIDO) ScopedFidoDiscoveryFactory {
+ public:
+ // There should be at most one instance of any subclass in scope at a time.
+ ScopedFidoDiscoveryFactory();
+ virtual ~ScopedFidoDiscoveryFactory();
+
+ const std::vector<CableDiscoveryData>& last_cable_data() const {
+ return last_cable_data_;
+ }
+
+ protected:
+ void set_last_cable_data(std::vector<CableDiscoveryData> cable_data) {
+ last_cable_data_ = std::move(cable_data);
+ }
+
+ virtual std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscovery(
+ FidoTransportProtocol transport,
+ ::service_manager::Connector* connector) = 0;
+
+ private:
+ static std::unique_ptr<FidoDiscoveryBase>
+ ForwardCreateFidoDiscoveryToCurrentFactory(
+ FidoTransportProtocol transport,
+ ::service_manager::Connector* connector);
+
+ static std::unique_ptr<FidoDiscoveryBase>
+ ForwardCreateCableDiscoveryToCurrentFactory(
+ std::vector<CableDiscoveryData> cable_data);
+
+ static ScopedFidoDiscoveryFactory* g_current_factory;
+
+ FidoDiscoveryFactory::FactoryFuncPtr original_factory_func_;
+ FidoDiscoveryFactory::CableFactoryFuncPtr original_cable_factory_func_;
+ std::vector<CableDiscoveryData> last_cable_data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFidoDiscoveryFactory);
+};
+
+} // namespace internal
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_DISCOVERY_FACTORY_H_
diff --git a/chromium/device/fido/fido_parsing_utils.h b/chromium/device/fido/fido_parsing_utils.h
index 6bf982dad91..fa6d5d2fdc9 100644
--- a/chromium/device/fido/fido_parsing_utils.h
+++ b/chromium/device/fido/fido_parsing_utils.h
@@ -10,6 +10,7 @@
#include <algorithm>
#include <array>
+#include <iterator>
#include <utility>
#include <vector>
@@ -22,14 +23,16 @@
namespace device {
namespace fido_parsing_utils {
-// Comparator object that calls base::make_span on its arguments before
-// comparing them with operator<. Useful when comparing sequence containers that
-// are of different types, but have similar semantics.
-struct SpanLess {
+// Comparator object that calls std::lexicographical_compare on the begin and
+// end iterators of the passed in ranges. Useful when comparing sequence
+// containers that are of different types, but have similar semantics.
+struct RangeLess {
template <typename T, typename U>
constexpr bool operator()(T&& lhs, U&& rhs) const {
- return base::make_span(std::forward<T>(lhs)) <
- base::make_span(std::forward<U>(rhs));
+ using std::begin;
+ using std::end;
+ return std::lexicographical_compare(begin(lhs), end(lhs), begin(rhs),
+ end(rhs));
}
using is_transparent = void;
diff --git a/chromium/device/fido/fido_parsing_utils_unittest.cc b/chromium/device/fido/fido_parsing_utils_unittest.cc
index 41ff123f595..a553d4dcdb2 100644
--- a/chromium/device/fido/fido_parsing_utils_unittest.cc
+++ b/chromium/device/fido/fido_parsing_utils_unittest.cc
@@ -20,64 +20,64 @@ constexpr uint8_t kThree[] = {0x03};
constexpr uint8_t kOneTwoThree[] = {0x01, 0x02, 0x03};
} // namespace
-TEST(U2fParsingUtils, SpanLess) {
+TEST(U2fParsingUtils, RangeLess) {
const std::array<int, 4> kOneTwoThreeFour = {1, 2, 3, 4};
- EXPECT_FALSE(SpanLess()(kOne, kOne));
- EXPECT_TRUE(SpanLess()(kOne, kOneTwo));
- EXPECT_TRUE(SpanLess()(kOne, kTwo));
- EXPECT_TRUE(SpanLess()(kOne, kTwoThree));
- EXPECT_TRUE(SpanLess()(kOne, kThree));
- EXPECT_TRUE(SpanLess()(kOne, kOneTwoThree));
- EXPECT_TRUE(SpanLess()(kOne, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kOneTwo, kOne));
- EXPECT_FALSE(SpanLess()(kOneTwo, kOneTwo));
- EXPECT_TRUE(SpanLess()(kOneTwo, kTwo));
- EXPECT_TRUE(SpanLess()(kOneTwo, kTwoThree));
- EXPECT_TRUE(SpanLess()(kOneTwo, kThree));
- EXPECT_TRUE(SpanLess()(kOneTwo, kOneTwoThree));
- EXPECT_TRUE(SpanLess()(kOneTwo, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kTwo, kOne));
- EXPECT_FALSE(SpanLess()(kTwo, kOneTwo));
- EXPECT_FALSE(SpanLess()(kTwo, kTwo));
- EXPECT_TRUE(SpanLess()(kTwo, kTwoThree));
- EXPECT_TRUE(SpanLess()(kTwo, kThree));
- EXPECT_FALSE(SpanLess()(kTwo, kOneTwoThree));
- EXPECT_FALSE(SpanLess()(kTwo, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kTwoThree, kOne));
- EXPECT_FALSE(SpanLess()(kTwoThree, kOneTwo));
- EXPECT_FALSE(SpanLess()(kTwoThree, kTwo));
- EXPECT_FALSE(SpanLess()(kTwoThree, kTwoThree));
- EXPECT_TRUE(SpanLess()(kTwoThree, kThree));
- EXPECT_FALSE(SpanLess()(kTwoThree, kOneTwoThree));
- EXPECT_FALSE(SpanLess()(kTwoThree, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kThree, kOne));
- EXPECT_FALSE(SpanLess()(kThree, kOneTwo));
- EXPECT_FALSE(SpanLess()(kThree, kTwo));
- EXPECT_FALSE(SpanLess()(kThree, kTwoThree));
- EXPECT_FALSE(SpanLess()(kThree, kThree));
- EXPECT_FALSE(SpanLess()(kThree, kOneTwoThree));
- EXPECT_FALSE(SpanLess()(kThree, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kOneTwoThree, kOne));
- EXPECT_FALSE(SpanLess()(kOneTwoThree, kOneTwo));
- EXPECT_TRUE(SpanLess()(kOneTwoThree, kTwo));
- EXPECT_TRUE(SpanLess()(kOneTwoThree, kTwoThree));
- EXPECT_TRUE(SpanLess()(kOneTwoThree, kThree));
- EXPECT_FALSE(SpanLess()(kOneTwoThree, kOneTwoThree));
- EXPECT_TRUE(SpanLess()(kOneTwoThree, kOneTwoThreeFour));
-
- EXPECT_FALSE(SpanLess()(kOneTwoThreeFour, kOne));
- EXPECT_FALSE(SpanLess()(kOneTwoThreeFour, kOneTwo));
- EXPECT_TRUE(SpanLess()(kOneTwoThreeFour, kTwo));
- EXPECT_TRUE(SpanLess()(kOneTwoThreeFour, kTwoThree));
- EXPECT_TRUE(SpanLess()(kOneTwoThreeFour, kThree));
- EXPECT_FALSE(SpanLess()(kOneTwoThreeFour, kOneTwoThree));
- EXPECT_FALSE(SpanLess()(kOneTwoThreeFour, kOneTwoThreeFour));
+ EXPECT_FALSE(RangeLess()(kOne, kOne));
+ EXPECT_TRUE(RangeLess()(kOne, kOneTwo));
+ EXPECT_TRUE(RangeLess()(kOne, kTwo));
+ EXPECT_TRUE(RangeLess()(kOne, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kOne, kThree));
+ EXPECT_TRUE(RangeLess()(kOne, kOneTwoThree));
+ EXPECT_TRUE(RangeLess()(kOne, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kOneTwo, kOne));
+ EXPECT_FALSE(RangeLess()(kOneTwo, kOneTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwo, kTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwo, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kOneTwo, kThree));
+ EXPECT_TRUE(RangeLess()(kOneTwo, kOneTwoThree));
+ EXPECT_TRUE(RangeLess()(kOneTwo, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kTwo, kOne));
+ EXPECT_FALSE(RangeLess()(kTwo, kOneTwo));
+ EXPECT_FALSE(RangeLess()(kTwo, kTwo));
+ EXPECT_TRUE(RangeLess()(kTwo, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kTwo, kThree));
+ EXPECT_FALSE(RangeLess()(kTwo, kOneTwoThree));
+ EXPECT_FALSE(RangeLess()(kTwo, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kTwoThree, kOne));
+ EXPECT_FALSE(RangeLess()(kTwoThree, kOneTwo));
+ EXPECT_FALSE(RangeLess()(kTwoThree, kTwo));
+ EXPECT_FALSE(RangeLess()(kTwoThree, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kTwoThree, kThree));
+ EXPECT_FALSE(RangeLess()(kTwoThree, kOneTwoThree));
+ EXPECT_FALSE(RangeLess()(kTwoThree, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kThree, kOne));
+ EXPECT_FALSE(RangeLess()(kThree, kOneTwo));
+ EXPECT_FALSE(RangeLess()(kThree, kTwo));
+ EXPECT_FALSE(RangeLess()(kThree, kTwoThree));
+ EXPECT_FALSE(RangeLess()(kThree, kThree));
+ EXPECT_FALSE(RangeLess()(kThree, kOneTwoThree));
+ EXPECT_FALSE(RangeLess()(kThree, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kOneTwoThree, kOne));
+ EXPECT_FALSE(RangeLess()(kOneTwoThree, kOneTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwoThree, kTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwoThree, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kOneTwoThree, kThree));
+ EXPECT_FALSE(RangeLess()(kOneTwoThree, kOneTwoThree));
+ EXPECT_TRUE(RangeLess()(kOneTwoThree, kOneTwoThreeFour));
+
+ EXPECT_FALSE(RangeLess()(kOneTwoThreeFour, kOne));
+ EXPECT_FALSE(RangeLess()(kOneTwoThreeFour, kOneTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwoThreeFour, kTwo));
+ EXPECT_TRUE(RangeLess()(kOneTwoThreeFour, kTwoThree));
+ EXPECT_TRUE(RangeLess()(kOneTwoThreeFour, kThree));
+ EXPECT_FALSE(RangeLess()(kOneTwoThreeFour, kOneTwoThree));
+ EXPECT_FALSE(RangeLess()(kOneTwoThreeFour, kOneTwoThreeFour));
}
TEST(U2fParsingUtils, Materialize) {
diff --git a/chromium/device/fido/fido_request_handler.h b/chromium/device/fido/fido_request_handler.h
index b1ac9025864..f54b79b0e1d 100644
--- a/chromium/device/fido/fido_request_handler.h
+++ b/chromium/device/fido/fido_request_handler.h
@@ -25,10 +25,10 @@ namespace device {
template <class Response>
class FidoRequestHandler : public FidoRequestHandlerBase {
public:
- using CompletionCallback =
- base::OnceCallback<void(FidoReturnCode status_code,
- base::Optional<Response> response_data,
- FidoTransportProtocol transport_used)>;
+ using CompletionCallback = base::OnceCallback<void(
+ FidoReturnCode status_code,
+ base::Optional<Response> response_data,
+ base::Optional<FidoTransportProtocol> transport_used)>;
// The |available_transports| should be the intersection of transports
// supported by the client and allowed by the relying party.
diff --git a/chromium/device/fido/fido_request_handler_base.cc b/chromium/device/fido/fido_request_handler_base.cc
index 6164f843369..d07ddc2f201 100644
--- a/chromium/device/fido/fido_request_handler_base.cc
+++ b/chromium/device/fido/fido_request_handler_base.cc
@@ -14,6 +14,7 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "device/fido/ble_adapter_manager.h"
+#include "device/fido/fido_discovery_factory.h"
#include "services/service_manager/public/cpp/connector.h"
namespace device {
@@ -57,7 +58,16 @@ FidoRequestHandlerBase::TransportAvailabilityObserver::
FidoRequestHandlerBase::FidoRequestHandlerBase(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& available_transports)
- : weak_factory_(this) {
+ : connector_(connector), weak_factory_(this) {
+#if defined(OS_WIN)
+ InitDiscoveriesWin(available_transports);
+#else
+ InitDiscoveries(available_transports);
+#endif // !defined(OS_WIN)
+}
+
+void FidoRequestHandlerBase::InitDiscoveries(
+ const base::flat_set<FidoTransportProtocol>& available_transports) {
// The number of times |notify_observer_callback_| needs to be invoked before
// Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this
// is used to wait until all the parts of |transport_availability_info_| are
@@ -84,7 +94,7 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
continue;
}
- auto discovery = FidoDeviceDiscovery::Create(transport, connector);
+ auto discovery = FidoDiscoveryFactory::Create(transport, connector_);
if (discovery == nullptr) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and
// HID transports are not configured.
@@ -115,6 +125,55 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
weak_factory_.GetWeakPtr()));
}
+#if defined(OS_WIN)
+void FidoRequestHandlerBase::InitDiscoveriesWin(
+ const base::flat_set<FidoTransportProtocol>& available_transports) {
+ // Try to instantiate the discovery for proxying requests to the native
+ // Windows WebAuthn API; or fall back to using the regular device transport
+ // discoveries if the API is unavailable.
+ auto discovery = FidoDiscoveryFactory::MaybeCreateWinWebAuthnApiDiscovery();
+ if (!discovery) {
+ InitDiscoveries(available_transports);
+ return;
+ }
+
+ // The Windows WebAuthn API is available. On this platform, communicating
+ // with authenticator devices directly is blocked by the OS, so we need to go
+ // through the native API instead. No device discoveries may be instantiated.
+ //
+ // The Windows API supports USB, NFC, BLE and platform authenticators, but
+ // not caBLE. Communicating with caBLE devices directly is subject to the
+ // same block by the OS, so this platform is without caBLE support for now.
+ //
+ // TODO(martinkr): Re-enable the caBLE discovery once caBLE has moved to a
+ // different UUID. See crbug.com/905111.
+
+ discovery->set_observer(this);
+ discoveries_.push_back(std::move(discovery));
+
+ // Tell the embedder to not render a UI and ignore all future callbacks. Also
+ // don't report any available transports; the embedder is not supposed to use
+ // this information anyway.
+ transport_availability_info_.disable_embedder_ui = true;
+ transport_availability_info_.available_transports = {};
+
+ // The number of times |notify_observer_callback_| needs to be invoked before
+ // Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this
+ // is used to wait until all the parts of |transport_availability_info_| are
+ // filled out. In the case of Windows, there are no transport discoveries to
+ // wait for, so the |notify_observer_callback_| is only invoked in:
+ // 1) SetPlatformAuthenticatorOrMarkUnavailable().
+ // 2) set_observer().
+ constexpr size_t transport_info_callback_count = 2u;
+
+ notify_observer_callback_ = base::BarrierClosure(
+ transport_info_callback_count,
+ base::BindOnce(
+ &FidoRequestHandlerBase::NotifyObserverTransportAvailability,
+ weak_factory_.GetWeakPtr()));
+}
+#endif // defined(OS_WIN)
+
FidoRequestHandlerBase::~FidoRequestHandlerBase() = default;
void FidoRequestHandlerBase::StartAuthenticatorRequest(
@@ -238,14 +297,16 @@ void FidoRequestHandlerBase::AuthenticatorIdChanged(
void FidoRequestHandlerBase::AuthenticatorPairingModeChanged(
FidoDiscoveryBase* discovery,
- const std::string& device_id) {
+ const std::string& device_id,
+ bool is_in_pairing_mode) {
DCHECK_EQ(FidoTransportProtocol::kBluetoothLowEnergy, discovery->transport());
auto it = active_authenticators_.find(device_id);
if (it == active_authenticators_.end())
return;
if (observer_)
- observer_->FidoAuthenticatorPairingModeChanged(device_id);
+ observer_->FidoAuthenticatorPairingModeChanged(device_id,
+ is_in_pairing_mode);
}
void FidoRequestHandlerBase::AddAuthenticator(
@@ -284,8 +345,9 @@ void FidoRequestHandlerBase::SetPlatformAuthenticatorOrMarkUnavailable(
FidoTransportProtocol::kInternal)) {
DCHECK(platform_authenticator_info->authenticator);
DCHECK(
- (platform_authenticator_info->authenticator->AuthenticatorTransport() ==
- FidoTransportProtocol::kInternal));
+ platform_authenticator_info->authenticator->AuthenticatorTransport() &&
+ *platform_authenticator_info->authenticator->AuthenticatorTransport() ==
+ FidoTransportProtocol::kInternal);
transport_availability_info_.has_recognized_mac_touch_id_credential =
platform_authenticator_info->has_recognized_mac_touch_id_credential;
platform_authenticator_ =
diff --git a/chromium/device/fido/fido_request_handler_base.h b/chromium/device/fido/fido_request_handler_base.h
index 76a301cc513..125984e4941 100644
--- a/chromium/device/fido/fido_request_handler_base.h
+++ b/chromium/device/fido/fido_request_handler_base.h
@@ -19,8 +19,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_piece_forward.h"
+#include "build/build_config.h"
#include "device/fido/fido_device_authenticator.h"
-#include "device/fido/fido_device_discovery.h"
+#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_transport_protocol.h"
namespace service_manager {
@@ -87,6 +88,12 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
bool has_recognized_mac_touch_id_credential = false;
bool is_ble_powered = false;
bool can_power_on_ble_adapter = false;
+
+ // If true, dispatch of the request cannot be controlled by
+ // the embedder. The embedder must not display a UI for this
+ // request and must ignore all subsequent invocations of the
+ // TransportAvailabilityObserver interface methods.
+ bool disable_embedder_ui = false;
};
class COMPONENT_EXPORT(DEVICE_FIDO) TransportAvailabilityObserver {
@@ -117,7 +124,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
base::StringPiece old_authenticator_id,
std::string new_authenticator_id) = 0;
virtual void FidoAuthenticatorPairingModeChanged(
- base::StringPiece authenticator_id) = 0;
+ base::StringPiece authenticator_id,
+ bool is_in_pairing_mode) = 0;
};
// TODO(https://crbug.com/769631): Remove the dependency on Connector once
@@ -179,6 +187,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
return transport_availability_info_;
}
+ const AuthenticatorMap& AuthenticatorsForTesting() {
+ return active_authenticators_;
+ }
+
protected:
// Subclasses implement this method to dispatch their request onto the given
// FidoAuthenticator. The FidoAuthenticator is owned by this
@@ -196,6 +208,13 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
private:
friend class FidoRequestHandlerTest;
+ void InitDiscoveries(
+ const base::flat_set<FidoTransportProtocol>& available_transports);
+#if defined(OS_WIN)
+ void InitDiscoveriesWin(
+ const base::flat_set<FidoTransportProtocol>& available_transports);
+#endif
+
// FidoDiscoveryBase::Observer
void AuthenticatorAdded(FidoDiscoveryBase* discovery,
FidoAuthenticator* authenticator) final;
@@ -205,7 +224,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
const std::string& previous_id,
std::string new_id) final;
void AuthenticatorPairingModeChanged(FidoDiscoveryBase* discovery,
- const std::string& device_id) final;
+ const std::string& device_id,
+ bool is_in_pairing_mode) final;
void AddAuthenticator(FidoAuthenticator* authenticator);
void NotifyObserverTransportAvailability();
@@ -226,6 +246,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
// TODO(martinkr): Inject platform authenticators through a new
// FidoDiscoveryBase specialization and hold ownership there.
std::unique_ptr<FidoAuthenticator> platform_authenticator_;
+ service_manager::Connector* const connector_;
base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
diff --git a/chromium/device/fido/fido_request_handler_unittest.cc b/chromium/device/fido/fido_request_handler_unittest.cc
index aea5531777e..bb4fea50748 100644
--- a/chromium/device/fido/fido_request_handler_unittest.cc
+++ b/chromium/device/fido/fido_request_handler_unittest.cc
@@ -33,14 +33,10 @@ namespace {
using FakeTaskCallback =
base::OnceCallback<void(CtapDeviceResponseCode status_code,
base::Optional<std::vector<uint8_t>>)>;
-using FakeHandlerCallback =
- base::OnceCallback<void(FidoReturnCode status_code,
- base::Optional<std::vector<uint8_t>> response_data,
- FidoTransportProtocol)>;
-using FakeHandlerCallbackReceiver =
- test::StatusAndValuesCallbackReceiver<FidoReturnCode,
- base::Optional<std::vector<uint8_t>>,
- FidoTransportProtocol>;
+using FakeHandlerCallbackReceiver = test::StatusAndValuesCallbackReceiver<
+ FidoReturnCode,
+ base::Optional<std::vector<uint8_t>>,
+ base::Optional<FidoTransportProtocol>>;
enum class FakeTaskResponse : uint8_t {
kSuccess = 0x00,
@@ -104,8 +100,8 @@ class TestTransportAvailabilityObserver
authenticator_id_change_notification_receiver_.callback().Run(
std::move(new_authenticator_id));
}
- void FidoAuthenticatorPairingModeChanged(
- base::StringPiece authenticator_id) override {}
+ void FidoAuthenticatorPairingModeChanged(base::StringPiece authenticator_id,
+ bool is_in_pairing_mode) override {}
private:
TransportAvailabilityNotificationReceiver
@@ -161,34 +157,35 @@ class FakeFidoTask : public FidoTask {
base::WeakPtrFactory<FakeFidoTask> weak_factory_;
};
-class FakeFidoAuthenticator : public FidoDeviceAuthenticator {
- public:
- explicit FakeFidoAuthenticator(std::unique_ptr<FidoDevice> device)
- : FidoDeviceAuthenticator(std::move(device)) {}
-
- void RunFakeTask(FakeTaskCallback callback) {
- SetTaskForTesting(
- std::make_unique<FakeFidoTask>(device(), std::move(callback)));
- }
-};
-
class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
public:
- FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
- FakeHandlerCallback callback)
- : FidoRequestHandler(nullptr /* connector */,
- protocols,
- std::move(callback)),
+ FakeFidoRequestHandler(service_manager::Connector* connector,
+ const base::flat_set<FidoTransportProtocol>& protocols,
+ CompletionCallback callback)
+ : FidoRequestHandler(connector, protocols, std::move(callback)),
weak_factory_(this) {
Start();
}
+ FakeFidoRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
+ CompletionCallback callback)
+ : FakeFidoRequestHandler(nullptr /* connector */,
+ protocols,
+ std::move(callback)) {}
~FakeFidoRequestHandler() override = default;
void DispatchRequest(FidoAuthenticator* authenticator) override {
- static_cast<FakeFidoAuthenticator*>(authenticator)
- ->RunFakeTask(
- base::BindOnce(&FakeFidoRequestHandler::OnAuthenticatorResponse,
- weak_factory_.GetWeakPtr(), authenticator));
+ // FidoRequestHandlerTest uses ScopedFakeDiscovery to inject mock devices
+ // that get wrapped in a FidoDeviceAuthenticator, so we can safely cast
+ // here.
+ auto* device_authenticator =
+ static_cast<FidoDeviceAuthenticator*>(authenticator);
+ // Instead of sending a real CTAP request, send an empty byte array. Note
+ // that during discovery, the device already has received a GetInfo command
+ // at this point.
+ device_authenticator->SetTaskForTesting(std::make_unique<FakeFidoTask>(
+ device_authenticator->device(),
+ base::BindOnce(&FakeFidoRequestHandler::OnAuthenticatorResponse,
+ weak_factory_.GetWeakPtr(), authenticator)));
}
private:
@@ -507,7 +504,7 @@ TEST_F(FidoRequestHandlerTest, TestSetPlatformAuthenticator) {
CreateFakeSuccessDeviceResponse());
device->SetDeviceTransport(FidoTransportProtocol::kInternal);
auto authenticator =
- std::make_unique<FakeFidoAuthenticator>(std::move(device));
+ std::make_unique<FidoDeviceAuthenticator>(std::move(device));
TestTransportAvailabilityObserver observer;
auto request_handler = std::make_unique<FakeFidoRequestHandler>(
@@ -543,7 +540,7 @@ TEST_F(FidoRequestHandlerTest,
CreateFakeSuccessDeviceResponse());
device->SetDeviceTransport(FidoTransportProtocol::kInternal);
auto authenticator =
- std::make_unique<FakeFidoAuthenticator>(std::move(device));
+ std::make_unique<FidoDeviceAuthenticator>(std::move(device));
TestTransportAvailabilityObserver observer;
auto request_handler = std::make_unique<FakeFidoRequestHandler>(
diff --git a/chromium/device/fido/fido_test_data.h b/chromium/device/fido/fido_test_data.h
index aac7760d294..95192fdeace 100644
--- a/chromium/device/fido/fido_test_data.h
+++ b/chromium/device/fido/fido_test_data.h
@@ -19,41 +19,49 @@ namespace test_data {
// Sample U2F register request parameters used in example 6 of the CTAP spec.
// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#using-the-ctap2-authenticatormakecredential-command-with-ctap1-u2f-authenticators
constexpr uint8_t kChallengeParameter[] = {
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42,
- 0x50, 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05,
- 0xB8, 0x8C, 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf,
+ 0x44, 0x3, 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
};
+// SHA256(kRelyingPartyId)
constexpr uint8_t kApplicationParameter[] = {
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B,
0xD7, 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40,
0x7B, 0xCF, 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
};
+// SHA256(kAppId)
constexpr uint8_t kAlternativeApplicationParameter[] = {
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03,
- 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
- 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
-};
+ 0x91, 0x14, 0xf2, 0xc9, 0xf2, 0x0b, 0x30, 0x7b, 0x49, 0xac, 0x96,
+ 0x2c, 0xf7, 0x6e, 0xa2, 0x08, 0x3c, 0xa7, 0xa7, 0x8d, 0xe1, 0xcd,
+ 0x4e, 0x82, 0x5e, 0xca, 0x3a, 0x98, 0x0f, 0x1a, 0x25, 0x6d};
+
+constexpr char kClientDataJson[] =
+ R"({"challenge":"foobar","new_keys_may_be_added_here":"do not compare clientDataJSON against a template. See https://goo.gl/yabPex","origin":"https://google.com","type":"webauthn.create"})";
+// SHA-256 hash of kClientDataJson.
constexpr uint8_t kClientDataHash[] = {
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e, 0x42,
- 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05,
- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41};
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf,
+ 0x44, 0x3, 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
+};
constexpr uint8_t kUserId[] = {0x10, 0x98, 0x23, 0x72, 0x35, 0x40, 0x98, 0x72};
constexpr char kRelyingPartyId[] = "acme.com";
+constexpr char kAppId[] = "acme.com/";
constexpr uint8_t kU2fRegisterCommandApduWithIndividualAttestation[] = {
// CLA, INS, P1, P2 APDU instructions
0x00, 0x01, 0x83, 0x00,
// Data length in 3 bytes in big endian order
0x00, 0x00, 0x40,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -67,10 +75,10 @@ constexpr uint8_t kU2fRegisterCommandApdu[] = {
0x00, 0x01, 0x03, 0x00,
// Data length in 3 bytes in big endian order.
0x00, 0x00, 0x40,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -111,10 +119,10 @@ constexpr uint8_t kU2fCheckOnlySignCommandApduWithKeyAlpha[] = {
0x00, 0x02, 0x07, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -132,10 +140,10 @@ constexpr uint8_t kU2fCheckOnlySignCommandApduWithKeyBeta[] = {
0x00, 0x02, 0x07, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -152,10 +160,10 @@ constexpr uint8_t kU2fCheckOnlySignCommandApduWithKeyGamma[] = {
0x00, 0x02, 0x07, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -173,10 +181,10 @@ constexpr uint8_t kU2fSignCommandApduWithKeyAlpha[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -194,10 +202,10 @@ constexpr uint8_t kU2fSignCommandApduWithKeyBeta[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -215,10 +223,10 @@ constexpr uint8_t kU2fSignCommandApduWithKeyGamma[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x42,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -236,10 +244,10 @@ constexpr uint8_t kU2fSignCommandApdu[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x81,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -262,10 +270,10 @@ constexpr uint8_t kU2fCheckOnlySignCommandApdu[] = {
0x00, 0x02, 0x07, 0x00,
// Data Length (3 bytes in big endian order).
0x00, 0x00, 0x81,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -288,14 +296,14 @@ constexpr uint8_t kU2fSignCommandApduWithAlternativeApplicationParameter[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order)
0x00, 0x00, 0x81,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Alternative application parameter
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
+ 0x91, 0x14, 0xf2, 0xc9, 0xf2, 0x0b, 0x30, 0x7b, 0x49, 0xac, 0x96, 0x2c,
+ 0xf7, 0x6e, 0xa2, 0x08, 0x3c, 0xa7, 0xa7, 0x8d, 0xe1, 0xcd, 0x4e, 0x82,
+ 0x5e, 0xca, 0x3a, 0x98, 0x0f, 0x1a, 0x25, 0x6d,
// Key handle length
0x40,
// Key handle
@@ -315,14 +323,14 @@ constexpr uint8_t
0x00, 0x02, 0x07, 0x00,
// Data Length (3 bytes in big endian order).
0x00, 0x00, 0x81,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea,
+ 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3,
+ 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Alternative application parameter
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
- 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04,
+ 0x91, 0x14, 0xf2, 0xc9, 0xf2, 0x0b, 0x30, 0x7b, 0x49, 0xac, 0x96, 0x2c,
+ 0xf7, 0x6e, 0xa2, 0x08, 0x3c, 0xa7, 0xa7, 0x8d, 0xe1, 0xcd, 0x4e, 0x82,
+ 0x5e, 0xca, 0x3a, 0x98, 0x0f, 0x1a, 0x25, 0x6d,
// Key handle length
0x40,
// Key handle
@@ -344,10 +352,10 @@ constexpr uint8_t kU2fSignCommandWithoutKeyHandle[] = {
0x00, 0x02, 0x03, 0x00,
// Data Length (3 bytes in big endian order).
0x00, 0x00, 0x61,
- // Challenge parameter
- 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xEC, 0x17, 0x20, 0x2E, 0x42, 0x50,
- 0x5F, 0x8E, 0xD2, 0xB1, 0x6A, 0xE2, 0x2F, 0x16, 0xBB, 0x05, 0xB8, 0x8C,
- 0x25, 0xDB, 0x9E, 0x60, 0x26, 0x45, 0xF1, 0x41,
+ // Challenge parameter -- see kClientDataHash
+ 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49, 0xea, 0xfa,
+ 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3, 0xa2, 0xe,
+ 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// Application parameter
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
@@ -842,10 +850,10 @@ constexpr uint8_t kCtapMakeCredentialRequest[] = {
0xa5,
// key(1) - clientDataHash
0x01,
- // bytes(32)
- 0x58, 0x20, 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e,
- 0x42, 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05,
- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41,
+ // bytes(32) -- see kClientDataHash
+ 0x58, 0x20, 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3,
+ 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// key(2) - rp
0x02,
// map(2)
@@ -931,10 +939,10 @@ constexpr uint8_t kTestComplexCtapGetAssertionRequest[] = {
0x68, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
// key(02) - client data hash
0x02,
- // value - bytes(32)
- 0x58, 0x20, 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e,
- 0x42, 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05,
- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41,
+ // bytes(32) -- see kClientDataHash
+ 0x58, 0x20, 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3,
+ 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// key(03) - allow list
0x03,
// value - array(2)
@@ -993,10 +1001,10 @@ constexpr uint8_t kCtapGetAssertionRequest[] = {
0x68, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
// key(02) - client data hash
0x02,
- // value - bytes(32)
- 0x58, 0x20, 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e,
- 0x42, 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05,
- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41,
+ // bytes(32) -- see kClientDataHash
+ 0x58, 0x20, 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3,
+ 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// key(03) - allow list
0x03,
// value - array(1)
@@ -1029,10 +1037,10 @@ constexpr uint8_t kCtapSilentGetAssertionRequest[] = {
0x68, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
// key(02) - client data hash
0x02,
- // value - bytes(32)
- 0x58, 0x20, 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e,
- 0x42, 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05,
- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41,
+ // bytes(32) -- see kClientDataHash
+ 0x58, 0x20, 0x8d, 0xd8, 0x74, 0x4d, 0x79, 0x3, 0xb0, 0xa3, 0x53, 0x8a, 0x49,
+ 0xea, 0xfa, 0xae, 0xc8, 0x33, 0xac, 0xbf, 0xd2, 0x85, 0xa5, 0xdf, 0x44, 0x3,
+ 0xa2, 0xe, 0x4e, 0x13, 0xe3, 0xd5, 0x3e, 0x50,
// key(03) - allow list
0x03,
// value - array(1)
@@ -1170,19 +1178,42 @@ constexpr uint8_t kTestMakeCredentialResponse[] = {
// key(02) - Authenticator Data
0x02,
// Byte(154)
- 0x58, 0x9a, 0x11, 0x94, 0x22, 0x8d, 0xa8, 0xfd, 0xbd, 0xee, 0xfd, 0x26,
- 0x1b, 0xd7, 0xb6, 0x59, 0x5c, 0xfd, 0x70, 0xa5, 0x0d, 0x70, 0xc6, 0x40,
- 0x7b, 0xcf, 0x01, 0x3d, 0xe9, 0x6d, 0x4e, 0xfb, 0x17, 0xde, 0x41, 0x00,
- 0x00, 0x00, 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80,
- 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59, 0xce,
- 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c,
- 0x6f, 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
- 0x61, 0x78, 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38,
- 0xdf, 0xa4, 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99,
- 0xf5, 0xe6, 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
- 0x61, 0x79, 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e,
- 0xa3, 0x21, 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89,
- 0xdd, 0x61, 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ 0x58, 0x9a,
+ // RP ID hash
+ 0x11, 0x94, 0x22, 0x8d, 0xa8, 0xfd, 0xbd, 0xee, 0xfd, 0x26, 0x1b, 0xd7,
+ 0xb6, 0x59, 0x5c, 0xfd, 0x70, 0xa5, 0x0d, 0x70, 0xc6, 0x40, 0x7b, 0xcf,
+ 0x01, 0x3d, 0xe9, 0x6d, 0x4e, 0xfb, 0x17, 0xde,
+ // Flags: user-presence + attested credential data
+ 0x41,
+ // Signature counter
+ 0x00, 0x00, 0x00, 0x0b,
+ // AAGUID
+ 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11,
+ 0x1f, 0x9e, 0xdc, 0x7d,
+ // Credential ID length (16)
+ 0x00, 0x10,
+ // Credential ID
+ 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6,
+ 0xd9, 0x43, 0x5c, 0x6f,
+ // Public key in COSE_key format
+ // map(3)
+ 0xa3,
+ // "x"
+ 0x61, 0x78,
+ // Byte(32)
+ 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4,
+ 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6,
+ 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
+ // "y"
+ 0x61, 0x79,
+ // Byte(32)
+ 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21,
+ 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61,
+ 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ // "alg"
+ 0x63, 0x61, 0x6c, 0x67,
+ // "ES256"
+ 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
// Key(03) - Attestation object
0x03,
// Map - Attestation object
@@ -1399,19 +1430,42 @@ constexpr uint8_t kCtap2MakeCredentialCertificate[] = {
0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3};
constexpr uint8_t kCtap2MakeCredentialAuthData[] = {
+ // RP ID hash
0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7,
0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF,
- 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, 0x41, 0x00, 0x00, 0x00,
- 0x0b, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17,
- 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b,
- 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa3,
- 0x63, 0x61, 0x6c, 0x67, 0x65, 0x45, 0x53, 0x32, 0x35, 0x36, 0x61, 0x78,
+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
+ // Flags: user-presence + attested-credential-data
+ 0x41,
+ // Signature counter
+ 0x00, 0x00, 0x00, 0x0b,
+ // AAGUID
+ 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11,
+ 0x1f, 0x9e, 0xdc, 0x7d,
+ // Credential ID length (16)
+ 0x00, 0x10,
+ // Credential ID
+ 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6,
+ 0xd9, 0x43, 0x5c, 0x6f,
+ // Public key in COSE_key format
+ // map(3)
+ 0xa3,
+ // "x"
+ 0x61, 0x78,
+ // byte(32)
0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4,
0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6,
- 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a, 0x61, 0x79,
+ 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
+ // "y"
+ 0x61, 0x79,
+ // byte(32)
0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21,
0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61,
- 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84};
+ 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ // "alg"
+ 0x63, 0x61, 0x6c, 0x67,
+ // "ES256"
+ 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
+};
constexpr uint8_t kCtap2MakeCredentialSignature[] = {
0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c,
@@ -1457,16 +1511,28 @@ constexpr uint8_t kNoneAttestationResponse[] = {
// Replaced device AAGUID
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
- // Credential information
+ // Credential ID length (16)
0x00, 0x10, 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a,
- 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x65,
- 0x45, 0x53, 0x32, 0x35, 0x36, 0x61, 0x78, 0x58, 0x20, 0xf7, 0xc4, 0xf4,
- 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4, 0xc9, 0xac, 0x50, 0x84, 0x8d,
- 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6, 0x0e, 0x51, 0xb4, 0x2a, 0x52,
- 0x1b, 0x35, 0xd3, 0xb6, 0x9a, 0x61, 0x79, 0x58, 0x20, 0xde, 0x7b, 0x7d,
- 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21, 0xa4, 0xd5, 0xd9, 0x6e, 0xa0,
- 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61, 0xd4, 0x89, 0x4c, 0x15, 0xac,
- 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f,
+ // Public key in COSE_key format
+ // map(3)
+ 0xa3,
+ // "x"
+ 0x61, 0x78,
+ // byte(32)
+ 0x58, 0x20, 0xf7, 0xc4, 0xf4, 0xa6, 0xf1, 0xd7, 0x95, 0x38, 0xdf, 0xa4,
+ 0xc9, 0xac, 0x50, 0x84, 0x8d, 0xf7, 0x08, 0xbc, 0x1c, 0x99, 0xf5, 0xe6,
+ 0x0e, 0x51, 0xb4, 0x2a, 0x52, 0x1b, 0x35, 0xd3, 0xb6, 0x9a,
+ // "y"
+ 0x61, 0x79,
+ // byte(32)
+ 0x58, 0x20, 0xde, 0x7b, 0x7d, 0x6c, 0xa5, 0x64, 0xe7, 0x0e, 0xa3, 0x21,
+ 0xa4, 0xd5, 0xd9, 0x6e, 0xa0, 0x0e, 0xf0, 0xe2, 0xdb, 0x89, 0xdd, 0x61,
+ 0xd4, 0x89, 0x4c, 0x15, 0xac, 0x58, 0x5b, 0xd2, 0x36, 0x84,
+ // "alg"
+ 0x63, 0x61, 0x6c, 0x67,
+ // "ES256"
+ 0x65, 0x45, 0x53, 0x32, 0x35, 0x36,
};
constexpr uint8_t kCtap2GetAssertionAuthData[] = {
diff --git a/chromium/device/fido/get_assertion_handler_unittest.cc b/chromium/device/fido/get_assertion_handler_unittest.cc
index 9f92be8a5e0..30391c3d161 100644
--- a/chromium/device/fido/get_assertion_handler_unittest.cc
+++ b/chromium/device/fido/get_assertion_handler_unittest.cc
@@ -7,8 +7,10 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/stl_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
#include "device/base/features.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -16,16 +18,23 @@
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/device_response_converter.h"
#include "device/fido/fake_fido_discovery.h"
+#include "device/fido/features.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/get_assertion_request_handler.h"
+#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+#include "device/fido/win/authenticator.h"
+#include "device/fido/win/fake_webauthn_api.h"
+#endif // defined(OS_WIN)
+
namespace device {
namespace {
@@ -35,7 +44,7 @@ constexpr uint8_t kBogusCredentialId[] = {0x01, 0x02, 0x03, 0x04};
using TestGetAssertionRequestCallback = test::StatusAndValuesCallbackReceiver<
FidoReturnCode,
base::Optional<AuthenticatorGetAssertionResponse>,
- FidoTransportProtocol>;
+ base::Optional<FidoTransportProtocol>>;
} // namespace
@@ -56,14 +65,14 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
CtapGetAssertionRequest CreateTestRequestWithCableExtension() {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetCableExtension({});
return request;
}
std::unique_ptr<GetAssertionRequestHandler> CreateGetAssertionHandlerU2f() {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetAllowList(
{{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}});
@@ -72,7 +81,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
std::unique_ptr<GetAssertionRequestHandler> CreateGetAssertionHandlerCtap() {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetAllowList({{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(
test_data::kTestGetAssertionCredentialId)}});
@@ -183,7 +192,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
TEST_F(FidoGetAssertionHandlerTest, TransportAvailabilityInfo) {
auto request_handler =
CreateGetAssertionHandlerWithRequest(CtapGetAssertionRequest(
- test_data::kRelyingPartyId, test_data::kClientDataHash));
+ test_data::kRelyingPartyId, test_data::kClientDataJson));
EXPECT_EQ(FidoRequestHandlerBase::RequestType::kGetAssertion,
request_handler->transport_availability_info().request_type);
@@ -252,7 +261,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestU2fSignWithoutCtapFlag) {
TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) {
auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetUserVerification(UserVerificationRequirement::kRequired);
auto request_handler =
CreateGetAssertionHandlerWithRequest(std::move(request));
@@ -270,7 +279,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) {
TEST_F(FidoGetAssertionHandlerTest,
TestU2fSignRequestWithUserVerificationRequired) {
auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetAllowList(
{{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}});
@@ -289,7 +298,7 @@ TEST_F(FidoGetAssertionHandlerTest,
TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
auto request_handler =
CreateGetAssertionHandlerWithRequest(CtapGetAssertionRequest(
- test_data::kRelyingPartyId, test_data::kClientDataHash));
+ test_data::kRelyingPartyId, test_data::kClientDataJson));
discovery()->WaitForCallToStartAndSimulateSuccess();
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
device->ExpectCtap2CommandAndRespondWith(
@@ -306,7 +315,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
// is not included in the allowed list.
TEST_F(FidoGetAssertionHandlerTest, InvalidCredential) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request.SetAllowList(
{{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha)}});
@@ -358,7 +367,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectUserEntity) {
// Use a GetAssertion request with an empty allow list.
auto request_handler =
CreateGetAssertionHandlerWithRequest(CtapGetAssertionRequest(
- test_data::kRelyingPartyId, test_data::kClientDataHash));
+ test_data::kRelyingPartyId, test_data::kClientDataJson));
discovery()->WaitForCallToStartAndSimulateSuccess();
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
device->ExpectCtap2CommandAndRespondWith(
@@ -434,7 +443,7 @@ TEST_F(FidoGetAssertionHandlerTest,
TEST_F(FidoGetAssertionHandlerTest,
CableDisabledIfAllowCredentialsListUndefinedButCableExtensionMissing) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
ASSERT_FALSE(!!request.cable_extension());
EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true));
auto request_handler =
@@ -449,7 +458,7 @@ TEST_F(FidoGetAssertionHandlerTest,
TEST_F(FidoGetAssertionHandlerTest,
CableDisabledIfExplicitlyAllowedButCableExtensionMissing) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
ASSERT_FALSE(!!request.cable_extension());
request.SetAllowList({
{CredentialType::kPublicKey,
@@ -711,4 +720,63 @@ TEST_F(FidoGetAssertionHandlerTest,
get_assertion_callback().status());
}
+#if defined(OS_WIN)
+class GetAssertionRequestHandlerWinTest : public ::testing::Test {
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ ScopedFakeWinWebAuthnApi scoped_fake_win_webauthn_api_;
+};
+
+// Verify that the request handler instantiates a HID device backed
+// FidoDeviceAuthenticator or a WinNativeCrossPlatformAuthenticator, depending
+// on feature flag and API availability.
+TEST_F(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
+ enum class DeviceType {
+ kHid,
+ kWinNative,
+ };
+ const struct TestCase {
+ bool enable_win_webauthn_api;
+ bool enable_feature_flag;
+ DeviceType expect_device_type;
+ } test_cases[] = {
+ {false, false, DeviceType::kHid},
+ {false, true, DeviceType::kHid},
+ {true, false, DeviceType::kHid},
+ {true, true, DeviceType::kWinNative},
+ };
+ size_t i = 0;
+ for (const auto& test : test_cases) {
+ SCOPED_TRACE(i++);
+ scoped_fake_win_webauthn_api_.set_available(test.enable_win_webauthn_api);
+ base::test::ScopedFeatureList scoped_feature_list;
+ // Feature is default off (even with API present).
+ if (test.enable_feature_flag)
+ scoped_feature_list.InitAndEnableFeature(kWebAuthUseNativeWinApi);
+
+ // Simulate a connected HID device.
+ ScopedFakeHidManager fake_hid_manager;
+ fake_hid_manager.AddFidoHidDevice("guid");
+
+ TestGetAssertionRequestCallback cb;
+ auto handler = std::make_unique<GetAssertionRequestHandler>(
+ fake_hid_manager.service_manager_connector(),
+ base::flat_set<FidoTransportProtocol>(
+ {FidoTransportProtocol::kUsbHumanInterfaceDevice}),
+ CtapGetAssertionRequest(test_data::kRelyingPartyId,
+ test_data::kClientDataJson),
+
+ cb.callback());
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(1u, handler->AuthenticatorsForTesting().size());
+ // Crudely distinguish authenticator type by FidoAuthenticator::GetId.
+ EXPECT_EQ(test.expect_device_type == DeviceType::kHid
+ ? "hid:guid"
+ : WinWebAuthnApiAuthenticator::kAuthenticatorId,
+ handler->AuthenticatorsForTesting().begin()->second->GetId());
+ }
+}
+#endif // defined(OS_WIN)
+
} // namespace device
diff --git a/chromium/device/fido/get_assertion_request_handler.cc b/chromium/device/fido/get_assertion_request_handler.cc
index 78d6424e79b..94e52a680e9 100644
--- a/chromium/device/fido/get_assertion_request_handler.cc
+++ b/chromium/device/fido/get_assertion_request_handler.cc
@@ -13,6 +13,7 @@
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/cable/fido_cable_discovery.h"
#include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_discovery_factory.h"
#include "device/fido/get_assertion_task.h"
namespace device {
@@ -70,17 +71,19 @@ bool CheckResponseCredentialIdMatchesRequestAllowList(
const auto& allow_list = request.allow_list();
if (!allow_list || allow_list->empty()) {
// Allow list can't be empty for authenticators w/o resident key support.
- return authenticator.Options().supports_resident_key();
+ return !authenticator.Options() ||
+ authenticator.Options()->supports_resident_key();
}
// Credential ID may be omitted if allow list has size 1. Otherwise, it needs
// to match.
- const auto transport_used = authenticator.AuthenticatorTransport();
+ const auto opt_transport_used = authenticator.AuthenticatorTransport();
return (allow_list->size() == 1 && !response.credential()) ||
std::any_of(allow_list->cbegin(), allow_list->cend(),
- [&response, transport_used](const auto& credential) {
+ [&response, opt_transport_used](const auto& credential) {
return credential.id() == response.raw_credential_id() &&
- base::ContainsKey(credential.transports(),
- transport_used);
+ (!opt_transport_used ||
+ base::ContainsKey(credential.transports(),
+ *opt_transport_used));
});
}
@@ -97,36 +100,22 @@ void SetCredentialIdForResponseWithEmptyCredential(
}
// Checks UserVerificationRequirement enum passed from the relying party is
-// compatible with the authenticator, and updates the request to the
-// "effective" user verification requirement.
-// https://w3c.github.io/webauthn/#effective-user-verification-requirement-for-assertion
+// compatible with the authenticator.
bool CheckUserVerificationCompatible(FidoAuthenticator* authenticator,
- CtapGetAssertionRequest* request) {
- const auto uv_availability =
- authenticator->Options().user_verification_availability();
+ const CtapGetAssertionRequest& request) {
+ const auto& opt_options = authenticator->Options();
+ if (!opt_options) {
+ // This authenticator doesn't know its capabilities yet, so we need
+ // to assume it can handle the request. This is the case for Windows,
+ // where we proxy the request to the native API.
+ return true;
+ }
- switch (request->user_verification()) {
- case UserVerificationRequirement::kRequired:
- return uv_availability ==
+ return request.user_verification() !=
+ UserVerificationRequirement::kRequired ||
+ opt_options->user_verification_availability() ==
AuthenticatorSupportedOptions::UserVerificationAvailability::
kSupportedAndConfigured;
-
- case UserVerificationRequirement::kDiscouraged:
- return true;
-
- case UserVerificationRequirement::kPreferred:
- if (uv_availability ==
- AuthenticatorSupportedOptions::UserVerificationAvailability::
- kSupportedAndConfigured) {
- request->SetUserVerification(UserVerificationRequirement::kRequired);
- } else {
- request->SetUserVerification(UserVerificationRequirement::kDiscouraged);
- }
- return true;
- }
-
- NOTREACHED();
- return false;
}
base::flat_set<FidoTransportProtocol> GetTransportsAllowedByRP(
@@ -170,7 +159,7 @@ GetAssertionRequestHandler::GetAssertionRequestHandler(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapGetAssertionRequest request,
- SignResponseCallback completion_callback)
+ CompletionCallback completion_callback)
: FidoRequestHandler(
connector,
base::STLSetIntersection<base::flat_set<FidoTransportProtocol>>(
@@ -188,7 +177,7 @@ GetAssertionRequestHandler::GetAssertionRequestHandler(
FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)) {
DCHECK(request_.cable_extension());
auto discovery =
- FidoDeviceDiscovery::CreateCable(*request_.cable_extension());
+ FidoDiscoveryFactory::CreateCable(*request_.cable_extension());
discovery->set_observer(this);
discoveries().push_back(std::move(discovery));
}
@@ -200,17 +189,12 @@ GetAssertionRequestHandler::~GetAssertionRequestHandler() = default;
void GetAssertionRequestHandler::DispatchRequest(
FidoAuthenticator* authenticator) {
- // The user verification field of the request may be adjusted to the
- // authenticator, so we need to make a copy.
- CtapGetAssertionRequest request_copy = request_;
- if (!CheckUserVerificationCompatible(authenticator, &request_copy)) {
+ if (!CheckUserVerificationCompatible(authenticator, request_))
return;
- }
authenticator->GetAssertion(
- std::move(request_copy),
- base::BindOnce(&GetAssertionRequestHandler::HandleResponse,
- weak_factory_.GetWeakPtr(), authenticator));
+ request_, base::BindOnce(&GetAssertionRequestHandler::HandleResponse,
+ weak_factory_.GetWeakPtr(), authenticator));
}
void GetAssertionRequestHandler::HandleResponse(
diff --git a/chromium/device/fido/get_assertion_request_handler.h b/chromium/device/fido/get_assertion_request_handler.h
index de6e0d378f9..0f5940383ce 100644
--- a/chromium/device/fido/get_assertion_request_handler.h
+++ b/chromium/device/fido/get_assertion_request_handler.h
@@ -25,11 +25,6 @@ namespace device {
class FidoAuthenticator;
class AuthenticatorGetAssertionResponse;
-using SignResponseCallback =
- base::OnceCallback<void(FidoReturnCode,
- base::Optional<AuthenticatorGetAssertionResponse>,
- FidoTransportProtocol)>;
-
class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
: public FidoRequestHandler<AuthenticatorGetAssertionResponse> {
public:
@@ -37,7 +32,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapGetAssertionRequest request_parameter,
- SignResponseCallback completion_callback);
+ CompletionCallback completion_callback);
~GetAssertionRequestHandler() override;
private:
diff --git a/chromium/device/fido/get_assertion_task_unittest.cc b/chromium/device/fido/get_assertion_task_unittest.cc
index 1ed026af0d3..5227452a1d2 100644
--- a/chromium/device/fido/get_assertion_task_unittest.cc
+++ b/chromium/device/fido/get_assertion_task_unittest.cc
@@ -63,7 +63,7 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAssertionSuccess) {
test_data::kTestGetAssertionResponse);
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request_param.SetAllowList({{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(
test_data::kTestGetAssertionCredentialId)}});
@@ -88,7 +88,7 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignSuccess) {
test_data::kApduEncodedNoErrorSignResponse);
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request_param.SetAllowList(
{{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}});
@@ -110,7 +110,7 @@ TEST_F(FidoGetAssertionTaskTest, TestSignSuccessWithFake) {
auto hash = fido_parsing_utils::CreateSHA256Hash(public_key);
std::vector<uint8_t> key_handle(hash.begin(), hash.end());
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request_param.SetAllowList({{CredentialType::kPublicKey, key_handle}});
auto device = std::make_unique<VirtualCtap2Device>();
@@ -162,7 +162,7 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignWithoutFlag) {
test_data::kApduEncodedNoErrorSignResponse);
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
request_param.SetAllowList(
{{CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)}});
@@ -185,7 +185,7 @@ TEST_F(FidoGetAssertionTaskTest, TestIncorrectGetAssertionResponse) {
auto task = std::make_unique<GetAssertionTask>(
device.get(),
CtapGetAssertionRequest(test_data::kRelyingPartyId,
- test_data::kClientDataHash),
+ test_data::kClientDataJson),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
@@ -196,7 +196,7 @@ TEST_F(FidoGetAssertionTaskTest, TestIncorrectGetAssertionResponse) {
TEST_F(FidoGetAssertionTaskTest, TestU2fSignRequestWithEmptyAllowedList) {
auto request = CtapGetAssertionRequest(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
auto device = MockFidoDevice::MakeU2f();
device->ExpectRequestAndRespondWith(
@@ -218,14 +218,13 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignRequestWithEmptyAllowedList) {
// of valid credentials via silent authentication.
TEST_F(FidoGetAssertionTaskTest, TestSilentSignInWhenAppIdExtensionPresent) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
std::vector<PublicKeyCredentialDescriptor> allowed_list;
allowed_list.push_back(PublicKeyCredentialDescriptor(
CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
- request.SetAlternativeApplicationParameter(
- test_data::kAlternativeApplicationParameter);
+ request.SetAppId(test_data::kAppId);
request.SetAllowList(std::move(allowed_list));
auto device = MockFidoDevice::MakeCtap();
@@ -245,14 +244,13 @@ TEST_F(FidoGetAssertionTaskTest, TestSilentSignInWhenAppIdExtensionPresent) {
TEST_F(FidoGetAssertionTaskTest, TestU2fFallbackForAppIdExtension) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
std::vector<PublicKeyCredentialDescriptor> allowed_list;
allowed_list.push_back(PublicKeyCredentialDescriptor(
CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
- request.SetAlternativeApplicationParameter(
- test_data::kAlternativeApplicationParameter);
+ request.SetAppId(test_data::kAppId);
request.SetAllowList(std::move(allowed_list));
::testing::InSequence s;
@@ -287,15 +285,14 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fFallbackForAppIdExtension) {
TEST_F(FidoGetAssertionTaskTest, TestAvoidSilentSignInForCtapOnlyDevice) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
std::vector<PublicKeyCredentialDescriptor> allowed_list;
allowed_list.push_back(PublicKeyCredentialDescriptor(
CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
- request.SetAlternativeApplicationParameter(
- test_data::kAlternativeApplicationParameter);
+ request.SetAppId(test_data::kAppId);
request.SetAllowList(std::move(allowed_list));
auto device = MockFidoDevice::MakeCtap(ReadCTAPGetInfoResponse(
diff --git a/chromium/device/fido/hid/fake_hid_impl_for_testing.cc b/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
index cf86174175a..7170324c560 100644
--- a/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
+++ b/chromium/device/fido/hid/fake_hid_impl_for_testing.cc
@@ -7,6 +7,10 @@
#include <utility>
#include "device/fido/fido_parsing_utils.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
namespace device {
@@ -126,6 +130,20 @@ void FakeHidManager::AddBinding2(device::mojom::HidManagerRequest request) {
bindings_.AddBinding(this, std::move(request));
}
+void FakeHidManager::AddFidoHidDevice(std::string guid) {
+ auto c_info = device::mojom::HidCollectionInfo::New();
+ c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
+ auto device = device::mojom::HidDeviceInfo::New();
+ device->guid = std::move(guid);
+ device->product_name = "Test Fido Device";
+ device->serial_number = "123FIDO";
+ device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
+ device->collections.push_back(std::move(c_info));
+ device->max_input_report_size = 64;
+ device->max_output_report_size = 64;
+ AddDevice(std::move(device));
+}
+
void FakeHidManager::GetDevicesAndSetClient(
device::mojom::HidManagerClientAssociatedPtrInfo client,
GetDevicesCallback callback) {
@@ -184,4 +202,15 @@ void FakeHidManager::RemoveDevice(const std::string device_guid) {
devices_.erase(it);
}
+ScopedFakeHidManager::ScopedFakeHidManager() {
+ service_manager::mojom::ConnectorRequest request;
+ connector_ = service_manager::Connector::Create(&request);
+ connector_->OverrideBinderForTesting(
+ service_manager::ServiceFilter::ByName(device::mojom::kServiceName),
+ device::mojom::HidManager::Name_,
+ base::BindRepeating(&FakeHidManager::AddBinding, base::Unretained(this)));
+}
+
+ScopedFakeHidManager::~ScopedFakeHidManager() = default;
+
} // namespace device
diff --git a/chromium/device/fido/hid/fake_hid_impl_for_testing.h b/chromium/device/fido/hid/fake_hid_impl_for_testing.h
index b69945adc0c..022775c0709 100644
--- a/chromium/device/fido/hid/fake_hid_impl_for_testing.h
+++ b/chromium/device/fido/hid/fake_hid_impl_for_testing.h
@@ -20,6 +20,10 @@
#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
+namespace service_manager {
+class Connector;
+}
+
namespace device {
class MockHidConnection : public device::mojom::HidConnection {
@@ -95,6 +99,9 @@ class FakeHidManager : public device::mojom::HidManager {
FakeHidManager();
~FakeHidManager() override;
+ // Invoke AddDevice with a device info struct that mirrors a FIDO USB device.
+ void AddFidoHidDevice(std::string guid);
+
// device::mojom::HidManager implementation:
void GetDevicesAndSetClient(
device::mojom::HidManagerClientAssociatedPtrInfo client,
@@ -118,6 +125,23 @@ class FakeHidManager : public device::mojom::HidManager {
DISALLOW_COPY_AND_ASSIGN(FakeHidManager);
};
+// ScopedFakeHidManager automatically binds itself to the device service for the
+// duration of its lifetime.
+class ScopedFakeHidManager : public FakeHidManager {
+ public:
+ ScopedFakeHidManager();
+ ~ScopedFakeHidManager() override;
+
+ service_manager::Connector* service_manager_connector() {
+ return connector_.get();
+ }
+
+ private:
+ std::unique_ptr<service_manager::Connector> connector_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedFakeHidManager);
+};
+
} // namespace device
#endif // DEVICE_FIDO_HID_FAKE_HID_IMPL_FOR_TESTING_H_
diff --git a/chromium/device/fido/hid/fido_hid_device.cc b/chromium/device/fido/hid/fido_hid_device.cc
index 9734a739218..db134be7e04 100644
--- a/chromium/device/fido/hid/fido_hid_device.cc
+++ b/chromium/device/fido/hid/fido_hid_device.cc
@@ -167,7 +167,8 @@ void FidoHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce,
auto received_nonce = base::make_span(payload).first(8);
// Received a broadcast message for a different client. Disregard and continue
// reading.
- if (base::make_span(nonce) != received_nonce) {
+ if (!std::equal(nonce.begin(), nonce.end(), received_nonce.begin(),
+ received_nonce.end())) {
auto repeating_callback =
base::AdaptCallbackForRepeating(std::move(callback));
ArmTimeout(repeating_callback);
diff --git a/chromium/device/fido/hid/fido_hid_discovery_unittest.cc b/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
index ebae8e79ea7..345e1ad9b98 100644
--- a/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
+++ b/chromium/device/fido/hid/fido_hid_discovery_unittest.cc
@@ -25,21 +25,6 @@ using ::testing::_;
namespace {
-device::mojom::HidDeviceInfoPtr MakeFidoHidDevice(std::string guid) {
- auto c_info = device::mojom::HidCollectionInfo::New();
- c_info->usage = device::mojom::HidUsageAndPage::New(1, 0xf1d0);
-
- auto u2f_device = device::mojom::HidDeviceInfo::New();
- u2f_device->guid = std::move(guid);
- u2f_device->product_name = "Test Fido Device";
- u2f_device->serial_number = "123FIDO";
- u2f_device->bus_type = device::mojom::HidBusType::kHIDBusTypeUSB;
- u2f_device->collections.push_back(std::move(c_info));
- u2f_device->max_input_report_size = 64;
- u2f_device->max_output_report_size = 64;
- return u2f_device;
-}
-
device::mojom::HidDeviceInfoPtr MakeOtherDevice(std::string guid) {
auto other_device = device::mojom::HidDeviceInfo::New();
other_device->guid = std::move(guid);
@@ -56,35 +41,16 @@ MATCHER_P(IdMatches, id, "") {
} // namespace
class FidoHidDiscoveryTest : public ::testing::Test {
- public:
- base::test::ScopedTaskEnvironment& scoped_task_environment() {
- return scoped_task_environment_;
- }
-
- void SetUp() override {
- fake_hid_manager_ = std::make_unique<FakeHidManager>();
-
- service_manager::mojom::ConnectorRequest request;
- connector_ = service_manager::Connector::Create(&request);
- service_manager::Connector::TestApi test_api(connector_.get());
- test_api.OverrideBinderForTesting(
- service_manager::Identity(device::mojom::kServiceName),
- device::mojom::HidManager::Name_,
- base::Bind(&FakeHidManager::AddBinding,
- base::Unretained(fake_hid_manager_.get())));
- }
-
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
- std::unique_ptr<service_manager::Connector> connector_;
- std::unique_ptr<FakeHidManager> fake_hid_manager_;
+ ScopedFakeHidManager fake_hid_manager_;
};
TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
- FidoHidDiscovery discovery(connector_.get());
+ FidoHidDiscovery discovery(fake_hid_manager_.service_manager_connector());
MockFidoDiscoveryObserver observer;
- fake_hid_manager_->AddDevice(MakeFidoHidDevice("known"));
+ fake_hid_manager_.AddFidoHidDevice("known");
EXPECT_CALL(observer, DiscoveryStarted(&discovery, true));
discovery.set_observer(&observer);
@@ -93,28 +59,28 @@ TEST_F(FidoHidDiscoveryTest, TestAddRemoveDevice) {
// Devices initially known to the service before discovery started should be
// reported as KNOWN.
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("known")));
- scoped_task_environment().RunUntilIdle();
+ scoped_task_environment_.RunUntilIdle();
// Devices added during the discovery should be reported as ADDED.
EXPECT_CALL(observer, AuthenticatorAdded(&discovery, IdMatches("added")));
- fake_hid_manager_->AddDevice(MakeFidoHidDevice("added"));
- scoped_task_environment().RunUntilIdle();
+ fake_hid_manager_.AddFidoHidDevice("added");
+ scoped_task_environment_.RunUntilIdle();
// Added non-U2F devices should not be reported at all.
EXPECT_CALL(observer, AuthenticatorAdded(_, _)).Times(0);
- fake_hid_manager_->AddDevice(MakeOtherDevice("other"));
+ fake_hid_manager_.AddDevice(MakeOtherDevice("other"));
// Removed non-U2F devices should not be reported at all.
EXPECT_CALL(observer, AuthenticatorRemoved(_, _)).Times(0);
- fake_hid_manager_->RemoveDevice("other");
- scoped_task_environment().RunUntilIdle();
+ fake_hid_manager_.RemoveDevice("other");
+ scoped_task_environment_.RunUntilIdle();
// Removed U2F devices should be reported as REMOVED.
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("known")));
EXPECT_CALL(observer, AuthenticatorRemoved(&discovery, IdMatches("added")));
- fake_hid_manager_->RemoveDevice("known");
- fake_hid_manager_->RemoveDevice("added");
- scoped_task_environment().RunUntilIdle();
+ fake_hid_manager_.RemoveDevice("known");
+ fake_hid_manager_.RemoveDevice("added");
+ scoped_task_environment_.RunUntilIdle();
}
} // namespace device
diff --git a/chromium/device/fido/mac/OWNERS b/chromium/device/fido/mac/OWNERS
index eac9cee5ed5..8bd04477873 100644
--- a/chromium/device/fido/mac/OWNERS
+++ b/chromium/device/fido/mac/OWNERS
@@ -1,5 +1,4 @@
-martinkr@chromium.org
-martinkr@google.com
+file://device/fido/OWNERS
-# TEAM: security-dev@chromium.org
# COMPONENT: Blink>WebAuthentication
+# TEAM: identity-dev@chromium.org
diff --git a/chromium/device/fido/mac/authenticator.h b/chromium/device/fido/mac/authenticator.h
index 1728623e756..1358f3ba91e 100644
--- a/chromium/device/fido/mac/authenticator.h
+++ b/chromium/device/fido/mac/authenticator.h
@@ -58,9 +58,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdAuthenticator
void Cancel() override;
std::string GetId() const override;
base::string16 GetDisplayName() const override;
- const AuthenticatorSupportedOptions& Options() const override;
- FidoTransportProtocol AuthenticatorTransport() const override;
+ const base::Optional<AuthenticatorSupportedOptions>& Options() const override;
+ base::Optional<FidoTransportProtocol> AuthenticatorTransport() const override;
bool IsInPairingMode() const override;
+ bool IsPaired() const override;
base::WeakPtr<FidoAuthenticator> GetWeakPtr() override;
private:
diff --git a/chromium/device/fido/mac/authenticator.mm b/chromium/device/fido/mac/authenticator.mm
index 2e055b83ec6..edcea5b6988 100644
--- a/chromium/device/fido/mac/authenticator.mm
+++ b/chromium/device/fido/mac/authenticator.mm
@@ -136,7 +136,8 @@ base::string16 TouchIdAuthenticator::GetDisplayName() const {
return base::string16();
}
-FidoTransportProtocol TouchIdAuthenticator::AuthenticatorTransport() const {
+base::Optional<FidoTransportProtocol>
+TouchIdAuthenticator::AuthenticatorTransport() const {
return FidoTransportProtocol::kInternal;
}
@@ -155,8 +156,9 @@ AuthenticatorSupportedOptions TouchIdAuthenticatorOptions() {
} // namespace
-const AuthenticatorSupportedOptions& TouchIdAuthenticator::Options() const {
- static const AuthenticatorSupportedOptions options =
+const base::Optional<AuthenticatorSupportedOptions>&
+TouchIdAuthenticator::Options() const {
+ static const base::Optional<AuthenticatorSupportedOptions> options =
TouchIdAuthenticatorOptions();
return options;
}
@@ -165,6 +167,10 @@ bool TouchIdAuthenticator::IsInPairingMode() const {
return false;
}
+bool TouchIdAuthenticator::IsPaired() const {
+ return false;
+}
+
base::WeakPtr<FidoAuthenticator> TouchIdAuthenticator::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
diff --git a/chromium/device/fido/mac/browsing_data_deletion_unittest.mm b/chromium/device/fido/mac/browsing_data_deletion_unittest.mm
index e1a6d6b444f..4ba0c955672 100644
--- a/chromium/device/fido/mac/browsing_data_deletion_unittest.mm
+++ b/chromium/device/fido/mac/browsing_data_deletion_unittest.mm
@@ -16,6 +16,7 @@
#include "device/base/features.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_test_data.h"
#include "device/fido/mac/authenticator.h"
#include "device/fido/mac/authenticator_config.h"
#include "device/fido/mac/keychain.h"
@@ -47,7 +48,6 @@ constexpr char kKeychainAccessGroup[] =
constexpr char kMetadataSecret[] = "supersecret";
constexpr char kOtherMetadataSecret[] = "reallynotsosecret";
-constexpr std::array<uint8_t, kClientDataHashLength> kClientDataHash = {};
constexpr char kRpId[] = "rp.example.com";
const std::vector<uint8_t> kUserId = {10, 11, 12, 13, 14, 15};
@@ -123,7 +123,7 @@ class BrowsingDataDeletionTest : public testing::Test {
protected:
CtapMakeCredentialRequest MakeRequest() {
return CtapMakeCredentialRequest(
- kClientDataHash, PublicKeyCredentialRpEntity(kRpId),
+ test_data::kClientDataJson, PublicKeyCredentialRpEntity(kRpId),
PublicKeyCredentialUserEntity(kUserId),
PublicKeyCredentialParams(
{{PublicKeyCredentialParams::
diff --git a/chromium/device/fido/mac/credential_metadata.cc b/chromium/device/fido/mac/credential_metadata.cc
index 60d9feafd77..54c69ed4728 100644
--- a/chromium/device/fido/mac/credential_metadata.cc
+++ b/chromium/device/fido/mac/credential_metadata.cc
@@ -7,9 +7,9 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
-#include "components/cbor/cbor_reader.h"
-#include "components/cbor/cbor_values.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/values.h"
+#include "components/cbor/writer.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/hkdf.h"
@@ -19,9 +19,9 @@ namespace device {
namespace fido {
namespace mac {
-using cbor::CBORWriter;
-using cbor::CBORReader;
-using cbor::CBORValue;
+using cbor::Writer;
+using cbor::Reader;
+using cbor::Value;
// static
std::string CredentialMetadata::GenerateRandomSecret() {
@@ -93,13 +93,12 @@ base::Optional<std::vector<uint8_t>> CredentialMetadata::SealCredentialId(
// The remaining bytes are the CBOR-encoded UserEntity, encrypted with
// AES-256-GCM and authenticated with the version and RP ID.
- CBORValue::ArrayValue cbor_user;
- cbor_user.emplace_back(CBORValue(user.id));
- cbor_user.emplace_back(CBORValue(user.name, CBORValue::Type::BYTE_STRING));
- cbor_user.emplace_back(
- CBORValue(user.display_name, CBORValue::Type::BYTE_STRING));
+ Value::ArrayValue cbor_user;
+ cbor_user.emplace_back(Value(user.id));
+ cbor_user.emplace_back(Value(user.name, Value::Type::BYTE_STRING));
+ cbor_user.emplace_back(Value(user.display_name, Value::Type::BYTE_STRING));
base::Optional<std::vector<uint8_t>> pt =
- CBORWriter::Write(CBORValue(std::move(cbor_user)));
+ Writer::Write(Value(std::move(cbor_user)));
if (!pt) {
return base::nullopt;
}
@@ -138,12 +137,12 @@ CredentialMetadata::UnsealCredentialId(
}
// The recovered plaintext should decode into the UserEntity struct.
- base::Optional<CBORValue> maybe_array = CBORReader::Read(base::make_span(
+ base::Optional<Value> maybe_array = Reader::Read(base::make_span(
reinterpret_cast<const uint8_t*>(plaintext->data()), plaintext->size()));
if (!maybe_array || !maybe_array->is_array()) {
return base::nullopt;
}
- const CBORValue::ArrayValue& array = maybe_array->GetArray();
+ const Value::ArrayValue& array = maybe_array->GetArray();
if (array.size() != 3 || !array[0].is_bytestring() ||
!array[1].is_bytestring() || !array[2].is_bytestring()) {
return base::nullopt;
diff --git a/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm b/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm
index 62457f7ee97..447d4be467c 100644
--- a/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm
+++ b/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm
@@ -13,6 +13,7 @@
#include "base/test/scoped_task_environment.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_test_data.h"
#include "device/fido/mac/make_credential_operation.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -25,14 +26,13 @@ namespace {
using test::TestCallbackReceiver;
-const std::array<uint8_t, kClientDataHashLength> kClientDataHash = {};
const std::string kRpId = "rp.example.com";
const std::vector<uint8_t> kUserId = {10, 11, 12, 13, 14, 15};
const char kKeychainAccessGroup[] =
"EQHXZ8M8AV.com.google.chrome.webauthn.test";
CtapGetAssertionRequest MakeTestRequest() {
- return CtapGetAssertionRequest(kRpId, kClientDataHash);
+ return CtapGetAssertionRequest(kRpId, test_data::kClientDataJson);
}
bool MakeCredential() API_AVAILABLE(macos(10.12.2)) {
@@ -40,7 +40,7 @@ bool MakeCredential() API_AVAILABLE(macos(10.12.2)) {
base::Optional<AuthenticatorMakeCredentialResponse>>
callback_receiver;
auto request = CtapMakeCredentialRequest(
- kClientDataHash, PublicKeyCredentialRpEntity(kRpId),
+ test_data::kClientDataJson, PublicKeyCredentialRpEntity(kRpId),
PublicKeyCredentialUserEntity(kUserId),
PublicKeyCredentialParams(
{{PublicKeyCredentialParams::
diff --git a/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm b/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm
index 183646af040..07c5f987267 100644
--- a/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm
+++ b/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm
@@ -13,6 +13,7 @@
#include "base/test/scoped_task_environment.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_test_data.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,7 +25,6 @@ namespace {
using test::TestCallbackReceiver;
-const std::array<uint8_t, kClientDataHashLength> kClientDataHash = {};
const std::string kRpId = "rp.example.com";
const std::vector<uint8_t> kUserId = {10, 11, 12, 13, 14, 15};
const char kKeychainAccessGroup[] =
@@ -32,7 +32,7 @@ const char kKeychainAccessGroup[] =
CtapMakeCredentialRequest MakeTestRequest() {
return CtapMakeCredentialRequest(
- kClientDataHash, PublicKeyCredentialRpEntity(kRpId),
+ test_data::kClientDataJson, PublicKeyCredentialRpEntity(kRpId),
PublicKeyCredentialUserEntity(kUserId),
PublicKeyCredentialParams(
{{PublicKeyCredentialParams::
diff --git a/chromium/device/fido/mac/util.mm b/chromium/device/fido/mac/util.mm
index b91556f5643..bd891c44745 100644
--- a/chromium/device/fido/mac/util.mm
+++ b/chromium/device/fido/mac/util.mm
@@ -16,7 +16,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "base/strings/string_number_conversions.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/writer.h"
#include "device/fido/ec_public_key.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
@@ -28,14 +28,15 @@ namespace mac {
using base::ScopedCFTypeRef;
using base::scoped_nsobject;
-using cbor::CBORWriter;
-using cbor::CBORValue;
+using cbor::Writer;
+using cbor::Value;
-// WebAuthn requires an all-zero AAGUID for authenticators using
-// self-attestation.
-constexpr std::array<uint8_t, 16> kAaguid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00};
+// The Touch ID authenticator AAGUID value. Despite using self-attestation,
+// Chrome will return this non-zero AAGUID for all MakeCredential
+// responses coming from the Touch ID platform authenticator.
+constexpr std::array<uint8_t, 16> kAaguid = {0xad, 0xce, 0x00, 0x02, 0x35, 0xbc,
+ 0xc6, 0x0a, 0x64, 0x8b, 0x0b, 0x25,
+ 0xf1, 0xf0, 0x55, 0x03};
// SecKeyRefToECPublicKey converts a SecKeyRef for a public key into an
// equivalent |ECPublicKey| instance. It returns |nullptr| if the key cannot be
diff --git a/chromium/device/fido/make_credential_handler_unittest.cc b/chromium/device/fido/make_credential_handler_unittest.cc
index 9fb5b67c3fe..dd3b3188916 100644
--- a/chromium/device/fido/make_credential_handler_unittest.cc
+++ b/chromium/device/fido/make_credential_handler_unittest.cc
@@ -39,7 +39,7 @@ namespace {
using TestMakeCredentialRequestCallback = test::StatusAndValuesCallbackReceiver<
FidoReturnCode,
base::Optional<AuthenticatorMakeCredentialResponse>,
- FidoTransportProtocol>;
+ base::Optional<FidoTransportProtocol>>;
} // namespace
@@ -73,7 +73,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
std::vector<PublicKeyCredentialParams::CredentialInfo>(1));
auto request_parameter = CtapMakeCredentialRequest(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
std::move(credential_params));
auto handler = std::make_unique<MakeCredentialRequestHandler>(
@@ -215,8 +215,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- false /* require_resident_key */,
+ AuthenticatorAttachment::kAny, false /* require_resident_key */,
UserVerificationRequirement::kRequired));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -231,8 +230,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- true /* require_resident_key */,
+ AuthenticatorAttachment::kAny, true /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -247,8 +245,7 @@ TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- false /* require_resident_key */,
+ AuthenticatorAttachment::kAny, false /* require_resident_key */,
UserVerificationRequirement::kRequired));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -271,8 +268,7 @@ TEST_F(FidoMakeCredentialHandlerTest, AnyAttachment) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- false /* require_resident_key */,
+ AuthenticatorAttachment::kAny, false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
// MakeCredentialHandler will not dispatch the kAny request to the platform
@@ -294,8 +290,7 @@ TEST_F(FidoMakeCredentialHandlerTest, CrossPlatformAttachment) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kCrossPlatform,
+ AuthenticatorAttachment::kCrossPlatform,
false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
@@ -320,8 +315,7 @@ TEST_F(FidoMakeCredentialHandlerTest, PlatformAttachment) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kPlatform,
+ AuthenticatorAttachment::kPlatform,
false /* require_resident_key */,
UserVerificationRequirement::kRequired));
@@ -333,8 +327,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyRequirementNotMet) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- true /* require_resident_key */,
+ AuthenticatorAttachment::kAny, true /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -352,8 +345,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kCrossPlatform,
+ AuthenticatorAttachment::kCrossPlatform,
true /* require_resident_key */,
UserVerificationRequirement::kRequired));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -392,8 +384,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kPlatform,
+ AuthenticatorAttachment::kPlatform,
true /* require_resident_key */,
UserVerificationRequirement::kRequired));
@@ -412,8 +403,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kCrossPlatform,
+ AuthenticatorAttachment::kCrossPlatform,
false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -443,8 +433,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kPlatform,
+ AuthenticatorAttachment::kPlatform,
true /* require_resident_key */,
UserVerificationRequirement::kRequired));
@@ -463,8 +452,7 @@ TEST_F(FidoMakeCredentialHandlerTest, SupportedTransportsAreOnlyBleAndNfc) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kCrossPlatform,
+ AuthenticatorAttachment::kCrossPlatform,
false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
@@ -475,8 +463,7 @@ TEST_F(FidoMakeCredentialHandlerTest, IncorrectRpIdHash) {
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- false /* require_resident_key */,
+ AuthenticatorAttachment::kAny, false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -503,8 +490,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- true /* require_resident_key */,
+ AuthenticatorAttachment::kAny, true /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -523,8 +509,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- true /* require_resident_key */,
+ AuthenticatorAttachment::kAny, true /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -550,8 +535,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::
- kPlatform,
+ AuthenticatorAttachment::kPlatform,
false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
@@ -572,8 +556,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
auto request_handler =
CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria(
AuthenticatorSelectionCriteria(
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny,
- false /* require_resident_key */,
+ AuthenticatorAttachment::kAny, false /* require_resident_key */,
UserVerificationRequirement::kPreferred));
discovery()->WaitForCallToStartAndSimulateSuccess();
diff --git a/chromium/device/fido/make_credential_request_handler.cc b/chromium/device/fido/make_credential_request_handler.cc
index ef72a287562..67410bf5898 100644
--- a/chromium/device/fido/make_credential_request_handler.cc
+++ b/chromium/device/fido/make_credential_request_handler.cc
@@ -22,57 +22,49 @@ namespace {
bool CheckIfAuthenticatorSelectionCriteriaAreSatisfied(
FidoAuthenticator* authenticator,
- const AuthenticatorSelectionCriteria& authenticator_selection_criteria,
- CtapMakeCredentialRequest* request) {
- using AuthenticatorAttachment =
- AuthenticatorSelectionCriteria::AuthenticatorAttachment;
+ const AuthenticatorSelectionCriteria& authenticator_selection_criteria) {
using UvAvailability =
AuthenticatorSupportedOptions::UserVerificationAvailability;
- const auto& options = authenticator->Options();
- if ((authenticator_selection_criteria.authenticator_attachement() ==
+ const auto& opt_options = authenticator->Options();
+ if (!opt_options) {
+ // This authenticator doesn't know its capabilities yet, so we need
+ // to assume it can handle the request. This is the case for Windows,
+ // where we proxy the request to the native API.
+ return true;
+ }
+
+ if ((authenticator_selection_criteria.authenticator_attachment() ==
AuthenticatorAttachment::kPlatform &&
- !options.is_platform_device()) ||
- (authenticator_selection_criteria.authenticator_attachement() ==
+ !opt_options->is_platform_device()) ||
+ (authenticator_selection_criteria.authenticator_attachment() ==
AuthenticatorAttachment::kCrossPlatform &&
- options.is_platform_device())) {
+ opt_options->is_platform_device()))
return false;
- }
if (authenticator_selection_criteria.require_resident_key() &&
- !options.supports_resident_key()) {
+ !opt_options->supports_resident_key())
return false;
- }
- request->SetResidentKeySupported(
- authenticator_selection_criteria.require_resident_key());
- const auto& user_verification_requirement =
- authenticator_selection_criteria.user_verification_requirement();
- if (user_verification_requirement == UserVerificationRequirement::kRequired) {
- request->SetUserVerificationRequired(true);
- }
-
- return user_verification_requirement !=
+ return authenticator_selection_criteria.user_verification_requirement() !=
UserVerificationRequirement::kRequired ||
- options.user_verification_availability() ==
+ opt_options->user_verification_availability() ==
UvAvailability::kSupportedAndConfigured;
}
base::flat_set<FidoTransportProtocol> GetTransportsAllowedByRP(
const AuthenticatorSelectionCriteria& authenticator_selection_criteria) {
- using AttachmentType =
- AuthenticatorSelectionCriteria::AuthenticatorAttachment;
const auto attachment_type =
- authenticator_selection_criteria.authenticator_attachement();
+ authenticator_selection_criteria.authenticator_attachment();
switch (attachment_type) {
- case AttachmentType::kPlatform:
+ case AuthenticatorAttachment::kPlatform:
return {FidoTransportProtocol::kInternal};
- case AttachmentType::kCrossPlatform:
+ case AuthenticatorAttachment::kCrossPlatform:
// Cloud-assisted BLE is not yet supported for MakeCredential requests.
return {FidoTransportProtocol::kUsbHumanInterfaceDevice,
FidoTransportProtocol::kBluetoothLowEnergy,
FidoTransportProtocol::kNearFieldCommunication};
- case AttachmentType::kAny:
+ case AuthenticatorAttachment::kAny:
// Cloud-assisted BLE is not yet supported for MakeCredential requests.
return {FidoTransportProtocol::kInternal,
FidoTransportProtocol::kNearFieldCommunication,
@@ -91,7 +83,7 @@ MakeCredentialRequestHandler::MakeCredentialRequestHandler(
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapMakeCredentialRequest request,
AuthenticatorSelectionCriteria authenticator_selection_criteria,
- RegisterResponseCallback completion_callback)
+ CompletionCallback completion_callback)
: FidoRequestHandler(
connector,
base::STLSetIntersection<base::flat_set<FidoTransportProtocol>>(
@@ -112,16 +104,23 @@ MakeCredentialRequestHandler::~MakeCredentialRequestHandler() = default;
void MakeCredentialRequestHandler::DispatchRequest(
FidoAuthenticator* authenticator) {
- // The user verification field of the request may be adjusted to the
- // authenticator, so we need to make a copy.
- CtapMakeCredentialRequest request_copy = request_parameter_;
if (!CheckIfAuthenticatorSelectionCriteriaAreSatisfied(
- authenticator, authenticator_selection_criteria_, &request_copy)) {
+ authenticator, authenticator_selection_criteria_))
return;
- }
+
+ // Set the rk, uv and attachment fields, which were only initialized to
+ // default values up to here. TODO(martinkr): Initialize these fields earlier
+ // (in AuthenticatorImpl) and get rid of the separate
+ // AuthenticatorSelectionCriteriaParameter.
+ request_parameter_.SetResidentKeyRequired(
+ authenticator_selection_criteria_.require_resident_key());
+ request_parameter_.SetUserVerification(
+ authenticator_selection_criteria_.user_verification_requirement());
+ request_parameter_.SetAuthenticatorAttachment(
+ authenticator_selection_criteria_.authenticator_attachment());
authenticator->MakeCredential(
- std::move(request_copy),
+ request_parameter_,
base::BindOnce(&MakeCredentialRequestHandler::HandleResponse,
weak_factory_.GetWeakPtr(), authenticator));
}
@@ -157,8 +156,8 @@ void MakeCredentialRequestHandler::SetPlatformAuthenticatorOrMarkUnavailable(
const bool has_transport_selection_ui =
observer() && observer()->EmbedderControlsAuthenticatorDispatch(
*platform_authenticator_info->authenticator);
- if (authenticator_selection_criteria_.authenticator_attachement() ==
- AuthenticatorSelectionCriteria::AuthenticatorAttachment::kAny &&
+ if (authenticator_selection_criteria_.authenticator_attachment() ==
+ AuthenticatorAttachment::kAny &&
!has_transport_selection_ui) {
platform_authenticator_info = base::nullopt;
}
diff --git a/chromium/device/fido/make_credential_request_handler.h b/chromium/device/fido/make_credential_request_handler.h
index a5e799f0f7f..90a3102c838 100644
--- a/chromium/device/fido/make_credential_request_handler.h
+++ b/chromium/device/fido/make_credential_request_handler.h
@@ -27,11 +27,6 @@ namespace device {
class FidoAuthenticator;
class AuthenticatorMakeCredentialResponse;
-using RegisterResponseCallback =
- base::OnceCallback<void(FidoReturnCode,
- base::Optional<AuthenticatorMakeCredentialResponse>,
- FidoTransportProtocol)>;
-
class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
: public FidoRequestHandler<AuthenticatorMakeCredentialResponse> {
public:
@@ -40,7 +35,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
const base::flat_set<FidoTransportProtocol>& supported_transports,
CtapMakeCredentialRequest request_parameter,
AuthenticatorSelectionCriteria authenticator_criteria,
- RegisterResponseCallback completion_callback);
+ CompletionCallback completion_callback);
~MakeCredentialRequestHandler() override;
// FidoRequestHandlerBase:
diff --git a/chromium/device/fido/make_credential_task.cc b/chromium/device/fido/make_credential_task.cc
index 233a82fd749..1206da092cb 100644
--- a/chromium/device/fido/make_credential_task.cc
+++ b/chromium/device/fido/make_credential_task.cc
@@ -25,10 +25,11 @@ namespace {
// is not required and the device supports U2F protocol.
// TODO(hongjunchoi): Remove this once ClientPin command is implemented.
// See: https://crbug.com/870892
-bool IsClientPinOptionCompatible(const FidoDevice* device,
- const CtapMakeCredentialRequest& request) {
- if (request.user_verification_required())
- return true;
+bool ShouldUseU2fBecauseCtapRequiresClientPin(
+ const FidoDevice* device,
+ const CtapMakeCredentialRequest& request) {
+ if (request.user_verification() == UserVerificationRequirement::kRequired)
+ return false;
DCHECK(device && device->device_info());
bool client_pin_set =
@@ -36,7 +37,7 @@ bool IsClientPinOptionCompatible(const FidoDevice* device,
AuthenticatorSupportedOptions::ClientPinAvailability::kSupportedAndPinSet;
bool supports_u2f = base::ContainsKey(device->device_info()->versions(),
ProtocolVersion::kU2f);
- return !client_pin_set || !supports_u2f;
+ return client_pin_set && supports_u2f;
}
} // namespace
@@ -55,7 +56,8 @@ MakeCredentialTask::~MakeCredentialTask() = default;
void MakeCredentialTask::StartTask() {
if (base::FeatureList::IsEnabled(kNewCtap2Device) &&
device()->supported_protocol() == ProtocolVersion::kCtap &&
- IsClientPinOptionCompatible(device(), request_parameter_)) {
+ !request_parameter_.is_u2f_only() &&
+ !ShouldUseU2fBecauseCtapRequiresClientPin(device(), request_parameter_)) {
MakeCredential();
} else {
device()->set_supported_protocol(ProtocolVersion::kU2f);
diff --git a/chromium/device/fido/make_credential_task_unittest.cc b/chromium/device/fido/make_credential_task_unittest.cc
index b150e876166..a63a27275f1 100644
--- a/chromium/device/fido/make_credential_task_unittest.cc
+++ b/chromium/device/fido/make_credential_task_unittest.cc
@@ -52,7 +52,7 @@ class FidoMakeCredentialTaskTest : public testing::Test {
return std::make_unique<MakeCredentialTask>(
device,
CtapMakeCredentialRequest(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1))),
callback_receiver_.callback());
@@ -174,10 +174,10 @@ TEST_F(FidoMakeCredentialTaskTest, EnforceClientPinWhenUserVerificationSet) {
PublicKeyCredentialUserEntity user(
fido_parsing_utils::Materialize(test_data::kUserId));
auto request = CtapMakeCredentialRequest(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
- request.SetUserVerificationRequired(true);
+ request.SetUserVerification(UserVerificationRequirement::kRequired);
const auto task = std::make_unique<MakeCredentialTask>(
device.get(), std::move(request), callback_receiver_.callback());
@@ -187,5 +187,32 @@ TEST_F(FidoMakeCredentialTaskTest, EnforceClientPinWhenUserVerificationSet) {
EXPECT_FALSE(make_credential_callback_receiver().value());
}
+TEST_F(FidoMakeCredentialTaskTest, TestU2fOnly) {
+ // Regardless of the device's supported protocol, it should receive a U2F
+ // request, because the task is instantiated in U2F-only mode.
+ auto device = MockFidoDevice::MakeCtap();
+
+ device->ExpectRequestAndRespondWith(
+ test_data::kU2fRegisterCommandApdu,
+ test_data::kApduEncodedNoErrorRegisterResponse);
+
+ PublicKeyCredentialRpEntity rp(test_data::kRelyingPartyId);
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(test_data::kUserId));
+ auto request = CtapMakeCredentialRequest(
+ test_data::kClientDataJson, std::move(rp), std::move(user),
+ PublicKeyCredentialParams(
+ std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
+ request.set_is_u2f_only(true);
+ const auto task = std::make_unique<MakeCredentialTask>(
+ device.get(), std::move(request), callback_receiver_.callback());
+ make_credential_callback_receiver().WaitForCallback();
+
+ EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
+ make_credential_callback_receiver().status());
+ EXPECT_TRUE(make_credential_callback_receiver().value());
+ EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f);
+}
+
} // namespace
} // namespace device
diff --git a/chromium/device/fido/mock_fido_discovery_observer.h b/chromium/device/fido/mock_fido_discovery_observer.h
index 883b20a3a97..ce022186b6c 100644
--- a/chromium/device/fido/mock_fido_discovery_observer.h
+++ b/chromium/device/fido/mock_fido_discovery_observer.h
@@ -29,8 +29,8 @@ class MockFidoDiscoveryObserver : public FidoDiscoveryBase::Observer {
void(FidoDiscoveryBase*, FidoAuthenticator*));
MOCK_METHOD3(AuthenticatorIdChanged,
void(FidoDiscoveryBase*, const std::string&, std::string));
- MOCK_METHOD2(AuthenticatorPairingModeChanged,
- void(FidoDiscoveryBase*, const std::string&));
+ MOCK_METHOD3(AuthenticatorPairingModeChanged,
+ void(FidoDiscoveryBase*, const std::string&, bool));
private:
DISALLOW_COPY_AND_ASSIGN(MockFidoDiscoveryObserver);
diff --git a/chromium/device/fido/opaque_attestation_statement.cc b/chromium/device/fido/opaque_attestation_statement.cc
index 8d6da11fd9a..8edb74207ed 100644
--- a/chromium/device/fido/opaque_attestation_statement.cc
+++ b/chromium/device/fido/opaque_attestation_statement.cc
@@ -6,24 +6,24 @@
#include <utility>
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
-using cbor::CBORValue;
+using cbor::Value;
namespace device {
OpaqueAttestationStatement::OpaqueAttestationStatement(
std::string attestation_format,
- CBORValue attestation_statement_map)
+ Value attestation_statement_map)
: AttestationStatement(std::move(attestation_format)),
attestation_statement_map_(std::move(attestation_statement_map)) {}
OpaqueAttestationStatement::~OpaqueAttestationStatement() = default;
// Returns the deep copied cbor map value of |attestation_statement_map_|.
-CBORValue::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
+Value::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
DCHECK(attestation_statement_map_.is_map());
- CBORValue::MapValue new_map;
+ Value::MapValue new_map;
new_map.reserve(attestation_statement_map_.GetMap().size());
for (const auto& map_it : attestation_statement_map_.GetMap()) {
new_map.try_emplace(new_map.end(), map_it.first.Clone(),
@@ -34,9 +34,9 @@ CBORValue::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
bool OpaqueAttestationStatement::IsSelfAttestation() {
DCHECK(attestation_statement_map_.is_map());
- const CBORValue::MapValue& m(attestation_statement_map_.GetMap());
- const CBORValue alg("alg");
- const CBORValue sig("sig");
+ const Value::MapValue& m(attestation_statement_map_.GetMap());
+ const Value alg("alg");
+ const Value sig("sig");
return format_ == "packed" && m.size() == 2 && m.count(std::move(alg)) == 1 &&
m.count(std::move(sig)) == 1;
@@ -50,14 +50,14 @@ bool OpaqueAttestationStatement::
base::Optional<base::span<const uint8_t>>
OpaqueAttestationStatement::GetLeafCertificate() const {
DCHECK(attestation_statement_map_.is_map());
- const CBORValue::MapValue& m(attestation_statement_map_.GetMap());
- const CBORValue x5c("x5c");
+ const Value::MapValue& m(attestation_statement_map_.GetMap());
+ const Value x5c("x5c");
const auto it = m.find(x5c);
if (it == m.end() || !it->second.is_array()) {
return base::nullopt;
}
- const CBORValue::ArrayValue& certs = it->second.GetArray();
+ const Value::ArrayValue& certs = it->second.GetArray();
if (certs.empty() || !certs[0].is_bytestring()) {
return base::nullopt;
}
diff --git a/chromium/device/fido/opaque_attestation_statement.h b/chromium/device/fido/opaque_attestation_statement.h
index 98bb2b97e3c..7f6cef00aeb 100644
--- a/chromium/device/fido/opaque_attestation_statement.h
+++ b/chromium/device/fido/opaque_attestation_statement.h
@@ -9,7 +9,7 @@
#include "base/component_export.h"
#include "base/macros.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "device/fido/attestation_statement.h"
namespace device {
@@ -19,17 +19,17 @@ class COMPONENT_EXPORT(DEVICE_FIDO) OpaqueAttestationStatement
: public AttestationStatement {
public:
OpaqueAttestationStatement(std::string attestation_format,
- cbor::CBORValue attestation_statement_map);
+ cbor::Value attestation_statement_map);
~OpaqueAttestationStatement() override;
// AttestationStatement:
- cbor::CBORValue::MapValue GetAsCBORMap() const override;
+ cbor::Value::MapValue GetAsCBORMap() const override;
bool IsSelfAttestation() override;
bool IsAttestationCertificateInappropriatelyIdentifying() override;
base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
private:
- cbor::CBORValue attestation_statement_map_;
+ cbor::Value attestation_statement_map_;
DISALLOW_COPY_AND_ASSIGN(OpaqueAttestationStatement);
};
diff --git a/chromium/device/fido/public_key_credential_descriptor.cc b/chromium/device/fido/public_key_credential_descriptor.cc
index 8bce337ce19..f0afd12334d 100644
--- a/chromium/device/fido/public_key_credential_descriptor.cc
+++ b/chromium/device/fido/public_key_credential_descriptor.cc
@@ -18,19 +18,18 @@ constexpr char kCredentialTypeKey[] = "type";
// static
base::Optional<PublicKeyCredentialDescriptor>
-PublicKeyCredentialDescriptor::CreateFromCBORValue(
- const cbor::CBORValue& cbor) {
+PublicKeyCredentialDescriptor::CreateFromCBORValue(const cbor::Value& cbor) {
if (!cbor.is_map()) {
return base::nullopt;
}
- const cbor::CBORValue::MapValue& map = cbor.GetMap();
- auto type = map.find(cbor::CBORValue(kCredentialTypeKey));
+ const cbor::Value::MapValue& map = cbor.GetMap();
+ auto type = map.find(cbor::Value(kCredentialTypeKey));
if (type == map.end() || !type->second.is_string() ||
type->second.GetString() != kPublicKey)
return base::nullopt;
- auto id = map.find(cbor::CBORValue(kCredentialIdKey));
+ auto id = map.find(cbor::Value(kCredentialIdKey));
if (id == map.end() || !id->second.is_bytestring())
return base::nullopt;
@@ -72,12 +71,12 @@ PublicKeyCredentialDescriptor& PublicKeyCredentialDescriptor::operator=(
PublicKeyCredentialDescriptor::~PublicKeyCredentialDescriptor() = default;
-cbor::CBORValue PublicKeyCredentialDescriptor::ConvertToCBOR() const {
- cbor::CBORValue::MapValue cbor_descriptor_map;
- cbor_descriptor_map[cbor::CBORValue(kCredentialIdKey)] = cbor::CBORValue(id_);
- cbor_descriptor_map[cbor::CBORValue(kCredentialTypeKey)] =
- cbor::CBORValue(CredentialTypeToString(credential_type_));
- return cbor::CBORValue(std::move(cbor_descriptor_map));
+cbor::Value PublicKeyCredentialDescriptor::ConvertToCBOR() const {
+ cbor::Value::MapValue cbor_descriptor_map;
+ cbor_descriptor_map[cbor::Value(kCredentialIdKey)] = cbor::Value(id_);
+ cbor_descriptor_map[cbor::Value(kCredentialTypeKey)] =
+ cbor::Value(CredentialTypeToString(credential_type_));
+ return cbor::Value(std::move(cbor_descriptor_map));
}
} // namespace device
diff --git a/chromium/device/fido/public_key_credential_descriptor.h b/chromium/device/fido/public_key_credential_descriptor.h
index 626832666d9..1dde94a1765 100644
--- a/chromium/device/fido/public_key_credential_descriptor.h
+++ b/chromium/device/fido/public_key_credential_descriptor.h
@@ -12,7 +12,7 @@
#include "base/component_export.h"
#include "base/containers/flat_set.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_transport_protocol.h"
@@ -25,7 +25,7 @@ namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialDescriptor {
public:
static base::Optional<PublicKeyCredentialDescriptor> CreateFromCBORValue(
- const cbor::CBORValue& cbor);
+ const cbor::Value& cbor);
PublicKeyCredentialDescriptor(CredentialType credential_type,
std::vector<uint8_t> id);
@@ -41,7 +41,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialDescriptor {
PublicKeyCredentialDescriptor&& other);
~PublicKeyCredentialDescriptor();
- cbor::CBORValue ConvertToCBOR() const;
+ cbor::Value ConvertToCBOR() const;
CredentialType credential_type() const { return credential_type_; }
const std::vector<uint8_t>& id() const { return id_; }
diff --git a/chromium/device/fido/public_key_credential_params.cc b/chromium/device/fido/public_key_credential_params.cc
index d9bc3b4a120..0ea270a8975 100644
--- a/chromium/device/fido/public_key_credential_params.cc
+++ b/chromium/device/fido/public_key_credential_params.cc
@@ -10,8 +10,7 @@ namespace device {
// static
base::Optional<PublicKeyCredentialParams>
-PublicKeyCredentialParams::CreateFromCBORValue(
- const cbor::CBORValue& cbor_value) {
+PublicKeyCredentialParams::CreateFromCBORValue(const cbor::Value& cbor_value) {
if (!cbor_value.is_array())
return base::nullopt;
@@ -22,9 +21,9 @@ PublicKeyCredentialParams::CreateFromCBORValue(
const auto& credential_map = credential.GetMap();
const auto credential_type_it =
- credential_map.find(cbor::CBORValue(kCredentialTypeMapKey));
+ credential_map.find(cbor::Value(kCredentialTypeMapKey));
const auto algorithm_type_it =
- credential_map.find(cbor::CBORValue(kCredentialAlgorithmMapKey));
+ credential_map.find(cbor::Value(kCredentialAlgorithmMapKey));
if (credential_type_it == credential_map.end() ||
!credential_type_it->second.is_string() ||
@@ -59,19 +58,19 @@ PublicKeyCredentialParams& PublicKeyCredentialParams::operator=(
PublicKeyCredentialParams::~PublicKeyCredentialParams() = default;
-cbor::CBORValue PublicKeyCredentialParams::ConvertToCBOR() const {
- cbor::CBORValue::ArrayValue credential_param_array;
+cbor::Value PublicKeyCredentialParams::ConvertToCBOR() const {
+ cbor::Value::ArrayValue credential_param_array;
credential_param_array.reserve(public_key_credential_params_.size());
for (const auto& credential : public_key_credential_params_) {
- cbor::CBORValue::MapValue cbor_credential_map;
+ cbor::Value::MapValue cbor_credential_map;
cbor_credential_map.emplace(kCredentialTypeMapKey,
CredentialTypeToString(credential.type));
cbor_credential_map.emplace(kCredentialAlgorithmMapKey,
credential.algorithm);
credential_param_array.emplace_back(std::move(cbor_credential_map));
}
- return cbor::CBORValue(std::move(credential_param_array));
+ return cbor::Value(std::move(credential_param_array));
}
} // namespace device
diff --git a/chromium/device/fido/public_key_credential_params.h b/chromium/device/fido/public_key_credential_params.h
index 06d2dc3d40d..cfb6f142355 100644
--- a/chromium/device/fido/public_key_credential_params.h
+++ b/chromium/device/fido/public_key_credential_params.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "device/fido/fido_constants.h"
namespace device {
@@ -29,7 +29,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialParams {
};
static base::Optional<PublicKeyCredentialParams> CreateFromCBORValue(
- const cbor::CBORValue& cbor_value);
+ const cbor::Value& cbor_value);
explicit PublicKeyCredentialParams(
std::vector<CredentialInfo> credential_params);
@@ -39,7 +39,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialParams {
PublicKeyCredentialParams& operator=(PublicKeyCredentialParams&& other);
~PublicKeyCredentialParams();
- cbor::CBORValue ConvertToCBOR() const;
+ cbor::Value ConvertToCBOR() const;
const std::vector<CredentialInfo>& public_key_credential_params() const {
return public_key_credential_params_;
}
diff --git a/chromium/device/fido/public_key_credential_rp_entity.cc b/chromium/device/fido/public_key_credential_rp_entity.cc
index 7b83513ac27..c46d0dfc046 100644
--- a/chromium/device/fido/public_key_credential_rp_entity.cc
+++ b/chromium/device/fido/public_key_credential_rp_entity.cc
@@ -13,7 +13,7 @@ namespace device {
// static
base::Optional<PublicKeyCredentialRpEntity>
-PublicKeyCredentialRpEntity::CreateFromCBORValue(const cbor::CBORValue& cbor) {
+PublicKeyCredentialRpEntity::CreateFromCBORValue(const cbor::Value& cbor) {
if (!cbor.is_map() || cbor.GetMap().size() > 3)
return base::nullopt;
@@ -31,9 +31,9 @@ PublicKeyCredentialRpEntity::CreateFromCBORValue(const cbor::CBORValue& cbor) {
if (!is_rp_map_format_correct)
return base::nullopt;
- const auto& id_it = rp_map.find(cbor::CBORValue(kEntityIdMapKey));
- const auto& name_it = rp_map.find(cbor::CBORValue(kEntityNameMapKey));
- const auto& icon_it = rp_map.find(cbor::CBORValue(kIconUrlMapKey));
+ const auto& id_it = rp_map.find(cbor::Value(kEntityIdMapKey));
+ const auto& name_it = rp_map.find(cbor::Value(kEntityNameMapKey));
+ const auto& icon_it = rp_map.find(cbor::Value(kIconUrlMapKey));
if (id_it == rp_map.end())
return base::nullopt;
PublicKeyCredentialRpEntity rp(id_it->second.GetString());
@@ -76,8 +76,8 @@ PublicKeyCredentialRpEntity& PublicKeyCredentialRpEntity::SetRpIconUrl(
return *this;
}
-cbor::CBORValue PublicKeyCredentialRpEntity::ConvertToCBOR() const {
- cbor::CBORValue::MapValue rp_map;
+cbor::Value PublicKeyCredentialRpEntity::ConvertToCBOR() const {
+ cbor::Value::MapValue rp_map;
rp_map.emplace(kEntityIdMapKey, rp_id_);
if (rp_name_)
rp_map.emplace(kEntityNameMapKey, *rp_name_);
@@ -85,7 +85,7 @@ cbor::CBORValue PublicKeyCredentialRpEntity::ConvertToCBOR() const {
if (rp_icon_url_)
rp_map.emplace(kIconUrlMapKey, rp_icon_url_->spec());
- return cbor::CBORValue(std::move(rp_map));
+ return cbor::Value(std::move(rp_map));
}
} // namespace device
diff --git a/chromium/device/fido/public_key_credential_rp_entity.h b/chromium/device/fido/public_key_credential_rp_entity.h
index d8c16e3a0ed..d7a7d23a28e 100644
--- a/chromium/device/fido/public_key_credential_rp_entity.h
+++ b/chromium/device/fido/public_key_credential_rp_entity.h
@@ -11,7 +11,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "url/gurl.h"
namespace device {
@@ -22,7 +22,7 @@ namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialRpEntity {
public:
static base::Optional<PublicKeyCredentialRpEntity> CreateFromCBORValue(
- const cbor::CBORValue& cbor);
+ const cbor::Value& cbor);
explicit PublicKeyCredentialRpEntity(std::string rp_id);
PublicKeyCredentialRpEntity(const PublicKeyCredentialRpEntity& other);
@@ -32,7 +32,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialRpEntity {
PublicKeyCredentialRpEntity& operator=(PublicKeyCredentialRpEntity&& other);
~PublicKeyCredentialRpEntity();
- cbor::CBORValue ConvertToCBOR() const;
+ cbor::Value ConvertToCBOR() const;
PublicKeyCredentialRpEntity& SetRpName(std::string rp_name);
PublicKeyCredentialRpEntity& SetRpIconUrl(GURL icon_url);
diff --git a/chromium/device/fido/public_key_credential_user_entity.cc b/chromium/device/fido/public_key_credential_user_entity.cc
index 114f1a24a94..7db7cb8f06c 100644
--- a/chromium/device/fido/public_key_credential_user_entity.cc
+++ b/chromium/device/fido/public_key_credential_user_entity.cc
@@ -12,31 +12,30 @@ namespace device {
// static
base::Optional<PublicKeyCredentialUserEntity>
-PublicKeyCredentialUserEntity::CreateFromCBORValue(
- const cbor::CBORValue& cbor) {
+PublicKeyCredentialUserEntity::CreateFromCBORValue(const cbor::Value& cbor) {
if (!cbor.is_map())
return base::nullopt;
- const cbor::CBORValue::MapValue& cbor_map = cbor.GetMap();
+ const cbor::Value::MapValue& cbor_map = cbor.GetMap();
- auto user_id = cbor_map.find(cbor::CBORValue(kEntityIdMapKey));
+ auto user_id = cbor_map.find(cbor::Value(kEntityIdMapKey));
if (user_id == cbor_map.end() || !user_id->second.is_bytestring())
return base::nullopt;
PublicKeyCredentialUserEntity user(user_id->second.GetBytestring());
- auto user_name = cbor_map.find(cbor::CBORValue(kEntityNameMapKey));
+ auto user_name = cbor_map.find(cbor::Value(kEntityNameMapKey));
if (user_name != cbor_map.end() && user_name->second.is_string()) {
user.SetUserName(user_name->second.GetString());
}
- auto user_display_name = cbor_map.find(cbor::CBORValue(kDisplayNameMapKey));
+ auto user_display_name = cbor_map.find(cbor::Value(kDisplayNameMapKey));
if (user_display_name != cbor_map.end() &&
user_display_name->second.is_string()) {
user.SetDisplayName(user_display_name->second.GetString());
}
- auto user_icon_url = cbor_map.find(cbor::CBORValue(kIconUrlMapKey));
+ auto user_icon_url = cbor_map.find(cbor::Value(kIconUrlMapKey));
if (user_icon_url != cbor_map.end() && user_icon_url->second.is_string()) {
user.SetIconUrl(GURL(user_icon_url->second.GetString()));
}
@@ -62,8 +61,8 @@ PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::operator=(
PublicKeyCredentialUserEntity::~PublicKeyCredentialUserEntity() = default;
-cbor::CBORValue PublicKeyCredentialUserEntity::ConvertToCBOR() const {
- cbor::CBORValue::MapValue user_map;
+cbor::Value PublicKeyCredentialUserEntity::ConvertToCBOR() const {
+ cbor::Value::MapValue user_map;
user_map.emplace(kEntityIdMapKey, user_id_);
if (user_name_)
user_map.emplace(kEntityNameMapKey, *user_name_);
@@ -72,7 +71,7 @@ cbor::CBORValue PublicKeyCredentialUserEntity::ConvertToCBOR() const {
if (user_display_name_) {
user_map.emplace(kDisplayNameMapKey, *user_display_name_);
}
- return cbor::CBORValue(std::move(user_map));
+ return cbor::Value(std::move(user_map));
}
PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::SetUserName(
diff --git a/chromium/device/fido/public_key_credential_user_entity.h b/chromium/device/fido/public_key_credential_user_entity.h
index d2d7bf5cd04..fcd77eb9729 100644
--- a/chromium/device/fido/public_key_credential_user_entity.h
+++ b/chromium/device/fido/public_key_credential_user_entity.h
@@ -11,7 +11,7 @@
#include "base/component_export.h"
#include "base/optional.h"
-#include "components/cbor/cbor_values.h"
+#include "components/cbor/values.h"
#include "url/gurl.h"
namespace device {
@@ -23,7 +23,7 @@ namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialUserEntity {
public:
static base::Optional<PublicKeyCredentialUserEntity> CreateFromCBORValue(
- const cbor::CBORValue& cbor);
+ const cbor::Value& cbor);
explicit PublicKeyCredentialUserEntity(std::vector<uint8_t> user_id);
PublicKeyCredentialUserEntity(const PublicKeyCredentialUserEntity& other);
@@ -34,7 +34,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialUserEntity {
PublicKeyCredentialUserEntity&& other);
~PublicKeyCredentialUserEntity();
- cbor::CBORValue ConvertToCBOR() const;
+ cbor::Value ConvertToCBOR() const;
PublicKeyCredentialUserEntity& SetUserName(std::string user_name);
PublicKeyCredentialUserEntity& SetDisplayName(std::string display_name);
PublicKeyCredentialUserEntity& SetIconUrl(GURL icon_url);
diff --git a/chromium/device/fido/scoped_virtual_fido_device.cc b/chromium/device/fido/scoped_virtual_fido_device.cc
index 7bfd960d045..4d5f999b54b 100644
--- a/chromium/device/fido/scoped_virtual_fido_device.cc
+++ b/chromium/device/fido/scoped_virtual_fido_device.cc
@@ -65,8 +65,7 @@ VirtualFidoDevice::State* ScopedVirtualFidoDevice::mutable_state() {
return state_.get();
}
-std::unique_ptr<FidoDeviceDiscovery>
-ScopedVirtualFidoDevice::CreateFidoDiscovery(
+std::unique_ptr<FidoDiscoveryBase> ScopedVirtualFidoDevice::CreateFidoDiscovery(
FidoTransportProtocol transport,
::service_manager::Connector* connector) {
if (transport != FidoTransportProtocol::kUsbHumanInterfaceDevice) {
diff --git a/chromium/device/fido/scoped_virtual_fido_device.h b/chromium/device/fido/scoped_virtual_fido_device.h
index 88bc6b4eb2e..bbe4a5dd213 100644
--- a/chromium/device/fido/scoped_virtual_fido_device.h
+++ b/chromium/device/fido/scoped_virtual_fido_device.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "device/fido/fido_constants.h"
-#include "device/fido/fido_device_discovery.h"
+#include "device/fido/fido_discovery_factory.h"
#include "device/fido/virtual_fido_device.h"
namespace device {
@@ -28,7 +28,7 @@ class ScopedVirtualFidoDevice
VirtualFidoDevice::State* mutable_state();
protected:
- std::unique_ptr<FidoDeviceDiscovery> CreateFidoDiscovery(
+ std::unique_ptr<FidoDiscoveryBase> CreateFidoDiscovery(
FidoTransportProtocol transport,
::service_manager::Connector* connector) override;
diff --git a/chromium/device/fido/u2f_command_constructor.cc b/chromium/device/fido/u2f_command_constructor.cc
index c195f22735d..733d99cfeb8 100644
--- a/chromium/device/fido/u2f_command_constructor.cc
+++ b/chromium/device/fido/u2f_command_constructor.cc
@@ -15,7 +15,8 @@ namespace device {
bool IsConvertibleToU2fRegisterCommand(
const CtapMakeCredentialRequest& request) {
- if (request.user_verification_required() || request.resident_key_supported())
+ if (request.user_verification() == UserVerificationRequirement::kRequired ||
+ request.resident_key_required())
return false;
const auto& public_key_credential_info =
diff --git a/chromium/device/fido/u2f_command_constructor_unittest.cc b/chromium/device/fido/u2f_command_constructor_unittest.cc
index c44a777c29c..d567709320c 100644
--- a/chromium/device/fido/u2f_command_constructor_unittest.cc
+++ b/chromium/device/fido/u2f_command_constructor_unittest.cc
@@ -29,13 +29,13 @@ CtapMakeCredentialRequest ConstructMakeCredentialRequest() {
.SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
return CtapMakeCredentialRequest(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams(PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1))));
}
CtapGetAssertionRequest ConstructGetAssertionRequest() {
- return CtapGetAssertionRequest("acme.com", test_data::kClientDataHash);
+ return CtapGetAssertionRequest("acme.com", test_data::kClientDataJson);
}
} // namespace
@@ -120,7 +120,7 @@ TEST(U2fCommandConstructorTest, TestU2fRegisterCredentialAlgorithmRequirement) {
.SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
CtapMakeCredentialRequest make_credential_param(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams({{CredentialType::kPublicKey, -257}}));
EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
@@ -128,14 +128,15 @@ TEST(U2fCommandConstructorTest, TestU2fRegisterCredentialAlgorithmRequirement) {
TEST(U2fCommandConstructorTest, TestU2fRegisterUserVerificationRequirement) {
auto make_credential_param = ConstructMakeCredentialRequest();
- make_credential_param.SetUserVerificationRequired(true);
+ make_credential_param.SetUserVerification(
+ UserVerificationRequirement::kRequired);
EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
}
TEST(U2fCommandConstructorTest, TestU2fRegisterResidentKeyRequirement) {
auto make_credential_param = ConstructMakeCredentialRequest();
- make_credential_param.SetResidentKeySupported(true);
+ make_credential_param.SetResidentKeyRequired(true);
EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
}
diff --git a/chromium/device/fido/u2f_register_operation_unittest.cc b/chromium/device/fido/u2f_register_operation_unittest.cc
index 2986830eab6..dacdfd3ff14 100644
--- a/chromium/device/fido/u2f_register_operation_unittest.cc
+++ b/chromium/device/fido/u2f_register_operation_unittest.cc
@@ -35,7 +35,7 @@ CtapMakeCredentialRequest CreateRegisterRequestWithRegisteredKeys(
fido_parsing_utils::Materialize(test_data::kUserId));
CtapMakeCredentialRequest request(
- test_data::kClientDataHash, std::move(rp), std::move(user),
+ test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1)));
request.SetExcludeList(std::move(registered_keys));
diff --git a/chromium/device/fido/u2f_sign_operation_unittest.cc b/chromium/device/fido/u2f_sign_operation_unittest.cc
index 7b53bb83226..47ba426a96f 100644
--- a/chromium/device/fido/u2f_sign_operation_unittest.cc
+++ b/chromium/device/fido/u2f_sign_operation_unittest.cc
@@ -38,7 +38,7 @@ class U2fSignOperationTest : public ::testing::Test {
CtapGetAssertionRequest CreateSignRequest(
std::vector<std::vector<uint8_t>> key_handles) {
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
- test_data::kClientDataHash);
+ test_data::kClientDataJson);
std::vector<PublicKeyCredentialDescriptor> allowed_list;
for (auto& key_handle : key_handles) {
@@ -347,8 +347,7 @@ TEST_F(U2fSignOperationTest, SignWithCorruptedResponse) {
TEST_F(U2fSignOperationTest, AlternativeApplicationParameter) {
auto request = CreateSignRequest(
{fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)});
- request.SetAlternativeApplicationParameter(
- test_data::kAlternativeApplicationParameter);
+ request.SetAppId(test_data::kAppId);
auto device = std::make_unique<MockFidoDevice>();
EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
@@ -387,8 +386,7 @@ TEST_F(U2fSignOperationTest, AlternativeApplicationParameter) {
TEST_F(U2fSignOperationTest, AlternativeApplicationParameterRejection) {
auto request = CreateSignRequest(
{fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)});
- request.SetAlternativeApplicationParameter(
- test_data::kAlternativeApplicationParameter);
+ request.SetAppId(test_data::kAppId);
auto device = std::make_unique<MockFidoDevice>();
EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
diff --git a/chromium/device/fido/virtual_ctap2_device.cc b/chromium/device/fido/virtual_ctap2_device.cc
index 8c13c295052..0a12d8600af 100644
--- a/chromium/device/fido/virtual_ctap2_device.cc
+++ b/chromium/device/fido/virtual_ctap2_device.cc
@@ -12,7 +12,8 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/cbor/cbor_writer.h"
+#include "components/cbor/reader.h"
+#include "components/cbor/writer.h"
#include "crypto/ec_private_key.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
@@ -51,10 +52,11 @@ void ReturnCtap2Response(
bool AreMakeCredentialOptionsValid(const AuthenticatorSupportedOptions& options,
const CtapMakeCredentialRequest& request) {
- if (request.resident_key_supported() && !options.supports_resident_key())
+ if (request.resident_key_required() && !options.supports_resident_key())
return false;
- return !request.user_verification_required() ||
+ return request.user_verification() !=
+ UserVerificationRequirement::kRequired ||
options.user_verification_availability() ==
AuthenticatorSupportedOptions::UserVerificationAvailability::
kSupportedAndConfigured;
@@ -112,12 +114,12 @@ std::vector<uint8_t> ConstructMakeCredentialResponse(
const base::Optional<std::vector<uint8_t>> attestation_certificate,
base::span<const uint8_t> signature,
AuthenticatorData authenticator_data) {
- cbor::CBORValue::MapValue attestation_map;
+ cbor::Value::MapValue attestation_map;
attestation_map.emplace("alg", -7);
attestation_map.emplace("sig", fido_parsing_utils::Materialize(signature));
if (attestation_certificate) {
- cbor::CBORValue::ArrayValue certificate_chain;
+ cbor::Value::ArrayValue certificate_chain;
certificate_chain.emplace_back(std::move(*attestation_certificate));
attestation_map.emplace("x5c", std::move(certificate_chain));
}
@@ -127,7 +129,7 @@ std::vector<uint8_t> ConstructMakeCredentialResponse(
AttestationObject(
std::move(authenticator_data),
std::make_unique<OpaqueAttestationStatement>(
- "packed", cbor::CBORValue(std::move(attestation_map)))));
+ "packed", cbor::Value(std::move(attestation_map)))));
return GetSerializedCtapDeviceResponse(make_credential_response);
}
@@ -145,6 +147,56 @@ std::vector<uint8_t> ConstructGetAssertionResponse(
return GetSerializedCtapDeviceResponse(response);
}
+bool IsMakeCredentialOptionMapFormatCorrect(
+ const cbor::Value::MapValue& option_map) {
+ return std::all_of(
+ option_map.begin(), option_map.end(), [](const auto& param) {
+ if (!param.first.is_string())
+ return false;
+
+ const auto& key = param.first.GetString();
+ return ((key == kResidentKeyMapKey || key == kUserVerificationMapKey) &&
+ param.second.is_bool());
+ });
+}
+
+bool AreMakeCredentialRequestMapKeysCorrect(
+ const cbor::Value::MapValue& request_map) {
+ return std::all_of(request_map.begin(), request_map.end(),
+ [](const auto& param) {
+ if (!param.first.is_integer())
+ return false;
+
+ const auto& key = param.first.GetInteger();
+ return (key <= 9u && key >= 1u);
+ });
+}
+
+bool IsGetAssertionOptionMapFormatCorrect(
+ const cbor::Value::MapValue& option_map) {
+ return std::all_of(
+ option_map.begin(), option_map.end(), [](const auto& param) {
+ if (!param.first.is_string())
+ return false;
+
+ const auto& key = param.first.GetString();
+ return (key == kUserPresenceMapKey || key == kUserVerificationMapKey) &&
+ param.second.is_bool();
+ });
+}
+
+bool AreGetAssertionRequestMapKeysCorrect(
+ const cbor::Value::MapValue& request_map) {
+ return std::all_of(request_map.begin(), request_map.end(),
+ [](const auto& param) {
+ if (!param.first.is_integer())
+ return false;
+
+ const auto& key = param.first.GetInteger();
+ return (key <= 7u || key >= 1u);
+ });
+}
+
} // namespace
VirtualCtap2Device::VirtualCtap2Device()
@@ -214,30 +266,33 @@ void VirtualCtap2Device::SetAuthenticatorSupportedOptions(
CtapDeviceResponseCode VirtualCtap2Device::OnMakeCredential(
base::span<const uint8_t> request_bytes,
std::vector<uint8_t>* response) {
- auto request = ParseCtapMakeCredentialRequest(request_bytes);
- if (!request) {
+ auto request_and_hash = ParseCtapMakeCredentialRequest(request_bytes);
+ if (!request_and_hash) {
DLOG(ERROR) << "Incorrectly formatted MakeCredential request.";
return CtapDeviceResponseCode::kCtap2ErrOther;
}
+ CtapMakeCredentialRequest request = std::get<0>(*request_and_hash);
+ CtapMakeCredentialRequest::ClientDataHash client_data_hash =
+ std::get<1>(*request_and_hash);
- if (!AreMakeCredentialOptionsValid(device_info_.options(), *request) ||
- !AreMakeCredentialParamsValid(*request)) {
+ if (!AreMakeCredentialOptionsValid(device_info_.options(), request) ||
+ !AreMakeCredentialParamsValid(request)) {
DLOG(ERROR) << "Virtual CTAP2 device does not support options required by "
"the request.";
return CtapDeviceResponseCode::kCtap2ErrOther;
}
// Client pin is not supported.
- if (request->pin_auth()) {
+ if (request.pin_auth()) {
DLOG(ERROR) << "Virtual CTAP2 device does not support client pin.";
return CtapDeviceResponseCode::kCtap2ErrPinInvalid;
}
// Check for already registered credentials.
const auto rp_id_hash =
- fido_parsing_utils::CreateSHA256Hash(request->rp().rp_id());
- if (request->exclude_list()) {
- for (const auto& excluded_credential : *request->exclude_list()) {
+ fido_parsing_utils::CreateSHA256Hash(request.rp().rp_id());
+ if (request.exclude_list()) {
+ for (const auto& excluded_credential : *request.exclude_list()) {
if (FindRegistrationData(excluded_credential.id(), rp_id_hash))
return CtapDeviceResponseCode::kCtap2ErrCredentialExcluded;
}
@@ -267,10 +322,19 @@ CtapDeviceResponseCode VirtualCtap2Device::OnMakeCredential(
AttestedCredentialData attested_credential_data(
aaguid, sha256_length, key_handle, ConstructECPublicKey(public_key));
+ base::Optional<cbor::Value> extensions;
+ if (request.hmac_secret()) {
+ cbor::Value::MapValue extensions_map;
+ extensions_map.emplace(cbor::Value(kExtensionHmacSecret),
+ cbor::Value(true));
+ extensions = cbor::Value(std::move(extensions_map));
+ }
+
auto authenticator_data = ConstructAuthenticatorData(
- rp_id_hash, 01ul, std::move(attested_credential_data));
+ rp_id_hash, 01ul, std::move(attested_credential_data),
+ std::move(extensions));
auto sign_buffer =
- ConstructSignatureBuffer(authenticator_data, request->client_data_hash());
+ ConstructSignatureBuffer(authenticator_data, client_data_hash);
// Sign with attestation key.
// Note: Non-deterministic, you need to mock this out if you rely on
@@ -301,36 +365,38 @@ CtapDeviceResponseCode VirtualCtap2Device::OnMakeCredential(
CtapDeviceResponseCode VirtualCtap2Device::OnGetAssertion(
base::span<const uint8_t> request_bytes,
std::vector<uint8_t>* response) {
- auto request = ParseCtapGetAssertionRequest(request_bytes);
- if (!request) {
+ auto request_and_hash = ParseCtapGetAssertionRequest(request_bytes);
+ if (!request_and_hash) {
DLOG(ERROR) << "Incorrectly formatted GetAssertion request.";
return CtapDeviceResponseCode::kCtap2ErrOther;
}
+ CtapGetAssertionRequest request = std::get<0>(*request_and_hash);
+ CtapGetAssertionRequest::ClientDataHash client_data_hash =
+ std::get<1>(*request_and_hash);
// Resident keys are not supported.
- if (!request->allow_list() || request->allow_list()->empty()) {
+ if (!request.allow_list() || request.allow_list()->empty()) {
DLOG(ERROR) << "Allowed credential list is empty, but Virtual CTAP2 device "
"does not support resident keys.";
return CtapDeviceResponseCode::kCtap2ErrNoCredentials;
}
// Client pin option is not supported.
- if (request->pin_auth()) {
+ if (request.pin_auth()) {
DLOG(ERROR) << "Virtual CTAP2 device does not support client pin.";
return CtapDeviceResponseCode::kCtap2ErrOther;
}
- if (!AreGetAssertionOptionsValid(device_info_.options(), *request)) {
+ if (!AreGetAssertionOptionsValid(device_info_.options(), request)) {
DLOG(ERROR) << "Unsupported options required from the request.";
return CtapDeviceResponseCode::kCtap2ErrOther;
}
- const auto rp_id_hash =
- fido_parsing_utils::CreateSHA256Hash(request->rp_id());
+ const auto rp_id_hash = fido_parsing_utils::CreateSHA256Hash(request.rp_id());
RegistrationData* found_data = nullptr;
base::span<const uint8_t> credential_id;
- for (const auto& allowed_credential : *request->allow_list()) {
+ for (const auto& allowed_credential : *request.allow_list()) {
if ((found_data =
FindRegistrationData(allowed_credential.id(), rp_id_hash))) {
credential_id = allowed_credential.id();
@@ -342,10 +408,10 @@ CtapDeviceResponseCode VirtualCtap2Device::OnGetAssertion(
return CtapDeviceResponseCode::kCtap2ErrNoCredentials;
found_data->counter++;
- auto authenticator_data =
- ConstructAuthenticatorData(rp_id_hash, found_data->counter);
+ auto authenticator_data = ConstructAuthenticatorData(
+ rp_id_hash, found_data->counter, base::nullopt, base::nullopt);
auto signature_buffer =
- ConstructSignatureBuffer(authenticator_data, request->client_data_hash());
+ ConstructSignatureBuffer(authenticator_data, client_data_hash);
// Sign with the private key of the received key handle.
std::vector<uint8_t> sig;
@@ -367,7 +433,8 @@ CtapDeviceResponseCode VirtualCtap2Device::OnAuthenticatorGetInfo(
AuthenticatorData VirtualCtap2Device::ConstructAuthenticatorData(
base::span<const uint8_t, kRpIdHashLength> rp_id_hash,
uint32_t current_signature_count,
- base::Optional<AttestedCredentialData> attested_credential_data) {
+ base::Optional<AttestedCredentialData> attested_credential_data,
+ base::Optional<cbor::Value> extensions) {
uint8_t flag =
base::strict_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
std::array<uint8_t, kSignCounterLength> signature_counter;
@@ -375,6 +442,10 @@ AuthenticatorData VirtualCtap2Device::ConstructAuthenticatorData(
// Constructing AuthenticatorData for registration operation.
if (attested_credential_data)
flag |= base::strict_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
+ if (extensions) {
+ flag |= base::strict_cast<uint8_t>(
+ AuthenticatorData::Flag::kExtensionDataIncluded);
+ }
signature_counter[0] = (current_signature_count >> 24) & 0xff;
signature_counter[1] = (current_signature_count >> 16) & 0xff;
@@ -382,7 +453,227 @@ AuthenticatorData VirtualCtap2Device::ConstructAuthenticatorData(
signature_counter[3] = (current_signature_count)&0xff;
return AuthenticatorData(rp_id_hash, flag, signature_counter,
- std::move(attested_credential_data));
+ std::move(attested_credential_data),
+ std::move(extensions));
+}
+
+base::Optional<std::pair<CtapMakeCredentialRequest,
+ CtapMakeCredentialRequest::ClientDataHash>>
+ParseCtapMakeCredentialRequest(base::span<const uint8_t> request_bytes) {
+ const auto& cbor_request = cbor::Reader::Read(request_bytes);
+ if (!cbor_request || !cbor_request->is_map())
+ return base::nullopt;
+
+ const auto& request_map = cbor_request->GetMap();
+ if (!AreMakeCredentialRequestMapKeysCorrect(request_map))
+ return base::nullopt;
+
+ const auto client_data_hash_it = request_map.find(cbor::Value(1));
+ if (client_data_hash_it == request_map.end() ||
+ !client_data_hash_it->second.is_bytestring())
+ return base::nullopt;
+
+ const auto client_data_hash =
+ base::make_span(client_data_hash_it->second.GetBytestring())
+ .subspan<0, kClientDataHashLength>();
+
+ const auto rp_entity_it = request_map.find(cbor::Value(2));
+ if (rp_entity_it == request_map.end() || !rp_entity_it->second.is_map())
+ return base::nullopt;
+
+ auto rp_entity =
+ PublicKeyCredentialRpEntity::CreateFromCBORValue(rp_entity_it->second);
+ if (!rp_entity)
+ return base::nullopt;
+
+ const auto user_entity_it = request_map.find(cbor::Value(3));
+ if (user_entity_it == request_map.end() || !user_entity_it->second.is_map())
+ return base::nullopt;
+
+ auto user_entity = PublicKeyCredentialUserEntity::CreateFromCBORValue(
+ user_entity_it->second);
+ if (!user_entity)
+ return base::nullopt;
+
+ const auto credential_params_it = request_map.find(cbor::Value(4));
+ if (credential_params_it == request_map.end())
+ return base::nullopt;
+
+ auto credential_params = PublicKeyCredentialParams::CreateFromCBORValue(
+ credential_params_it->second);
+ if (!credential_params)
+ return base::nullopt;
+
+ CtapMakeCredentialRequest request(
+ std::string() /* client_data_json */, std::move(*rp_entity),
+ std::move(*user_entity), std::move(*credential_params));
+
+ const auto exclude_list_it = request_map.find(cbor::Value(5));
+ if (exclude_list_it != request_map.end()) {
+ if (!exclude_list_it->second.is_array())
+ return base::nullopt;
+
+ const auto& credential_descriptors = exclude_list_it->second.GetArray();
+ std::vector<PublicKeyCredentialDescriptor> exclude_list;
+ for (const auto& credential_descriptor : credential_descriptors) {
+ auto excluded_credential =
+ PublicKeyCredentialDescriptor::CreateFromCBORValue(
+ credential_descriptor);
+ if (!excluded_credential)
+ return base::nullopt;
+
+ exclude_list.push_back(std::move(*excluded_credential));
+ }
+ request.SetExcludeList(std::move(exclude_list));
+ }
+
+ const auto extensions_it = request_map.find(cbor::Value(6));
+ if (extensions_it != request_map.end()) {
+ if (!extensions_it->second.is_map()) {
+ return base::nullopt;
+ }
+
+ const auto& extensions = extensions_it->second.GetMap();
+ const auto hmac_secret_it =
+ extensions.find(cbor::Value(kExtensionHmacSecret));
+ if (hmac_secret_it != extensions.end()) {
+ if (!hmac_secret_it->second.is_bool()) {
+ return base::nullopt;
+ }
+ request.SetHmacSecret(hmac_secret_it->second.GetBool());
+ }
+ }
+
+ const auto option_it = request_map.find(cbor::Value(7));
+ if (option_it != request_map.end()) {
+ if (!option_it->second.is_map())
+ return base::nullopt;
+
+ const auto& option_map = option_it->second.GetMap();
+ if (!IsMakeCredentialOptionMapFormatCorrect(option_map))
+ return base::nullopt;
+
+ const auto resident_key_option =
+ option_map.find(cbor::Value(kResidentKeyMapKey));
+ if (resident_key_option != option_map.end())
+ request.SetResidentKeyRequired(resident_key_option->second.GetBool());
+
+ const auto uv_option =
+ option_map.find(cbor::Value(kUserVerificationMapKey));
+ if (uv_option != option_map.end())
+ request.SetUserVerification(
+ uv_option->second.GetBool()
+ ? UserVerificationRequirement::kRequired
+ : UserVerificationRequirement::kDiscouraged);
+ }
+
+ const auto pin_auth_it = request_map.find(cbor::Value(8));
+ if (pin_auth_it != request_map.end()) {
+ if (!pin_auth_it->second.is_bytestring())
+ return base::nullopt;
+ request.SetPinAuth(pin_auth_it->second.GetBytestring());
+ }
+
+ const auto pin_protocol_it = request_map.find(cbor::Value(9));
+ if (pin_protocol_it != request_map.end()) {
+ if (!pin_protocol_it->second.is_unsigned() ||
+ pin_protocol_it->second.GetUnsigned() >
+ std::numeric_limits<uint8_t>::max())
+ return base::nullopt;
+ request.SetPinProtocol(pin_auth_it->second.GetUnsigned());
+ }
+
+ return std::make_pair(std::move(request),
+ fido_parsing_utils::Materialize(client_data_hash));
+}
+
+base::Optional<
+ std::pair<CtapGetAssertionRequest, CtapGetAssertionRequest::ClientDataHash>>
+ParseCtapGetAssertionRequest(base::span<const uint8_t> request_bytes) {
+ const auto& cbor_request = cbor::Reader::Read(request_bytes);
+ if (!cbor_request || !cbor_request->is_map())
+ return base::nullopt;
+
+ const auto& request_map = cbor_request->GetMap();
+ if (!AreGetAssertionRequestMapKeysCorrect(request_map))
+ return base::nullopt;
+
+ const auto rp_id_it = request_map.find(cbor::Value(1));
+ if (rp_id_it == request_map.end() || !rp_id_it->second.is_string())
+ return base::nullopt;
+
+ const auto client_data_hash_it = request_map.find(cbor::Value(2));
+ if (client_data_hash_it == request_map.end() ||
+ !client_data_hash_it->second.is_bytestring())
+ return base::nullopt;
+
+ const auto client_data_hash =
+ base::make_span(client_data_hash_it->second.GetBytestring())
+ .subspan<0, kClientDataHashLength>();
+
+ CtapGetAssertionRequest request(rp_id_it->second.GetString(),
+ std::string() /* client_data_json */);
+
+ const auto allow_list_it = request_map.find(cbor::Value(3));
+ if (allow_list_it != request_map.end()) {
+ if (!allow_list_it->second.is_array())
+ return base::nullopt;
+
+ const auto& credential_descriptors = allow_list_it->second.GetArray();
+ std::vector<PublicKeyCredentialDescriptor> allow_list;
+ for (const auto& credential_descriptor : credential_descriptors) {
+ auto allowed_credential =
+ PublicKeyCredentialDescriptor::CreateFromCBORValue(
+ credential_descriptor);
+ if (!allowed_credential)
+ return base::nullopt;
+
+ allow_list.push_back(std::move(*allowed_credential));
+ }
+ request.SetAllowList(std::move(allow_list));
+ }
+
+ const auto option_it = request_map.find(cbor::Value(5));
+ if (option_it != request_map.end()) {
+ if (!option_it->second.is_map())
+ return base::nullopt;
+
+ const auto& option_map = option_it->second.GetMap();
+ if (!IsGetAssertionOptionMapFormatCorrect(option_map))
+ return base::nullopt;
+
+ const auto user_presence_option =
+ option_map.find(cbor::Value(kUserPresenceMapKey));
+ if (user_presence_option != option_map.end())
+ request.SetUserPresenceRequired(user_presence_option->second.GetBool());
+
+ const auto uv_option =
+ option_map.find(cbor::Value(kUserVerificationMapKey));
+ if (uv_option != option_map.end())
+ request.SetUserVerification(
+ uv_option->second.GetBool()
+ ? UserVerificationRequirement::kRequired
+ : UserVerificationRequirement::kPreferred);
+ }
+
+ const auto pin_auth_it = request_map.find(cbor::Value(6));
+ if (pin_auth_it != request_map.end()) {
+ if (!pin_auth_it->second.is_bytestring())
+ return base::nullopt;
+ request.SetPinAuth(pin_auth_it->second.GetBytestring());
+ }
+
+ const auto pin_protocol_it = request_map.find(cbor::Value(7));
+ if (pin_protocol_it != request_map.end()) {
+ if (!pin_protocol_it->second.is_unsigned() ||
+ pin_protocol_it->second.GetUnsigned() >
+ std::numeric_limits<uint8_t>::max())
+ return base::nullopt;
+ request.SetPinProtocol(pin_auth_it->second.GetUnsigned());
+ }
+
+ return std::make_pair(std::move(request),
+ fido_parsing_utils::Materialize(client_data_hash));
}
} // namespace device
diff --git a/chromium/device/fido/virtual_ctap2_device.h b/chromium/device/fido/virtual_ctap2_device.h
index fa84a9c0425..622d4248a29 100644
--- a/chromium/device/fido/virtual_ctap2_device.h
+++ b/chromium/device/fido/virtual_ctap2_device.h
@@ -15,9 +15,12 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
+#include "components/cbor/values.h"
#include "device/fido/attested_credential_data.h"
#include "device/fido/authenticator_data.h"
#include "device/fido/authenticator_supported_options.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h"
#include "device/fido/virtual_fido_device.h"
@@ -50,8 +53,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
AuthenticatorData ConstructAuthenticatorData(
base::span<const uint8_t, kRpIdHashLength> rp_id_hash,
uint32_t current_signature_count,
- base::Optional<AttestedCredentialData> attested_credential_data =
- base::nullopt);
+ base::Optional<AttestedCredentialData> attested_credential_data,
+ base::Optional<cbor::Value> extensions);
AuthenticatorGetInfoResponse device_info_;
base::WeakPtrFactory<FidoDevice> weak_factory_;
@@ -59,6 +62,22 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
DISALLOW_COPY_AND_ASSIGN(VirtualCtap2Device);
};
+// Decodes a CBOR-encoded CTAP2 authenticatorMakeCredential request message. The
+// request's client_data_json() value will be empty, and the hashed client data
+// is returned separately.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::pair<CtapMakeCredentialRequest,
+ CtapMakeCredentialRequest::ClientDataHash>>
+ParseCtapMakeCredentialRequest(base::span<const uint8_t> request_bytes);
+
+// Decodes a CBOR-encoded CTAP2 authenticatorGetAssertion request message. The
+// request's client_data_json() value will be empty, and the hashed client data
+// is returned separately.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<
+ std::pair<CtapGetAssertionRequest, CtapGetAssertionRequest::ClientDataHash>>
+ParseCtapGetAssertionRequest(base::span<const uint8_t> request_bytes);
+
} // namespace device
#endif // DEVICE_FIDO_VIRTUAL_CTAP2_DEVICE_H_
diff --git a/chromium/device/fido/virtual_fido_device.cc b/chromium/device/fido/virtual_fido_device.cc
index 05bf30651cd..4ce078679e6 100644
--- a/chromium/device/fido/virtual_fido_device.cc
+++ b/chromium/device/fido/virtual_fido_device.cc
@@ -4,6 +4,7 @@
#include "device/fido/virtual_fido_device.h"
+#include <algorithm>
#include <tuple>
#include <utility>
@@ -156,9 +157,11 @@ VirtualFidoDevice::RegistrationData* VirtualFidoDevice::FindRegistrationData(
if (it == mutable_state()->registrations.end())
return nullptr;
- if (application_parameter !=
- base::make_span(it->second.application_parameter))
+ if (!std::equal(application_parameter.begin(), application_parameter.end(),
+ it->second.application_parameter.begin(),
+ it->second.application_parameter.end())) {
return nullptr;
+ }
return &(it->second);
}
@@ -173,8 +176,7 @@ std::string VirtualFidoDevice::GetId() const {
}
FidoTransportProtocol VirtualFidoDevice::DeviceTransport() const {
- // Virtual device are injected as HID devices.
- return FidoTransportProtocol::kUsbHumanInterfaceDevice;
+ return state_->transport;
}
} // namespace device
diff --git a/chromium/device/fido/virtual_fido_device.h b/chromium/device/fido/virtual_fido_device.h
index 06a65f7b870..c6cfb19187b 100644
--- a/chromium/device/fido/virtual_fido_device.h
+++ b/chromium/device/fido/virtual_fido_device.h
@@ -70,7 +70,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
// Registered keys. Keyed on key handle (a.k.a. "credential ID").
std::map<std::vector<uint8_t>,
RegistrationData,
- fido_parsing_utils::SpanLess>
+ fido_parsing_utils::RangeLess>
registrations;
// If set, this callback is called whenever a "press" is required. It allows
@@ -89,6 +89,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
// zero, in violation of the rules for self-attestation.
bool non_zero_aaguid_with_self_attestation = false;
+ FidoTransportProtocol transport =
+ FidoTransportProtocol::kUsbHumanInterfaceDevice;
+
// Adds a registration for the specified credential ID with the application
// parameter set to be valid for the given relying party ID (which would
// typically be a domain, e.g. "example.com").
diff --git a/chromium/device/fido/win/authenticator.cc b/chromium/device/fido/win/authenticator.cc
new file mode 100644
index 00000000000..eca65dabf8f
--- /dev/null
+++ b/chromium/device/fido/win/authenticator.cc
@@ -0,0 +1,294 @@
+// Copyright 2018 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 "device/fido/win/authenticator.h"
+
+#include <Combaseapi.h>
+#include <windows.h>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "device/fido/authenticator_supported_options.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_transport_protocol.h"
+#include "device/fido/win/type_conversions.h"
+#include "third_party/microsoft_webauthn/webauthn.h"
+
+namespace device {
+
+// Time out all Windows API requests after 5 minutes. We maintain our own
+// timeout and cancel the operation when it expires, so this value simply needs
+// to be larger than the largest internal request timeout.
+constexpr uint32_t kWinWebAuthnTimeoutMilliseconds = 1000 * 60 * 5;
+
+// static
+const char WinWebAuthnApiAuthenticator::kAuthenticatorId[] =
+ "WinWebAuthnApiAuthenticator";
+
+// static
+bool WinWebAuthnApiAuthenticator::
+ IsUserVerifyingPlatformAuthenticatorAvailable() {
+ BOOL result;
+ return WinWebAuthnApi::GetDefault()->IsAvailable() &&
+ WinWebAuthnApi::GetDefault()
+ ->IsUserVerifyingPlatformAuthenticatorAvailable(&result) ==
+ S_OK &&
+ result == TRUE;
+}
+
+WinWebAuthnApiAuthenticator::WinWebAuthnApiAuthenticator(
+ WinWebAuthnApi* win_api,
+ HWND current_window)
+ : FidoAuthenticator(),
+ win_api_(win_api),
+ current_window_(current_window),
+ weak_factory_(this) {
+ CHECK(win_api_->IsAvailable());
+ CoCreateGuid(&cancellation_id_);
+}
+
+WinWebAuthnApiAuthenticator::~WinWebAuthnApiAuthenticator() {
+ Cancel();
+}
+
+void WinWebAuthnApiAuthenticator::InitializeAuthenticator(
+ base::OnceClosure callback) {
+ std::move(callback).Run();
+}
+
+void WinWebAuthnApiAuthenticator::MakeCredential(
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) {
+ DCHECK(!is_pending_);
+ if (is_pending_)
+ return;
+
+ is_pending_ = true;
+
+ auto rp = request.rp();
+ auto user = request.user();
+ std::string client_data_json = request.client_data_json();
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values;
+ for (const PublicKeyCredentialParams::CredentialInfo& credential_info :
+ request.public_key_credential_params().public_key_credential_params()) {
+ if (credential_info.type != CredentialType::kPublicKey) {
+ continue;
+ }
+ cose_credential_parameter_values.push_back(
+ {WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION,
+ WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY, credential_info.algorithm});
+ }
+ std::vector<WEBAUTHN_EXTENSION> extensions;
+ if (request.hmac_secret()) {
+ static BOOL kHMACSecretTrue = TRUE;
+ extensions.emplace_back(
+ WEBAUTHN_EXTENSION{WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET,
+ sizeof(BOOL), static_cast<void*>(&kHMACSecretTrue)});
+ }
+ auto exclude_list = request.exclude_list();
+
+ uint32_t authenticator_attachment;
+ if (request.is_u2f_only()) {
+ authenticator_attachment =
+ WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2;
+ } else if (request.is_incognito_mode()) {
+ // Disable all platform authenticators in incognito mode. We are going to
+ // revisit this in crbug/908622.
+ authenticator_attachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
+ } else {
+ authenticator_attachment =
+ ToWinAuthenticatorAttachment(request.authenticator_attachment());
+ }
+ win_api_->AuthenticatorMakeCredential(
+ current_window_, cancellation_id_, std::move(rp), std::move(user),
+ std::move(cose_credential_parameter_values), std::move(client_data_json),
+ std::move(extensions), std::move(exclude_list),
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS{
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_3,
+ kWinWebAuthnTimeoutMilliseconds,
+ WEBAUTHN_CREDENTIALS{
+ 0, nullptr}, // Ignored because pExcludeCredentialList is set.
+ WEBAUTHN_EXTENSIONS{0, nullptr}, // will be set later
+ authenticator_attachment, request.resident_key_required(),
+ ToWinUserVerificationRequirement(request.user_verification()),
+ WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT, 0 /* flags */,
+ nullptr, // pCancellationId -- will be set later
+ nullptr, // pExcludeCredentialList -- will be set later
+ },
+ base::BindOnce(&WinWebAuthnApiAuthenticator::MakeCredentialDone,
+ weak_factory_.GetWeakPtr(), std::move(request),
+ std::move(callback)));
+}
+
+void WinWebAuthnApiAuthenticator::MakeCredentialDone(
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback,
+ HRESULT hresult,
+ WinWebAuthnApi::ScopedCredentialAttestation credential_attestation) {
+ DCHECK(is_pending_);
+ is_pending_ = false;
+ const CtapDeviceResponseCode status =
+ hresult == S_OK ? CtapDeviceResponseCode::kSuccess
+ : WinErrorNameToCtapDeviceResponseCode(
+ base::string16(win_api_->GetErrorName(hresult)));
+ if (waiting_for_cancellation_) {
+ // Don't bother invoking the reply callback if the caller has already
+ // cancelled the operation.
+ waiting_for_cancellation_ = false;
+ return;
+ }
+
+ if (status != CtapDeviceResponseCode::kSuccess) {
+ std::move(callback).Run(status, base::nullopt);
+ return;
+ }
+
+ base::Optional<AuthenticatorMakeCredentialResponse> response =
+ credential_attestation
+ ? ToAuthenticatorMakeCredentialResponse(*credential_attestation)
+ : base::nullopt;
+ if (!response) {
+ std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrInvalidCBOR,
+ base::nullopt);
+ return;
+ }
+
+ std::move(callback).Run(status, std::move(response));
+}
+
+void WinWebAuthnApiAuthenticator::GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) {
+ DCHECK(!is_pending_);
+ if (is_pending_)
+ return;
+
+ is_pending_ = true;
+
+ base::string16 rp_id16 = base::UTF8ToUTF16(request.rp_id());
+ base::Optional<base::string16> opt_app_id16 = base::nullopt;
+ if (request.app_id()) {
+ opt_app_id16 = base::UTF8ToUTF16(base::StringPiece(
+ reinterpret_cast<const char*>(request.app_id()->data()),
+ request.app_id()->size()));
+ }
+ std::string client_data_json = request.client_data_json();
+ auto allow_list = request.allow_list();
+
+ uint32_t authenticator_attachment;
+ if (opt_app_id16) {
+ authenticator_attachment =
+ WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2;
+ } else if (request.is_incognito_mode()) {
+ // Disable all platform authenticators in incognito mode. We are going to
+ // revisit this in crbug/908622.
+ authenticator_attachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
+ } else {
+ authenticator_attachment = WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
+ }
+
+ win_api_->AuthenticatorGetAssertion(
+ current_window_, cancellation_id_, std::move(rp_id16),
+ std::move(opt_app_id16), std::move(client_data_json),
+ std::move(allow_list),
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS{
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4,
+ kWinWebAuthnTimeoutMilliseconds,
+ WEBAUTHN_CREDENTIALS{
+ 0, nullptr}, // Ignored because pAllowCredentialList is set.
+ WEBAUTHN_EXTENSIONS{0, nullptr}, // None supported.
+ authenticator_attachment,
+ ToWinUserVerificationRequirement(request.user_verification()),
+ 0, // flags
+ nullptr, // pwszU2fAppId -- will be set later
+ nullptr, // pbU2fAppId -- will be set later
+ nullptr, // pCancellationId -- will be set later
+ nullptr, // pAllowCredentialList -- will be set later
+ },
+ base::BindOnce(&WinWebAuthnApiAuthenticator::GetAssertionDone,
+ weak_factory_.GetWeakPtr(), std::move(request),
+ std::move(callback)));
+}
+
+void WinWebAuthnApiAuthenticator::GetAssertionDone(
+ CtapGetAssertionRequest request,
+ GetAssertionCallback callback,
+ HRESULT hresult,
+ WinWebAuthnApi::ScopedAssertion assertion) {
+ DCHECK(is_pending_);
+ is_pending_ = false;
+ const CtapDeviceResponseCode status =
+ hresult == S_OK ? CtapDeviceResponseCode::kSuccess
+ : WinErrorNameToCtapDeviceResponseCode(
+ base::string16(win_api_->GetErrorName(hresult)));
+ if (waiting_for_cancellation_) {
+ // Don't bother invoking the reply callback if the caller has already
+ // cancelled the operation.
+ waiting_for_cancellation_ = false;
+ return;
+ }
+
+ base::Optional<AuthenticatorGetAssertionResponse> response =
+ (hresult == S_OK && assertion)
+ ? ToAuthenticatorGetAssertionResponse(*assertion)
+ : base::nullopt;
+ std::move(callback).Run(status, std::move(response));
+}
+
+void WinWebAuthnApiAuthenticator::Cancel() {
+ if (!is_pending_ || waiting_for_cancellation_)
+ return;
+
+ waiting_for_cancellation_ = true;
+ // This returns immediately.
+ win_api_->CancelCurrentOperation(&cancellation_id_);
+}
+
+std::string WinWebAuthnApiAuthenticator::GetId() const {
+ return kAuthenticatorId;
+}
+
+base::string16 WinWebAuthnApiAuthenticator::GetDisplayName() const {
+ return base::UTF8ToUTF16(GetId());
+}
+
+bool WinWebAuthnApiAuthenticator::IsInPairingMode() const {
+ return false;
+}
+
+bool WinWebAuthnApiAuthenticator::IsPaired() const {
+ return false;
+}
+
+base::Optional<FidoTransportProtocol>
+WinWebAuthnApiAuthenticator::AuthenticatorTransport() const {
+ // The Windows API could potentially use any external or
+ // platform authenticator.
+ return base::nullopt;
+}
+
+const base::Optional<AuthenticatorSupportedOptions>&
+WinWebAuthnApiAuthenticator::Options() const {
+ // The request can potentially be fulfilled by any device that Windows
+ // communicates with, so returning AuthenticatorSupportedOptions really
+ // doesn't make much sense.
+ static const base::Optional<AuthenticatorSupportedOptions> no_options =
+ base::nullopt;
+ return no_options;
+}
+
+base::WeakPtr<FidoAuthenticator> WinWebAuthnApiAuthenticator::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+} // namespace device
diff --git a/chromium/device/fido/win/authenticator.h b/chromium/device/fido/win/authenticator.h
new file mode 100644
index 00000000000..555705424a0
--- /dev/null
+++ b/chromium/device/fido/win/authenticator.h
@@ -0,0 +1,72 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_WIN_AUTHENTICATOR_H_
+#define DEVICE_FIDO_WIN_AUTHENTICATOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "device/fido/fido_authenticator.h"
+#include "device/fido/win/webauthn_api.h"
+
+namespace device {
+
+// WinWebAuthnApiAuthenticator forwards WebAuthn requests to external
+// authenticators via the native Windows WebAuthentication API
+// (webauthn.dll).
+class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticator
+ : public FidoAuthenticator {
+ public:
+ // The return value of |GetId|.
+ static const char kAuthenticatorId[];
+
+ static bool IsUserVerifyingPlatformAuthenticatorAvailable();
+
+ WinWebAuthnApiAuthenticator(WinWebAuthnApi* win_api, HWND current_window);
+ ~WinWebAuthnApiAuthenticator() override;
+
+ // FidoAuthenticator
+ void InitializeAuthenticator(base::OnceClosure callback) override;
+ void MakeCredential(CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) override;
+ void GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) override;
+ void Cancel() override;
+ std::string GetId() const override;
+ base::string16 GetDisplayName() const override;
+ bool IsInPairingMode() const override;
+ bool IsPaired() const override;
+ const base::Optional<AuthenticatorSupportedOptions>& Options() const override;
+ base::Optional<FidoTransportProtocol> AuthenticatorTransport() const override;
+ base::WeakPtr<FidoAuthenticator> GetWeakPtr() override;
+
+ private:
+ void MakeCredentialDone(
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback,
+ HRESULT result,
+ WinWebAuthnApi::ScopedCredentialAttestation credential_attestation);
+ void GetAssertionDone(CtapGetAssertionRequest request,
+ GetAssertionCallback callback,
+ HRESULT hresult,
+ WinWebAuthnApi::ScopedAssertion assertion);
+
+ WinWebAuthnApi* win_api_;
+ HWND current_window_;
+
+ bool is_pending_ = false;
+ bool waiting_for_cancellation_ = false;
+ GUID cancellation_id_ = {};
+ base::WeakPtrFactory<WinWebAuthnApiAuthenticator> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(WinWebAuthnApiAuthenticator);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_WIN_AUTHENTICATOR_H_
diff --git a/chromium/device/fido/win/discovery.cc b/chromium/device/fido/win/discovery.cc
new file mode 100644
index 00000000000..0e72b97ff12
--- /dev/null
+++ b/chromium/device/fido/win/discovery.cc
@@ -0,0 +1,36 @@
+// Copyright 2018 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 "device/fido/win/discovery.h"
+
+namespace device {
+
+WinWebAuthnApiAuthenticatorDiscovery::WinWebAuthnApiAuthenticatorDiscovery(
+ WinWebAuthnApi* const win_webauthn_api,
+ HWND parent_window)
+ : FidoDiscoveryBase(FidoTransportProtocol::kUsbHumanInterfaceDevice),
+ win_webauthn_api_(win_webauthn_api),
+ parent_window_(parent_window) {}
+
+WinWebAuthnApiAuthenticatorDiscovery::~WinWebAuthnApiAuthenticatorDiscovery() =
+ default;
+
+void WinWebAuthnApiAuthenticatorDiscovery::Start() {
+ DCHECK(!authenticator_);
+ if (!observer()) {
+ return;
+ }
+
+ if (!win_webauthn_api_->IsAvailable()) {
+ observer()->DiscoveryStarted(this, false /* discovery failed */);
+ return;
+ }
+
+ observer()->DiscoveryStarted(this, true /* success */);
+ authenticator_ = std::make_unique<WinWebAuthnApiAuthenticator>(
+ WinWebAuthnApi::GetDefault(), parent_window_);
+ observer()->AuthenticatorAdded(this, authenticator_.get());
+}
+
+} // namespace device
diff --git a/chromium/device/fido/win/discovery.h b/chromium/device/fido/win/discovery.h
new file mode 100644
index 00000000000..ba7a803af8d
--- /dev/null
+++ b/chromium/device/fido/win/discovery.h
@@ -0,0 +1,37 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_WIN_DISCOVERY_H_
+#define DEVICE_FIDO_WIN_DISCOVERY_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "device/fido/fido_discovery_base.h"
+#include "device/fido/win/authenticator.h"
+#include "device/fido/win/webauthn_api.h"
+
+namespace device {
+
+// Instantiates the authenticator subclass for forwarding requests to external
+// authenticators via the Windows WebAuthn API.
+class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApiAuthenticatorDiscovery
+ : public FidoDiscoveryBase {
+ public:
+ WinWebAuthnApiAuthenticatorDiscovery(WinWebAuthnApi* const win_webauthn_api,
+ HWND parent_window);
+ ~WinWebAuthnApiAuthenticatorDiscovery() override;
+
+ // FidoDiscoveryBase:
+ void Start() override;
+
+ private:
+ std::unique_ptr<WinWebAuthnApiAuthenticator> authenticator_;
+ WinWebAuthnApi* const win_webauthn_api_;
+ const HWND parent_window_;
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_WIN_DISCOVERY_H_
diff --git a/chromium/device/fido/win/fake_webauthn_api.cc b/chromium/device/fido/win/fake_webauthn_api.cc
new file mode 100644
index 00000000000..d741cb755f8
--- /dev/null
+++ b/chromium/device/fido/win/fake_webauthn_api.cc
@@ -0,0 +1,71 @@
+// Copyright 2018 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 "device/fido/win/fake_webauthn_api.h"
+
+#include "base/logging.h"
+#include "base/optional.h"
+
+namespace device {
+
+FakeWinWebAuthnApi::FakeWinWebAuthnApi() = default;
+FakeWinWebAuthnApi::~FakeWinWebAuthnApi() = default;
+
+bool FakeWinWebAuthnApi::IsAvailable() const {
+ return is_available_;
+}
+
+HRESULT FakeWinWebAuthnApi::IsUserVerifyingPlatformAuthenticatorAvailable(
+ BOOL* result) {
+ DCHECK(is_available_);
+ *result = is_uvpaa_;
+ return S_OK;
+}
+
+void FakeWinWebAuthnApi::AuthenticatorMakeCredential(
+ HWND h_wnd,
+ GUID cancellation_id,
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values,
+ std::string client_data_json,
+ std::vector<WEBAUTHN_EXTENSION> extensions,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list,
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS options,
+ AuthenticatorMakeCredentialCallback callback) {
+ DCHECK(is_available_);
+}
+
+void FakeWinWebAuthnApi::AuthenticatorGetAssertion(
+ HWND h_wnd,
+ GUID cancellation_id,
+ base::string16 rp_id,
+ base::Optional<base::string16> opt_app_id,
+ std::string client_data_json,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list,
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS options,
+ AuthenticatorGetAssertionCallback callback) {
+ DCHECK(is_available_);
+}
+
+HRESULT FakeWinWebAuthnApi::CancelCurrentOperation(GUID* cancellation_id) {
+ DCHECK(is_available_);
+ return E_NOTIMPL;
+}
+
+const wchar_t* FakeWinWebAuthnApi::GetErrorName(HRESULT hr) {
+ DCHECK(is_available_);
+ return L"not implemented";
+};
+
+ScopedFakeWinWebAuthnApi::ScopedFakeWinWebAuthnApi() : FakeWinWebAuthnApi() {
+ WinWebAuthnApi::SetDefaultForTesting(this);
+}
+
+ScopedFakeWinWebAuthnApi::~ScopedFakeWinWebAuthnApi() {
+ WinWebAuthnApi::ClearDefaultForTesting();
+}
+
+} // namespace device
diff --git a/chromium/device/fido/win/fake_webauthn_api.h b/chromium/device/fido/win/fake_webauthn_api.h
new file mode 100644
index 00000000000..96c65ab6074
--- /dev/null
+++ b/chromium/device/fido/win/fake_webauthn_api.h
@@ -0,0 +1,70 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
+#define DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
+
+#include "base/macros.h"
+#include "device/fido/win/webauthn_api.h"
+
+namespace device {
+
+class FakeWinWebAuthnApi : public WinWebAuthnApi {
+ public:
+ FakeWinWebAuthnApi();
+ ~FakeWinWebAuthnApi() override;
+
+ // Inject the return value for WinWebAuthnApi::IsAvailable().
+ void set_available(bool available) { is_available_ = available; }
+ // Inject the return value for
+ // WinWebAuthnApi::IsUserverifyingPlatformAuthenticatorAvailable().
+ void set_is_uvpaa(bool is_uvpaa) { is_uvpaa_ = is_uvpaa; }
+
+ // WinWebAuthnApi:
+ bool IsAvailable() const override;
+ // The following methods all return E_NOTIMPL immediately.
+ HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(
+ BOOL* available) override;
+ void AuthenticatorMakeCredential(
+ HWND h_wnd,
+ GUID cancellation_id,
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values,
+ std::string client_data_json,
+ std::vector<WEBAUTHN_EXTENSION> extensions,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list,
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS options,
+ AuthenticatorMakeCredentialCallback callback) override;
+ void AuthenticatorGetAssertion(
+ HWND h_wnd,
+ GUID cancellation_id,
+ base::string16 rp_id,
+ base::Optional<base::string16> opt_app_id,
+ std::string client_data_json,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list,
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS options,
+ AuthenticatorGetAssertionCallback callback) override;
+ HRESULT CancelCurrentOperation(GUID* cancellation_id) override;
+ // Returns L"not implemented".
+ const wchar_t* GetErrorName(HRESULT hr) override;
+
+ private:
+ bool is_available_ = true;
+ bool is_uvpaa_ = false;
+};
+
+// ScopedFakeWinWebAuthnApi overrides the value returned
+// by WinWebAuthnApi::GetDefault with itself for the duration of its
+// lifetime.
+class ScopedFakeWinWebAuthnApi : public FakeWinWebAuthnApi {
+ public:
+ ScopedFakeWinWebAuthnApi();
+ ~ScopedFakeWinWebAuthnApi() override;
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_WIN_FAKE_WEBAUTHN_API_H_
diff --git a/chromium/device/fido/win/type_conversions.cc b/chromium/device/fido/win/type_conversions.cc
new file mode 100644
index 00000000000..e7db7760090
--- /dev/null
+++ b/chromium/device/fido/win/type_conversions.cc
@@ -0,0 +1,229 @@
+// Copyright 2018 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 "device/fido/win/type_conversions.h"
+
+#include <vector>
+
+#include "base/containers/span.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/cbor/reader.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/fido_transport_protocol.h"
+#include "device/fido/opaque_attestation_statement.h"
+
+namespace device {
+
+base::Optional<AuthenticatorMakeCredentialResponse>
+ToAuthenticatorMakeCredentialResponse(
+ const WEBAUTHN_CREDENTIAL_ATTESTATION& credential_attestation) {
+ auto authenticator_data = AuthenticatorData::DecodeAuthenticatorData(
+ base::span<const uint8_t>(credential_attestation.pbAuthenticatorData,
+ credential_attestation.cbAuthenticatorData));
+ if (!authenticator_data) {
+ DLOG(ERROR) << "DecodeAuthenticatorData failed: "
+ << base::HexEncode(credential_attestation.pbAuthenticatorData,
+ credential_attestation.cbAuthenticatorData);
+ return base::nullopt;
+ }
+ base::Optional<cbor::Value> cbor_attestation_statement = cbor::Reader::Read(
+ base::span<const uint8_t>(credential_attestation.pbAttestation,
+ credential_attestation.cbAttestation));
+ if (!cbor_attestation_statement) {
+ DLOG(ERROR) << "CBOR decoding attestation statement failed: "
+ << base::HexEncode(credential_attestation.pbAttestation,
+ credential_attestation.cbAttestation);
+ return base::nullopt;
+ }
+
+ base::Optional<FidoTransportProtocol> transport_used;
+ if (credential_attestation.dwVersion >=
+ WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3) {
+ // dwUsedTransport should have exactly one of the
+ // WEBAUTHN_CTAP_TRANSPORT_* values set.
+ switch (credential_attestation.dwUsedTransport) {
+ case WEBAUTHN_CTAP_TRANSPORT_USB:
+ transport_used = FidoTransportProtocol::kUsbHumanInterfaceDevice;
+ break;
+ case WEBAUTHN_CTAP_TRANSPORT_NFC:
+ transport_used = FidoTransportProtocol::kNearFieldCommunication;
+ break;
+ case WEBAUTHN_CTAP_TRANSPORT_BLE:
+ transport_used = FidoTransportProtocol::kBluetoothLowEnergy;
+ break;
+ case WEBAUTHN_CTAP_TRANSPORT_INTERNAL:
+ transport_used = FidoTransportProtocol::kInternal;
+ break;
+ default:
+ // Ignore _TEST and possibly future others.
+ break;
+ }
+ }
+
+ return AuthenticatorMakeCredentialResponse(
+ base::nullopt /* transport_used */,
+ AttestationObject(
+ std::move(*authenticator_data),
+ std::make_unique<OpaqueAttestationStatement>(
+ base::UTF16ToUTF8(credential_attestation.pwszFormatType),
+ std::move(*cbor_attestation_statement))));
+}
+
+base::Optional<AuthenticatorGetAssertionResponse>
+ToAuthenticatorGetAssertionResponse(const WEBAUTHN_ASSERTION& assertion) {
+ auto authenticator_data =
+ AuthenticatorData::DecodeAuthenticatorData(base::span<const uint8_t>(
+ assertion.pbAuthenticatorData, assertion.cbAuthenticatorData));
+ if (!authenticator_data) {
+ DLOG(ERROR) << "DecodeAuthenticatorData failed: "
+ << base::HexEncode(assertion.pbAuthenticatorData,
+ assertion.cbAuthenticatorData);
+ return base::nullopt;
+ }
+ AuthenticatorGetAssertionResponse response(
+ std::move(*authenticator_data),
+ std::vector<uint8_t>(assertion.pbSignature,
+ assertion.pbSignature + assertion.cbSignature));
+ if (assertion.Credential.cbId > 0) {
+ response.SetCredential(PublicKeyCredentialDescriptor(
+ CredentialType::kPublicKey,
+ std::vector<uint8_t>(
+ assertion.Credential.pbId,
+ assertion.Credential.pbId + assertion.Credential.cbId)));
+ }
+ if (assertion.cbUserId > 0) {
+ response.SetUserEntity(PublicKeyCredentialUserEntity(std::vector<uint8_t>(
+ assertion.pbUserId, assertion.pbUserId + assertion.cbUserId)));
+ }
+ return response;
+}
+
+uint32_t ToWinUserVerificationRequirement(
+ UserVerificationRequirement user_verification_requirement) {
+ switch (user_verification_requirement) {
+ case UserVerificationRequirement::kRequired:
+ return WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+ case UserVerificationRequirement::kPreferred:
+ return WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED;
+ case UserVerificationRequirement::kDiscouraged:
+ return WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED;
+ }
+ NOTREACHED();
+ return WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED;
+}
+
+uint32_t ToWinAuthenticatorAttachment(
+ AuthenticatorAttachment authenticator_attachment) {
+ switch (authenticator_attachment) {
+ case AuthenticatorAttachment::kAny:
+ return WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
+ case AuthenticatorAttachment::kPlatform:
+ return WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM;
+ case AuthenticatorAttachment::kCrossPlatform:
+ return WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM;
+ }
+ NOTREACHED();
+ return WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY;
+}
+
+static uint32_t ToWinTransportsMask(
+ const base::flat_set<FidoTransportProtocol>& transports) {
+ uint32_t result = 0;
+ for (const FidoTransportProtocol transport : transports) {
+ switch (transport) {
+ case FidoTransportProtocol::kUsbHumanInterfaceDevice:
+ result |= WEBAUTHN_CTAP_TRANSPORT_USB;
+ break;
+ case FidoTransportProtocol::kNearFieldCommunication:
+ result |= WEBAUTHN_CTAP_TRANSPORT_NFC;
+ break;
+ case FidoTransportProtocol::kBluetoothLowEnergy:
+ result |= WEBAUTHN_CTAP_TRANSPORT_BLE;
+ break;
+ case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
+ // caBLE is unsupported by the Windows API.
+ break;
+ case FidoTransportProtocol::kInternal:
+ result |= WEBAUTHN_CTAP_TRANSPORT_INTERNAL;
+ break;
+ }
+ }
+ return result;
+}
+
+std::vector<WEBAUTHN_CREDENTIAL> ToWinCredentialVector(
+ const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
+ credentials) {
+ if (!credentials) {
+ return {};
+ }
+ std::vector<WEBAUTHN_CREDENTIAL> result;
+ for (const auto& credential : *credentials) {
+ if (credential.credential_type() != CredentialType::kPublicKey) {
+ continue;
+ }
+ result.push_back(WEBAUTHN_CREDENTIAL{
+ WEBAUTHN_CREDENTIAL_CURRENT_VERSION,
+ credential.id().size(),
+ const_cast<unsigned char*>(credential.id().data()),
+ WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY,
+ });
+ }
+ return result;
+}
+
+std::vector<WEBAUTHN_CREDENTIAL_EX> ToWinCredentialExVector(
+ const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
+ credentials) {
+ if (!credentials) {
+ return {};
+ }
+ std::vector<WEBAUTHN_CREDENTIAL_EX> result;
+ for (const auto& credential : *credentials) {
+ if (credential.credential_type() != CredentialType::kPublicKey) {
+ continue;
+ }
+ result.push_back(WEBAUTHN_CREDENTIAL_EX{
+ WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION, credential.id().size(),
+ const_cast<unsigned char*>(credential.id().data()),
+ WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY,
+ ToWinTransportsMask(credential.transports())});
+ }
+ return result;
+}
+
+CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode(
+ const base::string16& error_name) {
+ // TODO(crbug/896522): Another mismatch of our authenticator models. Windows
+ // returns WebAuthn authenticator model status, whereas FidoAuthenticator
+ // wants to pass on CTAP-level response codes. Do a best effort at mapping
+ // them back down for now.
+ //
+ // See WebAuthNGetErrorName in <webauthn.h> for these string values.
+ static base::flat_map<base::string16, CtapDeviceResponseCode>
+ kResponseCodeMap({
+ {L"Success", CtapDeviceResponseCode::kSuccess},
+ // This should be something else for GetAssertion but that currently
+ // doesn't make a difference.
+ {L"InvalidStateError",
+ CtapDeviceResponseCode::kCtap2ErrCredentialExcluded},
+ {L"ConstraintError",
+ CtapDeviceResponseCode::kCtap2ErrUnsupportedOption},
+ {L"NotSupportedError",
+ CtapDeviceResponseCode::kCtap2ErrUnsupportedAlgorithms},
+ {L"NotAllowedError",
+ CtapDeviceResponseCode::kCtap2ErrOperationDenied},
+ {L"UnknownError", CtapDeviceResponseCode::kCtap2ErrOther},
+ });
+ return base::ContainsKey(kResponseCodeMap, error_name)
+ ? kResponseCodeMap[error_name]
+ : CtapDeviceResponseCode::kCtap2ErrOther;
+}
+
+} // namespace device
diff --git a/chromium/device/fido/win/type_conversions.h b/chromium/device/fido/win/type_conversions.h
new file mode 100644
index 00000000000..b0656aea91f
--- /dev/null
+++ b/chromium/device/fido/win/type_conversions.h
@@ -0,0 +1,54 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_WIN_TYPE_CONVERSIONS_H_
+#define DEVICE_FIDO_WIN_TYPE_CONVERSIONS_H_
+
+#include <windows.h>
+
+#include "base/component_export.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/fido_constants.h"
+#include "third_party/microsoft_webauthn/webauthn.h"
+
+namespace device {
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<AuthenticatorMakeCredentialResponse>
+ToAuthenticatorMakeCredentialResponse(
+ const WEBAUTHN_CREDENTIAL_ATTESTATION& credential_attestation);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<AuthenticatorGetAssertionResponse>
+ToAuthenticatorGetAssertionResponse(
+ const WEBAUTHN_ASSERTION& credential_attestation);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+uint32_t ToWinUserVerificationRequirement(
+ UserVerificationRequirement user_verification_requirement);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+uint32_t ToWinAuthenticatorAttachment(
+ AuthenticatorAttachment authenticator_attachment);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::vector<WEBAUTHN_CREDENTIAL> ToWinCredentialVector(
+ const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
+ credentials);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::vector<WEBAUTHN_CREDENTIAL_EX> ToWinCredentialExVector(
+ const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
+ credentials);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode(
+ const base::string16& error_name);
+
+} // namespace device
+
+#endif // DEVICE_FIDO_WIN_TYPE_CONVERSIONS_H_
diff --git a/chromium/device/fido/win/webauthn_api.cc b/chromium/device/fido/win/webauthn_api.cc
new file mode 100644
index 00000000000..22765b41685
--- /dev/null
+++ b/chromium/device/fido/win/webauthn_api.cc
@@ -0,0 +1,348 @@
+// Copyright 2018 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 "device/fido/win/webauthn_api.h"
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/native_library.h"
+#include "base/no_destructor.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "device/fido/features.h"
+#include "device/fido/win/type_conversions.h"
+
+namespace device {
+
+// We do not integrate with older API versions of webauthn.dll because they
+// don't support BLE and direct device access to USB and BLE FIDO devices is
+// not yet blocked on those platforms.
+constexpr uint32_t kMinWinWebAuthnApiVersion = WEBAUTHN_API_VERSION_1;
+
+namespace {
+base::string16 OptionalGURLToUTF16(const base::Optional<GURL>& in) {
+ return in ? base::UTF8ToUTF16(in->spec()) : base::string16();
+}
+} // namespace
+
+// WinWebAuthnApiImpl is the default implementation of WinWebAuthnApi, which
+// attempts to load webauthn.dll on intialization.
+class WinWebAuthnApiImpl : public WinWebAuthnApi {
+ public:
+ WinWebAuthnApiImpl()
+ : is_bound_(false),
+ thread_(std::make_unique<base::Thread>("WindowsWebAuthnAPIRequest")) {
+ static HMODULE webauthn_dll = LoadLibraryA("webauthn.dll");
+ if (!webauthn_dll) {
+ return;
+ }
+
+#define BIND_FN(fn_pointer, lib_handle, fn_name) \
+ DCHECK(!fn_pointer); \
+ fn_pointer = reinterpret_cast<decltype(fn_pointer)>( \
+ GetProcAddress(lib_handle, fn_name));
+
+#define BIND_FN_OR_RETURN(fn_pointer, lib_handle, fn_name) \
+ BIND_FN(fn_pointer, lib_handle, fn_name); \
+ if (!fn_pointer) { \
+ DLOG(ERROR) << "failed to bind " << fn_name; \
+ return; \
+ }
+
+ BIND_FN_OR_RETURN(is_user_verifying_platform_authenticator_available_,
+ webauthn_dll,
+ "WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable");
+ BIND_FN_OR_RETURN(authenticator_make_credential_, webauthn_dll,
+ "WebAuthNAuthenticatorMakeCredential");
+ BIND_FN_OR_RETURN(authenticator_get_assertion_, webauthn_dll,
+ "WebAuthNAuthenticatorGetAssertion");
+ BIND_FN_OR_RETURN(cancel_current_operation_, webauthn_dll,
+ "WebAuthNCancelCurrentOperation");
+ BIND_FN_OR_RETURN(get_error_name_, webauthn_dll, "WebAuthNGetErrorName");
+ BIND_FN_OR_RETURN(free_credential_attestation_, webauthn_dll,
+ "WebAuthNFreeCredentialAttestation");
+ BIND_FN_OR_RETURN(free_assertion_, webauthn_dll, "WebAuthNFreeAssertion");
+
+ is_bound_ = true;
+
+ // Determine the API version of webauthn.dll. There is a version currently
+ // shipping with Windows RS5 from before WebAuthNGetApiVersionNumber was
+ // added (i.e., before WEBAUTHN_API_VERSION_1). Therefore we allow this
+ // function to be missing.
+ BIND_FN(get_api_version_number_, webauthn_dll,
+ "WebAuthNGetApiVersionNumber");
+ api_version_ = get_api_version_number_ ? get_api_version_number_() : 0;
+ thread_->Start();
+ }
+
+ ~WinWebAuthnApiImpl() override {}
+
+ // WinWebAuthnApi:
+ bool IsAvailable() const override {
+ return is_bound_ && (api_version_ >= kMinWinWebAuthnApiVersion ||
+ base::FeatureList::IsEnabled(
+ kWebAuthDisableWinApiVersionCheckForTesting));
+ }
+
+ HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(BOOL* result) override {
+ DCHECK(is_bound_);
+ return is_user_verifying_platform_authenticator_available_(result);
+ }
+
+ void AuthenticatorMakeCredential(
+ HWND h_wnd,
+ GUID cancellation_id,
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values,
+ std::string client_data_json,
+ std::vector<WEBAUTHN_EXTENSION> extensions,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list,
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS options,
+ AuthenticatorMakeCredentialCallback callback) override {
+ DCHECK(is_bound_);
+ base::PostTaskAndReplyWithResult(
+ thread_->task_runner().get(), FROM_HERE,
+ base::BindOnce(&WinWebAuthnApiImpl::AuthenticatorMakeCredentialBlocking,
+ base::Unretained(this), // |thread_| is owned by this.
+ h_wnd, cancellation_id, std::move(rp), std::move(user),
+ std::move(cose_credential_parameter_values),
+ std::move(client_data_json), std::move(extensions),
+ std::move(exclude_list), std::move(options)),
+ base::BindOnce(&WinWebAuthnApiImpl::AuthenticatorMakeCredentialDone,
+ base::Unretained(this),
+ base::SequencedTaskRunnerHandle::Get(),
+ std::move(callback)));
+ }
+
+ void AuthenticatorGetAssertion(
+ HWND h_wnd,
+ GUID cancellation_id,
+ base::string16 rp_id,
+ base::Optional<base::string16> opt_app_id,
+ std::string client_data_json,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list,
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS options,
+ AuthenticatorGetAssertionCallback callback) override {
+ DCHECK(is_bound_);
+ base::PostTaskAndReplyWithResult(
+ thread_->task_runner().get(), FROM_HERE,
+ base::BindOnce(&WinWebAuthnApiImpl::AuthenticatorGetAssertionBlocking,
+ base::Unretained(this), // |thread_| is owned by this.
+ h_wnd, cancellation_id, std::move(rp_id),
+ std::move(opt_app_id), std::move(client_data_json),
+ std::move(allow_list), std::move(options)),
+ base::BindOnce(&WinWebAuthnApiImpl::AuthenticatorGetAssertionDone,
+ base::Unretained(this),
+ base::SequencedTaskRunnerHandle::Get(),
+ std::move(callback)));
+ }
+
+ HRESULT CancelCurrentOperation(GUID* cancellation_id) override {
+ return cancel_current_operation_(cancellation_id);
+ }
+
+ const wchar_t* GetErrorName(HRESULT hr) override {
+ DCHECK(is_bound_);
+ return get_error_name_(hr);
+ };
+
+ private:
+ std::pair<HRESULT, ScopedCredentialAttestation>
+ AuthenticatorMakeCredentialBlocking(
+ HWND h_wnd,
+ GUID cancellation_id,
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values,
+ std::string client_data_json,
+ std::vector<WEBAUTHN_EXTENSION> extensions,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list,
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS options) {
+ base::string16 rp_id = base::UTF8ToUTF16(rp.rp_id());
+ base::string16 rp_name = base::UTF8ToUTF16(rp.rp_name().value_or(""));
+ base::string16 rp_icon_url = OptionalGURLToUTF16(rp.rp_icon_url());
+ base::string16 user_name = base::UTF8ToUTF16(user.user_name().value_or(""));
+ base::string16 user_icon_url = OptionalGURLToUTF16(user.user_icon_url());
+ WEBAUTHN_RP_ENTITY_INFORMATION rp_info{
+ WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION, rp_id.c_str(),
+ rp_name.c_str(), rp_icon_url.c_str()};
+
+ base::string16 user_display_name =
+ base::UTF8ToUTF16(user.user_display_name().value_or(""));
+ WEBAUTHN_USER_ENTITY_INFORMATION user_info{
+ WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION,
+ user.user_id().size(),
+ const_cast<unsigned char*>(user.user_id().data()),
+ user_name.c_str(),
+ user_icon_url.c_str(),
+ user_display_name.c_str(), // This appears to be ignored.
+ };
+
+ WEBAUTHN_COSE_CREDENTIAL_PARAMETERS cose_credential_parameters{
+ cose_credential_parameter_values.size(),
+ cose_credential_parameter_values.data()};
+
+ WEBAUTHN_CLIENT_DATA client_data{
+ WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, client_data_json.size(),
+ const_cast<unsigned char*>(
+ reinterpret_cast<const unsigned char*>(client_data_json.data())),
+ WEBAUTHN_HASH_ALGORITHM_SHA_256};
+
+ options.Extensions =
+ WEBAUTHN_EXTENSIONS{extensions.size(), extensions.data()};
+ options.pCancellationId = &cancellation_id;
+
+ std::vector<WEBAUTHN_CREDENTIAL_EX> exclude_list_credentials =
+ ToWinCredentialExVector(exclude_list);
+ std::vector<WEBAUTHN_CREDENTIAL_EX*> exclude_list_ptrs;
+ std::transform(exclude_list_credentials.begin(),
+ exclude_list_credentials.end(),
+ std::back_inserter(exclude_list_ptrs),
+ [](auto& cred) { return &cred; });
+ WEBAUTHN_CREDENTIAL_LIST exclude_credential_list{exclude_list_ptrs.size(),
+ exclude_list_ptrs.data()};
+ options.pExcludeCredentialList = &exclude_credential_list;
+
+ WEBAUTHN_CREDENTIAL_ATTESTATION* credential_attestation_ptr = nullptr;
+ HRESULT hresult = authenticator_make_credential_(
+ h_wnd, &rp_info, &user_info, &cose_credential_parameters, &client_data,
+ &options, &credential_attestation_ptr);
+ return std::make_pair(
+ hresult, ScopedCredentialAttestation(credential_attestation_ptr,
+ free_credential_attestation_));
+ }
+
+ std::pair<HRESULT, ScopedAssertion> AuthenticatorGetAssertionBlocking(
+ HWND h_wnd,
+ GUID cancellation_id,
+ base::string16 rp_id,
+ base::Optional<base::string16> opt_app_id,
+ std::string client_data_json,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list,
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS options) {
+ if (opt_app_id) {
+ options.pwszU2fAppId = opt_app_id->data();
+ static BOOL kUseAppIdTrue = TRUE; // const
+ options.pbU2fAppId = &kUseAppIdTrue;
+ } else {
+ static BOOL kUseAppIdFalse = FALSE; // const
+ options.pbU2fAppId = &kUseAppIdFalse;
+ }
+ options.pCancellationId = &cancellation_id;
+
+ std::vector<WEBAUTHN_CREDENTIAL_EX> allow_list_credentials =
+ ToWinCredentialExVector(allow_list);
+ std::vector<WEBAUTHN_CREDENTIAL_EX*> allow_list_ptrs;
+ std::transform(allow_list_credentials.begin(), allow_list_credentials.end(),
+ std::back_inserter(allow_list_ptrs),
+ [](auto& cred) { return &cred; });
+ WEBAUTHN_CREDENTIAL_LIST allow_credential_list{allow_list_ptrs.size(),
+ allow_list_ptrs.data()};
+ options.pAllowCredentialList = &allow_credential_list;
+
+ // As of Nov 2018, the WebAuthNAuthenticatorGetAssertion method will fail
+ // to challenge credentials via CTAP1 if the allowList is passed in the
+ // extended form in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS (i.e.
+ // pAllowCredentialList instead of CredentialList). The legacy
+ // CredentialList field works fine, but does not support setting
+ // transport restrictions on the credential descriptor.
+ //
+ // As a workaround, MS tells us to also set the CredentialList parameter
+ // with an accurate cCredentials count and some arbitrary pCredentials
+ // data.
+ auto legacy_credentials = ToWinCredentialVector(allow_list);
+ options.CredentialList = WEBAUTHN_CREDENTIALS{legacy_credentials.size(),
+ legacy_credentials.data()};
+
+ WEBAUTHN_CLIENT_DATA client_data{
+ WEBAUTHN_CLIENT_DATA_CURRENT_VERSION, client_data_json.size(),
+ const_cast<unsigned char*>(
+ reinterpret_cast<const unsigned char*>(client_data_json.data())),
+ WEBAUTHN_HASH_ALGORITHM_SHA_256};
+
+ WEBAUTHN_ASSERTION* assertion_ptr = nullptr;
+ HRESULT hresult = authenticator_get_assertion_(
+ h_wnd, rp_id.data(), &client_data, &options, &assertion_ptr);
+ return std::make_pair(hresult,
+ ScopedAssertion(assertion_ptr, free_assertion_));
+ }
+
+ void AuthenticatorMakeCredentialDone(
+ scoped_refptr<base::SequencedTaskRunner> callback_runner,
+ AuthenticatorMakeCredentialCallback callback,
+ std::pair<HRESULT, ScopedCredentialAttestation> result) {
+ callback_runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), result.first,
+ std::move(result.second)));
+ }
+
+ void AuthenticatorGetAssertionDone(
+ scoped_refptr<base::SequencedTaskRunner> callback_runner,
+ AuthenticatorGetAssertionCallback callback,
+ std::pair<HRESULT, ScopedAssertion> result) {
+ callback_runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), result.first,
+ std::move(result.second)));
+ }
+
+ decltype(&WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable)
+ is_user_verifying_platform_authenticator_available_ = nullptr;
+ decltype(
+ &WebAuthNAuthenticatorMakeCredential) authenticator_make_credential_ =
+ nullptr;
+ decltype(&WebAuthNAuthenticatorGetAssertion) authenticator_get_assertion_ =
+ nullptr;
+ decltype(&WebAuthNCancelCurrentOperation) cancel_current_operation_ = nullptr;
+ decltype(&WebAuthNGetErrorName) get_error_name_ = nullptr;
+ decltype(&WebAuthNFreeCredentialAttestation) free_credential_attestation_ =
+ nullptr;
+ decltype(&WebAuthNFreeAssertion) free_assertion_ = nullptr;
+
+ // This method is not available in all versions of webauthn.dll.
+ decltype(&WebAuthNGetApiVersionNumber) get_api_version_number_ = nullptr;
+
+ bool is_bound_ = false;
+ uint32_t api_version_ = 0;
+
+ std::unique_ptr<base::Thread> thread_;
+};
+
+static WinWebAuthnApi* kDefaultForTesting = nullptr;
+
+// static
+WinWebAuthnApi* WinWebAuthnApi::GetDefault() {
+ if (kDefaultForTesting) {
+ return kDefaultForTesting;
+ }
+
+ static base::NoDestructor<WinWebAuthnApiImpl> api;
+ return api.get();
+}
+
+// static
+void WinWebAuthnApi::SetDefaultForTesting(WinWebAuthnApi* api) {
+ DCHECK(!kDefaultForTesting);
+ kDefaultForTesting = api;
+}
+
+// static
+void WinWebAuthnApi::ClearDefaultForTesting() {
+ DCHECK(kDefaultForTesting);
+ kDefaultForTesting = nullptr;
+}
+
+WinWebAuthnApi::~WinWebAuthnApi() = default;
+
+} // namespace device
diff --git a/chromium/device/fido/win/webauthn_api.h b/chromium/device/fido/win/webauthn_api.h
new file mode 100644
index 00000000000..10f2a50c69a
--- /dev/null
+++ b/chromium/device/fido/win/webauthn_api.h
@@ -0,0 +1,116 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_FIDO_WIN_WEBAUTHN_API_H_
+#define DEVICE_FIDO_WIN_WEBAUTHN_API_H_
+
+#include <windows.h>
+#include <functional>
+#include <memory>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/fido/public_key_credential_descriptor.h"
+#include "device/fido/public_key_credential_rp_entity.h"
+#include "device/fido/public_key_credential_user_entity.h"
+#include "third_party/microsoft_webauthn/webauthn.h"
+
+namespace device {
+
+// WinWebAuthnApi is a wrapper for the native Windows WebAuthn API.
+//
+// The default singleton instance can be obtained by calling |GetDefault|.
+// Users must check the result of |IsAvailable| on the instance to verify that
+// the native library was loaded successfully before invoking any of the other
+// methods.
+class COMPONENT_EXPORT(DEVICE_FIDO) WinWebAuthnApi {
+ public:
+ // ScopedCredentialAttestation is a scoped deleter for a
+ // WEB_AUTHN_CREDENTIAL_ATTESTATION pointer.
+ //
+ // Instances must not outlive their WinWebAuthnApi.
+ using ScopedCredentialAttestation =
+ std::unique_ptr<WEBAUTHN_CREDENTIAL_ATTESTATION,
+ std::function<void(WEBAUTHN_CREDENTIAL_ATTESTATION*)>>;
+
+ // ScopedAssertion is a scoped deleter for a WEB_AUTHN_ASSERTION pointer.
+ //
+ // Instances must not outlive their WinWebAuthnApi.
+ using ScopedAssertion =
+ std::unique_ptr<WEBAUTHN_ASSERTION,
+ std::function<void(WEBAUTHN_ASSERTION*)>>;
+
+ using AuthenticatorMakeCredentialCallback =
+ base::OnceCallback<void(HRESULT, ScopedCredentialAttestation)>;
+ using AuthenticatorGetAssertionCallback =
+ base::OnceCallback<void(HRESULT, ScopedAssertion)>;
+
+ // Returns the default implementation of WinWebAuthnApi backed by
+ // webauthn.dll. May return nullptr if webauthn.dll cannot be loaded.
+ static WinWebAuthnApi* GetDefault();
+
+ virtual ~WinWebAuthnApi();
+
+ // Returns whether the API is available on this system. If this returns
+ // false, none of the other methods on this instance may be called.
+ virtual bool IsAvailable() const = 0;
+
+ // See WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable in <webauthn.h>.
+ virtual HRESULT IsUserVerifyingPlatformAuthenticatorAvailable(
+ BOOL* available) = 0;
+
+ // See WebAuthNAuthenticatorMakeCredential in <webauthn.h>.
+ //
+ // The following fields in |options| are ignored because they get filled in
+ // from the other parameters:
+ // - Extensions
+ // - pCancellationId
+ // - CredentialList / pExcludeCredentialList
+ virtual void AuthenticatorMakeCredential(
+ HWND h_wnd,
+ GUID cancellation_id,
+ PublicKeyCredentialRpEntity rp,
+ PublicKeyCredentialUserEntity user,
+ std::vector<WEBAUTHN_COSE_CREDENTIAL_PARAMETER>
+ cose_credential_parameter_values,
+ std::string client_data_json,
+ std::vector<WEBAUTHN_EXTENSION> extensions,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> exclude_list,
+ WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS options,
+ AuthenticatorMakeCredentialCallback callback) = 0;
+
+ // See WebAuthNAuthenticatorGetAssertion in <webauthn.h>.
+ //
+ // The following fields in |options| are ignored because they get filled in
+ // from the other parameters:
+ // - pwszU2fAppId / pbU2fAppId
+ // - pCancellationId
+ // - CredentialList / pAllowCredentialList
+ virtual void AuthenticatorGetAssertion(
+ HWND h_wnd,
+ GUID cancellation_id,
+ base::string16 rp_id,
+ base::Optional<base::string16> opt_app_id,
+ std::string client_data_json,
+ base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list,
+ WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS options,
+ AuthenticatorGetAssertionCallback callback) = 0;
+
+ // See WebAuthNCancelCurrentOperation in <webauthn.h>.
+ virtual HRESULT CancelCurrentOperation(GUID* cancellation_id) = 0;
+
+ // See WebAuthNGetErrorName in <webauthn.h>.
+ virtual const wchar_t* GetErrorName(HRESULT hr) = 0;
+
+ private:
+ friend class ScopedFakeWinWebAuthnApi;
+ static void SetDefaultForTesting(WinWebAuthnApi* api);
+ static void ClearDefaultForTesting();
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_WIN_WEBAUTHN_API_H_
diff --git a/chromium/device/gamepad/gamepad_provider.cc b/chromium/device/gamepad/gamepad_provider.cc
index 8b7b1b0c080..1078b56639b 100644
--- a/chromium/device/gamepad/gamepad_provider.cc
+++ b/chromium/device/gamepad/gamepad_provider.cc
@@ -144,8 +144,7 @@ void GamepadProvider::Pause() {
base::AutoLock lock(is_paused_lock_);
is_paused_ = true;
}
- base::MessageLoop* polling_loop = polling_thread_->message_loop();
- polling_loop->task_runner()->PostTask(
+ polling_thread_->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&GamepadProvider::SendPauseHint, Unretained(this), true));
}
@@ -158,11 +157,10 @@ void GamepadProvider::Resume() {
is_paused_ = false;
}
- base::MessageLoop* polling_loop = polling_thread_->message_loop();
- polling_loop->task_runner()->PostTask(
+ polling_thread_->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&GamepadProvider::SendPauseHint, Unretained(this), false));
- polling_loop->task_runner()->PostTask(
+ polling_thread_->task_runner()->PostTask(
FROM_HERE,
base::BindOnce(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
}
diff --git a/chromium/device/udev_linux/udev_watcher.cc b/chromium/device/udev_linux/udev_watcher.cc
index d9e490de63a..a2bf268e9f9 100644
--- a/chromium/device/udev_linux/udev_watcher.cc
+++ b/chromium/device/udev_linux/udev_watcher.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
+#include "base/threading/scoped_blocking_call.h"
namespace device {
@@ -16,6 +17,7 @@ void UdevWatcher::Observer::OnDeviceAdded(ScopedUdevDevicePtr device) {}
void UdevWatcher::Observer::OnDeviceRemoved(ScopedUdevDevicePtr device) {}
std::unique_ptr<UdevWatcher> UdevWatcher::StartWatching(Observer* observer) {
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
ScopedUdevPtr udev(udev_new());
if (!udev) {
LOG(ERROR) << "Failed to initialize udev.";
@@ -50,6 +52,7 @@ UdevWatcher::~UdevWatcher() {
void UdevWatcher::EnumerateExistingDevices() {
DCHECK(sequence_checker_.CalledOnValidSequence());
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get()));
if (!enumerate) {
LOG(ERROR) << "Failed to initialize a udev enumerator.";
@@ -84,6 +87,7 @@ UdevWatcher::UdevWatcher(ScopedUdevPtr udev,
}
void UdevWatcher::OnMonitorReadable() {
+ base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
ScopedUdevDevicePtr device(udev_monitor_receive_device(udev_monitor_.get()));
if (!device)
return;
diff --git a/chromium/device/usb/OWNERS b/chromium/device/usb/OWNERS
index b78b7788c92..a855859018f 100644
--- a/chromium/device/usb/OWNERS
+++ b/chromium/device/usb/OWNERS
@@ -1,5 +1,5 @@
pfeldman@chromium.org
reillyg@chromium.org
-rockot@chromium.org
+rockot@google.com
# COMPONENT: IO>USB
diff --git a/chromium/device/usb/mojo/device_impl.cc b/chromium/device/usb/mojo/device_impl.cc
index f97bcf079b0..49aa637f698 100644
--- a/chromium/device/usb/mojo/device_impl.cc
+++ b/chromium/device/usb/mojo/device_impl.cc
@@ -109,6 +109,11 @@ DeviceImpl::DeviceImpl(scoped_refptr<device::UsbDevice> device,
weak_factory_(this) {
DCHECK(device_);
observer_.Add(device_.get());
+
+ if (client_) {
+ client_.set_connection_error_handler(base::BindOnce(
+ &DeviceImpl::OnClientConnectionError, weak_factory_.GetWeakPtr()));
+ }
}
void DeviceImpl::CloseHandle() {
@@ -392,5 +397,11 @@ void DeviceImpl::OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) {
binding_->Close();
}
+void DeviceImpl::OnClientConnectionError() {
+ // Close the connection with Blink when WebUsbServiceImpl notifies the
+ // permission revocation from settings UI.
+ binding_->Close();
+}
+
} // namespace usb
} // namespace device
diff --git a/chromium/device/usb/mojo/device_impl.h b/chromium/device/usb/mojo/device_impl.h
index 74062646312..e1d99949273 100644
--- a/chromium/device/usb/mojo/device_impl.h
+++ b/chromium/device/usb/mojo/device_impl.h
@@ -95,6 +95,8 @@ class DeviceImpl : public mojom::UsbDevice, public device::UsbDevice::Observer {
// device::UsbDevice::Observer implementation:
void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override;
+ void OnClientConnectionError();
+
const scoped_refptr<device::UsbDevice> device_;
ScopedObserver<device::UsbDevice, device::UsbDevice::Observer> observer_;
diff --git a/chromium/device/usb/mojo/device_manager_impl.cc b/chromium/device/usb/mojo/device_manager_impl.cc
index 9a3e29e084c..f622141341b 100644
--- a/chromium/device/usb/mojo/device_manager_impl.cc
+++ b/chromium/device/usb/mojo/device_manager_impl.cc
@@ -37,11 +37,19 @@ void DeviceManagerImpl::AddBinding(mojom::UsbDeviceManagerRequest request) {
bindings_.AddBinding(this, std::move(request));
}
+void DeviceManagerImpl::EnumerateDevicesAndSetClient(
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
+ EnumerateDevicesAndSetClientCallback callback) {
+ usb_service_->GetDevices(base::Bind(
+ &DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
+ /*options=*/nullptr, base::Passed(&client), base::Passed(&callback)));
+}
+
void DeviceManagerImpl::GetDevices(mojom::UsbEnumerationOptionsPtr options,
GetDevicesCallback callback) {
- usb_service_->GetDevices(
- base::Bind(&DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
- base::Passed(&options), base::Passed(&callback)));
+ usb_service_->GetDevices(base::Bind(
+ &DeviceManagerImpl::OnGetDevices, weak_factory_.GetWeakPtr(),
+ base::Passed(&options), /*client=*/nullptr, base::Passed(&callback)));
}
void DeviceManagerImpl::GetDevice(const std::string& guid,
@@ -65,6 +73,7 @@ void DeviceManagerImpl::SetClient(
void DeviceManagerImpl::OnGetDevices(
mojom::UsbEnumerationOptionsPtr options,
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
GetDevicesCallback callback,
const std::vector<scoped_refptr<UsbDevice>>& devices) {
std::vector<mojom::UsbDeviceFilterPtr> filters;
@@ -79,6 +88,9 @@ void DeviceManagerImpl::OnGetDevices(
}
std::move(callback).Run(std::move(device_infos));
+
+ if (client)
+ SetClient(std::move(client));
}
void DeviceManagerImpl::OnDeviceAdded(scoped_refptr<UsbDevice> device) {
diff --git a/chromium/device/usb/mojo/device_manager_impl.h b/chromium/device/usb/mojo/device_manager_impl.h
index 1b6066ec782..139e401297d 100644
--- a/chromium/device/usb/mojo/device_manager_impl.h
+++ b/chromium/device/usb/mojo/device_manager_impl.h
@@ -39,6 +39,9 @@ class DeviceManagerImpl : public mojom::UsbDeviceManager,
private:
// DeviceManager implementation:
+ void EnumerateDevicesAndSetClient(
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
+ EnumerateDevicesAndSetClientCallback callback) override;
void GetDevices(mojom::UsbEnumerationOptionsPtr options,
GetDevicesCallback callback) override;
void GetDevice(const std::string& guid,
@@ -49,6 +52,7 @@ class DeviceManagerImpl : public mojom::UsbDeviceManager,
// Callbacks to handle the async responses from the underlying UsbService.
void OnGetDevices(mojom::UsbEnumerationOptionsPtr options,
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
GetDevicesCallback callback,
const std::vector<scoped_refptr<UsbDevice>>& devices);
diff --git a/chromium/device/usb/mojo/type_converters.cc b/chromium/device/usb/mojo/type_converters.cc
index 89034c933fe..c834249c282 100644
--- a/chromium/device/usb/mojo/type_converters.cc
+++ b/chromium/device/usb/mojo/type_converters.cc
@@ -113,6 +113,7 @@ TypeConverter<device::mojom::UsbDeviceInfoPtr, device::UsbDevice>::Convert(
info->manufacturer_name = device.manufacturer_string();
info->product_name = device.product_string();
info->serial_number = device.serial_number();
+ info->webusb_landing_page = device.webusb_landing_page();
const device::UsbConfigDescriptor* config = device.active_configuration();
info->active_configuration = config ? config->configuration_value : 0;
info->configurations =
diff --git a/chromium/device/usb/public/cpp/BUILD.gn b/chromium/device/usb/public/cpp/BUILD.gn
index df68a9d4b9a..ea55d7cf853 100644
--- a/chromium/device/usb/public/cpp/BUILD.gn
+++ b/chromium/device/usb/public/cpp/BUILD.gn
@@ -33,5 +33,6 @@ static_library("test_support") {
public_deps = [
"//base",
"//device/usb/public/mojom",
+ "//url:url",
]
}
diff --git a/chromium/device/usb/public/cpp/fake_usb_device.cc b/chromium/device/usb/public/cpp/fake_usb_device.cc
index a1a5b95a93b..c5929833509 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device.cc
+++ b/chromium/device/usb/public/cpp/fake_usb_device.cc
@@ -35,6 +35,11 @@ FakeUsbDevice::FakeUsbDevice(scoped_refptr<FakeUsbDeviceInfo> device,
: device_(device), observer_(this), client_(std::move(client)) {
DCHECK(device_);
observer_.Add(device_.get());
+
+ if (client_) {
+ client_.set_connection_error_handler(base::BindOnce(
+ &FakeUsbDevice::OnClientConnectionError, base::Unretained(this)));
+ }
}
void FakeUsbDevice::CloseHandle() {
@@ -130,4 +135,10 @@ void FakeUsbDevice::OnDeviceRemoved(scoped_refptr<FakeUsbDeviceInfo> device) {
binding_->Close();
}
+void FakeUsbDevice::OnClientConnectionError() {
+ // Close the binding with Blink when WebUsbService finds permission revoked
+ // from setting UI.
+ binding_->Close();
+}
+
} // namespace device
diff --git a/chromium/device/usb/public/cpp/fake_usb_device.h b/chromium/device/usb/public/cpp/fake_usb_device.h
index be85bdb73cd..c1e8d1ed6cb 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device.h
+++ b/chromium/device/usb/public/cpp/fake_usb_device.h
@@ -77,6 +77,8 @@ class FakeUsbDevice : public mojom::UsbDevice,
// FakeUsbDeviceInfo::Observer implementation:
void OnDeviceRemoved(scoped_refptr<FakeUsbDeviceInfo> device) override;
+ void OnClientConnectionError();
+
void CloseHandle();
const scoped_refptr<FakeUsbDeviceInfo> device_;
diff --git a/chromium/device/usb/public/cpp/fake_usb_device_info.cc b/chromium/device/usb/public/cpp/fake_usb_device_info.cc
index 8fad4d7b9b3..b014504dbb0 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device_info.cc
+++ b/chromium/device/usb/public/cpp/fake_usb_device_info.cc
@@ -33,13 +33,27 @@ FakeUsbDeviceInfo::FakeUsbDeviceInfo(uint16_t vendor_id,
uint16_t product_id,
const std::string& manufacturer_string,
const std::string& product_string,
- const std::string& serial_number) {
+ const std::string& serial_number)
+ : FakeUsbDeviceInfo(vendor_id,
+ product_id,
+ manufacturer_string,
+ product_string,
+ serial_number,
+ GURL()) {}
+
+FakeUsbDeviceInfo::FakeUsbDeviceInfo(uint16_t vendor_id,
+ uint16_t product_id,
+ const std::string& manufacturer_string,
+ const std::string& product_string,
+ const std::string& serial_number,
+ const GURL& webusb_landing_page) {
SetDefault();
device_info_.vendor_id = vendor_id;
device_info_.product_id = product_id;
device_info_.manufacturer_name = base::UTF8ToUTF16(manufacturer_string);
device_info_.product_name = base::UTF8ToUTF16(product_string),
device_info_.serial_number = base::UTF8ToUTF16(serial_number);
+ device_info_.webusb_landing_page = webusb_landing_page;
}
FakeUsbDeviceInfo::~FakeUsbDeviceInfo() = default;
diff --git a/chromium/device/usb/public/cpp/fake_usb_device_info.h b/chromium/device/usb/public/cpp/fake_usb_device_info.h
index fe3ec66b3e9..d69b442c079 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device_info.h
+++ b/chromium/device/usb/public/cpp/fake_usb_device_info.h
@@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h"
#include "device/usb/public/mojom/device.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "url/gurl.h"
namespace device {
@@ -33,6 +34,12 @@ class FakeUsbDeviceInfo : public base::RefCounted<FakeUsbDeviceInfo> {
const std::string& manufacturer_string,
const std::string& product_string,
const std::string& serial_number);
+ FakeUsbDeviceInfo(uint16_t vendor_id,
+ uint16_t product_id,
+ const std::string& manufacturer_string,
+ const std::string& product_string,
+ const std::string& serial_number,
+ const GURL& webusb_landing_page);
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
diff --git a/chromium/device/usb/public/cpp/fake_usb_device_manager.cc b/chromium/device/usb/public/cpp/fake_usb_device_manager.cc
index de2c0617251..046013fbf26 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device_manager.cc
+++ b/chromium/device/usb/public/cpp/fake_usb_device_manager.cc
@@ -19,6 +19,13 @@ FakeUsbDeviceManager::FakeUsbDeviceManager() : weak_factory_(this) {}
FakeUsbDeviceManager::~FakeUsbDeviceManager() {}
+void FakeUsbDeviceManager::EnumerateDevicesAndSetClient(
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
+ EnumerateDevicesAndSetClientCallback callback) {
+ GetDevices(nullptr, std::move(callback));
+ SetClient(std::move(client));
+}
+
// mojom::UsbDeviceManager implementation:
void FakeUsbDeviceManager::GetDevices(mojom::UsbEnumerationOptionsPtr options,
GetDevicesCallback callback) {
diff --git a/chromium/device/usb/public/cpp/fake_usb_device_manager.h b/chromium/device/usb/public/cpp/fake_usb_device_manager.h
index 1473fc0235d..d89a1a7a033 100644
--- a/chromium/device/usb/public/cpp/fake_usb_device_manager.h
+++ b/chromium/device/usb/public/cpp/fake_usb_device_manager.h
@@ -48,6 +48,9 @@ class FakeUsbDeviceManager : public mojom::UsbDeviceManager {
private:
// mojom::UsbDeviceManager implementation:
+ void EnumerateDevicesAndSetClient(
+ mojom::UsbDeviceManagerClientAssociatedPtrInfo client,
+ EnumerateDevicesAndSetClientCallback callback) override;
void GetDevices(mojom::UsbEnumerationOptionsPtr options,
GetDevicesCallback callback) override;
void GetDevice(const std::string& guid,
diff --git a/chromium/device/usb/public/mojom/BUILD.gn b/chromium/device/usb/public/mojom/BUILD.gn
index 703ff1e77d6..276a40410cf 100644
--- a/chromium/device/usb/public/mojom/BUILD.gn
+++ b/chromium/device/usb/public/mojom/BUILD.gn
@@ -10,8 +10,9 @@ mojom("mojom") {
"device_manager.mojom",
]
- deps = [
+ public_deps = [
"//mojo/public/mojom/base",
+ "//url/mojom:url_mojom_gurl",
]
# USB Mojom interfaces are exposed publicly to layout tests which use
diff --git a/chromium/device/usb/public/mojom/device.mojom b/chromium/device/usb/public/mojom/device.mojom
index 17b2b498442..59d77d5b3ec 100644
--- a/chromium/device/usb/public/mojom/device.mojom
+++ b/chromium/device/usb/public/mojom/device.mojom
@@ -5,6 +5,7 @@
module device.mojom;
import "mojo/public/mojom/base/string16.mojom";
+import "url/mojom/url.mojom";
enum UsbOpenDeviceError {
// Opening the device succeeded.
@@ -88,6 +89,7 @@ struct UsbDeviceInfo {
mojo_base.mojom.String16? manufacturer_name;
mojo_base.mojom.String16? product_name;
mojo_base.mojom.String16? serial_number;
+ url.mojom.Url? webusb_landing_page;
uint8 active_configuration;
array<UsbConfigurationInfo> configurations;
};
diff --git a/chromium/device/usb/public/mojom/device_manager.mojom b/chromium/device/usb/public/mojom/device_manager.mojom
index 633fbcb679f..95ecff70049 100644
--- a/chromium/device/usb/public/mojom/device_manager.mojom
+++ b/chromium/device/usb/public/mojom/device_manager.mojom
@@ -32,6 +32,11 @@ struct UsbEnumerationOptions {
interface UsbDeviceManager {
// Retrieves information about all devices available to the DeviceManager
+ // implementation and set client for device added/removed events.
+ EnumerateDevicesAndSetClient(associated UsbDeviceManagerClient client)
+ => (array<UsbDeviceInfo> results);
+
+ // Retrieves devices information filtered by |options| to the DeviceManager
// implementation.
GetDevices(UsbEnumerationOptions? options) => (array<UsbDeviceInfo> results);
diff --git a/chromium/device/usb/usb_device_handle_win.cc b/chromium/device/usb/usb_device_handle_win.cc
index 1084d49aa93..265c3f29e81 100644
--- a/chromium/device/usb/usb_device_handle_win.cc
+++ b/chromium/device/usb/usb_device_handle_win.cc
@@ -90,50 +90,61 @@ uint8_t BuildRequestFlags(UsbTransferDirection direction,
// Encapsulates waiting for the completion of an overlapped event.
class UsbDeviceHandleWin::Request : public base::win::ObjectWatcher::Delegate {
public:
- explicit Request(HANDLE handle)
- : handle_(handle), event_(CreateEvent(nullptr, false, false, nullptr)) {
+ Request(HANDLE handle, bool winusb_handle)
+ : handle_(handle),
+ winusb_handle_(winusb_handle),
+ event_(CreateEvent(nullptr, false, false, nullptr)) {
memset(&overlapped_, 0, sizeof(overlapped_));
overlapped_.hEvent = event_.Get();
}
- ~Request() override {
- if (callback_) {
- SetLastError(ERROR_REQUEST_ABORTED);
- std::move(callback_).Run(this, false, 0);
- }
- }
+ ~Request() override = default;
// Starts watching for completion of the overlapped event.
void MaybeStartWatching(
BOOL success,
+ DWORD last_error,
base::OnceCallback<void(Request*, DWORD, size_t)> callback) {
callback_ = std::move(callback);
if (success) {
OnObjectSignaled(event_.Get());
} else {
- DWORD error = GetLastError();
- if (error == ERROR_IO_PENDING) {
+ if (last_error == ERROR_IO_PENDING)
watcher_.StartWatchingOnce(event_.Get(), this);
- } else {
- std::move(callback_).Run(this, error, 0);
- }
+ else
+ std::move(callback_).Run(this, last_error, 0);
}
}
+ void Abort() {
+ watcher_.StopWatching();
+ std::move(callback_).Run(this, ERROR_REQUEST_ABORTED, 0);
+ }
+
OVERLAPPED* overlapped() { return &overlapped_; }
// base::win::ObjectWatcher::Delegate
void OnObjectSignaled(HANDLE object) override {
DCHECK_EQ(object, event_.Get());
DWORD size;
- if (GetOverlappedResult(handle_, &overlapped_, &size, true))
+ BOOL result;
+ if (winusb_handle_)
+ result = WinUsb_GetOverlappedResult(handle_, &overlapped_, &size, true);
+ else
+ result = GetOverlappedResult(handle_, &overlapped_, &size, true);
+ DWORD last_error = GetLastError();
+
+ if (result)
std::move(callback_).Run(this, ERROR_SUCCESS, size);
else
- std::move(callback_).Run(this, GetLastError(), 0);
+ std::move(callback_).Run(this, last_error, 0);
}
private:
HANDLE handle_;
+ // Records whether |handle_| above is a true HANDLE or a
+ // WINUSB_INTERFACE_HANDLE.
+ bool winusb_handle_;
OVERLAPPED overlapped_;
base::win::ScopedHandle event_;
base::win::ObjectWatcher watcher_;
@@ -163,7 +174,17 @@ void UsbDeviceHandleWin::Close() {
hub_handle_.Close();
}
- requests_.clear();
+ if (function_handle_.IsValid()) {
+ CancelIo(function_handle_.Get());
+ function_handle_.Close();
+ first_interface_handle_ = INVALID_HANDLE_VALUE;
+ }
+
+ // Aborting requests may run or destroy callbacks holding the last reference
+ // to this object so hold a reference for the rest of this method.
+ scoped_refptr<UsbDeviceHandleWin> self(this);
+ while (!requests_.empty())
+ requests_.begin()->second->Abort();
}
void UsbDeviceHandleWin::SetConfiguration(int configuration_value,
@@ -285,13 +306,15 @@ void UsbDeviceHandleWin::ControlTransfer(
auto* node_connection_info = new USB_NODE_CONNECTION_INFORMATION_EX;
node_connection_info->ConnectionIndex = device_->port_number();
- Request* request = MakeRequest(hub_handle_.Get());
+ Request* request = MakeRequest(false /* winusb_handle */);
+ BOOL result = DeviceIoControl(
+ hub_handle_.Get(), IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
+ node_connection_info, sizeof(*node_connection_info),
+ node_connection_info, sizeof(*node_connection_info), nullptr,
+ request->overlapped());
+ DWORD last_error = GetLastError();
request->MaybeStartWatching(
- DeviceIoControl(hub_handle_.Get(),
- IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
- node_connection_info, sizeof(*node_connection_info),
- node_connection_info, sizeof(*node_connection_info),
- nullptr, request->overlapped()),
+ result, last_error,
base::BindOnce(&UsbDeviceHandleWin::GotNodeConnectionInformation,
weak_factory_.GetWeakPtr(), std::move(callback),
base::Owned(node_connection_info), buffer));
@@ -309,13 +332,14 @@ void UsbDeviceHandleWin::ControlTransfer(
descriptor_request->SetupPacket.wIndex = index;
descriptor_request->SetupPacket.wLength = buffer->size();
- Request* request = MakeRequest(hub_handle_.Get());
+ Request* request = MakeRequest(false /* winusb_handle */);
+ BOOL result = DeviceIoControl(
+ hub_handle_.Get(), IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
+ request_buffer->front(), size, request_buffer->front(), size,
+ nullptr, request->overlapped());
+ DWORD last_error = GetLastError();
request->MaybeStartWatching(
- DeviceIoControl(hub_handle_.Get(),
- IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
- request_buffer->front(), size,
- request_buffer->front(), size, nullptr,
- request->overlapped()),
+ result, last_error,
base::BindOnce(&UsbDeviceHandleWin::GotDescriptorFromNodeConnection,
weak_factory_.GetWeakPtr(), std::move(callback),
request_buffer, buffer));
@@ -350,12 +374,16 @@ void UsbDeviceHandleWin::ControlTransfer(
setup.Index = index;
setup.Length = buffer->size();
- Request* control_request = MakeRequest(handle);
- control_request->MaybeStartWatching(
+ Request* control_request = MakeRequest(true /* winusb_handle */);
+ BOOL result =
WinUsb_ControlTransfer(handle, setup, buffer->front(), buffer->size(),
- nullptr, control_request->overlapped()),
+ nullptr, control_request->overlapped());
+ DWORD last_error = GetLastError();
+ control_request->MaybeStartWatching(
+ result, last_error,
base::BindOnce(&UsbDeviceHandleWin::TransferComplete,
- weak_factory_.GetWeakPtr(), std::move(callback), buffer));
+ weak_factory_.GetWeakPtr(), nullptr, std::move(callback),
+ buffer));
}
void UsbDeviceHandleWin::IsochronousTransferIn(
@@ -465,6 +493,8 @@ bool UsbDeviceHandleWin::OpenInterfaceHandle(Interface* interface) {
USB_PLOG(ERROR) << "Failed to initialize WinUSB handle";
return false;
}
+
+ first_interface_handle_ = handle;
} else {
auto first_interface_it = interfaces_.find(interface->first_interface);
DCHECK(first_interface_it != interfaces_.end());
@@ -532,8 +562,11 @@ WINUSB_INTERFACE_HANDLE UsbDeviceHandleWin::GetInterfaceForControlTransfer(
return interface->handle.Get();
}
-UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(HANDLE handle) {
- auto request = std::make_unique<Request>(hub_handle_.Get());
+UsbDeviceHandleWin::Request* UsbDeviceHandleWin::MakeRequest(
+ bool winusb_handle) {
+ auto request = std::make_unique<Request>(
+ winusb_handle ? first_interface_handle_ : hub_handle_.Get(),
+ winusb_handle);
Request* request_ptr = request.get();
requests_[request_ptr] = std::move(request);
return request_ptr;
@@ -602,22 +635,32 @@ void UsbDeviceHandleWin::GotDescriptorFromNodeConnection(
}
void UsbDeviceHandleWin::TransferComplete(
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
TransferCallback callback,
scoped_refptr<base::RefCountedBytes> buffer,
Request* request_ptr,
DWORD win32_result,
size_t bytes_transferred) {
std::unique_ptr<Request> request = UnlinkRequest(request_ptr);
+ UsbTransferStatus status = UsbTransferStatus::COMPLETED;
if (win32_result != ERROR_SUCCESS) {
SetLastError(win32_result);
USB_PLOG(ERROR) << "Transfer failed";
- std::move(callback).Run(UsbTransferStatus::TRANSFER_ERROR, nullptr, 0);
- return;
+
+ buffer = nullptr;
+ bytes_transferred = 0;
+ status = UsbTransferStatus::TRANSFER_ERROR;
}
- std::move(callback).Run(UsbTransferStatus::COMPLETED, std::move(buffer),
- bytes_transferred);
+ if (!callback_task_runner ||
+ callback_task_runner->RunsTasksInCurrentSequence()) {
+ std::move(callback).Run(status, std::move(buffer), bytes_transferred);
+ } else {
+ callback_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), status,
+ std::move(buffer), bytes_transferred));
+ }
}
void UsbDeviceHandleWin::GenericTransferInternal(
@@ -654,7 +697,7 @@ void UsbDeviceHandleWin::GenericTransferInternal(
}
DCHECK(interface->handle.IsValid());
- Request* request = MakeRequest(interface->handle.Get());
+ Request* request = MakeRequest(true /* winusb_handle */);
BOOL result;
if (direction == UsbTransferDirection::INBOUND) {
result = WinUsb_ReadPipe(interface->handle.Get(), endpoint_address,
@@ -665,10 +708,13 @@ void UsbDeviceHandleWin::GenericTransferInternal(
buffer->front(), buffer->size(), nullptr,
request->overlapped());
}
+ DWORD last_error = GetLastError();
request->MaybeStartWatching(
- result, base::BindOnce(&UsbDeviceHandleWin::TransferComplete,
- weak_factory_.GetWeakPtr(), std::move(callback),
- std::move(buffer)));
+ result, last_error,
+ base::BindOnce(&UsbDeviceHandleWin::TransferComplete,
+ weak_factory_.GetWeakPtr(),
+ std::move(callback_task_runner), std::move(callback),
+ std::move(buffer)));
}
void UsbDeviceHandleWin::ReportIsochronousError(
diff --git a/chromium/device/usb/usb_device_handle_win.h b/chromium/device/usb/usb_device_handle_win.h
index 75ccbd06fa4..4547ac543da 100644
--- a/chromium/device/usb/usb_device_handle_win.h
+++ b/chromium/device/usb/usb_device_handle_win.h
@@ -121,7 +121,7 @@ class UsbDeviceHandleWin : public UsbDeviceHandle {
void SetInterfaceAlternateSettingComplete(uint8_t interface_number,
uint8_t alternate_setting,
const ResultCallback& callback);
- Request* MakeRequest(HANDLE handle);
+ Request* MakeRequest(bool winusb_handle);
std::unique_ptr<Request> UnlinkRequest(Request* request);
void GotNodeConnectionInformation(TransferCallback callback,
void* node_connection_info,
@@ -136,11 +136,13 @@ class UsbDeviceHandleWin : public UsbDeviceHandle {
Request* request_ptr,
DWORD win32_result,
size_t bytes_transferred);
- void TransferComplete(TransferCallback callback,
- scoped_refptr<base::RefCountedBytes> buffer,
- Request* request_ptr,
- DWORD win32_result,
- size_t bytes_transferred);
+ void TransferComplete(
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+ TransferCallback callback,
+ scoped_refptr<base::RefCountedBytes> buffer,
+ Request* request_ptr,
+ DWORD win32_result,
+ size_t bytes_transferred);
void GenericTransferInternal(
UsbTransferDirection direction,
uint8_t endpoint_number,
@@ -163,6 +165,9 @@ class UsbDeviceHandleWin : public UsbDeviceHandle {
base::win::ScopedHandle hub_handle_;
base::win::ScopedHandle function_handle_;
+ // The handle returned by WinUsb_Initialize is special.
+ WINUSB_INTERFACE_HANDLE first_interface_handle_ = INVALID_HANDLE_VALUE;
+
std::map<uint8_t, Interface> interfaces_;
std::map<uint8_t, Endpoint> endpoints_;
std::map<Request*, std::unique_ptr<Request>> requests_;
diff --git a/chromium/device/vr/BUILD.gn b/chromium/device/vr/BUILD.gn
index 03921dcf8ed..a8577f98735 100644
--- a/chromium/device/vr/BUILD.gn
+++ b/chromium/device/vr/BUILD.gn
@@ -63,6 +63,8 @@ if (enable_vr) {
"android/gvr/gvr_gamepad_data_fetcher.cc",
"android/gvr/gvr_gamepad_data_fetcher.h",
"android/gvr/gvr_gamepad_data_provider.h",
+ "android/gvr/vr_module_delegate.cc",
+ "android/gvr/vr_module_delegate.h",
]
if (enable_arcore) {
diff --git a/chromium/device/vr/PRESUBMIT.py b/chromium/device/vr/PRESUBMIT.py
deleted file mode 100644
index efd7ca550a0..00000000000
--- a/chromium/device/vr/PRESUBMIT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (c) 2018 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.
-
-"""Top-level presubmit script for device/vr.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-
-def PostUploadHook(cl, change, output_api):
- """git cl upload will call this hook after the issue is created/modified.
-
- This hook modifies the CL description in order to run extra GPU
- tests (in particular, WebXR and WebVR browser tests) in addition
- to the regular CQ try bots. This test suite is too large to run
- against all Chromium commits, but should be run against changes
- likely to affect these tests.
- """
- return output_api.EnsureCQIncludeTrybotsAreAdded(
- cl,
- ['luci.chromium.try:win_optional_gpu_tests_rel'],
- 'Automatically added optional GPU tests to run on CQ.')
diff --git a/chromium/device/vr/android/gvr/gvr_delegate_provider.h b/chromium/device/vr/android/gvr/gvr_delegate_provider.h
index 60c3419e363..17625eea070 100644
--- a/chromium/device/vr/android/gvr/gvr_delegate_provider.h
+++ b/chromium/device/vr/android/gvr/gvr_delegate_provider.h
@@ -19,7 +19,6 @@ class DEVICE_VR_EXPORT GvrDelegateProvider {
public:
GvrDelegateProvider() = default;
virtual bool ShouldDisableGvrDevice() = 0;
- virtual void SetDeviceId(mojom::XRDeviceId device_id) = 0;
virtual void StartWebXRPresentation(
mojom::VRDisplayInfoPtr display_info,
mojom::XRRuntimeSessionOptionsPtr options,
@@ -28,7 +27,7 @@ class DEVICE_VR_EXPORT GvrDelegateProvider {
virtual void OnListeningForActivateChanged(bool listening) = 0;
protected:
- virtual ~GvrDelegateProvider() {}
+ virtual ~GvrDelegateProvider() = default;
private:
DISALLOW_COPY_AND_ASSIGN(GvrDelegateProvider);
diff --git a/chromium/device/vr/android/gvr/gvr_device.cc b/chromium/device/vr/android/gvr/gvr_device.cc
index a8a3118d278..f3a24a448d5 100644
--- a/chromium/device/vr/android/gvr/gvr_device.cc
+++ b/chromium/device/vr/android/gvr/gvr_device.cc
@@ -16,6 +16,7 @@
#include "device/vr/android/gvr/gvr_delegate_provider.h"
#include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
#include "device/vr/android/gvr/gvr_device_provider.h"
+#include "device/vr/android/gvr/vr_module_delegate.h"
#include "device/vr/vr_display_impl.h"
#include "jni/NonPresentingGvrContext_jni.h"
#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
@@ -161,33 +162,12 @@ void GvrDevice::RequestSession(
mojom::XRRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) {
if (!gvr_api_) {
- EnsureGvrReady();
- if (!gvr_api_) {
- std::move(callback).Run(nullptr, nullptr);
- return;
- }
- }
-
- if (!options->immersive) {
- // TODO(https://crbug.com/695937): This should be NOTREACHED() once we no
- // longer need the hacked GRV non-immersive mode. This should now only be
- // hit if orientation devices are disabled by flag.
- ReturnNonImmersiveSession(std::move(callback));
+ Init(base::BindOnce(&GvrDevice::OnInitRequestSessionFinished,
+ base::Unretained(this), std::move(options),
+ std::move(callback)));
return;
}
-
- GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
- if (!delegate_provider) {
- std::move(callback).Run(nullptr, nullptr);
- return;
- }
-
- // StartWebXRPresentation is async as we may trigger a DON (Device ON) flow
- // that pauses Chrome.
- delegate_provider->StartWebXRPresentation(
- GetVRDisplayInfo(), std::move(options),
- base::BindOnce(&GvrDevice::OnStartPresentResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+ OnInitRequestSessionFinished(std::move(options), std::move(callback), true);
}
void GvrDevice::OnStartPresentResult(
@@ -233,31 +213,7 @@ void GvrDevice::StopPresenting() {
exclusive_controller_binding_.Close();
}
-void GvrDevice::EnsureGvrReady() {
- if (!non_presenting_context_.obj() || !gvr_api_) {
- GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
- if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice())
- return;
- JNIEnv* env = base::android::AttachCurrentThread();
- non_presenting_context_.Reset(Java_NonPresentingGvrContext_create(
- env, reinterpret_cast<jlong>(this)));
- if (!non_presenting_context_.obj())
- return;
- jlong context = Java_NonPresentingGvrContext_getNativeGvrContext(
- env, non_presenting_context_);
- gvr_api_ =
- gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
- SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId()));
-
- if (paused_) {
- PauseTracking();
- } else {
- ResumeTracking();
- }
- }
-}
-
-void GvrDevice::OnMagicWindowFrameDataRequest(
+void GvrDevice::OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
if (!gvr_api_) {
std::move(callback).Run(nullptr);
@@ -295,17 +251,15 @@ void GvrDevice::ResumeTracking() {
}
void GvrDevice::EnsureInitialized(EnsureInitializedCallback callback) {
- EnsureGvrReady();
- std::move(callback).Run();
+ Init(base::BindOnce([](EnsureInitializedCallback callback,
+ bool success) { std::move(callback).Run(); },
+ std::move(callback)));
}
GvrDelegateProvider* GvrDevice::GetGvrDelegateProvider() {
- // GvrDelegateProviderFactory::Create() may fail transiently, so every time we
- // try to get it, set the device ID.
- GvrDelegateProvider* delegate_provider = GvrDelegateProviderFactory::Create();
- if (delegate_provider)
- delegate_provider->SetDeviceId(GetId());
- return delegate_provider;
+ // GvrDelegateProviderFactory::Create() may return a different
+ // pointer each time. Do not cache it.
+ return GvrDelegateProviderFactory::Create();
}
void GvrDevice::OnDisplayConfigurationChanged(JNIEnv* env,
@@ -319,4 +273,85 @@ void GvrDevice::Activate(mojom::VRDisplayEventReason reason,
OnActivate(reason, std::move(on_handled));
}
+void GvrDevice::Init(base::OnceCallback<void(bool)> on_finished) {
+ VrModuleDelegate* module_delegate = VrModuleDelegate::Get();
+ if (!module_delegate) {
+ std::move(on_finished).Run(false);
+ return;
+ }
+ if (!module_delegate->ModuleInstalled()) {
+ module_delegate->InstallModule(
+ base::BindOnce(&GvrDevice::OnVrModuleInstalled, base::Unretained(this),
+ std::move(on_finished)));
+ return;
+ }
+ OnVrModuleInstalled(std::move(on_finished), true);
+}
+
+void GvrDevice::OnVrModuleInstalled(base::OnceCallback<void(bool)> on_finished,
+ bool success) {
+ if (!success) {
+ std::move(on_finished).Run(false);
+ return;
+ }
+ GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
+ if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice()) {
+ std::move(on_finished).Run(false);
+ return;
+ }
+ CreateNonPresentingContext();
+ std::move(on_finished).Run(non_presenting_context_.obj() != nullptr);
+}
+
+void GvrDevice::CreateNonPresentingContext() {
+ if (non_presenting_context_.obj())
+ return;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ non_presenting_context_.Reset(
+ Java_NonPresentingGvrContext_create(env, reinterpret_cast<jlong>(this)));
+ if (!non_presenting_context_.obj())
+ return;
+ jlong context = Java_NonPresentingGvrContext_getNativeGvrContext(
+ env, non_presenting_context_);
+ gvr_api_ = gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
+ SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId()));
+
+ if (paused_) {
+ PauseTracking();
+ } else {
+ ResumeTracking();
+ }
+}
+
+void GvrDevice::OnInitRequestSessionFinished(
+ mojom::XRRuntimeSessionOptionsPtr options,
+ mojom::XRRuntime::RequestSessionCallback callback,
+ bool success) {
+ if (!success) {
+ std::move(callback).Run(nullptr, nullptr);
+ return;
+ }
+
+ GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
+ if (!delegate_provider) {
+ std::move(callback).Run(nullptr, nullptr);
+ return;
+ }
+
+ if (!options->immersive) {
+ // TODO(https://crbug.com/695937): This should be NOTREACHED() once we no
+ // longer need the hacked GVR non-immersive mode. This should now only be
+ // hit if orientation devices are disabled by flag.
+ ReturnNonImmersiveSession(std::move(callback));
+ return;
+ }
+
+ // StartWebXRPresentation is async as we may trigger a DON (Device ON) flow
+ // that pauses Chrome.
+ delegate_provider->StartWebXRPresentation(
+ GetVRDisplayInfo(), std::move(options),
+ base::BindOnce(&GvrDevice::OnStartPresentResult,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
} // namespace device
diff --git a/chromium/device/vr/android/gvr/gvr_device.h b/chromium/device/vr/android/gvr/gvr_device.h
index 93388c05a79..552787c276c 100644
--- a/chromium/device/vr/android/gvr/gvr_device.h
+++ b/chromium/device/vr/android/gvr/gvr_device.h
@@ -42,7 +42,7 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase,
private:
// VRDeviceBase
void OnListeningForActivate(bool listening) override;
- void OnMagicWindowFrameDataRequest(
+ void OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) override;
void OnStartPresentResult(mojom::XRRuntime::RequestSessionCallback callback,
@@ -53,9 +53,17 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase,
void OnPresentingControllerMojoConnectionError();
void StopPresenting();
- void EnsureGvrReady();
GvrDelegateProvider* GetGvrDelegateProvider();
+ void Init(base::OnceCallback<void(bool)> on_finished);
+ void OnVrModuleInstalled(base::OnceCallback<void(bool)> on_finished,
+ bool success);
+ void CreateNonPresentingContext();
+ void OnInitRequestSessionFinished(
+ mojom::XRRuntimeSessionOptionsPtr options,
+ mojom::XRRuntime::RequestSessionCallback callback,
+ bool success);
+
base::android::ScopedJavaGlobalRef<jobject> non_presenting_context_;
std::unique_ptr<gvr::GvrApi> gvr_api_;
diff --git a/chromium/device/vr/android/gvr/vr_module_delegate.cc b/chromium/device/vr/android/gvr/vr_module_delegate.cc
new file mode 100644
index 00000000000..d20434701f8
--- /dev/null
+++ b/chromium/device/vr/android/gvr/vr_module_delegate.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 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 "device/vr/android/gvr/vr_module_delegate.h"
+
+namespace device {
+
+namespace {
+// Storing the global delegate in a raw pointer - as opposed to e.g. an
+// std::unique_ptr - to avoid adding a static initializer.
+VrModuleDelegate* g_vr_module_delegate = nullptr;
+} // namespace
+
+// static
+VrModuleDelegate* VrModuleDelegate::Get() {
+ return g_vr_module_delegate;
+}
+
+// static
+void VrModuleDelegate::Set(std::unique_ptr<VrModuleDelegate> delegate) {
+ if (g_vr_module_delegate) {
+ delete g_vr_module_delegate;
+ }
+ g_vr_module_delegate = delegate.release();
+}
+
+} // namespace device
diff --git a/chromium/device/vr/android/gvr/vr_module_delegate.h b/chromium/device/vr/android/gvr/vr_module_delegate.h
new file mode 100644
index 00000000000..9e6c204f3a8
--- /dev/null
+++ b/chromium/device/vr/android/gvr/vr_module_delegate.h
@@ -0,0 +1,38 @@
+// Copyright 2018 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.
+
+#ifndef DEVICE_VR_ANDROID_GVR_VR_MODULE_DELEGATE_H_
+#define DEVICE_VR_ANDROID_GVR_VR_MODULE_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "device/vr/vr_export.h"
+
+namespace device {
+
+// Delegates installation of the VR module.
+class DEVICE_VR_EXPORT VrModuleDelegate {
+ public:
+ // Returns the global module delegate.
+ static VrModuleDelegate* Get();
+ // Sets the global module delegate.
+ static void Set(std::unique_ptr<VrModuleDelegate> delegate);
+
+ VrModuleDelegate() = default;
+ virtual ~VrModuleDelegate() = default;
+ // Returns true if the VR module is installed.
+ virtual bool ModuleInstalled() = 0;
+ // Asynchronously requests to install the VR module. |on_finished| is called
+ // after the module install is completed. If |success| is false the module
+ // install failed.
+ virtual void InstallModule(
+ base::OnceCallback<void(bool success)> on_finished) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VrModuleDelegate);
+};
+
+} // namespace device
+
+#endif // DEVICE_VR_ANDROID_GVR_VR_MODULE_DELEGATE_H_
diff --git a/chromium/device/vr/oculus/oculus_device.cc b/chromium/device/vr/oculus/oculus_device.cc
index 8b8929f7b0c..2af79021205 100644
--- a/chromium/device/vr/oculus/oculus_device.cc
+++ b/chromium/device/vr/oculus/oculus_device.cc
@@ -242,7 +242,7 @@ void OculusDevice::StopOvrSession() {
}
}
-void OculusDevice::OnMagicWindowFrameDataRequest(
+void OculusDevice::OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
if (!session_) {
std::move(callback).Run(nullptr);
diff --git a/chromium/device/vr/oculus/oculus_device.h b/chromium/device/vr/oculus/oculus_device.h
index 95b514f4d00..b8861b15d41 100644
--- a/chromium/device/vr/oculus/oculus_device.h
+++ b/chromium/device/vr/oculus/oculus_device.h
@@ -31,7 +31,7 @@ class DEVICE_VR_EXPORT OculusDevice
void RequestSession(
mojom::XRRuntimeSessionOptionsPtr options,
mojom::XRRuntime::RequestSessionCallback callback) override;
- void OnMagicWindowFrameDataRequest(
+ void OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) override;
void OnRequestSessionResult(mojom::XRRuntime::RequestSessionCallback callback,
bool result,
diff --git a/chromium/device/vr/oculus/oculus_render_loop.cc b/chromium/device/vr/oculus/oculus_render_loop.cc
index 84564c261c3..73a2284f3b2 100644
--- a/chromium/device/vr/oculus/oculus_render_loop.cc
+++ b/chromium/device/vr/oculus/oculus_render_loop.cc
@@ -80,6 +80,15 @@ mojom::XRGamepadDataPtr OculusRenderLoop::GetNextGamepadData() {
return OculusGamepadHelper::GetGamepadData(session_);
}
+void OculusRenderLoop::GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_provider) {
+ // Environment integration is not supported. This call should not
+ // be made on this device.
+ mojo::ReportBadMessage("Environment integration is not supported.");
+ return;
+}
+
bool OculusRenderLoop::StartRuntime() {
if (!session_) {
ovrInitParams initParams = {ovrInit_RequestVersion | ovrInit_MixedRendering,
diff --git a/chromium/device/vr/oculus/oculus_render_loop.h b/chromium/device/vr/oculus/oculus_render_loop.h
index 7e2f41b7ff3..9cbddaa15d7 100644
--- a/chromium/device/vr/oculus/oculus_render_loop.h
+++ b/chromium/device/vr/oculus/oculus_render_loop.h
@@ -33,6 +33,9 @@ class OculusRenderLoop : public XRCompositorCommon {
// XRDeviceAbstraction:
mojom::XRFrameDataPtr GetNextFrameData() override;
mojom::XRGamepadDataPtr GetNextGamepadData() override;
+ void GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_provider) override;
bool StartRuntime() override;
void StopRuntime() override;
void OnSessionStart() override;
diff --git a/chromium/device/vr/openvr/openvr_device.cc b/chromium/device/vr/openvr/openvr_device.cc
index d3be3f9e1a6..6d0c39322cd 100644
--- a/chromium/device/vr/openvr/openvr_device.cc
+++ b/chromium/device/vr/openvr/openvr_device.cc
@@ -298,7 +298,7 @@ void OpenVRDevice::OnPresentingControllerMojoConnectionError() {
exclusive_controller_binding_.Close();
}
-void OpenVRDevice::OnMagicWindowFrameDataRequest(
+void OpenVRDevice::OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
if (!openvr_) {
std::move(callback).Run(nullptr);
diff --git a/chromium/device/vr/openvr/openvr_device.h b/chromium/device/vr/openvr/openvr_device.h
index 1360a8c97d3..3faed27fb4f 100644
--- a/chromium/device/vr/openvr/openvr_device.h
+++ b/chromium/device/vr/openvr/openvr_device.h
@@ -47,7 +47,7 @@ class DEVICE_VR_EXPORT OpenVRDevice
private:
// VRDeviceBase
- void OnMagicWindowFrameDataRequest(
+ void OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) override;
// XRSessionController
diff --git a/chromium/device/vr/openvr/openvr_render_loop.cc b/chromium/device/vr/openvr/openvr_render_loop.cc
index 5986403265e..1e7e744d129 100644
--- a/chromium/device/vr/openvr/openvr_render_loop.cc
+++ b/chromium/device/vr/openvr/openvr_render_loop.cc
@@ -141,18 +141,13 @@ void OpenVRRenderLoop::OnSessionStart() {
openvr_->GetCompositor()->SuspendRendering(false);
// Measure the VrViewerType we are presenting with.
- using ViewerMap = std::map<std::string, VrViewerType>;
- CR_DEFINE_STATIC_LOCAL(ViewerMap, viewer_types,
- ({
- {"Oculus Rift CV1", VrViewerType::OPENVR_RIFT_CV1},
- {"Vive MV", VrViewerType::OPENVR_VIVE},
- }));
- VrViewerType type = VrViewerType::OPENVR_UNKNOWN;
std::string model =
GetOpenVRString(openvr_->GetSystem(), vr::Prop_ModelNumber_String);
- auto it = viewer_types.find(model);
- if (it != viewer_types.end())
- type = it->second;
+ VrViewerType type = VrViewerType::OPENVR_UNKNOWN;
+ if (model == "Oculus Rift CV1")
+ type = VrViewerType::OPENVR_RIFT_CV1;
+ else if (model == "Vive MV")
+ type = VrViewerType::OPENVR_VIVE;
base::UmaHistogramSparse("VRViewerType", static_cast<int>(type));
}
@@ -200,6 +195,15 @@ mojom::XRFrameDataPtr OpenVRRenderLoop::GetNextFrameData() {
return frame_data;
}
+void OpenVRRenderLoop::GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_provider) {
+ // Environment integration is not supported. This call should not
+ // be made on this device.
+ mojo::ReportBadMessage("Environment integration is not supported.");
+ return;
+}
+
std::vector<mojom::XRInputSourceStatePtr> OpenVRRenderLoop::GetInputState(
vr::TrackedDevicePose_t* poses,
uint32_t count) {
diff --git a/chromium/device/vr/openvr/openvr_render_loop.h b/chromium/device/vr/openvr/openvr_render_loop.h
index 2fb39602f17..a4cc3f9189b 100644
--- a/chromium/device/vr/openvr/openvr_render_loop.h
+++ b/chromium/device/vr/openvr/openvr_render_loop.h
@@ -34,6 +34,9 @@ class OpenVRRenderLoop : public XRCompositorCommon {
// XRDeviceAbstraction:
mojom::XRFrameDataPtr GetNextFrameData() override;
mojom::XRGamepadDataPtr GetNextGamepadData() override;
+ void GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_provider) override;
bool StartRuntime() override;
void StopRuntime() override;
void OnSessionStart() override;
diff --git a/chromium/device/vr/orientation/orientation_device.cc b/chromium/device/vr/orientation/orientation_device.cc
index 0d7fb6947ba..9f040c516fd 100644
--- a/chromium/device/vr/orientation/orientation_device.cc
+++ b/chromium/device/vr/orientation/orientation_device.cc
@@ -147,7 +147,7 @@ void VROrientationDevice::RequestSession(
ReturnNonImmersiveSession(std::move(callback));
}
-void VROrientationDevice::OnMagicWindowFrameDataRequest(
+void VROrientationDevice::OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
mojom::VRPosePtr pose = mojom::VRPose::New();
pose->orientation.emplace(4);
diff --git a/chromium/device/vr/orientation/orientation_device.h b/chromium/device/vr/orientation/orientation_device.h
index d6f3c329142..f6e39daa704 100644
--- a/chromium/device/vr/orientation/orientation_device.h
+++ b/chromium/device/vr/orientation/orientation_device.h
@@ -48,7 +48,7 @@ class DEVICE_VR_EXPORT VROrientationDevice : public VRDeviceBase,
mojom::XRRuntime::RequestSessionCallback callback) override;
// VRDeviceBase
- void OnMagicWindowFrameDataRequest(
+ void OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) override;
// Indicates whether the device was able to connect to orientation events.
diff --git a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
index d4fc8cfcac4..ea6e47dab3c 100644
--- a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -42,9 +42,8 @@ class VROrientationDeviceProviderTest : public testing::Test {
service_manager::mojom::ConnectorRequest request;
connector_ = service_manager::Connector::Create(&request);
- service_manager::Connector::TestApi test_api(connector_.get());
- test_api.OverrideBinderForTesting(
- service_manager::Identity(mojom::kServiceName),
+ connector_->OverrideBinderForTesting(
+ service_manager::ServiceFilter::ByName(mojom::kServiceName),
mojom::SensorProvider::Name_,
base::BindRepeating(&FakeSensorProvider::Bind,
base::Unretained(fake_sensor_provider_.get())));
diff --git a/chromium/device/vr/orientation/orientation_device_unittest.cc b/chromium/device/vr/orientation/orientation_device_unittest.cc
index 9934679c10e..12f4f8f63b8 100644
--- a/chromium/device/vr/orientation/orientation_device_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_unittest.cc
@@ -134,7 +134,7 @@ class VROrientationDeviceTest : public testing::Test {
base::RunLoop loop;
- device_->OnMagicWindowFrameDataRequest(base::BindOnce(
+ device_->OnGetInlineFrameData(base::BindOnce(
[](base::OnceClosure quit_closure,
base::OnceCallback<void(mojom::VRPosePtr)> callback,
mojom::XRFrameDataPtr ptr) {
@@ -233,7 +233,7 @@ TEST_F(VROrientationDeviceTest, SensorIsAvailableTest) {
}
TEST_F(VROrientationDeviceTest, GetOrientationTest) {
- // Tests that OnMagicWindowFrameDataRequest returns a pose ptr without mishap.
+ // Tests that OnGetInlineFrameData returns a pose ptr without mishap.
InitializeDevice(FakeInitParams());
diff --git a/chromium/device/vr/public/mojom/isolated_xr_service.mojom b/chromium/device/vr/public/mojom/isolated_xr_service.mojom
index ca921e0d161..acb578ca21e 100644
--- a/chromium/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/chromium/device/vr/public/mojom/isolated_xr_service.mojom
@@ -41,7 +41,7 @@ interface XRRuntimeEventListener {
struct XRRuntimeSessionOptions {
bool immersive;
- bool provide_passthrough_camera;
+ bool environment_integration;
// The following options are used for permission requests.
// TODO(crbug.com/854655): remove these fields, and do permission checks in
@@ -81,6 +81,8 @@ interface XRRuntime {
EnsureInitialized() => ();
SetListeningForActivate(bool listen_for_activation);
+
+ SetInlinePosesEnabled(bool enable);
};
// Represents the state of a single button or trigger.
diff --git a/chromium/device/vr/public/mojom/vr_service.mojom b/chromium/device/vr/public/mojom/vr_service.mojom
index e752a0729b3..8c9f3f22c06 100644
--- a/chromium/device/vr/public/mojom/vr_service.mojom
+++ b/chromium/device/vr/public/mojom/vr_service.mojom
@@ -43,7 +43,7 @@ enum XRTargetRayMode {
struct XRSessionOptions {
bool immersive;
- bool provide_passthrough_camera;
+ bool environment_integration;
// A flag to indicate if there has been a user activation when the request
// session is made.
@@ -73,7 +73,6 @@ struct XRSession {
// info to more sensible places so that this doesn't need to be sent here.
VRDisplayInfo display_info;
XRPresentationConnection? submit_frame_sink;
- XREnvironmentIntegrationProvider? environment_provider;
};
// This structure contains the infomation and interfaces needed to create a two
@@ -165,11 +164,11 @@ struct VRDisplayCapabilities {
// Indicates whether the display can actively show imagery on a headset.
bool canPresent;
- // If true, this is an AR display that can provide a background image along
- // with each pose. Clients who want them should send a frame image request
- // via getFrameData instead of getPose.
- // TODO(https://crbug.com/836349): this may need to change.
- bool can_provide_pass_through_images;
+ // Whether the display gathers data about the environment (for AR like
+ // planes, point clouds, meshes, etc.). The backend will decide whether
+ // it needs to provide camera frames or not based on whether it is a
+ // see-through HMD or camera-based AR system.
+ bool canProvideEnvironmentIntegration;
};
// Information about the optical properties for an eye in a VRDisplay.
@@ -303,17 +302,6 @@ interface XRDevice {
ExitPresent();
};
-// Provides the necessary functionality for a WebXR session to get data for
-// drawing frames. The kind of data it gets depends on what kind of session was
-// requested.
-// This interface is hosted in the Browser process, but will move to a sandboxed
-// utility process on Windows. The render process communicates with it.
-interface XRFrameDataProvider {
- // frame_data is optional and will not be set if and only if the call fails
- // for some reason, such as device disconnection.
- GetFrameData() => (XRFrameData? frame_data);
-};
-
// Provides functionality for integrating environment information into an
// XRSession. For example, some AR sessions would implement hit test to allow
// developers to get the information about the world that its sensors supply.
@@ -335,6 +323,19 @@ interface XREnvironmentIntegrationProvider {
RequestHitTest(XRRay ray) => (array<XRHitResult>? results);
};
+// Provides the necessary functionality for a WebXR session to get data for
+// drawing frames. The kind of data it gets depends on what kind of session was
+// requested.
+// This interface is hosted in the Browser process, but will move to a sandboxed
+// utility process on Windows. The render process communicates with it.
+interface XRFrameDataProvider {
+ // frame_data is optional and will not be set if and only if the call fails
+ // for some reason, such as device disconnection.
+ GetFrameData() => (XRFrameData? frame_data);
+ GetEnvironmentIntegrationProvider(
+ associated XREnvironmentIntegrationProvider& environment_provider);
+};
+
// Provides the necessary functionality for sending frames to a headset.
// This interface is hosted in the Browser process, but will move to a sandboxed
// utility process on Windows. The render process communicates with it.
diff --git a/chromium/device/vr/vr_device_base.cc b/chromium/device/vr/vr_device_base.cc
index 615568424d6..603f2e26024 100644
--- a/chromium/device/vr/vr_device_base.cc
+++ b/chromium/device/vr/vr_device_base.cc
@@ -40,10 +40,6 @@ bool VRDeviceBase::HasExclusiveSession() {
return presenting_;
}
-void VRDeviceBase::SetMagicWindowEnabled(bool enabled) {
- magic_window_enabled_ = enabled;
-}
-
void VRDeviceBase::ListenToDeviceChanges(
mojom::XRRuntimeEventListenerAssociatedPtrInfo listener_info,
mojom::XRRuntime::ListenToDeviceChangesCallback callback) {
@@ -51,14 +47,14 @@ void VRDeviceBase::ListenToDeviceChanges(
std::move(callback).Run(display_info_.Clone());
}
-void VRDeviceBase::GetFrameData(
+void VRDeviceBase::GetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
- if (!magic_window_enabled_) {
+ if (!inline_poses_enabled_) {
std::move(callback).Run(nullptr);
return;
}
- OnMagicWindowFrameDataRequest(std::move(callback));
+ OnGetInlineFrameData(std::move(callback));
}
void VRDeviceBase::SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info) {
@@ -88,7 +84,7 @@ bool VRDeviceBase::ShouldPauseTrackingWhenFrameDataRestricted() {
void VRDeviceBase::OnListeningForActivate(bool listening) {}
-void VRDeviceBase::OnMagicWindowFrameDataRequest(
+void VRDeviceBase::OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback) {
std::move(callback).Run(nullptr);
}
@@ -101,6 +97,10 @@ void VRDeviceBase::EnsureInitialized(EnsureInitializedCallback callback) {
std::move(callback).Run();
}
+void VRDeviceBase::SetInlinePosesEnabled(bool enable) {
+ inline_poses_enabled_ = enable;
+}
+
void VRDeviceBase::RequestHitTest(
mojom::XRRayPtr ray,
mojom::XREnvironmentIntegrationProvider::RequestHitTestCallback callback) {
@@ -113,16 +113,11 @@ void VRDeviceBase::ReturnNonImmersiveSession(
mojom::XRFrameDataProviderPtr data_provider;
mojom::XREnvironmentIntegrationProviderPtr environment_provider;
mojom::XRSessionControllerPtr controller;
- magic_window_sessions_.push_back(
- std::make_unique<VRDisplayImpl>(this, mojo::MakeRequest(&data_provider),
- mojo::MakeRequest(&environment_provider),
- mojo::MakeRequest(&controller)));
+ magic_window_sessions_.push_back(std::make_unique<VRDisplayImpl>(
+ this, mojo::MakeRequest(&data_provider), mojo::MakeRequest(&controller)));
auto session = mojom::XRSession::New();
session->data_provider = data_provider.PassInterface();
- // TODO(http://crbug.com/876135) Not all sessions want the environment
- // provider. This should be refactored to only be passed when requested.
- session->environment_provider = environment_provider.PassInterface();
if (display_info_) {
session->display_info = display_info_.Clone();
}
diff --git a/chromium/device/vr/vr_device_base.h b/chromium/device/vr/vr_device_base.h
index be6daa5a66e..ef9bf20b5d3 100644
--- a/chromium/device/vr/vr_device_base.h
+++ b/chromium/device/vr/vr_device_base.h
@@ -31,8 +31,10 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
mojom::XRRuntime::ListenToDeviceChangesCallback callback) final;
void SetListeningForActivate(bool is_listening) override;
void EnsureInitialized(EnsureInitializedCallback callback) override;
+ void SetInlinePosesEnabled(bool enable) override;
- void GetFrameData(mojom::XRFrameDataProvider::GetFrameDataCallback callback);
+ void GetInlineFrameData(
+ mojom::XRFrameDataProvider::GetFrameDataCallback callback);
virtual void RequestHitTest(
mojom::XRRayPtr ray,
@@ -52,7 +54,6 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
// GVR delegate.
virtual void PauseTracking();
virtual void ResumeTracking();
- void SetMagicWindowEnabled(bool enabled);
mojom::VRDisplayInfoPtr GetVRDisplayInfo();
@@ -84,7 +85,7 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
private:
// TODO(https://crbug.com/842227): Rename methods to HandleOnXXX
virtual void OnListeningForActivate(bool listening);
- virtual void OnMagicWindowFrameDataRequest(
+ virtual void OnGetInlineFrameData(
mojom::XRFrameDataProvider::GetFrameDataCallback callback);
mojom::XRRuntimeEventListenerAssociatedPtr listener_;
@@ -92,7 +93,7 @@ class DEVICE_VR_EXPORT VRDeviceBase : public mojom::XRRuntime {
bool presenting_ = false;
device::mojom::XRDeviceId id_;
- bool magic_window_enabled_ = true;
+ bool inline_poses_enabled_ = true;
mojo::Binding<mojom::XRRuntime> runtime_binding_;
diff --git a/chromium/device/vr/vr_device_base_unittest.cc b/chromium/device/vr/vr_device_base_unittest.cc
index 952ae70b00d..666f0f46553 100644
--- a/chromium/device/vr/vr_device_base_unittest.cc
+++ b/chromium/device/vr/vr_device_base_unittest.cc
@@ -160,10 +160,10 @@ TEST_F(VRDeviceTest, NoMagicWindowPosesWhileBrowsing) {
std::make_unique<FakeVRDevice>(static_cast<device::mojom::XRDeviceId>(1));
device->SetPose(mojom::VRPose::New());
- device->GetFrameData(base::BindOnce(
+ device->GetInlineFrameData(base::BindOnce(
[](device::mojom::XRFrameDataPtr data) { EXPECT_TRUE(data); }));
- device->SetMagicWindowEnabled(false);
- device->GetFrameData(base::BindOnce(
+ device->SetInlinePosesEnabled(false);
+ device->GetInlineFrameData(base::BindOnce(
[](device::mojom::XRFrameDataPtr data) { EXPECT_FALSE(data); }));
}
diff --git a/chromium/device/vr/vr_display_impl.cc b/chromium/device/vr/vr_display_impl.cc
index ce0c958e77e..2deff0c7914 100644
--- a/chromium/device/vr/vr_display_impl.cc
+++ b/chromium/device/vr/vr_display_impl.cc
@@ -18,10 +18,9 @@ namespace device {
VRDisplayImpl::VRDisplayImpl(
VRDeviceBase* device,
mojom::XRFrameDataProviderRequest magic_window_request,
- mojom::XREnvironmentIntegrationProviderRequest environment_request,
mojom::XRSessionControllerRequest session_request)
: magic_window_binding_(this, std::move(magic_window_request)),
- environment_binding_(this, std::move(environment_request)),
+ environment_binding_(this),
session_controller_binding_(this, std::move(session_request)),
device_(device) {
// Unretained is safe because the binding will close when we are destroyed,
@@ -40,7 +39,21 @@ void VRDisplayImpl::GetFrameData(
return;
}
- device_->GetFrameData(std::move(callback));
+ device_->GetInlineFrameData(std::move(callback));
+}
+
+void VRDisplayImpl::GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_request) {
+ if (!device_->GetVRDisplayInfo()
+ ->capabilities->canProvideEnvironmentIntegration) {
+ // Environment integration is not supported. This call should not
+ // be made on this device.
+ mojo::ReportBadMessage("Environment integration is not supported.");
+ return;
+ }
+
+ environment_binding_.Bind(std::move(environment_request));
}
void VRDisplayImpl::UpdateSessionGeometry(const gfx::Size& frame_size,
diff --git a/chromium/device/vr/vr_display_impl.h b/chromium/device/vr/vr_display_impl.h
index 219c9c8c611..72c7a774b3f 100644
--- a/chromium/device/vr/vr_display_impl.h
+++ b/chromium/device/vr/vr_display_impl.h
@@ -13,6 +13,7 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device.h"
#include "device/vr/vr_export.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "ui/display/display.h"
@@ -31,10 +32,12 @@ class DEVICE_VR_EXPORT VRDisplayImpl
public:
VRDisplayImpl(VRDeviceBase* device,
mojom::XRFrameDataProviderRequest,
- mojom::XREnvironmentIntegrationProviderRequest,
mojom::XRSessionControllerRequest);
~VRDisplayImpl() override;
+ void GetEnvironmentIntegrationProvider(
+ mojom::XREnvironmentIntegrationProviderAssociatedRequest
+ environment_provider) override;
gfx::Size sessionFrameSize() { return session_frame_size_; };
display::Display::Rotation sessionRotation() { return session_rotation_; };
@@ -55,7 +58,8 @@ class DEVICE_VR_EXPORT VRDisplayImpl
void OnMojoConnectionError();
mojo::Binding<mojom::XRFrameDataProvider> magic_window_binding_;
- mojo::Binding<mojom::XREnvironmentIntegrationProvider> environment_binding_;
+ mojo::AssociatedBinding<mojom::XREnvironmentIntegrationProvider>
+ environment_binding_;
mojo::Binding<mojom::XRSessionController> session_controller_binding_;
device::VRDeviceBase* device_;
bool restrict_frame_data_ = true;
diff --git a/chromium/device/vr/vr_display_impl_unittest.cc b/chromium/device/vr/vr_display_impl_unittest.cc
index fc8ad17219b..1e8ebf4d1ab 100644
--- a/chromium/device/vr/vr_display_impl_unittest.cc
+++ b/chromium/device/vr/vr_display_impl_unittest.cc
@@ -33,10 +33,8 @@ class VRDisplayImplTest : public testing::Test {
std::unique_ptr<VRDisplayImpl> MakeDisplay(
mojom::XRSessionControllerPtr* controller) {
mojom::XRFrameDataProviderPtr data_provider;
- mojom::XREnvironmentIntegrationProviderPtr environment_provider;
auto display = std::make_unique<VRDisplayImpl>(
device(), mojo::MakeRequest(&data_provider),
- mojo::MakeRequest(&environment_provider),
mojo::MakeRequest(controller));
static_cast<mojom::XRSessionController*>(display.get())
->SetFrameDataRestricted(true);