summaryrefslogtreecommitdiff
path: root/chromium/device
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-24 12:15:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:30:04 +0000
commitb014812705fc80bff0a5c120dfcef88f349816dc (patch)
tree25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/device
parent9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff)
downloadqtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/device')
-rw-r--r--chromium/device/BUILD.gn27
-rw-r--r--chromium/device/OWNERS1
-rw-r--r--chromium/device/base/features.cc2
-rw-r--r--chromium/device/base/features.h1
-rw-r--r--chromium/device/base/synchronization/one_writer_seqlock.cc11
-rw-r--r--chromium/device/base/synchronization/one_writer_seqlock.h1
-rw-r--r--chromium/device/base/synchronization/shared_memory_seqlock_buffer.h2
-rw-r--r--chromium/device/bluetooth/BUILD.gn7
-rw-r--r--chromium/device/bluetooth/DEPS1
-rw-r--r--chromium/device/bluetooth/OWNERS1
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter.cc2
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter.h20
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_android.cc15
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_android.h6
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.h7
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_mac.mm21
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_stub.cc2
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_unittest.cc34
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_win.cc56
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_win.h12
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_win_unittest.cc15
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.cc399
-rw-r--r--chromium/device/bluetooth/bluetooth_adapter_winrt.h123
-rw-r--r--chromium/device/bluetooth/bluetooth_device_win.h1
-rw-r--r--chromium/device/bluetooth/bluetooth_device_winrt.cc168
-rw-r--r--chromium/device/bluetooth/bluetooth_device_winrt.h77
-rw-r--r--chromium/device/bluetooth/bluetooth_socket_net.cc1
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc149
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h47
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc39
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_gatt_service_bluez.cc3
-rw-r--r--chromium/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc1
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc64
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_adapter_cast.h13
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_device_cast.cc49
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_device_cast.h14
-rw-r--r--chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc1
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc47
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_adapter_client.h17
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_device_client.cc1
-rw-r--r--chromium/device/bluetooth/dbus/bluetooth_device_client.h3
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc39
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h14
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc4
-rw-r--r--chromium/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc2
-rw-r--r--chromium/device/bluetooth/public/mojom/BUILD.gn2
-rw-r--r--chromium/device/bluetooth/strings/OWNERS1
-rw-r--r--chromium/device/fido/BUILD.gn47
-rw-r--r--chromium/device/fido/attested_credential_data.cc28
-rw-r--r--chromium/device/fido/attested_credential_data.h2
-rw-r--r--chromium/device/fido/authenticator_data.cc10
-rw-r--r--chromium/device/fido/authenticator_get_assertion_response.cc12
-rw-r--r--chromium/device/fido/authenticator_make_credential_response.cc4
-rw-r--r--chromium/device/fido/ctap_get_assertion_request.cc6
-rw-r--r--chromium/device/fido/ctap_get_assertion_request.h9
-rw-r--r--chromium/device/fido/ctap_make_credential_request.h4
-rw-r--r--chromium/device/fido/ctap_register_operation.cc46
-rw-r--r--chromium/device/fido/ctap_register_operation.h56
-rw-r--r--chromium/device/fido/ctap_request_unittest.cc34
-rw-r--r--chromium/device/fido/ctap_response_unittest.cc580
-rw-r--r--chromium/device/fido/device_operation.h46
-rw-r--r--chromium/device/fido/ec_public_key.cc39
-rw-r--r--chromium/device/fido/ec_public_key.h5
-rw-r--r--chromium/device/fido/fake_fido_discovery.cc12
-rw-r--r--chromium/device/fido/fake_fido_discovery.h5
-rw-r--r--chromium/device/fido/fake_hid_impl_for_testing.cc2
-rw-r--r--chromium/device/fido/fido_attestation_statement.cc5
-rw-r--r--chromium/device/fido/fido_authenticator.h53
-rw-r--r--chromium/device/fido/fido_ble_connection_unittest.cc187
-rw-r--r--chromium/device/fido/fido_ble_device.cc30
-rw-r--r--chromium/device/fido/fido_ble_device.h7
-rw-r--r--chromium/device/fido/fido_ble_device_unittest.cc26
-rw-r--r--chromium/device/fido/fido_ble_discovery.cc93
-rw-r--r--chromium/device/fido/fido_ble_discovery.h22
-rw-r--r--chromium/device/fido/fido_ble_discovery_base.cc94
-rw-r--r--chromium/device/fido/fido_ble_discovery_base.h56
-rw-r--r--chromium/device/fido/fido_ble_frames.cc4
-rw-r--r--chromium/device/fido/fido_ble_uuids.cc8
-rw-r--r--chromium/device/fido/fido_ble_uuids.h3
-rw-r--r--chromium/device/fido/fido_cable_device.cc178
-rw-r--r--chromium/device/fido/fido_cable_device.h78
-rw-r--r--chromium/device/fido/fido_cable_device_unittest.cc360
-rw-r--r--chromium/device/fido/fido_cable_discovery.cc286
-rw-r--r--chromium/device/fido/fido_cable_discovery.h100
-rw-r--r--chromium/device/fido/fido_cable_discovery_unittest.cc390
-rw-r--r--chromium/device/fido/fido_constants.cc14
-rw-r--r--chromium/device/fido/fido_constants.h31
-rw-r--r--chromium/device/fido/fido_device.h2
-rw-r--r--chromium/device/fido/fido_device_authenticator.cc56
-rw-r--r--chromium/device/fido/fido_device_authenticator.h63
-rw-r--r--chromium/device/fido/fido_discovery.cc17
-rw-r--r--chromium/device/fido/fido_hid_device.cc40
-rw-r--r--chromium/device/fido/fido_hid_device.h20
-rw-r--r--chromium/device/fido/fido_hid_device_unittest.cc170
-rw-r--r--chromium/device/fido/fido_hid_message.cc35
-rw-r--r--chromium/device/fido/fido_hid_message.h11
-rw-r--r--chromium/device/fido/fido_hid_message_unittest.cc2
-rw-r--r--chromium/device/fido/fido_parsing_utils.cc (renamed from chromium/device/fido/u2f_parsing_utils.cc)13
-rw-r--r--chromium/device/fido/fido_parsing_utils.h (renamed from chromium/device/fido/u2f_parsing_utils.h)29
-rw-r--r--chromium/device/fido/fido_parsing_utils_unittest.cc (renamed from chromium/device/fido/u2f_parsing_utils_unittest.cc)72
-rw-r--r--chromium/device/fido/fido_request_handler.h19
-rw-r--r--chromium/device/fido/fido_request_handler_base.cc65
-rw-r--r--chromium/device/fido/fido_request_handler_base.h32
-rw-r--r--chromium/device/fido/fido_request_handler_unittest.cc29
-rw-r--r--chromium/device/fido/fido_test_data.h329
-rw-r--r--chromium/device/fido/fido_transport_protocol.h2
-rw-r--r--chromium/device/fido/get_assertion_handler_unittest.cc8
-rw-r--r--chromium/device/fido/get_assertion_request_handler.cc28
-rw-r--r--chromium/device/fido/get_assertion_request_handler.h11
-rw-r--r--chromium/device/fido/get_assertion_task.h4
-rw-r--r--chromium/device/fido/get_assertion_task_unittest.cc18
-rw-r--r--chromium/device/fido/mac/authenticator.h68
-rw-r--r--chromium/device/fido/mac/authenticator.mm84
-rw-r--r--chromium/device/fido/mac/get_assertion_operation.h52
-rw-r--r--chromium/device/fido/mac/get_assertion_operation.mm157
-rw-r--r--chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm82
-rw-r--r--chromium/device/fido/mac/keychain.h62
-rw-r--r--chromium/device/fido/mac/keychain.mm50
-rw-r--r--chromium/device/fido/mac/make_credential_operation.h67
-rw-r--r--chromium/device/fido/mac/make_credential_operation.mm192
-rw-r--r--chromium/device/fido/mac/make_credential_operation_unittest_mac.mm64
-rw-r--r--chromium/device/fido/mac/operation.h31
-rw-r--r--chromium/device/fido/mac/operation_base.h101
-rw-r--r--chromium/device/fido/mac/touch_id_context.h59
-rw-r--r--chromium/device/fido/mac/touch_id_context.mm54
-rw-r--r--chromium/device/fido/mac/util.h51
-rw-r--r--chromium/device/fido/mac/util.mm142
-rw-r--r--chromium/device/fido/make_credential_handler_unittest.cc7
-rw-r--r--chromium/device/fido/make_credential_request_handler.cc18
-rw-r--r--chromium/device/fido/make_credential_request_handler.h10
-rw-r--r--chromium/device/fido/make_credential_task.cc27
-rw-r--r--chromium/device/fido/make_credential_task.h11
-rw-r--r--chromium/device/fido/make_credential_task_unittest.cc12
-rw-r--r--chromium/device/fido/mock_fido_device.cc20
-rw-r--r--chromium/device/fido/mock_fido_device.h2
-rw-r--r--chromium/device/fido/public_key_credential_descriptor.cc11
-rw-r--r--chromium/device/fido/public_key_credential_descriptor.h7
-rw-r--r--chromium/device/fido/public_key_credential_params.cc2
-rw-r--r--chromium/device/fido/response_data.cc8
-rw-r--r--chromium/device/fido/scoped_virtual_fido_device.cc3
-rw-r--r--chromium/device/fido/test_callback_receiver.h13
-rw-r--r--chromium/device/fido/test_callback_receiver_unittest.cc45
-rw-r--r--chromium/device/fido/u2f_command_constructor.cc130
-rw-r--r--chromium/device/fido/u2f_command_constructor.h79
-rw-r--r--chromium/device/fido/u2f_command_constructor_unittest.cc240
-rw-r--r--chromium/device/fido/u2f_register.cc3
-rw-r--r--chromium/device/fido/u2f_register_unittest.cc391
-rw-r--r--chromium/device/fido/u2f_request.cc90
-rw-r--r--chromium/device/fido/u2f_request.h12
-rw-r--r--chromium/device/fido/u2f_request_unittest.cc46
-rw-r--r--chromium/device/fido/u2f_sign.cc3
-rw-r--r--chromium/device/fido/u2f_sign.h13
-rw-r--r--chromium/device/fido/u2f_sign_unittest.cc181
-rw-r--r--chromium/device/fido/virtual_fido_device.cc269
-rw-r--r--chromium/device/fido/virtual_fido_device.h42
-rw-r--r--chromium/device/fido/virtual_u2f_device.cc261
-rw-r--r--chromium/device/fido/virtual_u2f_device.h51
-rw-r--r--chromium/device/gamepad/gamepad_platform_data_fetcher_win.h1
-rw-r--r--chromium/device/geolocation/geolocation_provider_impl_unittest.cc3
-rw-r--r--chromium/device/media_transfer_protocol/BUILD.gn43
-rw-r--r--chromium/device/media_transfer_protocol/DEPS6
-rw-r--r--chromium/device/media_transfer_protocol/OWNERS4
-rw-r--r--chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc554
-rw-r--r--chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h220
-rw-r--r--chromium/device/media_transfer_protocol/media_transfer_protocol_manager.cc707
-rw-r--r--chromium/device/media_transfer_protocol/media_transfer_protocol_manager.h197
-rw-r--r--chromium/device/media_transfer_protocol/public/mojom/BUILD.gn12
-rw-r--r--chromium/device/media_transfer_protocol/public/mojom/OWNERS2
-rw-r--r--chromium/device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom33
-rw-r--r--chromium/device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom25
-rw-r--r--chromium/device/serial/BUILD.gn8
-rw-r--r--chromium/device/serial/serial_device_enumerator_unittest.cc23
-rw-r--r--chromium/device/serial/serial_io_handler_win.cc6
-rw-r--r--chromium/device/usb/mock_usb_device.h2
-rw-r--r--chromium/device/usb/mojo/BUILD.gn1
-rw-r--r--chromium/device/usb/mojo/DEPS3
-rw-r--r--chromium/device/usb/mojo/device_manager_impl_unittest.cc6
-rw-r--r--chromium/device/usb/public/mojom/BUILD.gn1
-rw-r--r--chromium/device/usb/usb_device_handle_unittest.cc1
-rw-r--r--chromium/device/vr/BUILD.gn11
-rw-r--r--chromium/device/vr/android/arcore/arcore_device_provider_factory.cc33
-rw-r--r--chromium/device/vr/android/arcore/arcore_device_provider_factory.h34
-rw-r--r--chromium/device/vr/android/gvr/gvr_delegate_provider_factory.cc15
-rw-r--r--chromium/device/vr/android/gvr/gvr_delegate_provider_factory.h12
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.cc9
-rw-r--r--chromium/device/vr/android/gvr/gvr_device.h3
-rw-r--r--chromium/device/vr/buildflags/BUILD.gn1
-rw-r--r--chromium/device/vr/buildflags/buildflags.gni14
-rw-r--r--chromium/device/vr/oculus/oculus_device.cc2
-rw-r--r--chromium/device/vr/oculus/oculus_device.h1
-rw-r--r--chromium/device/vr/oculus/oculus_render_loop.cc4
-rw-r--r--chromium/device/vr/openvr/openvr_device.cc2
-rw-r--r--chromium/device/vr/openvr/openvr_device.h1
-rw-r--r--chromium/device/vr/openvr/openvr_render_loop.cc4
-rw-r--r--chromium/device/vr/orientation/orientation_device.cc6
-rw-r--r--chromium/device/vr/orientation/orientation_device.h14
-rw-r--r--chromium/device/vr/orientation/orientation_device_provider_unittest.cc7
-rw-r--r--chromium/device/vr/orientation/orientation_device_unittest.cc6
-rw-r--r--chromium/device/vr/public/mojom/BUILD.gn1
-rw-r--r--chromium/device/vr/public/mojom/vr_service.mojom47
-rw-r--r--chromium/device/vr/vr_device.h22
-rw-r--r--chromium/device/vr/vr_device_base.cc81
-rw-r--r--chromium/device/vr/vr_device_base.h37
-rw-r--r--chromium/device/vr/vr_device_base_unittest.cc81
-rw-r--r--chromium/device/vr/vr_display_impl.cc77
-rw-r--r--chromium/device/vr/vr_display_impl.h20
-rw-r--r--chromium/device/vr/vr_display_impl_unittest.cc48
207 files changed, 7124 insertions, 4220 deletions
diff --git a/chromium/device/BUILD.gn b/chromium/device/BUILD.gn
index 6982c5b52fa..e0df5c725c0 100644
--- a/chromium/device/BUILD.gn
+++ b/chromium/device/BUILD.gn
@@ -70,15 +70,20 @@ test("device_unittests") {
"fido/fido_ble_connection_unittest.cc",
"fido/fido_ble_device_unittest.cc",
"fido/fido_ble_frames_unittest.cc",
+ "fido/fido_cable_device_unittest.cc",
+ "fido/fido_cable_discovery_unittest.cc",
"fido/fido_discovery_unittest.cc",
"fido/fido_hid_message_unittest.cc",
+ "fido/fido_parsing_utils_unittest.cc",
"fido/fido_request_handler_unittest.cc",
"fido/get_assertion_handler_unittest.cc",
"fido/get_assertion_task_unittest.cc",
+ "fido/mac/get_assertion_operation_unittest_mac.mm",
+ "fido/mac/make_credential_operation_unittest_mac.mm",
"fido/make_credential_handler_unittest.cc",
"fido/make_credential_task_unittest.cc",
"fido/test_callback_receiver_unittest.cc",
- "fido/u2f_parsing_utils_unittest.cc",
+ "fido/u2f_command_constructor_unittest.cc",
"fido/u2f_register_unittest.cc",
"fido/u2f_request_unittest.cc",
"fido/u2f_sign_unittest.cc",
@@ -108,7 +113,6 @@ test("device_unittests") {
"//device/gamepad/public/mojom",
"//device/gamepad/public/mojom:gamepad_mojom_traits_test",
"//device/geolocation:unittests",
- "//mojo/common",
"//mojo/edk",
"//mojo/public/cpp/bindings",
"//net",
@@ -137,8 +141,11 @@ test("device_unittests") {
# Serial is supported in below platforms. See //device/servial/BUILD.gn
if (is_win || is_linux || is_mac) {
- sources += [ "serial/serial_io_handler_posix_unittest.cc" ]
+ sources += [ "serial/serial_device_enumerator_unittest.cc" ]
deps += [ "//device/serial" ]
+ if (is_linux || is_mac) {
+ sources += [ "serial/serial_io_handler_posix_unittest.cc" ]
+ }
}
}
@@ -241,6 +248,7 @@ test("device_unittests") {
deps += [
"//chromecast/device/bluetooth:util",
"//chromecast/device/bluetooth/le",
+ "//chromecast/device/bluetooth/le:test_support",
"//chromecast/device/bluetooth/shlib:mock_shlib",
]
} else {
@@ -275,10 +283,14 @@ test("device_unittests") {
"bluetooth/bluetooth_classic_win_fake.h",
"bluetooth/bluetooth_low_energy_win_fake.cc",
"bluetooth/bluetooth_low_energy_win_fake.h",
+ "bluetooth/test/fake_bluetooth_adapter_winrt.cc",
+ "bluetooth/test/fake_bluetooth_adapter_winrt.h",
+ "bluetooth/test/fake_device_information_winrt.cc",
+ "bluetooth/test/fake_device_information_winrt.h",
]
}
- if (enable_vr && is_android) {
+ if (enable_vr) {
sources += [
"vr/orientation/orientation_device_provider_unittest.cc",
"vr/orientation/orientation_device_unittest.cc",
@@ -286,10 +298,15 @@ test("device_unittests") {
"vr/vr_display_impl_unittest.cc",
]
+ if (is_android) {
+ deps += [ "//device/vr:java" ]
+ }
+
+ defines = [ "DEVICE_VR_IMPLEMENTATION" ]
+
deps += [
"//device/vr",
"//device/vr:fakes",
- "//device/vr:java",
"//device/vr/public/mojom",
"//services/device/public/cpp/generic_sensor",
"//ui/display",
diff --git a/chromium/device/OWNERS b/chromium/device/OWNERS
index d3db08f5d0a..2d212568dac 100644
--- a/chromium/device/OWNERS
+++ b/chromium/device/OWNERS
@@ -1,7 +1,6 @@
reillyg@chromium.org
rockot@chromium.org
-per-file *.gyp*=*
per-file BUILD.gn=*
# TEAM: device-dev@chromium.org
diff --git a/chromium/device/base/features.cc b/chromium/device/base/features.cc
index 0cb9b248adb..b38d28dbae4 100644
--- a/chromium/device/base/features.cc
+++ b/chromium/device/base/features.cc
@@ -11,6 +11,8 @@ namespace device {
#if defined(OS_WIN)
const base::Feature kNewUsbBackend{"NewUsbBackend",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kNewBLEWinImplementation{"NewBLEWinImplementation",
+ base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_WIN)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
diff --git a/chromium/device/base/features.h b/chromium/device/base/features.h
index 062f03f2494..c25697a021e 100644
--- a/chromium/device/base/features.h
+++ b/chromium/device/base/features.h
@@ -13,6 +13,7 @@ namespace device {
#if defined(OS_WIN)
DEVICE_BASE_EXPORT extern const base::Feature kNewUsbBackend;
+DEVICE_BASE_EXPORT extern const base::Feature kNewBLEWinImplementation;
#endif // defined(OS_WIN)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
diff --git a/chromium/device/base/synchronization/one_writer_seqlock.cc b/chromium/device/base/synchronization/one_writer_seqlock.cc
index b0eb3810dd4..7b855cfd1cb 100644
--- a/chromium/device/base/synchronization/one_writer_seqlock.cc
+++ b/chromium/device/base/synchronization/one_writer_seqlock.cc
@@ -24,17 +24,6 @@ base::subtle::Atomic32 OneWriterSeqLock::ReadBegin() const {
return version;
}
-void OneWriterSeqLock::TryRead(bool* can_read,
- base::subtle::Atomic32* version) const {
- DCHECK(can_read);
- DCHECK(version);
-
- *version = base::subtle::NoBarrier_Load(&sequence_);
- // If the counter is even, then the associated data might be in a
- // consistent state, so we can try to read.
- *can_read = (*version & 1) == 0;
-}
-
bool OneWriterSeqLock::ReadRetry(base::subtle::Atomic32 version) const {
// If the sequence number was updated then a read should be re-attempted.
// -- Load fence, read membarrier
diff --git a/chromium/device/base/synchronization/one_writer_seqlock.h b/chromium/device/base/synchronization/one_writer_seqlock.h
index 7be84056015..867fb82ba7a 100644
--- a/chromium/device/base/synchronization/one_writer_seqlock.h
+++ b/chromium/device/base/synchronization/one_writer_seqlock.h
@@ -32,7 +32,6 @@ class OneWriterSeqLock {
public:
OneWriterSeqLock();
base::subtle::Atomic32 ReadBegin() const;
- void TryRead(bool* can_read, base::subtle::Atomic32* version) const;
bool ReadRetry(base::subtle::Atomic32 version) const;
void WriteBegin();
void WriteEnd();
diff --git a/chromium/device/base/synchronization/shared_memory_seqlock_buffer.h b/chromium/device/base/synchronization/shared_memory_seqlock_buffer.h
index 1ad5a8a6a60..4835b097bc1 100644
--- a/chromium/device/base/synchronization/shared_memory_seqlock_buffer.h
+++ b/chromium/device/base/synchronization/shared_memory_seqlock_buffer.h
@@ -21,8 +21,6 @@ namespace device {
template <class Data>
class SharedMemorySeqLockBuffer {
public:
- SharedMemorySeqLockBuffer() {}
- explicit SharedMemorySeqLockBuffer(const Data& data) : data(data) {}
OneWriterSeqLock seqlock;
Data data;
};
diff --git a/chromium/device/bluetooth/BUILD.gn b/chromium/device/bluetooth/BUILD.gn
index 5cb4e7c2791..56b36d78949 100644
--- a/chromium/device/bluetooth/BUILD.gn
+++ b/chromium/device/bluetooth/BUILD.gn
@@ -237,6 +237,13 @@ component("bluetooth") {
}
if (is_win) {
+ sources += [
+ "bluetooth_adapter_winrt.cc",
+ "bluetooth_adapter_winrt.h",
+ "bluetooth_device_winrt.cc",
+ "bluetooth_device_winrt.h",
+ ]
+
libs = [
# Bthprops must be listed before BluetoothApis or else delay loading
# crashes.
diff --git a/chromium/device/bluetooth/DEPS b/chromium/device/bluetooth/DEPS
index d098881abd8..1eab7930bbc 100644
--- a/chromium/device/bluetooth/DEPS
+++ b/chromium/device/bluetooth/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+chromecast/device/bluetooth",
+ "+chromecast/public/bluetooth",
"+chromeos/dbus",
"+crypto",
"+dbus",
diff --git a/chromium/device/bluetooth/OWNERS b/chromium/device/bluetooth/OWNERS
index 7e02776acd4..8ac8597828e 100644
--- a/chromium/device/bluetooth/OWNERS
+++ b/chromium/device/bluetooth/OWNERS
@@ -3,7 +3,6 @@ ortuno@chromium.org
# For changes related to Chrome OS.
rkc@chromium.org
-per-file *.gyp*=*
per-file BUILD.gn=*
# TEAM: web-bluetooth@chromium.org
diff --git a/chromium/device/bluetooth/bluetooth_adapter.cc b/chromium/device/bluetooth/bluetooth_adapter.cc
index 092b3adca7f..64fd5c8fe4b 100644
--- a/chromium/device/bluetooth/bluetooth_adapter.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter.cc
@@ -28,7 +28,7 @@ BluetoothAdapter::ServiceOptions::~ServiceOptions() = default;
!defined(OS_WIN) && !defined(OS_LINUX)
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
+ InitCallback init_callback) {
return base::WeakPtr<BluetoothAdapter>();
}
#endif // !defined(OS_CHROMEOS) && !defined(OS_WIN) && !defined(OS_MACOSX)
diff --git a/chromium/device/bluetooth/bluetooth_adapter.h b/chromium/device/bluetooth/bluetooth_adapter.h
index 0923745b065..389dae23bf2 100644
--- a/chromium/device/bluetooth/bluetooth_adapter.h
+++ b/chromium/device/bluetooth/bluetooth_adapter.h
@@ -130,6 +130,14 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
virtual void DevicePairedChanged(BluetoothAdapter* adapter,
BluetoothDevice* device,
bool new_paired_status) {}
+
+ // This function is implemented for ChromeOS only.
+ // Called when the MTU |mtu| (Bluetooth Spec Vol 3, Part F, 3.4.2) used in
+ // ATT communication with device |device| known to the adapter |adapter|
+ // changed.
+ virtual void DeviceMTUChanged(BluetoothAdapter* adapter,
+ BluetoothDevice* device,
+ uint16_t mtu) {}
#endif
// Called when the device |device| is removed from the adapter |adapter|,
@@ -271,7 +279,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
// The InitCallback is used to trigger a callback after asynchronous
// initialization, if initialization is asynchronous on the platform.
- using InitCallback = base::Callback<void()>;
+ using InitCallback = base::OnceClosure;
using DiscoverySessionCallback =
base::Callback<void(std::unique_ptr<BluetoothDiscoverySession>)>;
@@ -294,7 +302,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
// caller is expected to call |AddRef()| on the returned pointer, typically by
// storing it into a |scoped_refptr|.
static base::WeakPtr<BluetoothAdapter> CreateAdapter(
- const InitCallback& init_callback);
+ InitCallback init_callback);
// Returns a weak pointer to an existing adapter for testing purposes only.
base::WeakPtr<BluetoothAdapter> GetWeakPtrForTesting();
@@ -556,7 +564,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
using PairingDelegatePair =
std::pair<BluetoothDevice::PairingDelegate*, PairingDelegatePriority>;
using DiscoverySessionErrorCallback =
- base::Callback<void(UMABluetoothDiscoverySessionOutcome)>;
+ base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)>;
// Implementations on Android and macOS need to store pending SetPowered()
// callbacks until an appropriate event is received, due to a lack of blocking
@@ -620,18 +628,18 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapter
virtual void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) = 0;
+ DiscoverySessionErrorCallback error_callback) = 0;
virtual void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) = 0;
+ DiscoverySessionErrorCallback error_callback) = 0;
// Used to set and update the discovery filter used by the underlying
// Bluetooth controller.
virtual void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) = 0;
+ DiscoverySessionErrorCallback error_callback) = 0;
// Called by RemovePairingDelegate() in order to perform any class-specific
// internal functionality necessary to remove the pairing delegate, such as
diff --git a/chromium/device/bluetooth/bluetooth_adapter_android.cc b/chromium/device/bluetooth/bluetooth_adapter_android.cc
index 910ca657f03..3d2b667cd5f 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_android.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_android.cc
@@ -44,7 +44,7 @@ namespace device {
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
+ InitCallback init_callback) {
return BluetoothAdapterAndroid::Create(
BluetoothAdapterWrapper_CreateWithDefaultAdapter());
}
@@ -281,7 +281,7 @@ bool BluetoothAdapterAndroid::SetPoweredImpl(bool powered) {
void BluetoothAdapterAndroid::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// TODO(scheib): Support filters crbug.com/490401
bool session_added = false;
if (IsPowered()) {
@@ -309,14 +309,14 @@ void BluetoothAdapterAndroid::AddDiscoverySession(
callback.Run();
} else {
// TODO(scheib): Eventually wire the SCAN_FAILED result through to here.
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
+ std::move(error_callback).Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
}
}
void BluetoothAdapterAndroid::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
bool session_removed = false;
if (num_discovery_sessions_ == 0) {
VLOG(1) << "RemoveDiscoverySession: No scan in progress.";
@@ -341,17 +341,18 @@ void BluetoothAdapterAndroid::RemoveDiscoverySession(
callback.Run();
} else {
// TODO(scheib): Eventually wire the SCAN_FAILED result through to here.
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
+ std::move(error_callback).Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
}
}
void BluetoothAdapterAndroid::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// TODO(scheib): Support filters crbug.com/490401
NOTIMPLEMENTED();
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
}
void BluetoothAdapterAndroid::RemovePairingDelegateInternal(
diff --git a/chromium/device/bluetooth/bluetooth_adapter_android.h b/chromium/device/bluetooth/bluetooth_adapter_android.h
index 483c634311e..113f9c985cb 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_android.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_android.h
@@ -115,15 +115,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterAndroid final
void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemovePairingDelegateInternal(
BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.h b/chromium/device/bluetooth/bluetooth_adapter_mac.h
index fe22655676f..a31b33b1b54 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.h
@@ -17,6 +17,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_discovery_manager_mac.h"
#include "device/bluetooth/bluetooth_export.h"
@@ -174,15 +175,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterMac
void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
// Start classic and/or low energy discovery sessions, according to the
// filter. If a discovery session is already running the filter is updated.
diff --git a/chromium/device/bluetooth/bluetooth_adapter_mac.mm b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
index 4a025982dcd..bb996bfd087 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/chromium/device/bluetooth/bluetooth_adapter_mac.mm
@@ -65,7 +65,7 @@ CBCentralManagerState GetCBManagerState(CBCentralManager* manager) {
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
+ InitCallback init_callback) {
return BluetoothAdapterMac::CreateAdapter();
}
@@ -350,7 +350,7 @@ void BluetoothAdapterMac::SetPowerStateFunctionForTesting(
void BluetoothAdapterMac::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
DVLOG(1) << __func__;
if (num_discovery_sessions_ > 0) {
DCHECK(IsDiscovering());
@@ -361,7 +361,7 @@ void BluetoothAdapterMac::AddDiscoverySession(
// TODO: Provide a more precise error here.
ui_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(error_callback,
+ base::BindOnce(std::move(error_callback),
UMABluetoothDiscoverySessionOutcome::UNKNOWN));
return;
}
@@ -375,7 +375,7 @@ void BluetoothAdapterMac::AddDiscoverySession(
// TODO: Provide a more precise error here.
ui_task_runner_->PostTask(
FROM_HERE,
- base::BindOnce(error_callback,
+ base::BindOnce(std::move(error_callback),
UMABluetoothDiscoverySessionOutcome::UNKNOWN));
return;
}
@@ -390,7 +390,7 @@ void BluetoothAdapterMac::AddDiscoverySession(
void BluetoothAdapterMac::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
DVLOG(1) << __func__;
if (num_discovery_sessions_ > 1) {
@@ -403,7 +403,8 @@ void BluetoothAdapterMac::RemoveDiscoverySession(
if (num_discovery_sessions_ == 0) {
DVLOG(1) << "No active discovery sessions. Returning error.";
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE);
return;
}
@@ -416,7 +417,8 @@ void BluetoothAdapterMac::RemoveDiscoverySession(
if (!classic_discovery_manager_->StopDiscovery()) {
DVLOG(1) << "Failed to stop classic discovery";
// TODO: Provide a more precise error here.
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN);
return;
}
}
@@ -437,9 +439,10 @@ void BluetoothAdapterMac::RemoveDiscoverySession(
void BluetoothAdapterMac::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
NOTIMPLEMENTED();
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
}
bool BluetoothAdapterMac::StartDiscovery(
diff --git a/chromium/device/bluetooth/bluetooth_adapter_stub.cc b/chromium/device/bluetooth/bluetooth_adapter_stub.cc
index fc62f95a54a..e32d07e0171 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_stub.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_stub.cc
@@ -11,7 +11,7 @@ namespace device {
// a particular platform.
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
+ InitCallback init_callback) {
return base::WeakPtr<BluetoothAdapter>();
}
diff --git a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
index 0bc7ba99ede..292c6734ba7 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -147,17 +147,17 @@ class TestBluetoothAdapter : public BluetoothAdapter {
void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override {}
+ DiscoverySessionErrorCallback error_callback) override {}
void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override {}
+ DiscoverySessionErrorCallback error_callback) override {}
void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override {}
+ DiscoverySessionErrorCallback error_callback) override {}
void RemovePairingDelegateInternal(
BluetoothDevice::PairingDelegate* pairing_delegate) override {}
@@ -434,12 +434,17 @@ TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterAllFields) {
}
// TODO(scheib): Enable BluetoothTest fixture tests on all platforms.
-#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_ConstructDefaultAdapter ConstructDefaultAdapter
#else
#define MAYBE_ConstructDefaultAdapter DISABLED_ConstructDefaultAdapter
#endif
+
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrt, ConstructDefaultAdapter) {
+#else
TEST_F(BluetoothTest, MAYBE_ConstructDefaultAdapter) {
+#endif
InitWithDefaultAdapter();
if (!adapter_->IsPresent()) {
LOG(WARNING) << "Bluetooth adapter not present; skipping unit test.";
@@ -464,13 +469,18 @@ TEST_F(BluetoothTest, MAYBE_ConstructDefaultAdapter) {
}
// TODO(scheib): Enable BluetoothTest fixture tests on all platforms.
-#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_ConstructWithoutDefaultAdapter ConstructWithoutDefaultAdapter
#else
#define MAYBE_ConstructWithoutDefaultAdapter \
DISABLED_ConstructWithoutDefaultAdapter
#endif
+
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrt, ConstructWithoutDefaultAdapter) {
+#else
TEST_F(BluetoothTest, MAYBE_ConstructWithoutDefaultAdapter) {
+#endif // defined(OS_WIN)
InitWithoutDefaultAdapter();
EXPECT_EQ(adapter_->GetAddress(), "");
EXPECT_EQ(adapter_->GetName(), "");
@@ -481,12 +491,17 @@ TEST_F(BluetoothTest, MAYBE_ConstructWithoutDefaultAdapter) {
}
// TODO(scheib): Enable BluetoothTest fixture tests on all platforms.
-#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
#define MAYBE_ConstructFakeAdapter ConstructFakeAdapter
#else
#define MAYBE_ConstructFakeAdapter DISABLED_ConstructFakeAdapter
#endif
+
+#if defined(OS_WIN)
+TEST_P(BluetoothTestWinrt, ConstructFakeAdapter) {
+#else
TEST_F(BluetoothTest, MAYBE_ConstructFakeAdapter) {
+#endif // defined(OS_WIN)
if (!PlatformSupportsLowEnergy()) {
LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
return;
@@ -1325,4 +1340,11 @@ TEST_F(BluetoothTest, DiscoverConnectedLowEnergyDeviceTwice) {
}
#endif // defined(OS_MACOSX)
+#if defined(OS_WIN)
+INSTANTIATE_TEST_CASE_P(
+ /* no prefix */,
+ BluetoothTestWinrt,
+ ::testing::Bool());
+#endif // defined(OS_WIN)
+
} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_adapter_win.cc b/chromium/device/bluetooth/bluetooth_adapter_win.cc
index 24f9d177df2..32e7fc89f50 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_win.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_win.cc
@@ -8,6 +8,7 @@
#include <string>
#include <utility>
+#include "base/feature_list.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -15,6 +16,9 @@
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/win/windows_version.h"
+#include "device/base/features.h"
+#include "device/bluetooth/bluetooth_adapter_winrt.h"
#include "device/bluetooth/bluetooth_device_win.h"
#include "device/bluetooth/bluetooth_discovery_session_outcome.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
@@ -26,21 +30,33 @@ namespace device {
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
- return BluetoothAdapterWin::CreateAdapter(init_callback);
+ InitCallback init_callback) {
+ return BluetoothAdapterWin::CreateAdapter(std::move(init_callback));
}
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapterWin::CreateAdapter(
- const InitCallback& init_callback) {
- BluetoothAdapterWin* adapter = new BluetoothAdapterWin(init_callback);
+ InitCallback init_callback) {
+ if (UseNewBLEWinImplementation()) {
+ auto* adapter = new BluetoothAdapterWinrt();
+ adapter->Init(std::move(init_callback));
+ return adapter->weak_ptr_factory_.GetWeakPtr();
+ }
+
+ auto* adapter = new BluetoothAdapterWin(std::move(init_callback));
adapter->Init();
return adapter->weak_ptr_factory_.GetWeakPtr();
}
-BluetoothAdapterWin::BluetoothAdapterWin(const InitCallback& init_callback)
+// static
+bool BluetoothAdapterWin::UseNewBLEWinImplementation() {
+ return base::FeatureList::IsEnabled(kNewBLEWinImplementation) &&
+ base::win::GetVersion() >= base::win::VERSION_WIN10;
+}
+
+BluetoothAdapterWin::BluetoothAdapterWin(InitCallback init_callback)
: BluetoothAdapter(),
- init_callback_(init_callback),
+ init_callback_(std::move(init_callback)),
initialized_(false),
powered_(false),
discovery_status_(NOT_DISCOVERING),
@@ -106,21 +122,23 @@ bool BluetoothAdapterWin::IsDiscovering() const {
}
static void RunDiscoverySessionErrorCallback(
- const base::Callback<void(UMABluetoothDiscoverySessionOutcome)>& callback,
+ base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)>
+ error_callback,
UMABluetoothDiscoverySessionOutcome outcome) {
- callback.Run(outcome);
+ std::move(error_callback).Run(outcome);
}
void BluetoothAdapterWin::DiscoveryStarted(bool success) {
discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING;
- for (const auto& callbacks : on_start_discovery_callbacks_) {
+ for (auto& callbacks : on_start_discovery_callbacks_) {
if (success)
ui_task_runner_->PostTask(FROM_HERE, callbacks.first);
else
ui_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&RunDiscoverySessionErrorCallback, callbacks.second,
- UMABluetoothDiscoverySessionOutcome::UNKNOWN));
+ base::BindOnce(&RunDiscoverySessionErrorCallback,
+ std::move(callbacks.second),
+ UMABluetoothDiscoverySessionOutcome::UNKNOWN));
}
num_discovery_listeners_ = on_start_discovery_callbacks_.size();
on_start_discovery_callbacks_.clear();
@@ -220,7 +238,7 @@ void BluetoothAdapterWin::AdapterStateChanged(
}
if (!initialized_) {
initialized_ = true;
- init_callback_.Run();
+ std::move(init_callback_).Run();
}
}
@@ -299,23 +317,24 @@ bool BluetoothAdapterWin::SetPoweredImpl(bool powered) {
void BluetoothAdapterWin::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
if (discovery_status_ == DISCOVERING) {
num_discovery_listeners_++;
callback.Run();
return;
}
on_start_discovery_callbacks_.push_back(
- std::make_pair(callback, error_callback));
+ std::make_pair(callback, std::move(error_callback)));
MaybePostStartDiscoveryTask();
}
void BluetoothAdapterWin::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
if (discovery_status_ == NOT_DISCOVERING) {
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE);
return;
}
on_stop_discovery_callbacks_.push_back(callback);
@@ -325,9 +344,10 @@ void BluetoothAdapterWin::RemoveDiscoverySession(
void BluetoothAdapterWin::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
NOTIMPLEMENTED();
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED);
}
void BluetoothAdapterWin::Init() {
diff --git a/chromium/device/bluetooth/bluetooth_adapter_win.h b/chromium/device/bluetooth/bluetooth_adapter_win.h
index 124ba6aa8b1..88ea310b7f0 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_win.h
+++ b/chromium/device/bluetooth/bluetooth_adapter_win.h
@@ -34,7 +34,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin
public BluetoothTaskManagerWin::Observer {
public:
static base::WeakPtr<BluetoothAdapter> CreateAdapter(
- const InitCallback& init_callback);
+ InitCallback init_callback);
+
+ static bool UseNewBLEWinImplementation();
// BluetoothAdapter:
std::string GetAddress() const override;
@@ -107,7 +109,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin
DISCOVERY_STOPPING
};
- explicit BluetoothAdapterWin(const InitCallback& init_callback);
+ explicit BluetoothAdapterWin(InitCallback init_callback);
~BluetoothAdapterWin() override;
// BluetoothAdapter:
@@ -115,15 +117,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWin
void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void Init();
void InitForTest(
diff --git a/chromium/device/bluetooth/bluetooth_adapter_win_unittest.cc b/chromium/device/bluetooth/bluetooth_adapter_win_unittest.cc
index 0537efb078a..7a991c94481 100644
--- a/chromium/device/bluetooth/bluetooth_adapter_win_unittest.cc
+++ b/chromium/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -89,19 +89,20 @@ class BluetoothAdapterWinTest : public testing::Test {
num_stop_discovery_error_callbacks_++;
}
- typedef base::Callback<void(UMABluetoothDiscoverySessionOutcome)>
+ typedef base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)>
DiscoverySessionErrorCallback;
- void CallAddDiscoverySession(
- const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
- adapter_win_->AddDiscoverySession(nullptr, callback, error_callback);
+ void CallAddDiscoverySession(const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) {
+ adapter_win_->AddDiscoverySession(nullptr, callback,
+ std::move(error_callback));
}
void CallRemoveDiscoverySession(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
- adapter_win_->RemoveDiscoverySession(nullptr, callback, error_callback);
+ DiscoverySessionErrorCallback error_callback) {
+ adapter_win_->RemoveDiscoverySession(nullptr, callback,
+ std::move(error_callback));
}
protected:
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.cc b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
new file mode 100644
index 00000000000..94cde0ca5a6
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -0,0 +1,399 @@
+// 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_adapter_winrt.h"
+
+#include <windows.foundation.h>
+#include <wrl/event.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/win/core_winrt_util.h"
+#include "device/bluetooth/bluetooth_discovery_filter.h"
+
+namespace device {
+
+namespace {
+
+// In order to avoid a name clash with device::BluetoothAdapter we need this
+// auxiliary namespace.
+namespace uwp {
+using ABI::Windows::Devices::Bluetooth::BluetoothAdapter;
+} // namespace uwp
+using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter;
+using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics;
+using ABI::Windows::Devices::Enumeration::DeviceInformation;
+using ABI::Windows::Devices::Enumeration::IDeviceInformation;
+using ABI::Windows::Devices::Enumeration::IDeviceInformationStatics;
+using ABI::Windows::Foundation::IAsyncOperation;
+using ABI::Windows::Foundation::IAsyncOperationCompletedHandler;
+using Microsoft::WRL::Callback;
+using Microsoft::WRL::ComPtr;
+
+bool ResolveCoreWinRT() {
+ return base::win::ResolveCoreWinRTDelayload() &&
+ base::win::ScopedHString::ResolveCoreWinRTStringDelayload();
+}
+
+// Utility functions to pretty print enum values.
+constexpr const char* ToCString(AsyncStatus async_status) {
+ switch (async_status) {
+ case AsyncStatus::Started:
+ return "AsyncStatus::Started";
+ case AsyncStatus::Completed:
+ return "AsyncStatus::Completed";
+ case AsyncStatus::Canceled:
+ return "AsyncStatus::Canceled";
+ case AsyncStatus::Error:
+ return "AsyncStatus::Error";
+ }
+
+ NOTREACHED();
+ return "";
+}
+
+template <typename T>
+using AsyncAbiT = typename ABI::Windows::Foundation::Internal::GetAbiType<
+ typename IAsyncOperation<T>::TResult_complex>::type;
+
+// Compile time switch to decide what container to use for the async results for
+// |T|. Depends on whether the underlying Abi type is a pointer to IUnknown or
+// not. It queries the internals of Windows::Foundation to obtain this
+// information.
+template <typename T>
+using AsyncResultsT =
+ std::conditional_t<std::is_convertible<AsyncAbiT<T>, IUnknown*>::value,
+ ComPtr<std::remove_pointer_t<AsyncAbiT<T>>>,
+ AsyncAbiT<T>>;
+
+// Obtains the results of the provided async operation. Returns it if the
+// operation completed successfully.
+template <typename T>
+AsyncResultsT<T> GetAsyncResults(IAsyncOperation<T>* async_op,
+ AsyncStatus async_status) {
+ if (async_status != AsyncStatus::Completed) {
+ VLOG(2) << "Got unexpected AsyncStatus: " << ToCString(async_status);
+ return {};
+ }
+
+ AsyncResultsT<T> results;
+ HRESULT hr = async_op->GetResults(&results);
+ if (FAILED(hr)) {
+ VLOG(2) << "GotAsyncResults failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+
+ return results;
+}
+
+// This method registers a completion handler for |async_op| and will post the
+// results to |callback| on |task_runner|. While a Callback can be constructed
+// from callable types such as a lambda or std::function objects, it cannot be
+// directly constructed from a base::OnceCallback. Thus the callback is moved
+// into a capturing lambda, which then posts the callback once it is run.
+// Posting the results to the TaskRunner is required, since the completion
+// callback might be invoked on an arbitrary thread. Lastly, the lambda takes
+// ownership of |async_op|, as this needs to be kept alive until GetAsyncResults
+// can be invoked. Once that is done it is safe to release the |async_op|.
+template <typename T>
+HRESULT PostAsyncResults(ComPtr<IAsyncOperation<T>> async_op,
+ scoped_refptr<base::TaskRunner> task_runner,
+ base::OnceCallback<void(AsyncResultsT<T>)> callback) {
+ auto async_op_raw = async_op.Get();
+ return async_op_raw->put_Completed(
+ Callback<IAsyncOperationCompletedHandler<T>>([
+ async_op(std::move(async_op)), task_runner(std::move(task_runner)),
+ callback(std::move(callback))
+ ](IAsyncOperation<T> * async_op_raw, AsyncStatus async_status) mutable {
+ // Note: We are using |async_op_raw| instead of async_op.Get(), as this
+ // could be executed on any thread and only |async_op_raw| is guaranteed
+ // to be in the correct COM apartment.
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback),
+ GetAsyncResults(async_op_raw, async_status)));
+ async_op.Reset();
+ return S_OK;
+ })
+ .Get());
+}
+
+} // namespace
+
+std::string BluetoothAdapterWinrt::GetAddress() const {
+ return address_;
+}
+
+std::string BluetoothAdapterWinrt::GetName() const {
+ return name_;
+}
+
+void BluetoothAdapterWinrt::SetName(const std::string& name,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+bool BluetoothAdapterWinrt::IsInitialized() const {
+ return is_initialized_;
+}
+
+bool BluetoothAdapterWinrt::IsPresent() const {
+ return is_present_;
+}
+
+bool BluetoothAdapterWinrt::IsPowered() const {
+ // Note: While the UWP APIs can provide access to the underlying radio [1] and
+ // its power state [2], this feature is not available for x86 Apps [3]. Thus
+ // we simply assume the adapter is powered if it is present.
+ //
+ // [1]
+ // https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.bluetoothadapter.getradioasync
+ // [2]
+ // https://docs.microsoft.com/en-us/uwp/api/windows.devices.radios.radiostate
+ // [3] https://github.com/Microsoft/cppwinrt/issues/47#issuecomment-335181782
+ if (IsPresent()) {
+ LOG(WARNING) << "Optimistically assuming the adapter is powered since it "
+ "is present. This might not actually be true.";
+ }
+
+ return IsPresent();
+}
+
+bool BluetoothAdapterWinrt::IsDiscoverable() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void BluetoothAdapterWinrt::SetDiscoverable(
+ bool discoverable,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+bool BluetoothAdapterWinrt::IsDiscovering() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+BluetoothAdapter::UUIDList BluetoothAdapterWinrt::GetUUIDs() const {
+ NOTIMPLEMENTED();
+ return UUIDList();
+}
+
+void BluetoothAdapterWinrt::CreateRfcommService(
+ const BluetoothUUID& uuid,
+ const ServiceOptions& options,
+ const CreateServiceCallback& callback,
+ const CreateServiceErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothAdapterWinrt::CreateL2capService(
+ const BluetoothUUID& uuid,
+ const ServiceOptions& options,
+ const CreateServiceCallback& callback,
+ const CreateServiceErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothAdapterWinrt::RegisterAdvertisement(
+ std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
+ const CreateAdvertisementCallback& callback,
+ const AdvertisementErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+BluetoothLocalGattService* BluetoothAdapterWinrt::GetGattService(
+ const std::string& identifier) const {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+BluetoothAdapterWinrt::BluetoothAdapterWinrt() : weak_ptr_factory_(this) {
+ ui_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+}
+
+BluetoothAdapterWinrt::~BluetoothAdapterWinrt() = default;
+
+void BluetoothAdapterWinrt::Init(InitCallback init_cb) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // We are wrapping |init_cb| in a ScopedClosureRunner to ensure it gets run no
+ // matter how the function exits. Furthermore, we set |is_initialized_| to
+ // true if adapter is still active when the callback gets run.
+ base::ScopedClosureRunner on_init(base::BindOnce(
+ [](base::WeakPtr<BluetoothAdapterWinrt> adapter, InitCallback init_cb) {
+ if (adapter)
+ adapter->is_initialized_ = true;
+ std::move(init_cb).Run();
+ },
+ weak_ptr_factory_.GetWeakPtr(), std::move(init_cb)));
+
+ if (!ResolveCoreWinRT())
+ return;
+
+ ComPtr<IBluetoothAdapterStatics> adapter_statics;
+ HRESULT hr = GetBluetoothAdapterStaticsActivationFactory(&adapter_statics);
+ if (FAILED(hr)) {
+ VLOG(2) << "GetBluetoothAdapterStaticsActivationFactory failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ ComPtr<IAsyncOperation<uwp::BluetoothAdapter*>> get_default_adapter_op;
+ hr = adapter_statics->GetDefaultAsync(&get_default_adapter_op);
+ if (FAILED(hr)) {
+ VLOG(2) << "BluetoothAdapter::GetDefaultAsync failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ hr = PostAsyncResults(
+ std::move(get_default_adapter_op), ui_task_runner_,
+ base::BindOnce(&BluetoothAdapterWinrt::OnGetDefaultAdapter,
+ weak_ptr_factory_.GetWeakPtr(), std::move(on_init)));
+
+ if (FAILED(hr)) {
+ VLOG(2) << "PostAsyncResults failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+}
+
+bool BluetoothAdapterWinrt::SetPoweredImpl(bool powered) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void BluetoothAdapterWinrt::AddDiscoverySession(
+ BluetoothDiscoveryFilter* discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothAdapterWinrt::RemoveDiscoverySession(
+ BluetoothDiscoveryFilter* discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothAdapterWinrt::SetDiscoveryFilter(
+ std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothAdapterWinrt::RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) {
+ NOTIMPLEMENTED();
+}
+
+HRESULT BluetoothAdapterWinrt::GetBluetoothAdapterStaticsActivationFactory(
+ IBluetoothAdapterStatics** statics) const {
+ return base::win::GetActivationFactory<
+ IBluetoothAdapterStatics,
+ RuntimeClass_Windows_Devices_Bluetooth_BluetoothAdapter>(statics);
+}
+
+HRESULT BluetoothAdapterWinrt::GetDeviceInformationStaticsActivationFactory(
+ IDeviceInformationStatics** statics) const {
+ return base::win::GetActivationFactory<
+ IDeviceInformationStatics,
+ RuntimeClass_Windows_Devices_Enumeration_DeviceInformation>(statics);
+}
+
+void BluetoothAdapterWinrt::OnGetDefaultAdapter(
+ base::ScopedClosureRunner on_init,
+ ComPtr<IBluetoothAdapter> adapter) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!adapter) {
+ VLOG(2) << "Getting Default Adapter failed.";
+ return;
+ }
+
+ // Obtaining the default adapter will fail if no physical adapter is present.
+ // Thus a non-zero |adapter| implies that a physical adapter is present.
+ is_present_ = true;
+ uint64_t raw_address;
+ HRESULT hr = adapter->get_BluetoothAddress(&raw_address);
+ if (FAILED(hr)) {
+ VLOG(2) << "Getting BluetoothAddress failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ address_ = BluetoothDevice::CanonicalizeAddress(
+ base::StringPrintf("%012llX", raw_address));
+ DCHECK(!address_.empty());
+
+ HSTRING device_id;
+ hr = adapter->get_DeviceId(&device_id);
+ if (FAILED(hr)) {
+ VLOG(2) << "Getting DeviceId failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ ComPtr<IDeviceInformationStatics> device_information_statics;
+ hr =
+ GetDeviceInformationStaticsActivationFactory(&device_information_statics);
+ if (FAILED(hr)) {
+ VLOG(2) << "GetDeviceInformationStaticsActivationFactory failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ ComPtr<IAsyncOperation<DeviceInformation*>> create_from_id_op;
+ hr = device_information_statics->CreateFromIdAsync(device_id,
+ &create_from_id_op);
+ if (FAILED(hr)) {
+ VLOG(2) << "CreateFromIdAsync failed: "
+ << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ hr = PostAsyncResults(
+ std::move(create_from_id_op), ui_task_runner_,
+ base::BindOnce(&BluetoothAdapterWinrt::OnCreateFromIdAsync,
+ weak_ptr_factory_.GetWeakPtr(), std::move(on_init)));
+ if (FAILED(hr)) {
+ VLOG(2) << "PostAsyncResults failed: "
+ << logging::SystemErrorCodeToString(hr);
+ }
+}
+
+void BluetoothAdapterWinrt::OnCreateFromIdAsync(
+ base::ScopedClosureRunner on_init,
+ ComPtr<IDeviceInformation> device_information) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!device_information) {
+ VLOG(2) << "Getting Device Information failed.";
+ return;
+ }
+
+ HSTRING name;
+ HRESULT hr = device_information->get_Name(&name);
+ if (FAILED(hr)) {
+ VLOG(2) << "Getting Name failed: " << logging::SystemErrorCodeToString(hr);
+ return;
+ }
+
+ name_ = base::win::ScopedHString(name).GetAsUTF8();
+}
+
+} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_adapter_winrt.h b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
new file mode 100644
index 00000000000..a607e31927d
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_adapter_winrt.h
@@ -0,0 +1,123 @@
+// 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_ADAPTER_WINRT_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_WINRT_H_
+
+#include <windows.devices.bluetooth.h>
+#include <windows.devices.enumeration.h>
+#include <wrl/client.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/bluetooth/bluetooth_export.h"
+
+namespace base {
+class ScopedClosureRunner;
+}
+
+namespace device {
+
+class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterWinrt : public BluetoothAdapter {
+ public:
+ // BluetoothAdapter:
+ std::string GetAddress() const override;
+ std::string GetName() const override;
+ void SetName(const std::string& name,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) override;
+ bool IsInitialized() const override;
+ bool IsPresent() const override;
+ bool IsPowered() const override;
+ bool IsDiscoverable() const override;
+ void SetDiscoverable(bool discoverable,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) override;
+ bool IsDiscovering() const override;
+ UUIDList GetUUIDs() const override;
+ void CreateRfcommService(
+ const BluetoothUUID& uuid,
+ const ServiceOptions& options,
+ const CreateServiceCallback& callback,
+ const CreateServiceErrorCallback& error_callback) override;
+ void CreateL2capService(
+ const BluetoothUUID& uuid,
+ const ServiceOptions& options,
+ const CreateServiceCallback& callback,
+ const CreateServiceErrorCallback& error_callback) override;
+ void RegisterAdvertisement(
+ std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
+ const CreateAdvertisementCallback& callback,
+ const AdvertisementErrorCallback& error_callback) override;
+ BluetoothLocalGattService* GetGattService(
+ const std::string& identifier) const override;
+
+ protected:
+ friend class BluetoothAdapterWin;
+ friend class BluetoothTestWin;
+
+ BluetoothAdapterWinrt();
+ ~BluetoothAdapterWinrt() override;
+
+ void Init(InitCallback init_cb);
+
+ // BluetoothAdapter:
+ bool SetPoweredImpl(bool powered) override;
+ void AddDiscoverySession(
+ BluetoothDiscoveryFilter* discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) override;
+ void RemoveDiscoverySession(
+ BluetoothDiscoveryFilter* discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) override;
+ void SetDiscoveryFilter(
+ std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
+ const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback) override;
+ void RemovePairingDelegateInternal(
+ BluetoothDevice::PairingDelegate* pairing_delegate) override;
+
+ // These are declared virtual so that they can be overridden by tests.
+ virtual HRESULT GetBluetoothAdapterStaticsActivationFactory(
+ ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics** statics)
+ const;
+ virtual HRESULT GetDeviceInformationStaticsActivationFactory(
+ ABI::Windows::Devices::Enumeration::IDeviceInformationStatics** statics)
+ const;
+
+ private:
+ void OnGetDefaultAdapter(
+ base::ScopedClosureRunner on_init,
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Devices::Bluetooth::IBluetoothAdapter> adapter);
+
+ void OnCreateFromIdAsync(
+ base::ScopedClosureRunner on_init,
+ Microsoft::WRL::ComPtr<
+ ABI::Windows::Devices::Enumeration::IDeviceInformation>
+ device_information);
+
+ bool is_initialized_ = false;
+ bool is_present_ = false;
+ std::string address_;
+ std::string name_;
+
+ THREAD_CHECKER(thread_checker_);
+
+ // Note: This should remain the last member so it'll be destroyed and
+ // invalidate its weak pointers before any other members are destroyed.
+ base::WeakPtrFactory<BluetoothAdapterWinrt> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothAdapterWinrt);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_ADAPTER_WINRT_H_
diff --git a/chromium/device/bluetooth/bluetooth_device_win.h b/chromium/device/bluetooth/bluetooth_device_win.h
index 0468b67e0c8..8ab8302987f 100644
--- a/chromium/device/bluetooth/bluetooth_device_win.h
+++ b/chromium/device/bluetooth/bluetooth_device_win.h
@@ -15,6 +15,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
+#include "base/sequenced_task_runner.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_export.h"
#include "device/bluetooth/bluetooth_task_manager_win.h"
diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.cc b/chromium/device/bluetooth/bluetooth_device_winrt.cc
new file mode 100644
index 00000000000..932f48c65ef
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_device_winrt.cc
@@ -0,0 +1,168 @@
+// 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_device_winrt.h"
+
+#include "base/logging.h"
+#include "device/bluetooth/bluetooth_adapter_winrt.h"
+
+namespace device {
+
+BluetoothDeviceWinrt::BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter)
+ : BluetoothDevice(adapter) {}
+
+BluetoothDeviceWinrt::~BluetoothDeviceWinrt() = default;
+
+uint32_t BluetoothDeviceWinrt::GetBluetoothClass() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+std::string BluetoothDeviceWinrt::GetAddress() const {
+ NOTIMPLEMENTED();
+ return std::string();
+}
+
+BluetoothDevice::VendorIDSource BluetoothDeviceWinrt::GetVendorIDSource()
+ const {
+ NOTIMPLEMENTED();
+ return VendorIDSource();
+}
+
+uint16_t BluetoothDeviceWinrt::GetVendorID() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+uint16_t BluetoothDeviceWinrt::GetProductID() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+uint16_t BluetoothDeviceWinrt::GetDeviceID() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+uint16_t BluetoothDeviceWinrt::GetAppearance() const {
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+base::Optional<std::string> BluetoothDeviceWinrt::GetName() const {
+ NOTIMPLEMENTED();
+ return base::nullopt;
+}
+
+bool BluetoothDeviceWinrt::IsPaired() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::IsConnected() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::IsGattConnected() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::IsConnectable() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::IsConnecting() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::ExpectingPinCode() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::ExpectingPasskey() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool BluetoothDeviceWinrt::ExpectingConfirmation() const {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void BluetoothDeviceWinrt::GetConnectionInfo(
+ const ConnectionInfoCallback& callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::SetConnectionLatency(
+ ConnectionLatency connection_latency,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::Connect(PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::SetPinCode(const std::string& pincode) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::SetPasskey(uint32_t passkey) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::ConfirmPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::RejectPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::CancelPairing() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::Disconnect(const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::Forget(const base::Closure& callback,
+ const ErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::ConnectToService(
+ const BluetoothUUID& uuid,
+ const ConnectToServiceCallback& callback,
+ const ConnectToServiceErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::ConnectToServiceInsecurely(
+ const device::BluetoothUUID& uuid,
+ const ConnectToServiceCallback& callback,
+ const ConnectToServiceErrorCallback& error_callback) {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::CreateGattConnectionImpl() {
+ NOTIMPLEMENTED();
+}
+
+void BluetoothDeviceWinrt::DisconnectGatt() {
+ NOTIMPLEMENTED();
+}
+
+} // namespace device
diff --git a/chromium/device/bluetooth/bluetooth_device_winrt.h b/chromium/device/bluetooth/bluetooth_device_winrt.h
new file mode 100644
index 00000000000..df656cbd7e4
--- /dev/null
+++ b/chromium/device/bluetooth/bluetooth_device_winrt.h
@@ -0,0 +1,77 @@
+// 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_DEVICE_WINRT_H_
+#define DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/bluetooth/bluetooth_device.h"
+#include "device/bluetooth/bluetooth_export.h"
+
+namespace device {
+
+class BluetoothAdapterWinrt;
+
+class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceWinrt : public BluetoothDevice {
+ public:
+ explicit BluetoothDeviceWinrt(BluetoothAdapterWinrt* adapter);
+ ~BluetoothDeviceWinrt() override;
+
+ // BluetoothDevice:
+ uint32_t GetBluetoothClass() const override;
+ std::string GetAddress() const override;
+ VendorIDSource GetVendorIDSource() const override;
+ uint16_t GetVendorID() const override;
+ uint16_t GetProductID() const override;
+ uint16_t GetDeviceID() const override;
+ uint16_t GetAppearance() const override;
+ base::Optional<std::string> GetName() const override;
+ bool IsPaired() const override;
+ bool IsConnected() const override;
+ bool IsGattConnected() const override;
+ bool IsConnectable() const override;
+ bool IsConnecting() const override;
+ bool ExpectingPinCode() const override;
+ bool ExpectingPasskey() const override;
+ bool ExpectingConfirmation() const override;
+ void GetConnectionInfo(const ConnectionInfoCallback& callback) override;
+ void SetConnectionLatency(ConnectionLatency connection_latency,
+ const base::Closure& callback,
+ const ErrorCallback& error_callback) override;
+ void Connect(PairingDelegate* pairing_delegate,
+ const base::Closure& callback,
+ const ConnectErrorCallback& error_callback) override;
+ void SetPinCode(const std::string& pincode) override;
+ void SetPasskey(uint32_t passkey) override;
+ void ConfirmPairing() override;
+ void RejectPairing() override;
+ void CancelPairing() override;
+ void Disconnect(const base::Closure& callback,
+ const ErrorCallback& error_callback) override;
+ void Forget(const base::Closure& callback,
+ const ErrorCallback& error_callback) override;
+ void ConnectToService(
+ const BluetoothUUID& uuid,
+ const ConnectToServiceCallback& callback,
+ const ConnectToServiceErrorCallback& error_callback) override;
+ void ConnectToServiceInsecurely(
+ const device::BluetoothUUID& uuid,
+ const ConnectToServiceCallback& callback,
+ const ConnectToServiceErrorCallback& error_callback) override;
+
+ protected:
+ // BluetoothDevice:
+ void CreateGattConnectionImpl() override;
+ void DisconnectGatt() override;
+
+ DISALLOW_COPY_AND_ASSIGN(BluetoothDeviceWinrt);
+};
+
+} // namespace device
+
+#endif // DEVICE_BLUETOOTH_BLUETOOTH_DEVICE_WINRT_H_
diff --git a/chromium/device/bluetooth/bluetooth_socket_net.cc b/chromium/device/bluetooth/bluetooth_socket_net.cc
index 31ce8af8c85..422be8c0c4d 100644
--- a/chromium/device/bluetooth/bluetooth_socket_net.cc
+++ b/chromium/device/bluetooth/bluetooth_socket_net.cc
@@ -17,6 +17,7 @@
#include "base/threading/thread_restrictions.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
+#include "net/base/completion_callback.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_source.h"
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index 8f92a3c3077..a5c5c498535 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -14,6 +14,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
@@ -103,8 +104,8 @@ namespace device {
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
- return bluez::BluetoothAdapterBlueZ::CreateAdapter(init_callback);
+ InitCallback init_callback) {
+ return bluez::BluetoothAdapterBlueZ::CreateAdapter(std::move(init_callback));
}
} // namespace device
@@ -160,8 +161,9 @@ void ResetAdvertisingErrorCallbackConnector(
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapterBlueZ::CreateAdapter(
- const InitCallback& init_callback) {
- BluetoothAdapterBlueZ* adapter = new BluetoothAdapterBlueZ(init_callback);
+ InitCallback init_callback) {
+ BluetoothAdapterBlueZ* adapter =
+ new BluetoothAdapterBlueZ(std::move(init_callback));
return adapter->weak_ptr_factory_.GetWeakPtr();
}
@@ -227,8 +229,8 @@ void BluetoothAdapterBlueZ::Shutdown() {
dbus_is_shutdown_ = true;
}
-BluetoothAdapterBlueZ::BluetoothAdapterBlueZ(const InitCallback& init_callback)
- : init_callback_(init_callback),
+BluetoothAdapterBlueZ::BluetoothAdapterBlueZ(InitCallback init_callback)
+ : init_callback_(std::move(init_callback)),
initialized_(false),
dbus_is_shutdown_(false),
num_discovery_sessions_(0),
@@ -256,7 +258,7 @@ void BluetoothAdapterBlueZ::Init() {
if (dbus_is_shutdown_ ||
!bluez::BluezDBusManager::Get()->IsObjectManagerSupported()) {
initialized_ = true;
- init_callback_.Run();
+ std::move(init_callback_).Run();
return;
}
@@ -281,7 +283,7 @@ void BluetoothAdapterBlueZ::Init() {
SetAdapter(object_paths[0]);
}
initialized_ = true;
- init_callback_.Run();
+ std::move(init_callback_).Run();
}
BluetoothAdapterBlueZ::~BluetoothAdapterBlueZ() {
@@ -678,6 +680,9 @@ void BluetoothAdapterBlueZ::DevicePropertyChanged(
NotifyDeviceChanged(device_bluez);
}
+ if (property_name == properties->mtu.name())
+ NotifyDeviceMTUChanged(device_bluez, properties->mtu.value());
+
if (property_name == properties->services_resolved.name() &&
properties->services_resolved.value()) {
device_bluez->UpdateGattServices(object_path);
@@ -1057,8 +1062,14 @@ void BluetoothAdapterBlueZ::RemoveAdapter() {
NotifyAdapterPoweredChanged(false);
if (properties->discoverable.value())
DiscoverableChanged(false);
- if (properties->discovering.value())
- DiscoveringChanged(false);
+
+ // The properties->discovering.value() may not be up to date with the real
+ // discovering state (BlueZ bug: http://crbug.com/822104).
+ // When the adapter is removed, make sure to clear all discovery sessions no
+ // matter what the current properties->discovering.value() is.
+ // DiscoveringChanged() properly handles the case where there is no discovery
+ // sessions currently.
+ DiscoveringChanged(false);
// Move all elements of the original devices list to a new list here,
// leaving the original list empty so that when we send DeviceRemoved(),
@@ -1117,6 +1128,14 @@ void BluetoothAdapterBlueZ::NotifyDeviceAddressChanged(
observer.DeviceAddressChanged(this, device, old_address);
}
+void BluetoothAdapterBlueZ::NotifyDeviceMTUChanged(BluetoothDeviceBlueZ* device,
+ uint16_t mtu) {
+ DCHECK(device->adapter_ == this);
+
+ for (auto& observer : observers_)
+ observer.DeviceMTUChanged(this, device, mtu);
+}
+
void BluetoothAdapterBlueZ::UseProfile(
const BluetoothUUID& uuid,
const dbus::ObjectPath& device_path,
@@ -1362,10 +1381,10 @@ bool BluetoothAdapterBlueZ::SetPoweredImpl(bool powered) {
void BluetoothAdapterBlueZ::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
if (!IsPresent()) {
- error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
@@ -1377,7 +1396,7 @@ void BluetoothAdapterBlueZ::AddDiscoverySession(
<< "Pending request to start/stop device discovery. Queueing "
<< "request to start a new discovery session.";
discovery_request_queue_.push(
- std::make_tuple(discovery_filter, callback, error_callback));
+ std::make_tuple(discovery_filter, callback, std::move(error_callback)));
return;
}
@@ -1390,7 +1409,7 @@ void BluetoothAdapterBlueZ::AddDiscoverySession(
num_discovery_sessions_++;
SetDiscoveryFilter(BluetoothDiscoveryFilter::Merge(
GetMergedDiscoveryFilter().get(), discovery_filter),
- callback, error_callback);
+ callback, std::move(error_callback));
return;
}
@@ -1403,12 +1422,16 @@ void BluetoothAdapterBlueZ::AddDiscoverySession(
std::unique_ptr<BluetoothDiscoveryFilter> df(
new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_DUAL));
df->CopyFrom(*discovery_filter);
+ auto copyable_error_callback =
+ base::AdaptCallbackForRepeating(std::move(error_callback));
SetDiscoveryFilter(
std::move(df),
base::Bind(&BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback),
base::Bind(&BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback));
return;
} else {
current_filter_.reset();
@@ -1416,33 +1439,39 @@ void BluetoothAdapterBlueZ::AddDiscoverySession(
// This is the first request to start device discovery.
discovery_request_pending_ = true;
+ auto copyable_error_callback =
+ base::AdaptCallbackForRepeating(std::move(error_callback));
bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
object_path_,
base::Bind(&BluetoothAdapterBlueZ::OnStartDiscovery,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback),
base::Bind(&BluetoothAdapterBlueZ::OnStartDiscoveryError,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback));
}
void BluetoothAdapterBlueZ::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
if (!IsPresent()) {
- error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT);
return;
}
BLUETOOTH_LOG(EVENT) << __func__;
// There are active sessions other than the one currently being removed.
if (num_discovery_sessions_ > 1) {
- DCHECK(IsDiscovering());
+ // DCHECK(IsDiscovering()) is removed due to BlueZ bug
+ // (https://crbug.com/822104).
+ // TODO(sonnysasaka): Put it back here when BlueZ bug is fixed.
DCHECK(!discovery_request_pending_);
num_discovery_sessions_--;
SetDiscoveryFilter(GetMergedDiscoveryFilterMasked(discovery_filter),
- callback, error_callback);
+ callback, std::move(error_callback));
return;
}
@@ -1451,8 +1480,8 @@ void BluetoothAdapterBlueZ::RemoveDiscoverySession(
BLUETOOTH_LOG(DEBUG)
<< "Pending request to start/stop device discovery. Queueing "
<< "request to stop discovery session.";
- error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST);
return;
}
@@ -1462,8 +1491,9 @@ void BluetoothAdapterBlueZ::RemoveDiscoverySession(
// DiscoverySession API. Replace this case with an assert once it's
// the deprecated methods have been removed. (See crbug.com/3445008).
BLUETOOTH_LOG(DEBUG) << "No active discovery sessions. Returning error.";
- error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::ACTIVE_SESSION_NOT_IN_ADAPTER);
+ std::move(error_callback)
+ .Run(
+ UMABluetoothDiscoverySessionOutcome::ACTIVE_SESSION_NOT_IN_ADAPTER);
return;
}
@@ -1472,18 +1502,21 @@ void BluetoothAdapterBlueZ::RemoveDiscoverySession(
DCHECK_EQ(num_discovery_sessions_, 1);
discovery_request_pending_ = true;
bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StopDiscovery(
- object_path_, base::Bind(&BluetoothAdapterBlueZ::OnStopDiscovery,
- weak_ptr_factory_.GetWeakPtr(), callback),
- base::Bind(&BluetoothAdapterBlueZ::OnStopDiscoveryError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ object_path_,
+ base::Bind(&BluetoothAdapterBlueZ::OnStopDiscovery,
+ weak_ptr_factory_.GetWeakPtr(), callback),
+ base::BindOnce(&BluetoothAdapterBlueZ::OnStopDiscoveryError,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
void BluetoothAdapterBlueZ::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
if (!IsPresent()) {
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
return;
}
@@ -1532,19 +1565,23 @@ void BluetoothAdapterBlueZ::SetDiscoveryFilter(
}
}
+ auto copyable_error_callback =
+ base::AdaptCallbackForRepeating(std::move(error_callback));
bluez::BluezDBusManager::Get()
->GetBluetoothAdapterClient()
->SetDiscoveryFilter(
object_path_, dbus_discovery_filter,
base::Bind(&BluetoothAdapterBlueZ::OnSetDiscoveryFilter,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback),
base::Bind(&BluetoothAdapterBlueZ::OnSetDiscoveryFilterError,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback));
}
void BluetoothAdapterBlueZ::OnStartDiscovery(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// Report success on the original request and increment the count.
BLUETOOTH_LOG(EVENT) << __func__;
DCHECK(discovery_request_pending_);
@@ -1554,7 +1591,8 @@ void BluetoothAdapterBlueZ::OnStartDiscovery(
if (IsPresent()) {
callback.Run();
} else {
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
}
// Try to add a new discovery session for each queued request.
@@ -1563,7 +1601,7 @@ void BluetoothAdapterBlueZ::OnStartDiscovery(
void BluetoothAdapterBlueZ::OnStartDiscoveryError(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
+ DiscoverySessionErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message) {
BLUETOOTH_LOG(ERROR) << object_path_.value()
@@ -1575,7 +1613,7 @@ void BluetoothAdapterBlueZ::OnStartDiscoveryError(
DCHECK(discovery_request_pending_);
discovery_request_pending_ = false;
- error_callback.Run(TranslateDiscoveryErrorToUMA(error_name));
+ std::move(error_callback).Run(TranslateDiscoveryErrorToUMA(error_name));
// Try to add a new discovery session for each queued request.
ProcessQueuedDiscoveryRequests();
@@ -1599,7 +1637,7 @@ void BluetoothAdapterBlueZ::OnStopDiscovery(const base::Closure& callback) {
}
void BluetoothAdapterBlueZ::OnStopDiscoveryError(
- const DiscoverySessionErrorCallback& error_callback,
+ DiscoverySessionErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message) {
// Failed to stop discovery. This can only happen if the count is at 1.
@@ -1623,7 +1661,7 @@ void BluetoothAdapterBlueZ::OnStopDiscoveryError(
<< error_message;
}
- error_callback.Run(TranslateDiscoveryErrorToUMA(error_name));
+ std::move(error_callback).Run(TranslateDiscoveryErrorToUMA(error_name));
// Try to add a new discovery session for each queued request.
ProcessQueuedDiscoveryRequests();
@@ -1631,22 +1669,26 @@ void BluetoothAdapterBlueZ::OnStopDiscoveryError(
void BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// This is the first request to start device discovery.
DCHECK(discovery_request_pending_);
DCHECK_EQ(num_discovery_sessions_, 0);
+ auto copyable_error_callback =
+ base::AdaptCallbackForRepeating(std::move(error_callback));
bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StartDiscovery(
object_path_,
base::Bind(&BluetoothAdapterBlueZ::OnStartDiscovery,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback),
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback),
base::Bind(&BluetoothAdapterBlueZ::OnStartDiscoveryError,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
+ weak_ptr_factory_.GetWeakPtr(), callback,
+ copyable_error_callback));
}
void BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
+ DiscoverySessionErrorCallback error_callback,
UMABluetoothDiscoverySessionOutcome outcome) {
BLUETOOTH_LOG(ERROR) << object_path_.value()
<< ": Failed to pre set discovery filter.";
@@ -1656,7 +1698,7 @@ void BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError(
DCHECK(discovery_request_pending_);
discovery_request_pending_ = false;
- error_callback.Run(outcome);
+ std::move(error_callback).Run(outcome);
// Try to add a new discovery session for each queued request.
ProcessQueuedDiscoveryRequests();
@@ -1664,19 +1706,20 @@ void BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError(
void BluetoothAdapterBlueZ::OnSetDiscoveryFilter(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// Report success on the original request and increment the count.
BLUETOOTH_LOG(EVENT) << __func__;
if (IsPresent()) {
callback.Run();
} else {
- error_callback.Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED);
}
}
void BluetoothAdapterBlueZ::OnSetDiscoveryFilterError(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
+ DiscoverySessionErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message) {
BLUETOOTH_LOG(ERROR) << object_path_.value()
@@ -1692,7 +1735,7 @@ void BluetoothAdapterBlueZ::OnSetDiscoveryFilterError(
outcome = UMABluetoothDiscoverySessionOutcome::
BLUEZ_DBUS_FAILED_MAYBE_UNSUPPORTED_TRANSPORT;
}
- error_callback.Run(outcome);
+ std::move(error_callback).Run(outcome);
// Try to add a new discovery session for each queued request.
ProcessQueuedDiscoveryRequests();
@@ -1701,10 +1744,10 @@ void BluetoothAdapterBlueZ::OnSetDiscoveryFilterError(
void BluetoothAdapterBlueZ::ProcessQueuedDiscoveryRequests() {
while (!discovery_request_queue_.empty()) {
BLUETOOTH_LOG(EVENT) << "Process queued discovery request.";
- DiscoveryParamTuple params = discovery_request_queue_.front();
+ DiscoveryParamTuple params = std::move(discovery_request_queue_.front());
discovery_request_queue_.pop();
AddDiscoverySession(std::get<0>(params), std::get<1>(params),
- std::get<2>(params));
+ std::move(std::get<2>(params)));
// If the queued request resulted in a pending call, then let it
// asynchonously process the remaining queued requests once the pending
diff --git a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
index 384c62c349b..093ed7825a7 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
+++ b/chromium/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -84,7 +84,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
// Calls |init_callback| after a BluetoothAdapter is fully initialized.
static base::WeakPtr<BluetoothAdapter> CreateAdapter(
- const InitCallback& init_callback);
+ InitCallback init_callback);
// BluetoothAdapter:
void Shutdown() override;
@@ -164,6 +164,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
void NotifyDeviceAddressChanged(BluetoothDeviceBlueZ* device,
const std::string& old_address);
+ // Announce to observers MTU change in ATT communication to |device|.
+ void NotifyDeviceMTUChanged(BluetoothDeviceBlueZ* device, uint16_t mtu);
+
// Returns the object path of the adapter.
const dbus::ObjectPath& object_path() const { return object_path_; }
@@ -243,7 +246,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
using RegisterProfileCompletionPair =
std::pair<base::Closure, ErrorCompletionCallback>;
- explicit BluetoothAdapterBlueZ(const InitCallback& init_callback);
+ explicit BluetoothAdapterBlueZ(InitCallback init_callback);
~BluetoothAdapterBlueZ() override;
// Init will get asynchronouly called once we know if Object Manager is
@@ -339,46 +342,42 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterBlueZ
void AddDiscoverySession(
device::BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemoveDiscoverySession(
device::BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void SetDiscoveryFilter(
std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
// Called by dbus:: on completion of the D-Bus method call to start discovery.
void OnStartDiscovery(const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback);
- void OnStartDiscoveryError(
- const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
- const std::string& error_name,
- const std::string& error_message);
+ DiscoverySessionErrorCallback error_callback);
+ void OnStartDiscoveryError(const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback,
+ const std::string& error_name,
+ const std::string& error_message);
// Called by dbus:: on completion of the D-Bus method call to stop discovery.
void OnStopDiscovery(const base::Closure& callback);
- void OnStopDiscoveryError(const DiscoverySessionErrorCallback& error_callback,
+ void OnStopDiscoveryError(DiscoverySessionErrorCallback error_callback,
const std::string& error_name,
const std::string& error_message);
- void OnPreSetDiscoveryFilter(
- const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback);
+ void OnPreSetDiscoveryFilter(const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback);
void OnPreSetDiscoveryFilterError(
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
+ DiscoverySessionErrorCallback error_callback,
device::UMABluetoothDiscoverySessionOutcome outcome);
- void OnSetDiscoveryFilter(
- const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback);
- void OnSetDiscoveryFilterError(
- const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback,
- const std::string& error_name,
- const std::string& error_message);
+ void OnSetDiscoveryFilter(const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback);
+ void OnSetDiscoveryFilterError(const base::Closure& callback,
+ DiscoverySessionErrorCallback error_callback,
+ const std::string& error_name,
+ const std::string& error_message);
// Called by dbus:: on completion of the D-Bus method to register a profile.
void OnRegisterProfile(const device::BluetoothUUID& uuid,
diff --git a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index b3ceaa6f728..0d5201a17e1 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -452,9 +452,12 @@ TEST_F(BluetoothBlueZTest, BecomeNotPresent) {
address.compare(
bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress) == 0);
+ // DiscoveringChanged() should be triggered regardless of the current value
+ // of Discovering property.
+ EXPECT_EQ(1, observer.discovering_changed_count());
+
// Other callbacks shouldn't be called since the values are false.
EXPECT_EQ(0, observer.powered_changed_count());
- EXPECT_EQ(0, observer.discovering_changed_count());
EXPECT_FALSE(adapter_->IsPowered());
EXPECT_FALSE(adapter_->IsDiscovering());
}
@@ -494,9 +497,12 @@ TEST_F(BluetoothBlueZTest, SecondAdapter) {
address.compare(
bluez::FakeBluetoothDeviceClient::kPairedDeviceAddress) == 0);
+ // DiscoveringChanged() should be triggered regardless of the current value
+ // of Discovering property.
+ EXPECT_EQ(1, observer.discovering_changed_count());
+
// Other callbacks shouldn't be called since the values are false.
EXPECT_EQ(0, observer.powered_changed_count());
- EXPECT_EQ(0, observer.discovering_changed_count());
EXPECT_FALSE(adapter_->IsPowered());
EXPECT_FALSE(adapter_->IsDiscovering());
@@ -2440,6 +2446,35 @@ TEST_F(BluetoothBlueZTest, DevicePairedChanged) {
EXPECT_TRUE(observer.device_new_paired_status());
EXPECT_EQ(devices[idx], observer.last_device());
}
+
+TEST_F(BluetoothBlueZTest, DeviceMTUChanged) {
+ // Simulate a change of MTU of a device.
+ 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 DeviceMTUChanged method to be called with the
+ // updated MTU values.
+ TestBluetoothAdapterObserver observer(adapter_);
+
+ bluez::FakeBluetoothDeviceClient::Properties* properties =
+ fake_bluetooth_device_client_->GetProperties(
+ dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+ ASSERT_EQ(0, observer.device_mtu_changed_count());
+
+ properties->mtu.ReplaceValue(258);
+ EXPECT_EQ(1, observer.device_mtu_changed_count());
+ EXPECT_EQ(258, observer.last_mtu_value());
+
+ properties->mtu.ReplaceValue(128);
+ EXPECT_EQ(2, observer.device_mtu_changed_count());
+ EXPECT_EQ(128, observer.last_mtu_value());
+}
#endif
TEST_F(BluetoothBlueZTest, DeviceUuidsChanged) {
diff --git a/chromium/device/bluetooth/bluez/bluetooth_gatt_service_bluez.cc b/chromium/device/bluetooth/bluez/bluetooth_gatt_service_bluez.cc
index 9d88b747391..aace302a83e 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_gatt_service_bluez.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_gatt_service_bluez.cc
@@ -34,8 +34,7 @@ BluetoothGattServiceBlueZ::DBusErrorToServiceError(std::string error_name) {
code = GATT_ERROR_IN_PROGRESS;
} else if (error_name == bluetooth_gatt_service::kErrorInvalidValueLength) {
code = GATT_ERROR_INVALID_LENGTH;
- } else if (error_name == bluetooth_gatt_service::kErrorReadNotPermitted ||
- error_name == bluetooth_gatt_service::kErrorWriteNotPermitted) {
+ } else if (error_name == bluetooth_gatt_service::kErrorNotPermitted) {
code = GATT_ERROR_NOT_PERMITTED;
} else if (error_name == bluetooth_gatt_service::kErrorNotAuthorized) {
code = GATT_ERROR_NOT_AUTHORIZED;
diff --git a/chromium/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc b/chromium/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
index af35997b09e..024761df4ec 100644
--- a/chromium/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
+++ b/chromium/device/bluetooth/bluez/bluetooth_service_record_bluez_unittest.cc
@@ -10,7 +10,6 @@
#include "base/bind_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluez/bluetooth_adapter_bluez.h"
diff --git a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
index ba185a232df..af5df4cbd04 100644
--- a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
+++ b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.cc
@@ -38,10 +38,12 @@ BluetoothAdapterCast::DiscoveryParams::DiscoveryParams(
DiscoverySessionErrorCallback error_callback)
: filter(filter),
success_callback(success_callback),
- error_callback(error_callback) {}
+ error_callback(std::move(error_callback)) {}
-BluetoothAdapterCast::DiscoveryParams::DiscoveryParams(const DiscoveryParams&) =
- default;
+BluetoothAdapterCast::DiscoveryParams::DiscoveryParams(
+ DiscoveryParams&& params) noexcept = default;
+BluetoothAdapterCast::DiscoveryParams& BluetoothAdapterCast::DiscoveryParams::
+operator=(DiscoveryParams&& params) = default;
BluetoothAdapterCast::DiscoveryParams::~DiscoveryParams() = default;
BluetoothAdapterCast::BluetoothAdapterCast(
@@ -184,7 +186,7 @@ bool BluetoothAdapterCast::SetPoweredImpl(bool powered) {
void BluetoothAdapterCast::AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// The discovery filter is unused for now, as the Cast bluetooth stack does
// not expose scan filters yet. However, implementation of filtering would
// save numerous UI<->IO threadhops by eliminating uneccessary calls to
@@ -200,8 +202,8 @@ void BluetoothAdapterCast::AddDiscoverySession(
}
// Add this request to the queue.
- pending_discovery_requests_.push(DiscoveryParams(
- discovery_filter, std::move(callback), std::move(error_callback)));
+ pending_discovery_requests_.emplace(discovery_filter, std::move(callback),
+ std::move(error_callback));
// If the queue length is greater than 1 (i.e. there was a pending request
// when this method was called), exit early. This request will be processed
@@ -219,7 +221,7 @@ void BluetoothAdapterCast::AddDiscoverySession(
void BluetoothAdapterCast::RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// The discovery filter is unused for now, as the Cast bluetooth stack does
// not expose scan filters yet. However, implementation of filtering would
// save numerous UI<->IO threadhops by eliminating uneccessary calls to
@@ -230,8 +232,8 @@ void BluetoothAdapterCast::RemoveDiscoverySession(
// If there are pending requests, run the error call immediately.
if (pending_discovery_requests_.size() > 0u ||
pending_disable_discovery_request_) {
- error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST);
+ std::move(error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST);
return;
}
@@ -242,8 +244,8 @@ void BluetoothAdapterCast::RemoveDiscoverySession(
}
// This was the last active discovery session. Disable scanning.
- pending_disable_discovery_request_ =
- DiscoveryParams(discovery_filter, callback, error_callback);
+ pending_disable_discovery_request_.emplace(discovery_filter, callback,
+ std::move(error_callback));
le_scan_manager_->SetScanEnable(
false, base::BindOnce(&BluetoothAdapterCast::OnScanDisabled,
weak_factory_.GetWeakPtr()));
@@ -252,7 +254,7 @@ void BluetoothAdapterCast::RemoveDiscoverySession(
void BluetoothAdapterCast::SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) {
+ DiscoverySessionErrorCallback error_callback) {
// The discovery filter is unused for now, as the Cast bluetooth stack does
// not expose scan filters yet. However, implementation of filtering would
// save numerous UI<->IO threadhops by eliminating unnecessary calls to
@@ -298,24 +300,6 @@ void BluetoothAdapterCast::OnMtuChanged(
<< " mtu: " << mtu;
}
-void BluetoothAdapterCast::OnServicesUpdated(
- scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
- std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services) {
- DVLOG(1) << __func__;
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
- std::string address = GetCanonicalBluetoothAddress(device->addr());
- BluetoothDeviceCast* cast_device = GetCastDevice(address);
- if (!cast_device)
- return;
-
- if (!cast_device->UpdateServices(services))
- LOG(WARNING) << "The services were not updated. Alerting anyway.";
-
- cast_device->SetGattServicesDiscoveryComplete(true);
- NotifyGattServicesDiscovered(cast_device);
-}
-
void BluetoothAdapterCast::OnCharacteristicNotification(
scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
@@ -345,17 +329,19 @@ void BluetoothAdapterCast::OnNewScanResult(
// to send an async request to |gatt_client_manager_| for a handle to the
// device.
if (devices_.find(address) == devices_.end()) {
+ bool first_time_seen =
+ pending_scan_results_.find(address) == pending_scan_results_.end();
+ // These results will be used to construct the BluetoothDeviceCast.
+ pending_scan_results_[address].push_back(result);
+
// Only send a request if this is the first time we've seen this |address|
// in a scan. This may happen if we pick up additional GAP advertisements
// while the first request is in-flight.
- if (pending_scan_results_.find(address) == pending_scan_results_.end()) {
+ if (first_time_seen) {
gatt_client_manager_->GetDevice(
result.addr, base::BindOnce(&BluetoothAdapterCast::OnGetDevice,
weak_factory_.GetWeakPtr()));
}
-
- // These results will be used to construct the BluetoothDeviceCast.
- pending_scan_results_[address].push_back(result);
return;
}
@@ -416,8 +402,8 @@ void BluetoothAdapterCast::OnScanEnabled(bool enabled) {
// Run the error callback.
DCHECK(!pending_discovery_requests_.empty());
- pending_discovery_requests_.front().error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::FAILED);
+ std::move(pending_discovery_requests_.front().error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::FAILED);
pending_discovery_requests_.pop();
// If there is another pending request, try again.
@@ -450,8 +436,8 @@ void BluetoothAdapterCast::OnScanDisabled(bool success) {
LOG(WARNING) << "Failed to stop scan.";
// Run the error callback.
- pending_disable_discovery_request_->error_callback.Run(
- UMABluetoothDiscoverySessionOutcome::FAILED);
+ std::move(pending_disable_discovery_request_->error_callback)
+ .Run(UMABluetoothDiscoverySessionOutcome::FAILED);
pending_disable_discovery_request_ = base::nullopt;
return;
}
@@ -527,7 +513,7 @@ base::WeakPtr<BluetoothAdapter> BluetoothAdapterCast::Create(
// static
base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
- const InitCallback& init_callback) {
+ InitCallback init_callback) {
return BluetoothAdapterCast::Create(std::move(init_callback));
}
diff --git a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
index bf09fc72eba..7dca46652a5 100644
--- a/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
+++ b/chromium/device/bluetooth/cast/bluetooth_adapter_cast.h
@@ -93,15 +93,15 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
void AddDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemoveDiscoverySession(
BluetoothDiscoveryFilter* discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void SetDiscoveryFilter(
std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter,
const base::Closure& callback,
- const DiscoverySessionErrorCallback& error_callback) override;
+ DiscoverySessionErrorCallback error_callback) override;
void RemovePairingDelegateInternal(
BluetoothDevice::PairingDelegate* pairing_delegate) override;
@@ -137,10 +137,6 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
bool connected) override;
void OnMtuChanged(scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
int mtu) override;
- void OnServicesUpdated(
- scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
- std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services)
- override;
void OnCharacteristicNotification(
scoped_refptr<chromecast::bluetooth::RemoteDevice> device,
scoped_refptr<chromecast::bluetooth::RemoteCharacteristic> characteristic,
@@ -173,7 +169,8 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterCast
DiscoveryParams(device::BluetoothDiscoveryFilter* filter,
base::Closure success_callback,
DiscoverySessionErrorCallback error_callback);
- DiscoveryParams(const DiscoveryParams&);
+ DiscoveryParams(DiscoveryParams&& params) noexcept;
+ DiscoveryParams& operator=(DiscoveryParams&& params);
~DiscoveryParams();
device::BluetoothDiscoveryFilter* filter = nullptr;
base::Closure success_callback;
diff --git a/chromium/device/bluetooth/cast/bluetooth_device_cast.cc b/chromium/device/bluetooth/cast/bluetooth_device_cast.cc
index 1dfeba95197..32ccb2a546c 100644
--- a/chromium/device/bluetooth/cast/bluetooth_device_cast.cc
+++ b/chromium/device/bluetooth/cast/bluetooth_device_cast.cc
@@ -14,6 +14,7 @@
#include "chromecast/device/bluetooth/bluetooth_util.h"
#include "chromecast/device/bluetooth/le/remote_characteristic.h"
#include "chromecast/device/bluetooth/le/remote_service.h"
+#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h"
#include "device/bluetooth/cast/bluetooth_remote_gatt_service_cast.h"
#include "device/bluetooth/cast/bluetooth_utils.h"
@@ -57,9 +58,15 @@ BluetoothDeviceCast::BluetoothDeviceCast(
BluetoothAdapter* adapter,
scoped_refptr<chromecast::bluetooth::RemoteDevice> device)
: BluetoothDevice(adapter),
+ connected_(device->IsConnected()),
remote_device_(std::move(device)),
address_(GetCanonicalBluetoothAddress(remote_device_->addr())),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ if (connected_) {
+ remote_device_->GetServices(base::BindOnce(
+ &BluetoothDeviceCast::OnGetServices, weak_factory_.GetWeakPtr()));
+ }
+}
BluetoothDeviceCast::~BluetoothDeviceCast() {}
@@ -285,6 +292,8 @@ bool BluetoothDeviceCast::SetConnected(bool connected) {
// fired.
if (!was_connected && connected) {
DidConnectGatt();
+ remote_device_->GetServices(base::BindOnce(
+ &BluetoothDeviceCast::OnGetServices, weak_factory_.GetWeakPtr()));
} else if (was_connected && !connected) {
DidDisconnectGatt();
}
@@ -293,43 +302,23 @@ bool BluetoothDeviceCast::SetConnected(bool connected) {
return was_connected != connected;
}
-bool BluetoothDeviceCast::UpdateServices(
+void BluetoothDeviceCast::OnGetServices(
std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>> services) {
DVLOG(2) << __func__;
- bool changed = false;
-
- // Create a look-up for the updated list of services.
- std::unordered_set<std::string> new_service_uuids;
- for (const auto& service : services)
- new_service_uuids.insert(GetCanonicalBluetoothUuid(service->uuid()));
-
- // Remove any services in |gatt_services_| that are not present in |services|.
- for (auto it = gatt_services_.cbegin(); it != gatt_services_.cend();) {
- if (new_service_uuids.find(it->first) == new_service_uuids.end()) {
- gatt_services_.erase(it++);
- changed = true;
- } else {
- ++it;
- }
- }
+ gatt_services_.clear();
// Add new services.
for (auto& service : services) {
auto key = GetCanonicalBluetoothUuid(service->uuid());
-
- if (gatt_services_.find(key) != gatt_services_.end())
- continue;
-
auto cast_service = std::make_unique<BluetoothRemoteGattServiceCast>(
this, std::move(service));
DCHECK_EQ(key, cast_service->GetIdentifier());
gatt_services_[key] = std::move(cast_service);
- changed = true;
}
- if (changed)
- device_uuids_.ReplaceServiceUUIDs(gatt_services_);
- return changed;
+ device_uuids_.ReplaceServiceUUIDs(gatt_services_);
+ SetGattServicesDiscoveryComplete(true);
+ adapter_->NotifyGattServicesDiscovered(this);
}
bool BluetoothDeviceCast::UpdateCharacteristicValue(
@@ -374,18 +363,14 @@ void BluetoothDeviceCast::DisconnectGatt() {
void BluetoothDeviceCast::OnConnect(bool success) {
DVLOG(2) << __func__ << " success:" << success;
pending_connect_ = false;
- if (success)
- SetConnected(true);
- else
+ if (!success)
DidFailToConnectGatt(ERROR_FAILED);
}
void BluetoothDeviceCast::OnDisconnect(bool success) {
DVLOG(2) << __func__ << " success:" << success;
pending_disconnect_ = false;
- if (success)
- SetConnected(false);
- else
+ if (!success)
LOG(ERROR) << "Request to DisconnectGatt() failed!";
}
diff --git a/chromium/device/bluetooth/cast/bluetooth_device_cast.h b/chromium/device/bluetooth/cast/bluetooth_device_cast.h
index 562ba724dfa..0f212b1f357 100644
--- a/chromium/device/bluetooth/cast/bluetooth_device_cast.h
+++ b/chromium/device/bluetooth/cast/bluetooth_device_cast.h
@@ -95,13 +95,6 @@ class BluetoothDeviceCast : public BluetoothDevice {
// connection state changed as a result.
bool SetConnected(bool connected);
- // Called by BluetoothAdapterCast when the GATT services for this device are
- // updated. Updates the services in this devices to reflect |services|.
- // Returns true if a service was added or removed.
- bool UpdateServices(
- std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>>
- services);
-
// Called by BluetoothAdapterCast when the value of a characteristic in one of
// this device's services has changed, resulting in a notification to the
// device. Locate the characteristc and update the underluing value. If the
@@ -132,7 +125,12 @@ class BluetoothDeviceCast : public BluetoothDevice {
// Called back from disconnect requests.
void OnDisconnect(bool success);
- bool connected_ = false;
+ // Called in response to GetServices
+ void OnGetServices(
+ std::vector<scoped_refptr<chromecast::bluetooth::RemoteService>>
+ services);
+
+ bool connected_;
bool pending_connect_ = false;
bool pending_disconnect_ = false;
diff --git a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
index b0ae0d4b06c..3876ee9d587 100644
--- a/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
+++ b/chromium/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
@@ -164,7 +164,6 @@ void BluetoothRemoteGattCharacteristicCast::WriteRemoteCharacteristic(
const base::Closure& callback,
const ErrorCallback& error_callback) {
remote_characteristic_->Write(
- chromecast::bluetooth_v2_shlib::Gatt::WriteType::WRITE_TYPE_DEFAULT,
value,
base::BindOnce(
&BluetoothRemoteGattCharacteristicCast::OnWriteRemoteCharacteristic,
diff --git a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
index a707cc78670..11d9ca5d255 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
+++ b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.cc
@@ -203,14 +203,14 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
// BluetoothAdapterClient override.
void StartDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStartDiscovery);
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -219,20 +219,21 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
// BluetoothAdapterClient override.
void StopDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kStopDiscovery);
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -241,14 +242,15 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
// BluetoothAdapterClient override.
void RemoveDevice(const dbus::ObjectPath& object_path,
const dbus::ObjectPath& device_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveDevice);
@@ -258,7 +260,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -267,14 +269,15 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
// BluetoothAdapterClient override.
void SetDiscoveryFilter(const dbus::ObjectPath& object_path,
const DiscoveryFilter& discovery_filter,
const base::Closure& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kSetDiscoveryFilter);
@@ -284,7 +287,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -346,14 +349,15 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
// BluetoothAdapterClient override.
void CreateServiceRecord(const dbus::ObjectPath& object_path,
const bluez::BluetoothServiceRecordBlueZ& record,
const ServiceRecordCallback& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kCreateServiceRecord);
@@ -374,7 +378,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -383,14 +387,15 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnCreateServiceRecord,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
// BluetoothAdapterClient override.
void RemoveServiceRecord(const dbus::ObjectPath& object_path,
uint32_t handle,
const base::Closure& callback,
- const ErrorCallback& error_callback) override {
+ ErrorCallback error_callback) override {
dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
bluetooth_adapter::kRemoveServiceRecord);
@@ -399,7 +404,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
dbus::ObjectProxy* object_proxy =
object_manager_->GetObjectProxy(object_path);
if (!object_proxy) {
- error_callback.Run(kUnknownAdapterError, "");
+ std::move(error_callback).Run(kUnknownAdapterError, "");
return;
}
@@ -408,7 +413,8 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
weak_ptr_factory_.GetWeakPtr(), callback),
base::BindOnce(&BluetoothAdapterClientImpl::OnError,
- weak_ptr_factory_.GetWeakPtr(), error_callback));
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(error_callback)));
}
protected:
@@ -466,8 +472,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
}
// Called when a response for a failed method call is received.
- void OnError(const ErrorCallback& error_callback,
- dbus::ErrorResponse* response) {
+ void OnError(ErrorCallback error_callback, dbus::ErrorResponse* response) {
// Error response has optional error message argument.
std::string error_name;
std::string error_message;
@@ -479,7 +484,7 @@ class BluetoothAdapterClientImpl : public BluetoothAdapterClient,
error_name = kNoResponseError;
error_message = "";
}
- error_callback.Run(error_name, error_message);
+ std::move(error_callback).Run(error_name, error_message);
}
dbus::ObjectManager* object_manager_;
diff --git a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
index ba625268a86..0288b76627a 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
+++ b/chromium/device/bluetooth/dbus/bluetooth_adapter_client.h
@@ -143,19 +143,20 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
// The ErrorCallback is used by adapter methods to indicate failure.
// It receives two arguments: the name of the error in |error_name| and
// an optional message in |error_message|.
- typedef base::Callback<void(const std::string& error_name,
- const std::string& error_message)> ErrorCallback;
+ typedef base::OnceCallback<void(const std::string& error_name,
+ const std::string& error_message)>
+ ErrorCallback;
// Starts a device discovery on the adapter with object path |object_path|.
virtual void StartDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// 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,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// Removes from the adapter with object path |object_path| the remote
// device with object path |object_path| from the list of known devices
@@ -163,7 +164,7 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
virtual void RemoveDevice(const dbus::ObjectPath& object_path,
const dbus::ObjectPath& device_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// Sets the device discovery filter on the adapter with object path
// |object_path|. When this method is called with no filter parameter, filter
@@ -174,21 +175,21 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothAdapterClient : public BluezDBusClient {
virtual void SetDiscoveryFilter(const dbus::ObjectPath& object_path,
const DiscoveryFilter& discovery_filter,
const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// Creates the service record |record| on the adapter with the object path
// |object_path|.
virtual void CreateServiceRecord(const dbus::ObjectPath& object_path,
const BluetoothServiceRecordBlueZ& record,
const ServiceRecordCallback& callback,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// Removes the service record with the uuid |uuid| on the adapter with the
// object path |object_path|.
virtual void RemoveServiceRecord(const dbus::ObjectPath& object_path,
uint32_t handle,
const base::Closure& callback,
- const ErrorCallback& error_callback) = 0;
+ ErrorCallback error_callback) = 0;
// Creates the instance.
static BluetoothAdapterClient* Create();
diff --git a/chromium/device/bluetooth/dbus/bluetooth_device_client.cc b/chromium/device/bluetooth/dbus/bluetooth_device_client.cc
index df13ba34189..9a69b3ef415 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_device_client.cc
+++ b/chromium/device/bluetooth/dbus/bluetooth_device_client.cc
@@ -208,6 +208,7 @@ BluetoothDeviceClient::Properties::Properties(
&services_resolved);
RegisterProperty(bluetooth_device::kAdvertisingDataFlagsProperty,
&advertising_data_flags);
+ RegisterProperty(bluetooth_device::kMTUProperty, &mtu);
}
BluetoothDeviceClient::Properties::~Properties() = default;
diff --git a/chromium/device/bluetooth/dbus/bluetooth_device_client.h b/chromium/device/bluetooth/dbus/bluetooth_device_client.h
index a7313bad404..d670b360f67 100644
--- a/chromium/device/bluetooth/dbus/bluetooth_device_client.h
+++ b/chromium/device/bluetooth/dbus/bluetooth_device_client.h
@@ -123,6 +123,9 @@ class DEVICE_BLUETOOTH_EXPORT BluetoothDeviceClient : public BluezDBusClient {
// The Advertising Data Flags of the remote device. Read-only.
dbus::Property<std::vector<uint8_t>> advertising_data_flags;
+ // The MTU used in ATT communication with the remote device. Read-only.
+ dbus::Property<uint16_t> mtu;
+
Properties(dbus::ObjectProxy* object_proxy,
const std::string& interface_name,
const PropertyChangedCallback& callback);
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
index 2f24e8cda68..0577108ff3a 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
@@ -133,9 +133,10 @@ FakeBluetoothAdapterClient::GetProperties(const dbus::ObjectPath& object_path) {
void FakeBluetoothAdapterClient::StartDiscovery(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
- PostDelayedTask(base::Bind(error_callback, kNoResponseError, ""));
+ PostDelayedTask(
+ base::BindOnce(std::move(error_callback), kNoResponseError, ""));
return;
}
@@ -157,15 +158,17 @@ void FakeBluetoothAdapterClient::StartDiscovery(
void FakeBluetoothAdapterClient::StopDiscovery(
const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
- PostDelayedTask(base::Bind(error_callback, kNoResponseError, ""));
+ PostDelayedTask(
+ base::BindOnce(std::move(error_callback), kNoResponseError, ""));
return;
}
if (!discovering_count_) {
LOG(WARNING) << "StopDiscovery called when not discovering";
- PostDelayedTask(base::Bind(error_callback, kNoResponseError, ""));
+ PostDelayedTask(
+ base::BindOnce(std::move(error_callback), kNoResponseError, ""));
return;
}
@@ -194,9 +197,9 @@ void FakeBluetoothAdapterClient::RemoveDevice(
const dbus::ObjectPath& object_path,
const dbus::ObjectPath& device_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
- error_callback.Run(kNoResponseError, "");
+ std::move(error_callback).Run(kNoResponseError, "");
return;
}
@@ -218,15 +221,17 @@ void FakeBluetoothAdapterClient::SetDiscoveryFilter(
const dbus::ObjectPath& object_path,
const DiscoveryFilter& discovery_filter,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
if (object_path != dbus::ObjectPath(kAdapterPath)) {
- PostDelayedTask(base::Bind(error_callback, kNoResponseError, ""));
+ PostDelayedTask(
+ base::BindOnce(std::move(error_callback), kNoResponseError, ""));
return;
}
VLOG(1) << "SetDiscoveryFilter: " << object_path.value();
if (set_discovery_filter_should_fail_) {
- PostDelayedTask(base::Bind(error_callback, kNoResponseError, ""));
+ PostDelayedTask(
+ base::BindOnce(std::move(error_callback), kNoResponseError, ""));
set_discovery_filter_should_fail_ = false;
return;
}
@@ -240,7 +245,7 @@ void FakeBluetoothAdapterClient::CreateServiceRecord(
const dbus::ObjectPath& object_path,
const bluez::BluetoothServiceRecordBlueZ& record,
const ServiceRecordCallback& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
++last_handle_;
records_.insert(
std::pair<uint32_t, BluetoothServiceRecordBlueZ>(last_handle_, record));
@@ -251,11 +256,12 @@ void FakeBluetoothAdapterClient::RemoveServiceRecord(
const dbus::ObjectPath& object_path,
uint32_t handle,
const base::Closure& callback,
- const ErrorCallback& error_callback) {
+ ErrorCallback error_callback) {
auto it = records_.find(handle);
if (it == records_.end()) {
- error_callback.Run(bluetooth_adapter::kErrorDoesNotExist,
- "Service record does not exist.");
+ std::move(error_callback)
+ .Run(bluetooth_adapter::kErrorDoesNotExist,
+ "Service record does not exist.");
return;
}
records_.erase(it);
@@ -337,10 +343,9 @@ void FakeBluetoothAdapterClient::OnPropertyChanged(
}
}
-void FakeBluetoothAdapterClient::PostDelayedTask(
- const base::Closure& callback) {
+void FakeBluetoothAdapterClient::PostDelayedTask(base::OnceClosure callback) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, callback,
+ FROM_HERE, std::move(callback),
base::TimeDelta::FromMilliseconds(simulation_interval_ms_));
}
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
index f43bddd4ca7..7e8b234dc16 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
@@ -48,26 +48,26 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothAdapterClient
Properties* GetProperties(const dbus::ObjectPath& object_path) override;
void StartDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
void StopDiscovery(const dbus::ObjectPath& object_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
void RemoveDevice(const dbus::ObjectPath& object_path,
const dbus::ObjectPath& device_path,
const base::Closure& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
void SetDiscoveryFilter(const dbus::ObjectPath& object_path,
const DiscoveryFilter& discovery_filter,
const base::Closure& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
void CreateServiceRecord(const dbus::ObjectPath& object_path,
const bluez::BluetoothServiceRecordBlueZ& record,
const ServiceRecordCallback& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
void RemoveServiceRecord(const dbus::ObjectPath& object_path,
uint32_t handle,
const base::Closure& callback,
- const ErrorCallback& error_callback) override;
+ ErrorCallback error_callback) override;
// Sets the current simulation timeout interval.
void SetSimulationIntervalMs(int interval_ms);
@@ -104,7 +104,7 @@ class DEVICE_BLUETOOTH_EXPORT FakeBluetoothAdapterClient
// Posts the delayed task represented by |callback| onto the current
// message loop to be executed after |simulation_interval_ms_| milliseconds.
- void PostDelayedTask(const base::Closure& callback);
+ void PostDelayedTask(base::OnceClosure callback);
// List of observers interested in event notifications from us.
base::ObserverList<Observer> observers_;
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
index 8973c603915..66fc0f11abe 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
@@ -148,7 +148,7 @@ void FakeBluetoothGattCharacteristicClient::ReadValue(
}
if (object_path.value() == heart_rate_control_point_path_) {
- error_callback.Run(bluetooth_gatt_service::kErrorReadNotPermitted,
+ error_callback.Run(bluetooth_gatt_service::kErrorNotPermitted,
"Reads of this value are not allowed");
return;
}
@@ -226,7 +226,7 @@ void FakeBluetoothGattCharacteristicClient::WriteValue(
}
if (object_path.value() != heart_rate_control_point_path_) {
- error_callback.Run(bluetooth_gatt_service::kErrorWriteNotPermitted,
+ error_callback.Run(bluetooth_gatt_service::kErrorNotPermitted,
"Writes of this value are not allowed");
return;
}
diff --git a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
index 1d4783a3c0b..974571534a8 100644
--- a/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
+++ b/chromium/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
@@ -138,7 +138,7 @@ void FakeBluetoothGattDescriptorClient::WriteValue(
// Since the only fake descriptor is "Client Characteristic Configuration"
// and BlueZ doesn't allow writing to it, return failure.
- error_callback.Run(bluetooth_gatt_service::kErrorWriteNotPermitted,
+ error_callback.Run(bluetooth_gatt_service::kErrorNotPermitted,
"Writing to the Client Characteristic Configuration "
"descriptor not allowed");
}
diff --git a/chromium/device/bluetooth/public/mojom/BUILD.gn b/chromium/device/bluetooth/public/mojom/BUILD.gn
index b4c1b1893af..0adcd734d1e 100644
--- a/chromium/device/bluetooth/public/mojom/BUILD.gn
+++ b/chromium/device/bluetooth/public/mojom/BUILD.gn
@@ -24,8 +24,6 @@ mojom("fake_bluetooth_interfaces") {
":mojom",
]
- use_once_callback = true
-
# This mojom interface is exposed publicly to layout tests which use
# prepackaged redistributable JS bindings. It is therefore not desirable to
# scramble these messages.
diff --git a/chromium/device/bluetooth/strings/OWNERS b/chromium/device/bluetooth/strings/OWNERS
index b1598b50912..3d41590efa9 100644
--- a/chromium/device/bluetooth/strings/OWNERS
+++ b/chromium/device/bluetooth/strings/OWNERS
@@ -1,2 +1 @@
-per-file *.gyp*=*
per-file BUILD.gn=*
diff --git a/chromium/device/fido/BUILD.gn b/chromium/device/fido/BUILD.gn
index ea09dff5dfb..9ac467aa604 100644
--- a/chromium/device/fido/BUILD.gn
+++ b/chromium/device/fido/BUILD.gn
@@ -31,34 +31,48 @@ component("fido") {
"ctap_get_assertion_request.h",
"ctap_make_credential_request.cc",
"ctap_make_credential_request.h",
+ "ctap_register_operation.cc",
+ "ctap_register_operation.h",
+ "device_operation.h",
"device_response_converter.cc",
"device_response_converter.h",
"ec_public_key.cc",
"ec_public_key.h",
"fido_attestation_statement.cc",
"fido_attestation_statement.h",
+ "fido_authenticator.h",
"fido_ble_connection.cc",
"fido_ble_connection.h",
"fido_ble_device.cc",
"fido_ble_device.h",
"fido_ble_discovery.cc",
"fido_ble_discovery.h",
+ "fido_ble_discovery_base.cc",
+ "fido_ble_discovery_base.h",
"fido_ble_frames.cc",
"fido_ble_frames.h",
"fido_ble_transaction.cc",
"fido_ble_transaction.h",
"fido_ble_uuids.cc",
"fido_ble_uuids.h",
+ "fido_cable_device.cc",
+ "fido_cable_device.h",
+ "fido_cable_discovery.cc",
+ "fido_cable_discovery.h",
"fido_constants.cc",
"fido_constants.h",
"fido_device.cc",
"fido_device.h",
+ "fido_device_authenticator.cc",
+ "fido_device_authenticator.h",
"fido_discovery.cc",
"fido_discovery.h",
"fido_hid_message.cc",
"fido_hid_message.h",
"fido_hid_packet.cc",
"fido_hid_packet.h",
+ "fido_parsing_utils.cc",
+ "fido_parsing_utils.h",
"fido_request_handler.h",
"fido_request_handler_base.cc",
"fido_request_handler_base.h",
@@ -89,8 +103,8 @@ component("fido") {
"public_key_credential_user_entity.h",
"response_data.cc",
"response_data.h",
- "u2f_parsing_utils.cc",
- "u2f_parsing_utils.h",
+ "u2f_command_constructor.cc",
+ "u2f_command_constructor.h",
"u2f_register.cc",
"u2f_register.h",
"u2f_request.cc",
@@ -99,6 +113,8 @@ component("fido") {
"u2f_sign.h",
"virtual_fido_device.cc",
"virtual_fido_device.h",
+ "virtual_u2f_device.cc",
+ "virtual_u2f_device.h",
]
defines = [ "IS_DEVICE_FIDO_IMPL" ]
@@ -119,6 +135,8 @@ component("fido") {
"//services/device/public/mojom",
]
+ libs = [] # Extended for mac.
+
# HID is not supported on Android.
if (!is_android) {
sources += [
@@ -133,6 +151,31 @@ component("fido") {
"//services/device/public/mojom",
]
}
+
+ if (is_mac) {
+ sources += [
+ "mac/authenticator.h",
+ "mac/authenticator.mm",
+ "mac/get_assertion_operation.h",
+ "mac/get_assertion_operation.mm",
+ "mac/keychain.h",
+ "mac/keychain.mm",
+ "mac/make_credential_operation.h",
+ "mac/make_credential_operation.mm",
+ "mac/operation.h",
+ "mac/operation_base.h",
+ "mac/touch_id_context.h",
+ "mac/touch_id_context.mm",
+ "mac/util.h",
+ "mac/util.mm",
+ ]
+
+ libs += [
+ "Foundation.framework",
+ "LocalAuthentication.framework",
+ "Security.framework",
+ ]
+ }
}
source_set("mocks") {
diff --git a/chromium/device/fido/attested_credential_data.cc b/chromium/device/fido/attested_credential_data.cc
index 77ae6606840..90bc165a558 100644
--- a/chromium/device/fido/attested_credential_data.cc
+++ b/chromium/device/fido/attested_credential_data.cc
@@ -8,9 +8,9 @@
#include <utility>
#include "base/numerics/safe_math.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/opaque_public_key.h"
#include "device/fido/public_key.h"
-#include "device/fido/u2f_parsing_utils.h"
namespace device {
@@ -22,12 +22,12 @@ AttestedCredentialData::DecodeFromCtapResponse(
return base::nullopt;
std::array<uint8_t, kAaguidLength> aaguid;
- if (!u2f_parsing_utils::ExtractArray(buffer, 0, &aaguid))
+ if (!fido_parsing_utils::ExtractArray(buffer, 0, &aaguid))
return base::nullopt;
std::array<uint8_t, kCredentialIdLengthLength> credential_id_length_array;
- if (!u2f_parsing_utils::ExtractArray(buffer, kAaguidLength,
- &credential_id_length_array)) {
+ if (!fido_parsing_utils::ExtractArray(buffer, kAaguidLength,
+ &credential_id_length_array)) {
return base::nullopt;
}
@@ -36,7 +36,7 @@ AttestedCredentialData::DecodeFromCtapResponse(
(base::strict_cast<size_t>(credential_id_length_array[0]) << 8) |
base::strict_cast<size_t>(credential_id_length_array[1]);
- auto credential_id = u2f_parsing_utils::Extract(
+ auto credential_id = fido_parsing_utils::Extract(
buffer, kAaguidLength + kCredentialIdLengthLength, credential_id_length);
if (credential_id.empty())
return base::nullopt;
@@ -60,8 +60,8 @@ AttestedCredentialData::CreateFromU2fRegisterResponse(
// TODO(crbug/799075): Introduce a CredentialID class to do this extraction.
// Extract the length of the credential (i.e. of the U2FResponse key
// handle). Length is big endian.
- std::vector<uint8_t> extracted_length = u2f_parsing_utils::Extract(
- u2f_data, u2f_parsing_utils::kU2fResponseKeyHandleLengthPos, 1);
+ std::vector<uint8_t> extracted_length = fido_parsing_utils::Extract(
+ u2f_data, fido_parsing_utils::kU2fResponseKeyHandleLengthPos, 1);
if (extracted_length.empty()) {
return base::nullopt;
@@ -76,8 +76,8 @@ AttestedCredentialData::CreateFromU2fRegisterResponse(
0, extracted_length[0]};
// Extract the credential id (i.e. key handle).
- std::vector<uint8_t> credential_id = u2f_parsing_utils::Extract(
- u2f_data, u2f_parsing_utils::kU2fResponseKeyHandleStartPos,
+ std::vector<uint8_t> credential_id = fido_parsing_utils::Extract(
+ u2f_data, fido_parsing_utils::kU2fResponseKeyHandleStartPos,
base::strict_cast<size_t>(credential_id_length[1]));
if (credential_id.empty()) {
@@ -103,13 +103,13 @@ void AttestedCredentialData::DeleteAaguid() {
std::vector<uint8_t> AttestedCredentialData::SerializeAsBytes() const {
std::vector<uint8_t> attestation_data;
- u2f_parsing_utils::Append(&attestation_data,
- base::make_span(aaguid_.data(), kAaguidLength));
- u2f_parsing_utils::Append(
+ fido_parsing_utils::Append(&attestation_data,
+ base::make_span(aaguid_.data(), kAaguidLength));
+ fido_parsing_utils::Append(
&attestation_data,
base::make_span(credential_id_length_.data(), kCredentialIdLengthLength));
- u2f_parsing_utils::Append(&attestation_data, credential_id_);
- u2f_parsing_utils::Append(&attestation_data, public_key_->EncodeAsCOSEKey());
+ fido_parsing_utils::Append(&attestation_data, credential_id_);
+ fido_parsing_utils::Append(&attestation_data, public_key_->EncodeAsCOSEKey());
return attestation_data;
}
diff --git a/chromium/device/fido/attested_credential_data.h b/chromium/device/fido/attested_credential_data.h
index c33dccbaea2..7e4f02e132d 100644
--- a/chromium/device/fido/attested_credential_data.h
+++ b/chromium/device/fido/attested_credential_data.h
@@ -48,7 +48,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AttestedCredentialData {
// * Credential Public Key.
std::vector<uint8_t> SerializeAsBytes() const;
- private:
static constexpr size_t kAaguidLength = 16;
// Number of bytes used to represent length of credential ID.
static constexpr size_t kCredentialIdLengthLength = 2;
@@ -59,6 +58,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) AttestedCredentialData {
std::vector<uint8_t> credential_id,
std::unique_ptr<PublicKey> public_key);
+ private:
// The 16-byte AAGUID of the authenticator.
std::array<uint8_t, kAaguidLength> aaguid_;
diff --git a/chromium/device/fido/authenticator_data.cc b/chromium/device/fido/authenticator_data.cc
index cfd67692240..e979b0a31be 100644
--- a/chromium/device/fido/authenticator_data.cc
+++ b/chromium/device/fido/authenticator_data.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "device/fido/attested_credential_data.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -69,14 +69,14 @@ void AuthenticatorData::DeleteDeviceAaguid() {
std::vector<uint8_t> AuthenticatorData::SerializeToByteArray() const {
std::vector<uint8_t> authenticator_data;
- u2f_parsing_utils::Append(&authenticator_data, application_parameter_);
+ fido_parsing_utils::Append(&authenticator_data, application_parameter_);
authenticator_data.insert(authenticator_data.end(), flags_);
- u2f_parsing_utils::Append(&authenticator_data, counter_);
+ fido_parsing_utils::Append(&authenticator_data, counter_);
if (attested_data_) {
// Attestations are returned in registration responses but not in assertion
// responses.
- u2f_parsing_utils::Append(&authenticator_data,
- attested_data_->SerializeAsBytes());
+ fido_parsing_utils::Append(&authenticator_data,
+ attested_data_->SerializeAsBytes());
}
return authenticator_data;
}
diff --git a/chromium/device/fido/authenticator_get_assertion_response.cc b/chromium/device/fido/authenticator_get_assertion_response.cc
index 7d801c317ea..dc83b75b500 100644
--- a/chromium/device/fido/authenticator_get_assertion_response.cc
+++ b/chromium/device/fido/authenticator_get_assertion_response.cc
@@ -8,7 +8,7 @@
#include "base/optional.h"
#include "device/fido/authenticator_data.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -31,27 +31,27 @@ AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
if (key_handle.empty())
return base::nullopt;
- auto flags = u2f_parsing_utils::Extract(u2f_data, kFlagIndex, kFlagLength);
+ auto flags = fido_parsing_utils::Extract(u2f_data, kFlagIndex, kFlagLength);
if (flags.empty())
return base::nullopt;
auto counter =
- u2f_parsing_utils::Extract(u2f_data, kCounterIndex, kCounterLength);
+ fido_parsing_utils::Extract(u2f_data, kCounterIndex, kCounterLength);
if (counter.empty())
return base::nullopt;
AuthenticatorData authenticator_data(relying_party_id_hash, flags[0],
std::move(counter), base::nullopt);
- auto signature = u2f_parsing_utils::Extract(
+ auto signature = fido_parsing_utils::Extract(
u2f_data, kSignatureIndex, u2f_data.size() - kSignatureIndex);
if (signature.empty())
return base::nullopt;
AuthenticatorGetAssertionResponse response(std::move(authenticator_data),
std::move(signature));
- response.SetCredential(PublicKeyCredentialDescriptor(
- to_string(CredentialType::kPublicKey), key_handle));
+ response.SetCredential(
+ PublicKeyCredentialDescriptor(CredentialType::kPublicKey, key_handle));
return std::move(response);
}
diff --git a/chromium/device/fido/authenticator_make_credential_response.cc b/chromium/device/fido/authenticator_make_credential_response.cc
index addc6f1e16f..e916787ef60 100644
--- a/chromium/device/fido/authenticator_make_credential_response.cc
+++ b/chromium/device/fido/authenticator_make_credential_response.cc
@@ -11,7 +11,7 @@
#include "device/fido/authenticator_data.h"
#include "device/fido/ec_public_key.h"
#include "device/fido/fido_attestation_statement.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -21,7 +21,7 @@ AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
const std::vector<uint8_t>& relying_party_id_hash,
base::span<const uint8_t> u2f_data) {
auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
- u2f_parsing_utils::kEs256, u2f_data);
+ fido_parsing_utils::kEs256, u2f_data);
if (!public_key)
return base::nullopt;
diff --git a/chromium/device/fido/ctap_get_assertion_request.cc b/chromium/device/fido/ctap_get_assertion_request.cc
index 9e3dfc171da..8fb876ad766 100644
--- a/chromium/device/fido/ctap_get_assertion_request.cc
+++ b/chromium/device/fido/ctap_get_assertion_request.cc
@@ -112,4 +112,10 @@ CtapGetAssertionRequest& CtapGetAssertionRequest::SetPinProtocol(
return *this;
}
+CtapGetAssertionRequest& CtapGetAssertionRequest::SetCableExtension(
+ std::vector<FidoCableDiscovery::CableDiscoveryData> cable_extension) {
+ cable_extension_ = std::move(cable_extension);
+ return *this;
+}
+
} // namespace device
diff --git a/chromium/device/fido/ctap_get_assertion_request.h b/chromium/device/fido/ctap_get_assertion_request.h
index 3983ceb9a36..25ee8a6a186 100644
--- a/chromium/device/fido/ctap_get_assertion_request.h
+++ b/chromium/device/fido/ctap_get_assertion_request.h
@@ -13,6 +13,7 @@
#include "base/component_export.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "device/fido/fido_cable_discovery.h"
#include "device/fido/fido_constants.h"
#include "device/fido/public_key_credential_descriptor.h"
@@ -43,6 +44,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
std::vector<PublicKeyCredentialDescriptor> allow_list);
CtapGetAssertionRequest& SetPinAuth(std::vector<uint8_t> pin_auth);
CtapGetAssertionRequest& SetPinProtocol(uint8_t pin_protocol);
+ CtapGetAssertionRequest& SetCableExtension(
+ std::vector<FidoCableDiscovery::CableDiscoveryData> cable_extension);
const std::string& rp_id() const { return rp_id_; }
const std::vector<uint8_t>& client_data_hash() const {
@@ -64,6 +67,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
}
const base::Optional<uint8_t>& pin_protocol() const { return pin_protocol_; }
+ const base::Optional<std::vector<FidoCableDiscovery::CableDiscoveryData>>&
+ cable_extension() const {
+ return cable_extension_;
+ }
private:
std::string rp_id_;
@@ -75,6 +82,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapGetAssertionRequest {
base::Optional<std::vector<PublicKeyCredentialDescriptor>> allow_list_;
base::Optional<std::vector<uint8_t>> pin_auth_;
base::Optional<uint8_t> pin_protocol_;
+ base::Optional<std::vector<FidoCableDiscovery::CableDiscoveryData>>
+ cable_extension_;
};
} // namespace device
diff --git a/chromium/device/fido/ctap_make_credential_request.h b/chromium/device/fido/ctap_make_credential_request.h
index 574bd48aea9..2e47e855ef5 100644
--- a/chromium/device/fido/ctap_make_credential_request.h
+++ b/chromium/device/fido/ctap_make_credential_request.h
@@ -61,6 +61,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CtapMakeCredentialRequest {
return user_verification_required_;
}
bool resident_key_supported() const { return resident_key_supported_; }
+ const base::Optional<std::vector<PublicKeyCredentialDescriptor>>&
+ exclude_list() const {
+ return exclude_list_;
+ }
private:
std::vector<uint8_t> client_data_hash_;
diff --git a/chromium/device/fido/ctap_register_operation.cc b/chromium/device/fido/ctap_register_operation.cc
new file mode 100644
index 00000000000..c2776cffd6f
--- /dev/null
+++ b/chromium/device/fido/ctap_register_operation.cc
@@ -0,0 +1,46 @@
+// 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/ctap_register_operation.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/device_response_converter.h"
+#include "device/fido/fido_device.h"
+
+namespace device {
+
+CtapRegisterOperation::CtapRegisterOperation(
+ FidoDevice* device,
+ const CtapMakeCredentialRequest* request,
+ DeviceResponseCallback callback)
+ : DeviceOperation(device, std::move(callback)),
+ request_(request),
+ weak_factory_(this) {}
+
+CtapRegisterOperation::~CtapRegisterOperation() = default;
+
+void CtapRegisterOperation::Start() {
+ device_->DeviceTransact(
+ request_->EncodeAsCBOR(),
+ base::BindOnce(&CtapRegisterOperation::OnResponseReceived,
+ weak_factory_.GetWeakPtr()));
+}
+
+void CtapRegisterOperation::OnResponseReceived(
+ base::Optional<std::vector<uint8_t>> device_response) {
+ if (!device_response) {
+ std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
+ base::nullopt);
+ return;
+ }
+
+ std::move(callback_).Run(GetResponseCode(*device_response),
+ ReadCTAPMakeCredentialResponse(*device_response));
+}
+
+} // namespace device
diff --git a/chromium/device/fido/ctap_register_operation.h b/chromium/device/fido/ctap_register_operation.h
new file mode 100644
index 00000000000..b188d18b5e2
--- /dev/null
+++ b/chromium/device/fido/ctap_register_operation.h
@@ -0,0 +1,56 @@
+// 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_CTAP_REGISTER_OPERATION_H_
+#define DEVICE_FIDO_CTAP_REGISTER_OPERATION_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "device/fido/device_operation.h"
+#include "device/fido/fido_constants.h"
+
+namespace device {
+
+class FidoDevice;
+class CtapMakeCredentialRequest;
+class AuthenticatorMakeCredentialResponse;
+
+// Represents per device registration logic for CTAP device.
+// CtapRegisterOperation is owned by MakeCredentialTask, and the lifetime of
+// CtapRegisterOperation does not exceed that of MakeCredentialTask. As so,
+// |request_| member variable is dependency injected from MakeCredentialTask.
+class COMPONENT_EXPORT(DEVICE_FIDO) CtapRegisterOperation
+ : public DeviceOperation<CtapMakeCredentialRequest,
+ AuthenticatorMakeCredentialResponse> {
+ public:
+ CtapRegisterOperation(FidoDevice* device,
+ const CtapMakeCredentialRequest* request,
+ DeviceResponseCallback callback);
+
+ ~CtapRegisterOperation() override;
+
+ // DeviceOperation:
+ void Start() override;
+
+ private:
+ void OnResponseReceived(base::Optional<std::vector<uint8_t>> device_response);
+
+ const CtapMakeCredentialRequest* const request_;
+
+ base::WeakPtrFactory<CtapRegisterOperation> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CtapRegisterOperation);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_CTAP_REGISTER_OPERATION_H_
diff --git a/chromium/device/fido/ctap_request_unittest.cc b/chromium/device/fido/ctap_request_unittest.cc
index 40b6f1df0dc..725d0514ff7 100644
--- a/chromium/device/fido/ctap_request_unittest.cc
+++ b/chromium/device/fido/ctap_request_unittest.cc
@@ -6,6 +6,8 @@
#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_parsing_utils.h"
+#include "device/fido/fido_test_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,16 +16,6 @@ namespace device {
// Leveraging example 4 of section 6.1 of the spec
// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
TEST(CTAPRequestTest, TestConstructMakeCredentialRequestParam) {
- static 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};
-
- static constexpr uint8_t kUserId[] = {
- 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
- 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0,
- 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82};
-
static constexpr uint8_t kSerializedRequest[] = {
// clang-format off
0x01, // authenticatorMakeCredential command
@@ -50,10 +42,8 @@ TEST(CTAPRequestTest, TestConstructMakeCredentialRequestParam) {
0xa4, // map(4)
0x62, // text(2)
0x69, 0x64, // "id"
- 0x58, 0x20, // bytes(32) - user id
- 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
- 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82,
+ 0x48, // bytes(8) - user id
+ 0x10, 0x98, 0x23, 0x72, 0x35, 0x40, 0x98, 0x72,
0x64, // text(4)
0x69, 0x63, 0x6f, 0x6e, // "icon"
0x78, 0x28, // text(40)
@@ -112,13 +102,13 @@ TEST(CTAPRequestTest, TestConstructMakeCredentialRequestParam) {
rp.SetRpName("Acme");
PublicKeyCredentialUserEntity user(
- std::vector<uint8_t>(kUserId, std::end(kUserId)));
+ fido_parsing_utils::Materialize(test_data::kUserId));
user.SetUserName("johnpsmith@example.com")
.SetDisplayName("John P. Smith")
.SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
CtapMakeCredentialRequest make_credential_param(
- std::vector<uint8_t>(kClientDataHash, std::end(kClientDataHash)),
+ fido_parsing_utils::Materialize(test_data::kClientDataHash),
std::move(rp), std::move(user),
PublicKeyCredentialParams({{CredentialType::kPublicKey, 7},
{CredentialType::kPublicKey, 257}}));
@@ -129,11 +119,6 @@ TEST(CTAPRequestTest, TestConstructMakeCredentialRequestParam) {
}
TEST(CTAPRequestTest, TestConstructGetAssertionRequest) {
- static 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};
-
static constexpr uint8_t kSerializedRequest[] = {
// clang-format off
0x02, // authenticatorGetAssertion command
@@ -198,12 +183,11 @@ TEST(CTAPRequestTest, TestConstructGetAssertionRequest) {
};
CtapGetAssertionRequest get_assertion_req(
- "acme.com",
- std::vector<uint8_t>(kClientDataHash, std::end(kClientDataHash)));
+ "acme.com", fido_parsing_utils::Materialize(test_data::kClientDataHash));
std::vector<PublicKeyCredentialDescriptor> allowed_list;
allowed_list.push_back(PublicKeyCredentialDescriptor(
- "public-key",
+ CredentialType::kPublicKey,
{0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94,
0x2f, 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b,
0x3d, 0xf8, 0xbe, 0x08, 0xed, 0x01, 0xfc, 0x44, 0x26, 0x46, 0xd0,
@@ -211,7 +195,7 @@ TEST(CTAPRequestTest, TestConstructGetAssertionRequest) {
0x08, 0xd9, 0x4f, 0xcb, 0xee, 0x82, 0xb9, 0xb2, 0xef, 0x66, 0x77,
0xaf, 0x0a, 0xdc, 0xc3, 0x58, 0x52, 0xea, 0x6b, 0x9e}));
allowed_list.push_back(PublicKeyCredentialDescriptor(
- "public-key",
+ CredentialType::kPublicKey,
{0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
diff --git a/chromium/device/fido/ctap_response_unittest.cc b/chromium/device/fido/ctap_response_unittest.cc
index dcafb902223..45c44c3e9a3 100644
--- a/chromium/device/fido/ctap_response_unittest.cc
+++ b/chromium/device/fido/ctap_response_unittest.cc
@@ -4,10 +4,15 @@
#include "components/cbor/cbor_reader.h"
#include "components/cbor/cbor_values.h"
+#include "components/cbor/cbor_writer.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/device_response_converter.h"
+#include "device/fido/ec_public_key.h"
+#include "device/fido/fido_attestation_statement.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/fido_test_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,162 +20,125 @@ namespace device {
namespace {
-const uint8_t kDeviceMakeCredentialResponse[] = {
- // clang-format off
- 0x00, // Success response code
- 0xa3, // map(3)
- 0x01, // unsigned(1)
- 0x66, // text(6)
- // "packed"
- 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64,
-
- 0x02, // unsigned(2)
- 0x58, 0x9a, // bytes(154)
- // auth data
- 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
- 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
- 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 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,
-
- 0x03, // unsigned(3)
- 0xa3, // map(3)
- 0x63, // text(3)
- 0x61, 0x6c, 0x67, // "alg"
- 0x07, // 7
- 0x63, // text(3)
- 0x73, 0x69, 0x67, // "sig"
- 0x58, 0x47, // bytes(71)
- // signature
- 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c,
- 0xc1, 0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4,
- 0x62, 0xd5, 0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89,
- 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5,
- 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7,
- 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29,
-
- 0x63, // text(3)
- 0x78, 0x35, 0x63, // "x5c"
- 0x81, // array(1)
- 0x59, 0x01, 0x97, // bytes(407)
- // certificate
- 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29,
- 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
- 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73,
- 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19,
- 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f,
- 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31,
- 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x32,
- 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
- 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59,
- 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22,
- 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74,
- 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41,
- 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59,
- 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
- 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
- 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52, 0xe5, 0x3a, 0xd5, 0xdf, 0xed,
- 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf, 0x8f, 0x22,
- 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04,
- 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c,
- 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60,
- 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08,
- 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30,
- 0x46, 0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25,
- 0xf7, 0x37, 0x3e, 0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94,
- 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7,
- 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43,
- 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9,
- 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3
- // clang-format on
+// The attested credential data, excluding the public key bytes. Append
+// with kTestECPublicKeyCOSE to get the complete attestation data.
+constexpr uint8_t kTestAttestedCredentialDataPrefix[] = {
+ // 16-byte aaguid
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ // 2-byte length
+ 0x00, 0x40,
+ // 64-byte key handle
+ 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26,
+ 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3,
+ 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94,
+ 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64,
+ 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08,
+ 0xFE, 0x42, 0x00, 0x38,
};
+// The authenticator data, excluding the attested credential data bytes. Append
+// with attested credential data to get the complete authenticator data.
+constexpr uint8_t kTestAuthenticatorDataPrefix[] = {
+ // sha256 hash of rp id.
+ 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 (TUP and AT bits set)
+ 0x41,
+ // counter
+ 0x00, 0x00, 0x00, 0x00};
+
+// Components of the CBOR needed to form an authenticator object.
+// Combined diagnostic notation:
+// {"fmt": "fido-u2f", "attStmt": {"sig": h'30...}, "authData": h'D4C9D9...'}
+constexpr uint8_t kFormatFidoU2fCBOR[] = {
+ // map(3)
+ 0xA3,
+ // text(3)
+ 0x63,
+ // "fmt"
+ 0x66, 0x6D, 0x74,
+ // text(8)
+ 0x68,
+ // "fido-u2f"
+ 0x66, 0x69, 0x64, 0x6F, 0x2D, 0x75, 0x32, 0x66};
+
+constexpr uint8_t kAttStmtCBOR[] = {
+ // text(7)
+ 0x67,
+ // "attStmt"
+ 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74};
+
+constexpr uint8_t kAuthDataCBOR[] = {
+ // text(8)
+ 0x68,
+ // "authData"
+ 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
+ // bytes(196). i.e., the authenticator_data byte array corresponding to
+ // kTestAuthenticatorDataPrefix|, |kTestAttestedCredentialDataPrefix|,
+ // and test_data::kTestECPublicKeyCOSE.
+ 0x58, 0xC4};
+
+std::vector<uint8_t> GetTestAttestedCredentialDataBytes() {
+ // Combine kTestAttestedCredentialDataPrefix and kTestECPublicKeyCOSE.
+ auto test_attested_data =
+ fido_parsing_utils::Materialize(kTestAttestedCredentialDataPrefix);
+ fido_parsing_utils::Append(&test_attested_data,
+ test_data::kTestECPublicKeyCOSE);
+ return test_attested_data;
+}
+
+std::vector<uint8_t> GetTestAuthenticatorDataBytes() {
+ // Build the test authenticator data.
+ auto test_authenticator_data =
+ fido_parsing_utils::Materialize(kTestAuthenticatorDataPrefix);
+ auto test_attested_data = GetTestAttestedCredentialDataBytes();
+ fido_parsing_utils::Append(&test_authenticator_data, test_attested_data);
+ return test_authenticator_data;
+}
+
+std::vector<uint8_t> GetTestAttestationObjectBytes() {
+ auto test_authenticator_object =
+ fido_parsing_utils::Materialize(kFormatFidoU2fCBOR);
+ fido_parsing_utils::Append(&test_authenticator_object, kAttStmtCBOR);
+ fido_parsing_utils::Append(&test_authenticator_object,
+ test_data::kU2fAttestationStatementCBOR);
+ fido_parsing_utils::Append(&test_authenticator_object, kAuthDataCBOR);
+ auto test_authenticator_data = GetTestAuthenticatorDataBytes();
+ fido_parsing_utils::Append(&test_authenticator_object,
+ test_authenticator_data);
+ return test_authenticator_object;
+}
+
+std::vector<uint8_t> GetTestSignResponse() {
+ return fido_parsing_utils::Materialize(test_data::kTestU2fSignResponse);
+}
+
+std::vector<uint8_t> GetTestSignatureCounter() {
+ return fido_parsing_utils::Materialize(test_data::kTestSignatureCounter);
+}
+
+// Get a subset of the response for testing error handling.
+std::vector<uint8_t> GetTestCorruptedSignResponse(size_t length) {
+ DCHECK_LE(length, arraysize(test_data::kTestU2fSignResponse));
+ return fido_parsing_utils::Materialize(fido_parsing_utils::ExtractSpan(
+ test_data::kTestU2fSignResponse, 0, length));
+}
+
+// Return a key handle used for GetAssertion request.
+std::vector<uint8_t> GetTestCredentialRawIdBytes() {
+ return fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle);
+}
+
} // namespace
// Leveraging example 4 of section 6.1 of the spec https://fidoalliance.org
// /specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-
// 20170927.html
TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
- constexpr uint8_t kCertificate[] = {
- 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29,
- 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
- 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73,
- 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19,
- 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f,
- 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31,
- 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x32,
- 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31,
- 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
- 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59,
- 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22,
- 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74,
- 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41,
- 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59,
- 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
- 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
- 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52, 0xe5, 0x3a, 0xd5, 0xdf, 0xed,
- 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf, 0x8f, 0x22,
- 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04,
- 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c,
- 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60,
- 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08,
- 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30,
- 0x46, 0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25,
- 0xf7, 0x37, 0x3e, 0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94,
- 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7,
- 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43,
- 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9,
- 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3};
-
- constexpr uint8_t kAuthData[] = {
- 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
- 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
- 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 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};
-
- constexpr uint8_t kSignature[] = {
- 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c,
- 0xc1, 0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4,
- 0x62, 0xd5, 0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89,
- 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5,
- 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7,
- 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29};
-
- constexpr uint8_t kCredentialId[] = {
- 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16,
- 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f,
- };
-
auto make_credential_response =
- ReadCTAPMakeCredentialResponse(kDeviceMakeCredentialResponse);
+ ReadCTAPMakeCredentialResponse(test_data::kDeviceMakeCredentialResponse);
ASSERT_TRUE(make_credential_response);
auto cbor_attestation_object = cbor::CBORReader::Read(
make_credential_response->GetCBOREncodedAttestationObject());
@@ -186,8 +154,9 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
it = attestation_object_map.find(cbor::CBORValue(kAuthDataKey));
ASSERT_TRUE(it != attestation_object_map.end());
ASSERT_TRUE(it->second.is_bytestring());
- EXPECT_THAT(it->second.GetBytestring(),
- ::testing::ElementsAreArray(kAuthData));
+ EXPECT_THAT(
+ it->second.GetBytestring(),
+ ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialAuthData));
it = attestation_object_map.find(cbor::CBORValue(kAttestationStatementKey));
ASSERT_TRUE(it != attestation_object_map.end());
@@ -203,8 +172,9 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
attStmt_it = attestation_statement_map.find(cbor::CBORValue("sig"));
ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
ASSERT_TRUE(attStmt_it->second.is_bytestring());
- EXPECT_THAT(attStmt_it->second.GetBytestring(),
- ::testing::ElementsAreArray(kSignature));
+ EXPECT_THAT(
+ attStmt_it->second.GetBytestring(),
+ ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialSignature));
attStmt_it = attestation_statement_map.find(cbor::CBORValue("x5c"));
ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
@@ -212,162 +182,188 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) {
ASSERT_TRUE(certificate.is_array());
ASSERT_EQ(certificate.GetArray().size(), 1u);
ASSERT_TRUE(certificate.GetArray()[0].is_bytestring());
- EXPECT_THAT(certificate.GetArray()[0].GetBytestring(),
- ::testing::ElementsAreArray(kCertificate));
- EXPECT_THAT(make_credential_response->raw_credential_id(),
- ::testing::ElementsAreArray(kCredentialId));
+ EXPECT_THAT(
+ certificate.GetArray()[0].GetBytestring(),
+ ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialCertificate));
+ EXPECT_THAT(
+ make_credential_response->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialCredentialId));
}
TEST(CTAPResponseTest, TestMakeCredentialNoneAttestationResponse) {
- constexpr uint8_t kNoneAttestationResponse[] = {
- // clang-format off
- 0xa3, // map(3)
- // Format
- 0x63, // text(3)
- 0x66, 0x6D, 0x74, // "fmt"
- 0x64, // text(6)
- // "none"
- 0x6E, 0x6F, 0x6E, 0x65,
- // Attestation statement
- 0x67, // text(7)
- 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74, // "attStmt"
- 0xa0, // Empty CBOR Map
- // Authenticator data
- 0x68, // text(8)
- 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
- 0x58, 0x9a, // bytes(154)
- 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
- 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
- 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0x41, 0x00, 0x00, 0x00,
- 0x0b,
- // Replaced device AAGUID
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- // Credential information
- 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,
- // clang-format on
- };
-
auto make_credential_response =
- ReadCTAPMakeCredentialResponse(kDeviceMakeCredentialResponse);
+ ReadCTAPMakeCredentialResponse(test_data::kDeviceMakeCredentialResponse);
ASSERT_TRUE(make_credential_response);
make_credential_response->EraseAttestationStatement();
EXPECT_THAT(make_credential_response->GetCBOREncodedAttestationObject(),
- ::testing::ElementsAreArray(kNoneAttestationResponse));
+ ::testing::ElementsAreArray(test_data::kNoneAttestationResponse));
}
-// Leveraging example 5 of section 6.1 of the spec https://fidoalliance.org
-// /specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-
-// 20170927.html
+// Leveraging example 5 of section 6.1 of the CTAP spec.
+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
TEST(CTAPResponseTest, TestReadGetAssertionResponse) {
- constexpr uint8_t kAuthData[] = {
- 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b,
- 0xba, 0x8c, 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5,
- 0x03, 0xd9, 0x11, 0x4a, 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0,
- 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x11};
-
- constexpr uint8_t kSignature[] = {
- 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
- 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
- 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
- 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
- 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
- 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
- };
-
- constexpr uint8_t kDeviceGetAssertionResponse[] = {
- // clang-format off
- 0x00, // Success response code
- 0xa5, // map(5)
- 0x01, // unsigned(1) - Credential
- 0xa2, // map(2)
- 0x62, // text(2)
- 0x69, 0x64, // "id"
- 0x58, 0x40, // bytes(64)
- // credential id
- 0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94, 0x2f,
- 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b, 0x3d, 0xf8,
- 0xbe, 0x08, 0xed, 0x01, 0xfc, 0x44, 0x26, 0x46, 0xd0, 0x34, 0x85, 0x8a,
- 0xc7, 0x5b, 0xed, 0x3f, 0xd5, 0x80, 0xbf, 0x98, 0x08, 0xd9, 0x4f, 0xcb,
- 0xee, 0x82, 0xb9, 0xb2, 0xef, 0x66, 0x77, 0xaf, 0x0a, 0xdc, 0xc3, 0x58,
- 0x52, 0xea, 0x6b, 0x9e,
- 0x64, // text(4)
- 0x74, 0x79, 0x70, 0x65, // "type"
- 0x6a, // text(10)
- // "public-key"
- 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79,
-
- 0x02, // unsigned(2) - Auth data
- 0x58, 0x25, // bytes(37)
- // auth data
- 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b, 0xba, 0x8c,
- 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5, 0x03, 0xd9, 0x11, 0x4a,
- 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0, 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00,
- 0x11,
-
- 0x03, // unsigned(3) - signature
- 0x58, 0x47, // bytes(71)
- // signature
- 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
- 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
- 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
- 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
- 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
- 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
-
- 0x04, // unsigned(4) - publicKeyCredentialUserEntity
- 0xa4, // map(4)
- 0x62, // text(2)
- 0x69, 0x64, // "id"
- 0x58, 0x20, // bytes(32) - user id
- 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
- 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
- 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82,
- 0x64, // text(4)
- 0x69, 0x63, 0x6f, 0x6e, // "icon"
- 0x78, 0x28, // text(40)
- // "https://pics.acme.com/00/p/aBjjjpqPb.png"
- 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x70, 0x69, 0x63, 0x73,
- 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x30,
- 0x2f, 0x70, 0x2f, 0x61, 0x42, 0x6a, 0x6a, 0x6a, 0x70, 0x71, 0x50, 0x62,
- 0x2e, 0x70, 0x6e, 0x67,
- 0x64, // text(4)
- 0x6e, 0x61, 0x6d, 0x65, // "name"
- 0x76, // text(22)
- // "johnpsmith@example.com"
- 0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74, 0x68, 0x40, 0x65,
- 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
- 0x6b, // text(11)
- // "displayName"
- 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
- 0x6d, // text(13)
- // "John P. Smith"
- 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x50, 0x2e, 0x20, 0x53, 0x6d, 0x69, 0x74,
- 0x68,
-
- 0x05, // unsigned(5) - number of credentials
- 0x01, // 1
- // clang-format on
- };
-
auto get_assertion_response =
- ReadCTAPGetAssertionResponse(kDeviceGetAssertionResponse);
+ ReadCTAPGetAssertionResponse(test_data::kDeviceGetAssertionResponse);
ASSERT_TRUE(get_assertion_response);
ASSERT_TRUE(get_assertion_response->num_credentials());
EXPECT_EQ(*get_assertion_response->num_credentials(), 1u);
- EXPECT_THAT(get_assertion_response->auth_data().SerializeToByteArray(),
- ::testing::ElementsAreArray(kAuthData));
- EXPECT_THAT(get_assertion_response->signature(),
- ::testing::ElementsAreArray(kSignature));
+ EXPECT_THAT(
+ get_assertion_response->auth_data().SerializeToByteArray(),
+ ::testing::ElementsAreArray(test_data::kCtap2GetAssertionAuthData));
+ EXPECT_THAT(
+ get_assertion_response->signature(),
+ ::testing::ElementsAreArray(test_data::kCtap2GetAssertionSignature));
+}
+
+// Test that U2F register response is properly parsed.
+TEST(CTAPResponseTest, TestParseRegisterResponseData) {
+ auto response =
+ AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ test_data::kTestU2fRegisterResponse);
+ ASSERT_TRUE(response);
+ EXPECT_THAT(response->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
+ EXPECT_EQ(GetTestAttestationObjectBytes(),
+ response->GetCBOREncodedAttestationObject());
+}
+
+// These test the parsing of the U2F raw bytes of the registration response.
+// Test that an EC public key serializes to CBOR properly.
+TEST(CTAPResponseTest, TestSerializedPublicKey) {
+ auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
+ fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
+ ASSERT_TRUE(public_key);
+ EXPECT_THAT(public_key->EncodeAsCOSEKey(),
+ ::testing::ElementsAreArray(test_data::kTestECPublicKeyCOSE));
+}
+
+// Test that the attestation statement cbor map is constructed properly.
+TEST(CTAPResponseTest, TestParseU2fAttestationStatementCBOR) {
+ auto fido_attestation_statement =
+ FidoAttestationStatement::CreateFromU2fRegisterResponse(
+ test_data::kTestU2fRegisterResponse);
+ ASSERT_TRUE(fido_attestation_statement);
+ auto cbor = cbor::CBORWriter::Write(
+ cbor::CBORValue(fido_attestation_statement->GetAsCBORMap()));
+ ASSERT_TRUE(cbor);
+ EXPECT_THAT(*cbor, ::testing::ElementsAreArray(
+ test_data::kU2fAttestationStatementCBOR));
+}
+
+// Tests that well-formed attested credential data serializes properly.
+TEST(CTAPResponseTest, TestSerializeAttestedCredentialData) {
+ auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
+ fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
+ auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
+ test_data::kTestU2fRegisterResponse, std::move(public_key));
+ ASSERT_TRUE(attested_data);
+ EXPECT_EQ(GetTestAttestedCredentialDataBytes(),
+ attested_data->SerializeAsBytes());
+}
+
+// Tests that well-formed authenticator data serializes properly.
+TEST(CTAPResponseTest, TestSerializeAuthenticatorData) {
+ auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
+ fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
+ auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
+ test_data::kTestU2fRegisterResponse, std::move(public_key));
+
+ constexpr uint8_t flags =
+ static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
+ static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
+
+ AuthenticatorData authenticator_data(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter), flags,
+ std::vector<uint8_t>(4) /* counter */, std::move(attested_data));
+
+ EXPECT_EQ(GetTestAuthenticatorDataBytes(),
+ authenticator_data.SerializeToByteArray());
+}
+
+// Tests that a U2F attestation object serializes properly.
+TEST(CTAPResponseTest, TestSerializeU2fAttestationObject) {
+ auto public_key = ECPublicKey::ExtractFromU2fRegistrationResponse(
+ fido_parsing_utils::kEs256, test_data::kTestU2fRegisterResponse);
+ auto attested_data = AttestedCredentialData::CreateFromU2fRegisterResponse(
+ test_data::kTestU2fRegisterResponse, std::move(public_key));
+
+ constexpr uint8_t flags =
+ static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
+ static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
+ AuthenticatorData authenticator_data(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter), flags,
+ std::vector<uint8_t>(4) /* counter */, std::move(attested_data));
+
+ // Construct the attestation statement.
+ auto fido_attestation_statement =
+ FidoAttestationStatement::CreateFromU2fRegisterResponse(
+ test_data::kTestU2fRegisterResponse);
+
+ // Construct the attestation object.
+ auto attestation_object = std::make_unique<AttestationObject>(
+ std::move(authenticator_data), std::move(fido_attestation_statement));
+
+ ASSERT_TRUE(attestation_object);
+ EXPECT_EQ(GetTestAttestationObjectBytes(),
+ attestation_object->SerializeToCBOREncodedBytes());
+}
+
+// Tests that U2F authenticator data is properly serialized.
+TEST(CTAPResponseTest, TestSerializeAuthenticatorDataForSign) {
+ constexpr uint8_t flags =
+ static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
+
+ EXPECT_THAT(
+ AuthenticatorData(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ flags, GetTestSignatureCounter(), base::nullopt)
+ .SerializeToByteArray(),
+ ::testing::ElementsAreArray(test_data::kTestSignAuthenticatorData));
+}
+
+TEST(CTAPResponseTest, TestParseSignResponseData) {
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ GetTestSignResponse(), GetTestCredentialRawIdBytes());
+ ASSERT_TRUE(response);
+ EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_credential_id());
+ EXPECT_THAT(
+ response->auth_data().SerializeToByteArray(),
+ ::testing::ElementsAreArray(test_data::kTestSignAuthenticatorData));
+ EXPECT_THAT(response->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
+}
+
+TEST(CTAPResponseTest, TestParseU2fSignWithNullNullKeyHandle) {
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ GetTestSignResponse(), std::vector<uint8_t>());
+ EXPECT_FALSE(response);
+}
+
+TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse) {
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ std::vector<uint8_t>(), GetTestCredentialRawIdBytes());
+ EXPECT_FALSE(response);
+}
+
+TEST(CTAPResponseTest, TestParseU2fSignWithNullCorruptedCounter) {
+ // A sign response of less than 5 bytes.
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ GetTestCorruptedSignResponse(3), GetTestCredentialRawIdBytes());
+ EXPECT_FALSE(response);
+}
+
+TEST(CTAPResponseTest, TestParseU2fSignWithNullCorruptedSignature) {
+ // A sign response no more than 5 bytes.
+ auto response = AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ GetTestCorruptedSignResponse(5), GetTestCredentialRawIdBytes());
+ EXPECT_FALSE(response);
}
} // namespace device
diff --git a/chromium/device/fido/device_operation.h b/chromium/device/fido/device_operation.h
new file mode 100644
index 00000000000..8d4b57a4ffb
--- /dev/null
+++ b/chromium/device/fido/device_operation.h
@@ -0,0 +1,46 @@
+// 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_DEVICE_OPERATION_H_
+#define DEVICE_FIDO_DEVICE_OPERATION_H_
+
+#include <stdint.h>
+
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/authenticator_make_credential_response.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_device.h"
+
+namespace device {
+
+template <class Request, class Response>
+class DeviceOperation {
+ public:
+ using DeviceResponseCallback =
+ base::OnceCallback<void(CtapDeviceResponseCode,
+ base::Optional<Response>)>;
+
+ DeviceOperation(FidoDevice* device, DeviceResponseCallback callback)
+ : device_(device), callback_(std::move(callback)) {}
+ virtual ~DeviceOperation() = default;
+
+ virtual void Start() = 0;
+
+ protected:
+ FidoDevice* const device_ = nullptr;
+ DeviceResponseCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceOperation);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_DEVICE_OPERATION_H_
diff --git a/chromium/device/fido/ec_public_key.cc b/chromium/device/fido/ec_public_key.cc
index 9d922b4e979..effded9a490 100644
--- a/chromium/device/fido/ec_public_key.cc
+++ b/chromium/device/fido/ec_public_key.cc
@@ -7,39 +7,44 @@
#include <utility>
#include "components/cbor/cbor_writer.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
namespace {
-// The key is located after the first byte of the response
-// (which is a reserved byte). It's in X9.62 format:
+// In a U2F registration response, the key is located after the first byte of
+// the response (which is a reserved byte). It's in X9.62 format:
// - a constant 0x04 prefix to indicate an uncompressed key
// - the 32-byte x coordinate
// - the 32-byte y coordinate.
-constexpr size_t kKeyCompressionTypeOffset = 1;
-constexpr size_t kUncompressedKey = 0x04;
-constexpr size_t kHeaderLength = 2; // Account for reserved byte and prefix.
-constexpr size_t kKeyLength = 32;
+constexpr size_t kReservedLength = 1;
+constexpr uint8_t kUncompressedKey = 0x04;
+constexpr size_t kFieldElementLength = 32;
} // namespace
// static
std::unique_ptr<ECPublicKey> ECPublicKey::ExtractFromU2fRegistrationResponse(
std::string algorithm,
base::span<const uint8_t> u2f_data) {
- if (u2f_data.size() < kHeaderLength ||
- u2f_data[kKeyCompressionTypeOffset] != kUncompressedKey)
- return nullptr;
+ return ParseX962Uncompressed(
+ std::move(algorithm),
+ fido_parsing_utils::ExtractSuffixSpan(u2f_data, kReservedLength));
+}
- std::vector<uint8_t> x =
- u2f_parsing_utils::Extract(u2f_data, kHeaderLength, kKeyLength);
+// static
+std::unique_ptr<ECPublicKey> ECPublicKey::ParseX962Uncompressed(
+ std::string algorithm,
+ base::span<const uint8_t> input) {
+ if (input.empty() || input[0] != kUncompressedKey)
+ return nullptr;
+ const std::vector<uint8_t> x =
+ fido_parsing_utils::Extract(input, 1, kFieldElementLength);
if (x.empty())
return nullptr;
- std::vector<uint8_t> y = u2f_parsing_utils::Extract(
- u2f_data, kHeaderLength + kKeyLength, kKeyLength);
-
+ const std::vector<uint8_t> y = fido_parsing_utils::Extract(
+ input, 1 + kFieldElementLength, kFieldElementLength);
if (y.empty())
return nullptr;
@@ -53,8 +58,8 @@ ECPublicKey::ECPublicKey(std::string algorithm,
: PublicKey(std::move(algorithm)),
x_coordinate_(std::move(x)),
y_coordinate_(std::move(y)) {
- DCHECK_EQ(x_coordinate_.size(), kKeyLength);
- DCHECK_EQ(y_coordinate_.size(), kKeyLength);
+ DCHECK_EQ(x_coordinate_.size(), kFieldElementLength);
+ DCHECK_EQ(y_coordinate_.size(), kFieldElementLength);
}
ECPublicKey::~ECPublicKey() = default;
diff --git a/chromium/device/fido/ec_public_key.h b/chromium/device/fido/ec_public_key.h
index dfd66ad3fdb..b49e4d2776d 100644
--- a/chromium/device/fido/ec_public_key.h
+++ b/chromium/device/fido/ec_public_key.h
@@ -26,6 +26,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) ECPublicKey : public PublicKey {
std::string algorithm,
base::span<const uint8_t> u2f_data);
+ // Parse a public key encoded in ANSI X9.62 uncompressed format.
+ static std::unique_ptr<ECPublicKey> ParseX962Uncompressed(
+ std::string algorithm,
+ base::span<const uint8_t> input);
+
ECPublicKey(std::string algorithm,
std::vector<uint8_t> x,
std::vector<uint8_t> y);
diff --git a/chromium/device/fido/fake_fido_discovery.cc b/chromium/device/fido/fake_fido_discovery.cc
index e7e53351abd..5a73d3a5d9b 100644
--- a/chromium/device/fido/fake_fido_discovery.cc
+++ b/chromium/device/fido/fake_fido_discovery.cc
@@ -73,6 +73,13 @@ FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextBleDiscovery(
return next_ble_discovery_.get();
}
+FakeFidoDiscovery* ScopedFakeFidoDiscoveryFactory::ForgeNextCableDiscovery(
+ FakeFidoDiscovery::StartMode mode) {
+ next_cable_discovery_ = std::make_unique<FakeFidoDiscovery>(
+ FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy, mode);
+ return next_cable_discovery_.get();
+}
+
std::unique_ptr<FidoDiscovery>
ScopedFakeFidoDiscoveryFactory::CreateFidoDiscovery(
FidoTransportProtocol transport,
@@ -84,6 +91,11 @@ ScopedFakeFidoDiscoveryFactory::CreateFidoDiscovery(
return std::move(next_nfc_discovery_);
case FidoTransportProtocol::kBluetoothLowEnergy:
return std::move(next_ble_discovery_);
+ case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
+ return std::move(next_cable_discovery_);
+ case FidoTransportProtocol::kInternal:
+ NOTREACHED() << "Internal authenticators should be handled separately.";
+ return nullptr;
}
NOTREACHED();
return nullptr;
diff --git a/chromium/device/fido/fake_fido_discovery.h b/chromium/device/fido/fake_fido_discovery.h
index de4428eb399..15f55bd152a 100644
--- a/chromium/device/fido/fake_fido_discovery.h
+++ b/chromium/device/fido/fake_fido_discovery.h
@@ -103,7 +103,7 @@ class ScopedFakeFidoDiscoveryFactory
ScopedFakeFidoDiscoveryFactory();
~ScopedFakeFidoDiscoveryFactory() override;
- // Constructs a fake BLE/HID discovery to be returned from the next call to
+ // Constructs a fake discovery to be returned from the next call to
// FidoDiscovery::Create. Returns a raw pointer to the fake so that tests can
// set it up according to taste.
//
@@ -112,6 +112,8 @@ class ScopedFakeFidoDiscoveryFactory
FakeFidoDiscovery* ForgeNextHidDiscovery(StartMode mode = StartMode::kManual);
FakeFidoDiscovery* ForgeNextNfcDiscovery(StartMode mode = StartMode::kManual);
FakeFidoDiscovery* ForgeNextBleDiscovery(StartMode mode = StartMode::kManual);
+ FakeFidoDiscovery* ForgeNextCableDiscovery(
+ StartMode mode = StartMode::kManual);
protected:
std::unique_ptr<FidoDiscovery> CreateFidoDiscovery(
@@ -122,6 +124,7 @@ class ScopedFakeFidoDiscoveryFactory
std::unique_ptr<FakeFidoDiscovery> next_hid_discovery_;
std::unique_ptr<FakeFidoDiscovery> next_nfc_discovery_;
std::unique_ptr<FakeFidoDiscovery> next_ble_discovery_;
+ std::unique_ptr<FakeFidoDiscovery> next_cable_discovery_;
DISALLOW_COPY_AND_ASSIGN(ScopedFakeFidoDiscoveryFactory);
};
diff --git a/chromium/device/fido/fake_hid_impl_for_testing.cc b/chromium/device/fido/fake_hid_impl_for_testing.cc
index 24041b74dc3..dc2a5d56db8 100644
--- a/chromium/device/fido/fake_hid_impl_for_testing.cc
+++ b/chromium/device/fido/fake_hid_impl_for_testing.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
diff --git a/chromium/device/fido/fido_attestation_statement.cc b/chromium/device/fido/fido_attestation_statement.cc
index 77a30b24d77..b4f80574124 100644
--- a/chromium/device/fido/fido_attestation_statement.cc
+++ b/chromium/device/fido/fido_attestation_statement.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/logging.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
#include "third_party/boringssl/src/include/openssl/bytestring.h"
namespace device {
@@ -88,7 +88,8 @@ FidoAttestationStatement::CreateFromU2fRegisterResponse(
// The format of |u2f_data| is specified here:
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success
uint8_t credential_length;
- if (!CBS_skip(&response, u2f_parsing_utils::kU2fResponseKeyHandleLengthPos) ||
+ if (!CBS_skip(&response,
+ fido_parsing_utils::kU2fResponseKeyHandleLengthPos) ||
!CBS_get_u8(&response, &credential_length) ||
!CBS_skip(&response, credential_length) ||
!CBS_get_asn1_element(&response, &cert, CBS_ASN1_SEQUENCE)) {
diff --git a/chromium/device/fido/fido_authenticator.h b/chromium/device/fido/fido_authenticator.h
new file mode 100644
index 00000000000..1eddfe5038f
--- /dev/null
+++ b/chromium/device/fido/fido_authenticator.h
@@ -0,0 +1,53 @@
+// 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_AUTHENTICATOR_H_
+#define DEVICE_FIDO_FIDO_AUTHENTICATOR_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/authenticator_make_credential_response.h"
+
+namespace device {
+
+class AuthenticatorSelectionCriteria;
+class CtapGetAssertionRequest;
+class CtapMakeCredentialRequest;
+
+// FidoAuthenticator is an authenticator from the WebAuthn Authenticator model
+// (https://www.w3.org/TR/webauthn/#sctn-authenticator-model). It may be a
+// physical device, or a built-in (platform) authenticator.
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoAuthenticator {
+ public:
+ using MakeCredentialCallback = base::OnceCallback<void(
+ CtapDeviceResponseCode,
+ base::Optional<AuthenticatorMakeCredentialResponse>)>;
+ using GetAssertionCallback = base::OnceCallback<void(
+ CtapDeviceResponseCode,
+ base::Optional<AuthenticatorGetAssertionResponse>)>;
+
+ FidoAuthenticator() = default;
+ virtual ~FidoAuthenticator() = default;
+
+ virtual void MakeCredential(
+ AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) = 0;
+ virtual void GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) = 0;
+ virtual void Cancel() = 0;
+ virtual std::string GetId() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FidoAuthenticator);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_AUTHENTICATOR_H_
diff --git a/chromium/device/fido/fido_ble_connection_unittest.cc b/chromium/device/fido/fido_ble_connection_unittest.cc
index 93b1df2b8c3..d7cf1a24156 100644
--- a/chromium/device/fido/fido_ble_connection_unittest.cc
+++ b/chromium/device/fido/fido_ble_connection_unittest.cc
@@ -20,6 +20,7 @@
#include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h"
#include "device/bluetooth/test/mock_bluetooth_gatt_service.h"
#include "device/fido/fido_ble_uuids.h"
+#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -114,77 +115,13 @@ class TestReadCallback {
base::Optional<base::RunLoop> run_loop_{base::in_place};
};
-class TestReadControlPointLengthCallback {
- public:
- void OnReadControlPointLength(base::Optional<uint16_t> value) {
- value_ = std::move(value);
- run_loop_->Quit();
- }
-
- const base::Optional<uint16_t>& WaitForResult() {
- run_loop_->Run();
- run_loop_.emplace();
- return value_;
- }
-
- FidoBleConnection::ControlPointLengthCallback GetCallback() {
- return base::BindOnce(
- &TestReadControlPointLengthCallback::OnReadControlPointLength,
- base::Unretained(this));
- }
+using TestReadControlPointLengthCallback =
+ test::ValueCallbackReceiver<base::Optional<uint16_t>>;
- private:
- base::Optional<uint16_t> value_;
- base::Optional<base::RunLoop> run_loop_{base::in_place};
-};
-
-class TestReadServiceRevisionsCallback {
- public:
- void OnReadServiceRevisions(
- std::set<FidoBleConnection::ServiceRevision> revisions) {
- revisions_ = std::move(revisions);
- run_loop_->Quit();
- }
-
- const std::set<FidoBleConnection::ServiceRevision>& WaitForResult() {
- run_loop_->Run();
- run_loop_.emplace();
- return revisions_;
- }
-
- FidoBleConnection::ServiceRevisionsCallback GetCallback() {
- return base::BindOnce(
- &TestReadServiceRevisionsCallback::OnReadServiceRevisions,
- base::Unretained(this));
- }
-
- private:
- std::set<FidoBleConnection::ServiceRevision> revisions_;
- base::Optional<base::RunLoop> run_loop_{base::in_place};
-};
-
-class TestWriteCallback {
- public:
- void OnWrite(bool success) {
- success_ = success;
- run_loop_->Quit();
- }
-
- bool WaitForResult() {
- run_loop_->Run();
- run_loop_.emplace();
- return success_;
- }
-
- FidoBleConnection::WriteCallback GetCallback() {
- return base::BindOnce(&TestWriteCallback::OnWrite, base::Unretained(this));
- }
-
- private:
- bool success_ = false;
- base::Optional<base::RunLoop> run_loop_{base::in_place};
-};
+using TestReadServiceRevisionsCallback =
+ test::ValueCallbackReceiver<std::set<FidoBleConnection::ServiceRevision>>;
+using TestWriteCallback = test::ValueCallbackReceiver<bool>;
} // namespace
class FidoBleConnectionTest : public ::testing::Test {
@@ -540,26 +477,26 @@ TEST_F(FidoBleConnectionTest, ReadControlPointLength) {
TestReadControlPointLengthCallback length_callback;
SetNextReadControlPointLengthReponse(false, {});
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(base::nullopt, length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(base::nullopt, length_callback.value());
// The Control Point Length should consist of exactly two bytes, hence we
// EXPECT_EQ(base::nullopt) for payloads of size 0, 1 and 3.
SetNextReadControlPointLengthReponse(true, {});
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(base::nullopt, length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(base::nullopt, length_callback.value());
SetNextReadControlPointLengthReponse(true, {0xAB});
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(base::nullopt, length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(base::nullopt, length_callback.value());
SetNextReadControlPointLengthReponse(true, {0xAB, 0xCD});
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(0xABCD, *length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(0xABCD, *length_callback.value());
SetNextReadControlPointLengthReponse(true, {0xAB, 0xCD, 0xEF});
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(base::nullopt, length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(base::nullopt, length_callback.value());
}
TEST_F(FidoBleConnectionTest, ReadServiceRevisions) {
@@ -578,76 +515,76 @@ TEST_F(FidoBleConnectionTest, ReadServiceRevisions) {
TestReadServiceRevisionsCallback revisions_callback;
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(), IsEmpty());
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(), IsEmpty());
SetNextReadServiceRevisionResponse(true, ToByteVector("bogus"));
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(), IsEmpty());
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(), IsEmpty());
SetNextReadServiceRevisionResponse(true, ToByteVector("1.0"));
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_0));
SetNextReadServiceRevisionResponse(true, ToByteVector("1.1"));
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_1));
SetNextReadServiceRevisionResponse(true, ToByteVector("1.2"));
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_2));
// Version 1.3 currently does not exist, so this should be treated as an
// error.
SetNextReadServiceRevisionResponse(true, ToByteVector("1.3"));
SetNextReadServiceRevisionBitfieldResponse(false, {});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(), IsEmpty());
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(), IsEmpty());
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0x00});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(), IsEmpty());
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(), IsEmpty());
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0x80});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_1));
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0x40});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_2));
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0xC0});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_1,
FidoBleConnection::ServiceRevision::VERSION_1_2));
// All bits except the first two should be ignored.
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0xFF});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_1,
FidoBleConnection::ServiceRevision::VERSION_1_2));
// All bytes except the first one should be ignored.
SetNextReadServiceRevisionResponse(false, {});
SetNextReadServiceRevisionBitfieldResponse(true, {0xC0, 0xFF});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_1,
FidoBleConnection::ServiceRevision::VERSION_1_2));
@@ -655,8 +592,8 @@ TEST_F(FidoBleConnectionTest, ReadServiceRevisions) {
// supported as well.
SetNextReadServiceRevisionResponse(true, ToByteVector("1.0"));
SetNextReadServiceRevisionBitfieldResponse(true, {0xC0});
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(),
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(),
ElementsAre(FidoBleConnection::ServiceRevision::VERSION_1_0,
FidoBleConnection::ServiceRevision::VERSION_1_1,
FidoBleConnection::ServiceRevision::VERSION_1_2));
@@ -678,13 +615,13 @@ TEST_F(FidoBleConnectionTest, WriteControlPoint) {
TestWriteCallback write_callback;
SetNextWriteControlPointResponse(false);
- connection.WriteControlPoint({}, write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ connection.WriteControlPoint({}, write_callback.callback());
+ result = write_callback.value();
EXPECT_FALSE(result);
SetNextWriteControlPointResponse(true);
- connection.WriteControlPoint({}, write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ connection.WriteControlPoint({}, write_callback.callback());
+ result = write_callback.value();
EXPECT_TRUE(result);
}
@@ -707,31 +644,31 @@ TEST_F(FidoBleConnectionTest, WriteServiceRevision) {
SetNextWriteServiceRevisionResponse(false);
connection.WriteServiceRevision(
FidoBleConnection::ServiceRevision::VERSION_1_1,
- write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ write_callback.callback());
+ result = write_callback.value();
EXPECT_FALSE(result);
// Expect a successful write of version 1.1.
SetNextWriteServiceRevisionResponse(true);
connection.WriteServiceRevision(
FidoBleConnection::ServiceRevision::VERSION_1_1,
- write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ write_callback.callback());
+ result = write_callback.value();
EXPECT_TRUE(result);
// Expect a successful write of version 1.2.
SetNextWriteServiceRevisionResponse(true);
connection.WriteServiceRevision(
FidoBleConnection::ServiceRevision::VERSION_1_2,
- write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ write_callback.callback());
+ result = write_callback.value();
EXPECT_TRUE(result);
// Writing version 1.0 to the bitfield is not intended, so this should fail.
connection.WriteServiceRevision(
FidoBleConnection::ServiceRevision::VERSION_1_0,
- write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ write_callback.callback());
+ result = write_callback.value();
EXPECT_FALSE(result);
}
@@ -755,23 +692,23 @@ TEST_F(FidoBleConnectionTest, ReadsAndWriteFailWhenDisconnected) {
// Reads should always fail on a disconnected device.
TestReadControlPointLengthCallback length_callback;
- connection.ReadControlPointLength(length_callback.GetCallback());
- EXPECT_EQ(base::nullopt, length_callback.WaitForResult());
+ connection.ReadControlPointLength(length_callback.callback());
+ EXPECT_EQ(base::nullopt, length_callback.value());
TestReadServiceRevisionsCallback revisions_callback;
- connection.ReadServiceRevisions(revisions_callback.GetCallback());
- EXPECT_THAT(revisions_callback.WaitForResult(), IsEmpty());
+ connection.ReadServiceRevisions(revisions_callback.callback());
+ EXPECT_THAT(revisions_callback.value(), IsEmpty());
// Writes should always fail on a disconnected device.
TestWriteCallback write_callback;
connection.WriteServiceRevision(
FidoBleConnection::ServiceRevision::VERSION_1_1,
- write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ write_callback.callback());
+ result = write_callback.value();
EXPECT_FALSE(result);
- connection.WriteControlPoint({}, write_callback.GetCallback());
- result = write_callback.WaitForResult();
+ connection.WriteControlPoint({}, write_callback.callback());
+ result = write_callback.value();
EXPECT_FALSE(result);
}
diff --git a/chromium/device/fido/fido_ble_device.cc b/chromium/device/fido/fido_ble_device.cc
index c4ee5cc0619..ae49580fd68 100644
--- a/chromium/device/fido/fido_ble_device.cc
+++ b/chromium/device/fido/fido_ble_device.cc
@@ -84,6 +84,23 @@ base::WeakPtr<FidoDevice> FidoBleDevice::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
+void FidoBleDevice::OnResponseFrame(FrameCallback callback,
+ base::Optional<FidoBleFrame> frame) {
+ // The request is done, time to reset |transaction_|.
+ ResetTransaction();
+
+ state_ = frame ? State::kReady : State::kDeviceError;
+ auto self = GetWeakPtr();
+ std::move(callback).Run(std::move(frame));
+ // Executing callbacks may free |this|. Check |self| first.
+ if (self)
+ Transition();
+}
+
+void FidoBleDevice::ResetTransaction() {
+ transaction_.reset();
+}
+
void FidoBleDevice::Transition() {
switch (state_) {
case State::kInit:
@@ -165,19 +182,6 @@ void FidoBleDevice::SendRequestFrame(FidoBleFrame frame,
std::move(callback)));
}
-void FidoBleDevice::OnResponseFrame(FrameCallback callback,
- base::Optional<FidoBleFrame> frame) {
- // The request is done, time to reset |transaction_|.
- transaction_.reset();
-
- state_ = frame ? State::kReady : State::kDeviceError;
- auto self = GetWeakPtr();
- std::move(callback).Run(std::move(frame));
- // Executing callbacks may free |this|. Check |self| first.
- if (self)
- Transition();
-}
-
void FidoBleDevice::StartTimeout() {
timer_.Start(FROM_HERE, kDeviceTimeout, this, &FidoBleDevice::OnTimeout);
}
diff --git a/chromium/device/fido/fido_ble_device.h b/chromium/device/fido/fido_ble_device.h
index 419d823994b..58b11218840 100644
--- a/chromium/device/fido/fido_ble_device.h
+++ b/chromium/device/fido/fido_ble_device.h
@@ -52,12 +52,15 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDevice : public FidoDevice {
DeviceCallback callback) override;
base::WeakPtr<FidoDevice> GetWeakPtr() override;
- private:
+ virtual void OnResponseFrame(FrameCallback callback,
+ base::Optional<FidoBleFrame> frame);
void Transition();
void AddToPendingFrames(FidoBleDeviceCommand cmd,
std::vector<uint8_t> request,
DeviceCallback callback);
+ void ResetTransaction();
+ private:
void OnConnectionStatus(bool success);
void OnStatusMessage(std::vector<uint8_t> data);
@@ -66,8 +69,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDevice : public FidoDevice {
void SendPendingRequestFrame();
void SendRequestFrame(FidoBleFrame frame, FrameCallback callback);
- void OnResponseFrame(FrameCallback callback,
- base::Optional<FidoBleFrame> frame);
void StartTimeout();
void StopTimeout();
diff --git a/chromium/device/fido/fido_ble_device_unittest.cc b/chromium/device/fido/fido_ble_device_unittest.cc
index fac9b88bc3c..39916f831ec 100644
--- a/chromium/device/fido/fido_ble_device_unittest.cc
+++ b/chromium/device/fido/fido_ble_device_unittest.cc
@@ -9,9 +9,9 @@
#include "base/test/scoped_task_environment.h"
#include "device/bluetooth/test/bluetooth_test.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/mock_fido_ble_connection.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,7 +22,7 @@ using ::testing::_;
using ::testing::Invoke;
using ::testing::Test;
using TestDeviceCallbackReceiver =
- test::TestCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
+ test::ValueCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
constexpr uint16_t kControlPointLength = 20;
constexpr uint8_t kTestData[] = {'T', 'E', 'S', 'T'};
@@ -100,11 +100,11 @@ TEST_F(FidoBleDeviceTest, SendPingTest_Failure_WriteFailed) {
}));
TestDeviceCallbackReceiver callback_receiver;
- auto payload = u2f_parsing_utils::Materialize(kTestData);
+ auto payload = fido_parsing_utils::Materialize(kTestData);
device()->SendPing(std::move(payload), callback_receiver.callback());
callback_receiver.WaitForCallback();
- EXPECT_FALSE(std::get<0>(*callback_receiver.result()));
+ EXPECT_FALSE(callback_receiver.value());
}
TEST_F(FidoBleDeviceTest, SendPingTest_Failure_NoResponse) {
@@ -116,11 +116,11 @@ TEST_F(FidoBleDeviceTest, SendPingTest_Failure_NoResponse) {
}));
TestDeviceCallbackReceiver callback_receiver;
- const auto payload = u2f_parsing_utils::Materialize(kTestData);
+ const auto payload = fido_parsing_utils::Materialize(kTestData);
device()->SendPing(payload, callback_receiver.callback());
callback_receiver.WaitForCallback();
- EXPECT_FALSE(std::get<0>(*callback_receiver.result()));
+ EXPECT_FALSE(callback_receiver.value().has_value());
}
TEST_F(FidoBleDeviceTest, SendPingTest_Failure_SlowResponse) {
@@ -132,10 +132,10 @@ TEST_F(FidoBleDeviceTest, SendPingTest_Failure_SlowResponse) {
}));
TestDeviceCallbackReceiver callback_receiver;
- auto payload = u2f_parsing_utils::Materialize(kTestData);
+ auto payload = fido_parsing_utils::Materialize(kTestData);
device()->SendPing(payload, callback_receiver.callback());
callback_receiver.WaitForCallback();
- EXPECT_FALSE(std::get<0>(*callback_receiver.result()));
+ EXPECT_FALSE(callback_receiver.value());
// Imitate a ping response from the device after the timeout has passed.
for (auto&& fragment :
@@ -158,13 +158,13 @@ TEST_F(FidoBleDeviceTest, SendPingTest) {
}));
TestDeviceCallbackReceiver callback_receiver;
- const auto payload = u2f_parsing_utils::Materialize(kTestData);
+ const auto payload = fido_parsing_utils::Materialize(kTestData);
device()->SendPing(payload, callback_receiver.callback());
callback_receiver.WaitForCallback();
- const auto& result = std::get<0>(*callback_receiver.result());
- ASSERT_TRUE(result);
- EXPECT_EQ(payload, *result);
+ const auto& value = callback_receiver.value();
+ ASSERT_TRUE(value);
+ EXPECT_EQ(payload, *value);
}
TEST_F(FidoBleDeviceTest, SendCancelTest) {
@@ -174,7 +174,7 @@ TEST_F(FidoBleDeviceTest, SendCancelTest) {
ConnectWithLength(kControlPointLength);
EXPECT_CALL(*connection(),
WriteControlPointPtr(
- u2f_parsing_utils::Materialize(kBleCancelCommand), _));
+ fido_parsing_utils::Materialize(kBleCancelCommand), _));
device()->Cancel();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
diff --git a/chromium/device/fido/fido_ble_discovery.cc b/chromium/device/fido/fido_ble_discovery.cc
index ef8b2c53d88..16de4ad732f 100644
--- a/chromium/device/fido/fido_ble_discovery.cc
+++ b/chromium/device/fido/fido_ble_discovery.cc
@@ -4,18 +4,12 @@
#include "device/fido/fido_ble_discovery.h"
-#include <string>
#include <utility>
#include "base/bind.h"
-#include "base/location.h"
-#include "base/stl_util.h"
-#include "base/strings/string_piece.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "base/callback_helpers.h"
+#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_common.h"
-#include "device/bluetooth/bluetooth_discovery_filter.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/bluetooth_uuid.h"
#include "device/fido/fido_ble_device.h"
@@ -23,15 +17,9 @@
namespace device {
-FidoBleDiscovery::FidoBleDiscovery()
- : FidoDiscovery(FidoTransportProtocol::kBluetoothLowEnergy),
- weak_factory_(this) {}
-FidoBleDiscovery::~FidoBleDiscovery() {
- if (adapter_)
- adapter_->RemoveObserver(this);
+FidoBleDiscovery::FidoBleDiscovery() : weak_factory_(this) {}
- // Destroying |discovery_session_| will best-effort-stop discovering.
-}
+FidoBleDiscovery::~FidoBleDiscovery() = default;
// static
const BluetoothUUID& FidoBleDiscovery::FidoServiceUUID() {
@@ -39,29 +27,11 @@ const BluetoothUUID& FidoBleDiscovery::FidoServiceUUID() {
return service_uuid;
}
-void FidoBleDiscovery::OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter) {
- DCHECK(!adapter_);
- adapter_ = std::move(adapter);
- DCHECK(adapter_);
- VLOG(2) << "Got adapter " << adapter_->GetAddress();
-
- adapter_->AddObserver(this);
- if (adapter_->IsPowered()) {
- OnSetPowered();
- } else {
- adapter_->SetPowered(
- true,
- base::Bind(&FidoBleDiscovery::OnSetPowered, weak_factory_.GetWeakPtr()),
- base::Bind(&FidoBleDiscovery::OnSetPoweredError,
- weak_factory_.GetWeakPtr()));
- }
-}
-
void FidoBleDiscovery::OnSetPowered() {
- DCHECK(adapter_);
- VLOG(2) << "Adapter " << adapter_->GetAddress() << " is powered on.";
+ DCHECK(adapter());
+ VLOG(2) << "Adapter " << adapter()->GetAddress() << " is powered on.";
- for (BluetoothDevice* device : adapter_->GetDevices()) {
+ for (BluetoothDevice* device : adapter()->GetDevices()) {
if (base::ContainsKey(device->GetUUIDs(), FidoServiceUUID())) {
VLOG(2) << "U2F BLE device: " << device->GetAddress();
AddDevice(std::make_unique<FidoBleDevice>(device->GetAddress()));
@@ -72,49 +42,14 @@ void FidoBleDiscovery::OnSetPowered() {
BluetoothTransport::BLUETOOTH_TRANSPORT_LE);
filter->AddUUID(FidoServiceUUID());
- adapter_->StartDiscoverySessionWithFilter(
+ adapter()->StartDiscoverySessionWithFilter(
std::move(filter),
- base::Bind(&FidoBleDiscovery::OnStartDiscoverySessionWithFilter,
- weak_factory_.GetWeakPtr()),
- base::Bind(&FidoBleDiscovery::OnStartDiscoverySessionWithFilterError,
- weak_factory_.GetWeakPtr()));
-}
-
-void FidoBleDiscovery::OnSetPoweredError() {
- DLOG(ERROR) << "Failed to power on the adapter.";
- NotifyDiscoveryStarted(false);
-}
-
-void FidoBleDiscovery::OnStartDiscoverySessionWithFilter(
- std::unique_ptr<BluetoothDiscoverySession> session) {
- discovery_session_ = std::move(session);
- DVLOG(2) << "Discovery session started.";
- NotifyDiscoveryStarted(true);
-}
-
-void FidoBleDiscovery::OnStartDiscoverySessionWithFilterError() {
- DLOG(ERROR) << "Discovery session not started.";
- NotifyDiscoveryStarted(false);
-}
-
-void FidoBleDiscovery::StartInternal() {
- auto& factory = BluetoothAdapterFactory::Get();
- auto callback = base::BindRepeating(&FidoBleDiscovery::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::BindRepeating(
- [](BluetoothAdapterFactory::AdapterCallback callback,
- scoped_refptr<BluetoothAdapter> adapter) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindRepeating(callback, adapter));
- },
- std::move(callback));
-#endif // defined(OS_MACOSX)
- factory.GetAdapter(std::move(callback));
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoBleDiscovery::OnStartDiscoverySessionWithFilter,
+ weak_factory_.GetWeakPtr())),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoBleDiscovery::OnStartDiscoverySessionError,
+ weak_factory_.GetWeakPtr())));
}
void FidoBleDiscovery::DeviceAdded(BluetoothAdapter* adapter,
diff --git a/chromium/device/fido/fido_ble_discovery.h b/chromium/device/fido/fido_ble_discovery.h
index 6e560b97513..abf6f27476f 100644
--- a/chromium/device/fido/fido_ble_discovery.h
+++ b/chromium/device/fido/fido_ble_discovery.h
@@ -9,20 +9,16 @@
#include "base/component_export.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
-#include "device/bluetooth/bluetooth_adapter.h"
-#include "device/fido/fido_discovery.h"
+#include "device/fido/fido_ble_discovery_base.h"
namespace device {
class BluetoothDevice;
-class BluetoothDiscoverySession;
class BluetoothUUID;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
- : public FidoDiscovery,
- BluetoothAdapter::Observer {
+ : public FidoBleDiscoveryBase {
public:
FidoBleDiscovery();
~FidoBleDiscovery() override;
@@ -30,15 +26,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
private:
static const BluetoothUUID& FidoServiceUUID();
- void OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter);
- void OnSetPowered();
- void OnSetPoweredError();
- void OnStartDiscoverySessionWithFilter(
- std::unique_ptr<BluetoothDiscoverySession>);
- void OnStartDiscoverySessionWithFilterError();
-
- // FidoDiscovery:
- void StartInternal() override;
+ // FidoBleDiscoveryBase:
+ void OnSetPowered() override;
// BluetoothAdapter::Observer:
void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
@@ -47,9 +36,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscovery
void DeviceRemoved(BluetoothAdapter* adapter,
BluetoothDevice* device) override;
- scoped_refptr<BluetoothAdapter> adapter_;
- std::unique_ptr<BluetoothDiscoverySession> discovery_session_;
-
base::WeakPtrFactory<FidoBleDiscovery> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(FidoBleDiscovery);
diff --git a/chromium/device/fido/fido_ble_discovery_base.cc b/chromium/device/fido/fido_ble_discovery_base.cc
new file mode 100644
index 00000000000..b118bc1e1e7
--- /dev/null
+++ b/chromium/device/fido/fido_ble_discovery_base.cc
@@ -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.
+
+#include "device/fido/fido_ble_discovery_base.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_common.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
+
+namespace device {
+
+FidoBleDiscoveryBase::FidoBleDiscoveryBase()
+ : FidoDiscovery(FidoTransportProtocol::kBluetoothLowEnergy),
+ weak_factory_(this) {}
+
+FidoBleDiscoveryBase::~FidoBleDiscoveryBase() {
+ if (adapter_)
+ adapter_->RemoveObserver(this);
+
+ // Destroying |discovery_session_| will best-effort-stop discovering.
+}
+
+void FidoBleDiscoveryBase::OnStartDiscoverySessionWithFilter(
+ std::unique_ptr<BluetoothDiscoverySession> session) {
+ SetDiscoverySession(std::move(session));
+ DVLOG(2) << "Discovery session started.";
+ NotifyDiscoveryStarted(true);
+}
+
+void FidoBleDiscoveryBase::OnSetPoweredError() {
+ DLOG(ERROR) << "Failed to power on the adapter.";
+ NotifyDiscoveryStarted(false);
+}
+
+void FidoBleDiscoveryBase::OnStartDiscoverySessionError() {
+ DLOG(ERROR) << "Discovery session not started.";
+ NotifyDiscoveryStarted(false);
+}
+
+void FidoBleDiscoveryBase::SetDiscoverySession(
+ std::unique_ptr<BluetoothDiscoverySession> discovery_session) {
+ discovery_session_ = std::move(discovery_session);
+}
+
+void FidoBleDiscoveryBase::OnGetAdapter(
+ scoped_refptr<BluetoothAdapter> adapter) {
+ DCHECK(!adapter_);
+ adapter_ = std::move(adapter);
+ DCHECK(adapter_);
+ VLOG(2) << "Got adapter " << adapter_->GetAddress();
+
+ adapter_->AddObserver(this);
+ if (adapter_->IsPowered()) {
+ OnSetPowered();
+ } else {
+ adapter_->SetPowered(
+ true,
+ base::AdaptCallbackForRepeating(base::BindOnce(
+ &FidoBleDiscoveryBase::OnSetPowered, weak_factory_.GetWeakPtr())),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoBleDiscoveryBase::OnSetPoweredError,
+ weak_factory_.GetWeakPtr())));
+ }
+}
+
+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)));
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_ble_discovery_base.h b/chromium/device/fido/fido_ble_discovery_base.h
new file mode 100644
index 00000000000..dd4a0f14e54
--- /dev/null
+++ b/chromium/device/fido/fido_ble_discovery_base.h
@@ -0,0 +1,56 @@
+// 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_BLE_DISCOVERY_BASE_H_
+#define DEVICE_FIDO_FIDO_BLE_DISCOVERY_BASE_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+#include "device/fido/fido_discovery.h"
+
+namespace device {
+
+class BluetoothDiscoverySession;
+
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoBleDiscoveryBase
+ : public FidoDiscovery,
+ public BluetoothAdapter::Observer {
+ public:
+ FidoBleDiscoveryBase();
+ ~FidoBleDiscoveryBase() override;
+
+ protected:
+ virtual void OnSetPowered() = 0;
+ virtual void OnStartDiscoverySessionWithFilter(
+ std::unique_ptr<BluetoothDiscoverySession>);
+
+ void OnSetPoweredError();
+ void OnStartDiscoverySessionError();
+ void SetDiscoverySession(
+ std::unique_ptr<BluetoothDiscoverySession> discovery_session);
+
+ BluetoothAdapter* adapter() { return adapter_.get(); }
+
+ private:
+ void OnGetAdapter(scoped_refptr<BluetoothAdapter> adapter);
+
+ // FidoDiscovery:
+ void StartInternal() override;
+
+ scoped_refptr<BluetoothAdapter> adapter_;
+ std::unique_ptr<BluetoothDiscoverySession> discovery_session_;
+
+ base::WeakPtrFactory<FidoBleDiscoveryBase> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FidoBleDiscoveryBase);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_BLE_DISCOVERY_BASE_H_
diff --git a/chromium/device/fido/fido_ble_frames.cc b/chromium/device/fido/fido_ble_frames.cc
index 1f0425319ad..314519c0726 100644
--- a/chromium/device/fido/fido_ble_frames.cc
+++ b/chromium/device/fido/fido_ble_frames.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "device/fido/fido_constants.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -73,7 +73,7 @@ FidoBleFrame::ToFragments(size_t max_fragment_size) const {
// Subtract 1 to account for SEQ byte.
for (auto cont_data :
- u2f_parsing_utils::SplitSpan(data_view, max_fragment_size - 1)) {
+ fido_parsing_utils::SplitSpan(data_view, max_fragment_size - 1)) {
// High bit must stay cleared.
other_fragments.emplace(cont_data, other_fragments.size() & 0x7F);
}
diff --git a/chromium/device/fido/fido_ble_uuids.cc b/chromium/device/fido/fido_ble_uuids.cc
index 8fe32d093c4..2f96f75d4dc 100644
--- a/chromium/device/fido/fido_ble_uuids.cc
+++ b/chromium/device/fido/fido_ble_uuids.cc
@@ -4,6 +4,8 @@
#include "device/fido/fido_ble_uuids.h"
+#include "build/build_config.h"
+
namespace device {
const char kFidoServiceUUID[] = "0000fffd-0000-1000-8000-00805f9b34fb";
@@ -15,4 +17,10 @@ const char kFidoServiceRevisionUUID[] = "00002a28-0000-1000-8000-00805f9b34fb";
const char kFidoServiceRevisionBitfieldUUID[] =
"f1d0fff4-deaa-ecee-b42f-c9ba7ed623bb";
+#if defined(OS_MACOSX)
+const char kCableAdvertisementUUID[] = "fde2";
+#else
+const char kCableAdvertisementUUID[] = "0000fde2-0000-1000-8000-00805f9b34fb";
+#endif
+
} // namespace device
diff --git a/chromium/device/fido/fido_ble_uuids.h b/chromium/device/fido/fido_ble_uuids.h
index 61c4a559f72..a2ead64b534 100644
--- a/chromium/device/fido/fido_ble_uuids.h
+++ b/chromium/device/fido/fido_ble_uuids.h
@@ -22,6 +22,9 @@ COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoControlPointLengthUUID[];
COMPONENT_EXPORT(DEVICE_FIDO) extern const char kFidoServiceRevisionUUID[];
COMPONENT_EXPORT(DEVICE_FIDO)
extern const char kFidoServiceRevisionBitfieldUUID[];
+// TODO(hongjunchoi): Add URL to the specification once CaBLE protocol is
+// standardized.
+COMPONENT_EXPORT(DEVICE_FIDO) extern const char kCableAdvertisementUUID[];
} // namespace device
diff --git a/chromium/device/fido/fido_cable_device.cc b/chromium/device/fido/fido_cable_device.cc
new file mode 100644
index 00000000000..02deea187df
--- /dev/null
+++ b/chromium/device/fido/fido_cable_device.cc
@@ -0,0 +1,178 @@
+// 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_cable_device.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/strings/string_piece.h"
+#include "device/fido/fido_ble_connection.h"
+#include "device/fido/fido_ble_frames.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+
+namespace device {
+
+namespace switches {
+constexpr char kEnableCableEncryption[] = "enable-cable-encryption";
+} // namespace switches
+
+namespace {
+
+// Maximum size of EncryptionData::read_sequence_num or
+// EncryptionData::write_sequence_num allowed. If we encounter
+// counter larger than |kMaxCounter| FidoCableDevice should error out.
+constexpr size_t kMaxCounter = (1 << 24) - 1;
+
+base::StringPiece ConvertToStringPiece(const std::vector<uint8_t>& data) {
+ return base::StringPiece(reinterpret_cast<const char*>(data.data()),
+ data.size());
+}
+
+// static
+bool IsEncryptionEnabled() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(switches::kEnableCableEncryption);
+}
+
+base::Optional<std::vector<uint8_t>> ConstructEncryptionNonce(
+ base::span<const uint8_t> nonce,
+ bool is_sender_client,
+ uint32_t counter) {
+ if (counter > kMaxCounter)
+ return base::nullopt;
+
+ auto constructed_nonce = fido_parsing_utils::Materialize(nonce);
+ constructed_nonce.push_back(is_sender_client ? 0x00 : 0x01);
+ constructed_nonce.push_back(counter >> 16 & 0xFF);
+ constructed_nonce.push_back(counter >> 8 & 0xFF);
+ constructed_nonce.push_back(counter & 0xFF);
+ return constructed_nonce;
+}
+
+bool EncryptOutgoingMessage(
+ const FidoCableDevice::EncryptionData& encryption_data,
+ std::vector<uint8_t>* message_to_encrypt) {
+ const auto nonce = ConstructEncryptionNonce(
+ encryption_data.nonce, true /* is_sender_client */,
+ encryption_data.write_sequence_num);
+ if (!nonce)
+ return false;
+
+ DCHECK_EQ(nonce->size(), encryption_data.aes_key.NonceLength());
+ std::string ciphertext;
+ bool encryption_success = encryption_data.aes_key.Seal(
+ ConvertToStringPiece(*message_to_encrypt), ConvertToStringPiece(*nonce),
+ nullptr /* additional_data */, &ciphertext);
+ if (!encryption_success)
+ return false;
+
+ message_to_encrypt->assign(ciphertext.begin(), ciphertext.end());
+ return true;
+}
+
+bool DecryptIncomingMessage(
+ const FidoCableDevice::EncryptionData& encryption_data,
+ FidoBleFrame* incoming_frame) {
+ const auto nonce = ConstructEncryptionNonce(
+ encryption_data.nonce, false /* is_sender_client */,
+ encryption_data.read_sequence_num);
+ if (!nonce)
+ return false;
+
+ DCHECK_EQ(nonce->size(), encryption_data.aes_key.NonceLength());
+ std::string ciphertext;
+
+ bool decryption_success = encryption_data.aes_key.Open(
+ ConvertToStringPiece(incoming_frame->data()),
+ ConvertToStringPiece(*nonce), nullptr /* additional_data */, &ciphertext);
+ if (!decryption_success)
+ return false;
+
+ incoming_frame->data().assign(ciphertext.begin(), ciphertext.end());
+ return true;
+}
+
+} // namespace
+
+// FidoCableDevice::EncryptionData ----------------------------------------
+
+FidoCableDevice::EncryptionData::EncryptionData(
+ std::string session_key,
+ const std::array<uint8_t, 8>& nonce)
+ : encryption_key(std::move(session_key)), nonce(nonce) {
+ DCHECK_EQ(encryption_key.size(), aes_key.KeyLength());
+ aes_key.Init(&encryption_key);
+}
+
+FidoCableDevice::EncryptionData::EncryptionData(EncryptionData&& data) =
+ default;
+
+FidoCableDevice::EncryptionData& FidoCableDevice::EncryptionData::operator=(
+ EncryptionData&& other) = default;
+
+FidoCableDevice::EncryptionData::~EncryptionData() = default;
+
+// FidoCableDevice::EncryptionData ----------------------------------------
+
+FidoCableDevice::FidoCableDevice(std::string address,
+ std::string session_key,
+ const std::array<uint8_t, 8>& nonce)
+ : FidoBleDevice(std::move(address)),
+ encryption_data_(std::move(session_key), nonce),
+ weak_factory_(this) {}
+
+FidoCableDevice::FidoCableDevice(std::unique_ptr<FidoBleConnection> connection,
+ std::string session_key,
+ const std::array<uint8_t, 8>& nonce)
+ : FidoBleDevice(std::move(connection)),
+ encryption_data_(std::move(session_key), nonce),
+ weak_factory_(this) {}
+
+FidoCableDevice::~FidoCableDevice() = default;
+
+void FidoCableDevice::DeviceTransact(std::vector<uint8_t> command,
+ DeviceCallback callback) {
+ if (IsEncryptionEnabled()) {
+ if (!EncryptOutgoingMessage(encryption_data_, &command)) {
+ state_ = State::kDeviceError;
+ return;
+ }
+
+ ++encryption_data_.write_sequence_num;
+ }
+
+ AddToPendingFrames(FidoBleDeviceCommand::kMsg, std::move(command),
+ std::move(callback));
+}
+
+void FidoCableDevice::OnResponseFrame(FrameCallback callback,
+ base::Optional<FidoBleFrame> frame) {
+ // The request is done, time to reset |transaction_|.
+ ResetTransaction();
+ state_ = frame ? State::kReady : State::kDeviceError;
+
+ if (frame && IsEncryptionEnabled()) {
+ if (!DecryptIncomingMessage(encryption_data_, &frame.value())) {
+ state_ = State::kDeviceError;
+ frame = base::nullopt;
+ }
+
+ ++encryption_data_.read_sequence_num;
+ }
+
+ auto self = GetWeakPtr();
+ std::move(callback).Run(std::move(frame));
+
+ // Executing callbacks may free |this|. Check |self| first.
+ if (self)
+ Transition();
+}
+
+base::WeakPtr<FidoDevice> FidoCableDevice::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_cable_device.h b/chromium/device/fido/fido_cable_device.h
new file mode 100644
index 00000000000..e8c76fe0c6a
--- /dev/null
+++ b/chromium/device/fido/fido_cable_device.h
@@ -0,0 +1,78 @@
+// 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_CABLE_DEVICE_H_
+#define DEVICE_FIDO_FIDO_CABLE_DEVICE_H_
+
+#include <array>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "crypto/aead.h"
+#include "device/fido/fido_ble_device.h"
+
+namespace device {
+
+class FidoBleFrame;
+class FidoBleConnection;
+
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDevice : public FidoBleDevice {
+ public:
+ // Encapsulates state FidoCableDevice maintains to encrypt and decrypt
+ // data within FidoBleFrame.
+ struct COMPONENT_EXPORT(DEVICE_FIDO) EncryptionData {
+ EncryptionData() = delete;
+ EncryptionData(std::string session_key,
+ const std::array<uint8_t, 8>& nonce);
+ EncryptionData(EncryptionData&& data);
+ EncryptionData& operator=(EncryptionData&& other);
+ ~EncryptionData();
+
+ std::string encryption_key;
+ std::array<uint8_t, 8> nonce;
+ crypto::Aead aes_key{crypto::Aead::AES_256_GCM};
+ uint32_t write_sequence_num = 0;
+ uint32_t read_sequence_num = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(EncryptionData);
+ };
+
+ using FrameCallback = FidoBleTransaction::FrameCallback;
+
+ FidoCableDevice(std::string address,
+ std::string session_key,
+ const std::array<uint8_t, 8>& nonce);
+ // Constructor used for testing purposes.
+ FidoCableDevice(std::unique_ptr<FidoBleConnection> connection,
+ std::string session_key,
+ const std::array<uint8_t, 8>& nonce);
+ ~FidoCableDevice() override;
+
+ // FidoBleDevice:
+ void DeviceTransact(std::vector<uint8_t> command,
+ DeviceCallback callback) override;
+ void OnResponseFrame(FrameCallback callback,
+ base::Optional<FidoBleFrame> frame) override;
+ base::WeakPtr<FidoDevice> GetWeakPtr() override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(FidoCableDeviceTest,
+ TestCableDeviceSendMultipleRequests);
+ FRIEND_TEST_ALL_PREFIXES(FidoCableDeviceTest,
+ TestCableDeviceErrorOnMaxCounter);
+
+ EncryptionData encryption_data_;
+ base::WeakPtrFactory<FidoCableDevice> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FidoCableDevice);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_CABLE_DEVICE_H_
diff --git a/chromium/device/fido/fido_cable_device_unittest.cc b/chromium/device/fido/fido_cable_device_unittest.cc
new file mode 100644
index 00000000000..75ad4acbb6f
--- /dev/null
+++ b/chromium/device/fido/fido_cable_device_unittest.cc
@@ -0,0 +1,360 @@
+// 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_cable_device.h"
+
+#include <array>
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/optional.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "crypto/aead.h"
+#include "device/bluetooth/test/bluetooth_test.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/mock_fido_ble_connection.h"
+#include "device/fido/test_callback_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Test;
+using TestDeviceCallbackReceiver =
+ test::ValueCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
+
+// Sufficiently large test control point length as we are not interested
+// in testing fragmentations of BLE messages. All Cable messages are encrypted
+// and decrypted per request frame, not fragment.
+constexpr auto kControlPointLength = std::numeric_limits<uint16_t>::max();
+// Counter value that is larger than FidoCableDevice::kMaxCounter.
+constexpr uint32_t kInvalidCounter = 1 << 24;
+constexpr char kTestSessionKey[] = "00000000000000000000000000000000";
+constexpr std::array<uint8_t, 8> kTestEncryptionNonce = {
+ {1, 1, 1, 1, 1, 1, 1, 1}};
+constexpr uint8_t kTestData[] = {'T', 'E', 'S', 'T'};
+
+std::vector<uint8_t> ConstructSerializedOutgoingFragment(
+ base::span<const uint8_t> data) {
+ FidoBleFrame response_frame(FidoBleDeviceCommand::kMsg,
+ fido_parsing_utils::Materialize(data));
+ const auto response_fragment =
+ std::get<0>(response_frame.ToFragments(kControlPointLength));
+
+ std::vector<uint8_t> outgoing_message;
+ response_fragment.Serialize(&outgoing_message);
+ return outgoing_message;
+}
+
+class FakeCableAuthenticator {
+ public:
+ // Returns encrypted message of the ciphertext received from the client.
+ std::vector<uint8_t> ReplyWithSameMessage(base::span<const uint8_t> message) {
+ auto decrypted_message = DecryptMessage(message);
+ auto message_to_send = EncryptMessage(std::move(decrypted_message));
+ return std::vector<uint8_t>(message_to_send.begin(), message_to_send.end());
+ }
+
+ void SetSessionKey(const std::string& session_key) {
+ session_key_ = session_key;
+ }
+
+ void SetAuthenticatorCounter(uint32_t authenticator_counter) {
+ authenticator_counter_ = authenticator_counter;
+ }
+
+ private:
+ std::string EncryptMessage(std::string message) {
+ crypto::Aead aead(crypto::Aead::AES_256_GCM);
+ DCHECK_EQ(session_key_.size(), aead.KeyLength());
+ aead.Init(&session_key_);
+
+ auto encryption_nonce = fido_parsing_utils::Materialize(nonce_);
+ encryption_nonce.push_back(0x01);
+ encryption_nonce.push_back(authenticator_counter_ >> 16 & 0xFF);
+ encryption_nonce.push_back(authenticator_counter_ >> 8 & 0xFF);
+ encryption_nonce.push_back(authenticator_counter_ & 0xFF);
+ DCHECK(encryption_nonce.size() == aead.NonceLength());
+
+ std::string ciphertext;
+ aead.Seal(message,
+ base::StringPiece(
+ reinterpret_cast<const char*>(encryption_nonce.data()),
+ encryption_nonce.size()),
+ nullptr /* additional_data */, &ciphertext);
+ authenticator_counter_++;
+ return ciphertext;
+ }
+
+ std::string DecryptMessage(base::span<const uint8_t> message) {
+ crypto::Aead aead(crypto::Aead::AES_256_GCM);
+ DCHECK_EQ(session_key_.size(), aead.KeyLength());
+ aead.Init(&session_key_);
+
+ auto encryption_nonce = fido_parsing_utils::Materialize(nonce_);
+ encryption_nonce.push_back(0x00);
+ encryption_nonce.push_back(expected_client_counter_ >> 16 & 0xFF);
+ encryption_nonce.push_back(expected_client_counter_ >> 8 & 0xFF);
+ encryption_nonce.push_back(expected_client_counter_ & 0xFF);
+ DCHECK(encryption_nonce.size() == aead.NonceLength());
+
+ std::string ciphertext;
+ aead.Open(base::StringPiece(reinterpret_cast<const char*>(message.data()),
+ message.size()),
+ base::StringPiece(
+ reinterpret_cast<const char*>(encryption_nonce.data()),
+ encryption_nonce.size()),
+ nullptr /* additional_data */, &ciphertext);
+ expected_client_counter_++;
+ return ciphertext;
+ }
+
+ std::array<uint8_t, 8> nonce_ = kTestEncryptionNonce;
+ std::string session_key_ = kTestSessionKey;
+ uint32_t expected_client_counter_ = 0;
+ uint32_t authenticator_counter_ = 0;
+};
+
+} // namespace
+
+class FidoCableDeviceTest : public Test {
+ public:
+ FidoCableDeviceTest() {
+ auto connection = std::make_unique<MockFidoBleConnection>(
+ BluetoothTestBase::kTestDeviceAddress1);
+ connection_ = connection.get();
+ device_ = std::make_unique<FidoCableDevice>(
+ std::move(connection), kTestSessionKey, kTestEncryptionNonce);
+
+ connection_->connection_status_callback() =
+ device_->GetConnectionStatusCallbackForTesting();
+ connection_->read_callback() = device_->GetReadCallbackForTesting();
+ }
+
+ void ConnectWithLength(uint16_t length) {
+ EXPECT_CALL(*connection(), Connect()).WillOnce(Invoke([this] {
+ connection()->connection_status_callback().Run(true);
+ }));
+
+ EXPECT_CALL(*connection(), ReadControlPointLengthPtr(_))
+ .WillOnce(Invoke([length](auto* cb) { std::move(*cb).Run(length); }));
+
+ device()->Connect();
+ }
+
+ void SetUpEncryptionSwitch() {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ "enable-cable-encryption");
+ }
+
+ FidoCableDevice* device() { return device_.get(); }
+ MockFidoBleConnection* connection() { return connection_; }
+ FakeCableAuthenticator* authenticator() { return &authenticator_; }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ private:
+ FakeCableAuthenticator authenticator_;
+ MockFidoBleConnection* connection_;
+ std::unique_ptr<FidoCableDevice> device_;
+};
+
+TEST_F(FidoCableDeviceTest, TestCaBleDeviceSendData) {
+ SetUpEncryptionSwitch();
+ ConnectWithLength(kControlPointLength);
+
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .WillOnce(Invoke([this](const auto& data, auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ const auto authenticator_reply = authenticator()->ReplyWithSameMessage(
+ base::make_span(data).subspan(3));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(),
+ ConstructSerializedOutgoingFragment(
+ authenticator_reply)));
+ }));
+
+ TestDeviceCallbackReceiver callback_receiver;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ const auto& value = callback_receiver.value();
+ ASSERT_TRUE(value);
+ EXPECT_THAT(*value, ::testing::ElementsAreArray(kTestData));
+}
+
+// Test that FidoCableDevice properly updates counters when sending/receiving
+// multiple requests.
+TEST_F(FidoCableDeviceTest, TestCableDeviceSendMultipleRequests) {
+ SetUpEncryptionSwitch();
+ ConnectWithLength(kControlPointLength);
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .Times(2)
+ .WillRepeatedly(Invoke([this](const auto& data, auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ const auto authenticator_reply = authenticator()->ReplyWithSameMessage(
+ base::make_span(data).subspan(3));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(),
+ ConstructSerializedOutgoingFragment(
+ authenticator_reply)));
+ }));
+
+ EXPECT_EQ(0u, device()->encryption_data_.write_sequence_num);
+ EXPECT_EQ(0u, device()->encryption_data_.read_sequence_num);
+
+ TestDeviceCallbackReceiver callback_receiver1;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver1.callback());
+ callback_receiver1.WaitForCallback();
+ const auto& value1 = callback_receiver1.value();
+ ASSERT_TRUE(value1);
+ EXPECT_THAT(*value1, ::testing::ElementsAreArray(kTestData));
+ EXPECT_EQ(1u, device()->encryption_data_.write_sequence_num);
+ EXPECT_EQ(1u, device()->encryption_data_.read_sequence_num);
+
+ constexpr uint8_t kTestData2[] = {'T', 'E', 'S', 'T', '2'};
+ TestDeviceCallbackReceiver callback_receiver2;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData2),
+ callback_receiver2.callback());
+ callback_receiver2.WaitForCallback();
+ const auto& value2 = callback_receiver2.value();
+ ASSERT_TRUE(value2);
+ EXPECT_THAT(*value2, ::testing::ElementsAreArray(kTestData2));
+ EXPECT_EQ(2u, device()->encryption_data_.write_sequence_num);
+ EXPECT_EQ(2u, device()->encryption_data_.read_sequence_num);
+}
+
+TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnIncorrectSessionKey) {
+ constexpr char kIncorrectSessionKey[] = "11111111111111111111111111111111";
+ SetUpEncryptionSwitch();
+ ConnectWithLength(kControlPointLength);
+
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .WillOnce(Invoke([this, &kIncorrectSessionKey](const auto& data,
+ auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ authenticator()->SetSessionKey(kIncorrectSessionKey);
+ const auto authenticator_reply = authenticator()->ReplyWithSameMessage(
+ base::make_span(data).subspan(3));
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(),
+ ConstructSerializedOutgoingFragment(
+ authenticator_reply)));
+ }));
+
+ TestDeviceCallbackReceiver callback_receiver;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ const auto& value = callback_receiver.value();
+ EXPECT_FALSE(value);
+}
+
+TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnUnexpectedCounter) {
+ constexpr uint32_t kIncorrectAuthenticatorCounter = 1;
+ SetUpEncryptionSwitch();
+ ConnectWithLength(kControlPointLength);
+
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .WillOnce(Invoke([this, kIncorrectAuthenticatorCounter](const auto& data,
+ auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ authenticator()->SetAuthenticatorCounter(
+ kIncorrectAuthenticatorCounter);
+ const auto authenticator_reply = authenticator()->ReplyWithSameMessage(
+ base::make_span(data).subspan(3));
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(),
+ ConstructSerializedOutgoingFragment(
+ authenticator_reply)));
+ }));
+
+ TestDeviceCallbackReceiver callback_receiver;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ const auto& value = callback_receiver.value();
+ EXPECT_FALSE(value);
+}
+
+// Test the unlikely event that the authenticator and client has sent/received
+// requests more than FidoCableDevice::kMaxCounter amount of times. As we are
+// only using 3 bytes to encapsulate counter during encryption, any counter
+// value that is above FidoCableDevice::kMaxCounter -- even though it may be
+// the expected counter value -- should return an error.
+TEST_F(FidoCableDeviceTest, TestCableDeviceErrorOnMaxCounter) {
+ ConnectWithLength(kControlPointLength);
+ SetUpEncryptionSwitch();
+
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .WillOnce(Invoke([this](const auto& data, auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ authenticator()->SetAuthenticatorCounter(kInvalidCounter);
+ const auto authenticator_reply = authenticator()->ReplyWithSameMessage(
+ base::make_span(data).subspan(3));
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(),
+ ConstructSerializedOutgoingFragment(
+ authenticator_reply)));
+ }));
+
+ TestDeviceCallbackReceiver callback_receiver;
+ device()->encryption_data_.read_sequence_num = kInvalidCounter;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ const auto& value = callback_receiver.value();
+ EXPECT_FALSE(value);
+}
+
+TEST_F(FidoCableDeviceTest, TestEncryptionDisabledWithoutCommandLineSwitch) {
+ ConnectWithLength(kControlPointLength);
+
+ EXPECT_CALL(*connection(), WriteControlPointPtr(_, _))
+ .WillOnce(Invoke([this](const auto& data, auto* cb) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(*cb), true));
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(connection()->read_callback(), data));
+ }));
+
+ TestDeviceCallbackReceiver callback_receiver;
+ device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
+ callback_receiver.callback());
+
+ callback_receiver.WaitForCallback();
+ const auto& value = callback_receiver.value();
+ ASSERT_TRUE(value);
+ EXPECT_THAT(*value, ::testing::ElementsAreArray(kTestData));
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_cable_discovery.cc b/chromium/device/fido/fido_cable_discovery.cc
new file mode 100644
index 00000000000..1468db3d37d
--- /dev/null
+++ b/chromium/device/fido/fido_cable_discovery.cc
@@ -0,0 +1,286 @@
+// 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_cable_discovery.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "build/build_config.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "device/bluetooth/bluetooth_discovery_session.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/fido/fido_ble_uuids.h"
+#include "device/fido/fido_cable_device.h"
+#include "device/fido/fido_parsing_utils.h"
+
+namespace device {
+
+namespace {
+
+#if defined(OS_MACOSX)
+
+// Convert byte array into GUID formatted string as defined by RFC 4122.
+// As we are converting 128 bit UUID, |bytes| must be have length of 16.
+// https://tools.ietf.org/html/rfc4122
+std::string ConvertBytesToUuid(base::span<const uint8_t, 16> bytes) {
+ uint64_t most_significant_bytes = 0;
+ for (size_t i = 0; i < sizeof(uint64_t); i++) {
+ most_significant_bytes |= base::strict_cast<uint64_t>(bytes[i])
+ << 8 * (7 - i);
+ }
+
+ uint64_t least_significant_bytes = 0;
+ for (size_t i = 0; i < sizeof(uint64_t); i++) {
+ least_significant_bytes |= base::strict_cast<uint64_t>(bytes[i + 8])
+ << 8 * (7 - i);
+ }
+
+ return base::StringPrintf(
+ "%08x-%04x-%04x-%04x-%012llx",
+ static_cast<unsigned int>(most_significant_bytes >> 32),
+ static_cast<unsigned int>((most_significant_bytes >> 16) & 0x0000ffff),
+ static_cast<unsigned int>(most_significant_bytes & 0x0000ffff),
+ static_cast<unsigned int>(least_significant_bytes >> 48),
+ least_significant_bytes & 0x0000ffff'ffffffffULL);
+}
+
+#endif
+
+const BluetoothUUID& CableAdvertisementUUID() {
+ static const BluetoothUUID service_uuid(kCableAdvertisementUUID);
+ return service_uuid;
+}
+
+bool IsCableDevice(const BluetoothDevice* device) {
+ return base::ContainsKey(device->GetServiceData(), CableAdvertisementUUID());
+}
+
+// Construct advertisement data with different formats depending on client's
+// operating system. Ideally, we advertise EIDs as part of Service Data, but
+// this isn't available on all platforms. On Windows we use Manufacturer Data
+// instead, and on Mac our only option is to advertise an additional service
+// with the EID as its UUID.
+std::unique_ptr<BluetoothAdvertisement::Data> ConstructAdvertisementData(
+ uint8_t version_number,
+ base::span<const uint8_t, FidoCableDiscovery::kEphemeralIdSize>
+ client_eid) {
+ auto advertisement_data = std::make_unique<BluetoothAdvertisement::Data>(
+ BluetoothAdvertisement::AdvertisementType::ADVERTISEMENT_TYPE_BROADCAST);
+
+#if defined(OS_MACOSX)
+ auto list = std::make_unique<BluetoothAdvertisement::UUIDList>();
+ list->emplace_back(kCableAdvertisementUUID);
+ list->emplace_back(ConvertBytesToUuid(client_eid));
+ advertisement_data->set_service_uuids(std::move(list));
+
+#elif defined(OS_WIN)
+ constexpr uint16_t kFidoManufacturerId = 0xFFFD;
+ constexpr std::array<uint8_t, 2> kFidoManufacturerDataHeader = {0x51, 0xFE};
+
+ auto manufacturer_data =
+ std::make_unique<BluetoothAdvertisement::ManufacturerData>();
+ std::vector<uint8_t> manufacturer_data_value;
+ fido_parsing_utils::Append(&manufacturer_data_value,
+ kFidoManufacturerDataHeader);
+ fido_parsing_utils::Append(&manufacturer_data_value, client_eid);
+ manufacturer_data->emplace(kFidoManufacturerId,
+ std::move(manufacturer_data_value));
+ advertisement_data->set_manufacturer_data(std::move(manufacturer_data));
+
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+ // Service data for ChromeOS and Linux is 1 byte corresponding to Cable
+ // version number, followed by 7 empty(0x00) bytes, followed by 16 bytes
+ // corresponding to client EID.
+ auto service_data = std::make_unique<BluetoothAdvertisement::ServiceData>();
+ std::vector<uint8_t> service_data_value(24, 0);
+ service_data_value[0] = version_number;
+ std::copy(client_eid.begin(), client_eid.end(),
+ service_data_value.begin() + 8);
+ service_data->emplace(kCableAdvertisementUUID, std::move(service_data_value));
+ advertisement_data->set_service_data(std::move(service_data));
+#endif
+
+ return advertisement_data;
+}
+
+} // namespace
+
+// FidoCableDiscovery::CableDiscoveryData -------------------------------------
+
+FidoCableDiscovery::CableDiscoveryData::CableDiscoveryData(
+ uint8_t version,
+ const EidArray& client_eid,
+ const EidArray& authenticator_eid,
+ const SessionKeyArray& session_key)
+ : version(version),
+ client_eid(client_eid),
+ authenticator_eid(authenticator_eid),
+ session_key(session_key) {}
+
+FidoCableDiscovery::CableDiscoveryData::CableDiscoveryData(
+ const CableDiscoveryData& data) = default;
+
+FidoCableDiscovery::CableDiscoveryData& FidoCableDiscovery::CableDiscoveryData::
+operator=(const CableDiscoveryData& other) = default;
+
+FidoCableDiscovery::CableDiscoveryData::~CableDiscoveryData() = default;
+
+// FidoCableDiscovery ---------------------------------------------------------
+
+FidoCableDiscovery::FidoCableDiscovery(
+ std::vector<CableDiscoveryData> discovery_data)
+ : discovery_data_(std::move(discovery_data)), weak_factory_(this) {}
+
+// This is a workaround for https://crbug.com/846522
+FidoCableDiscovery::~FidoCableDiscovery() {
+ for (auto advertisement : advertisements_)
+ advertisement.second->Unregister(base::DoNothing(), base::DoNothing());
+}
+
+void FidoCableDiscovery::DeviceAdded(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ if (!IsCableDevice(device))
+ return;
+
+ DVLOG(2) << "Discovered Cable device: " << device->GetAddress();
+ CableDeviceFound(adapter, device);
+}
+
+void FidoCableDiscovery::DeviceChanged(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ if (!IsCableDevice(device))
+ return;
+
+ DVLOG(2) << "Device changed for Cable device: " << device->GetAddress();
+ CableDeviceFound(adapter, device);
+}
+
+void FidoCableDiscovery::DeviceRemoved(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ if (IsCableDevice(device) && GetFoundCableDiscoveryData(device)) {
+ const auto& device_address = device->GetAddress();
+ VLOG(2) << "Cable device removed: " << device_address;
+ RemoveDevice(FidoBleDevice::GetId(device_address));
+ }
+}
+
+void FidoCableDiscovery::OnSetPowered() {
+ DCHECK(adapter());
+
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&FidoCableDiscovery::StartAdvertisement,
+ weak_factory_.GetWeakPtr()));
+}
+
+void FidoCableDiscovery::StartAdvertisement() {
+ DCHECK(adapter());
+
+ for (const auto& data : discovery_data_) {
+ adapter()->RegisterAdvertisement(
+ ConstructAdvertisementData(data.version, data.client_eid),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegistered,
+ weak_factory_.GetWeakPtr(), data.client_eid)),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoCableDiscovery::OnAdvertisementRegisterError,
+ weak_factory_.GetWeakPtr())));
+ }
+}
+
+void FidoCableDiscovery::OnAdvertisementRegistered(
+ const EidArray& client_eid,
+ scoped_refptr<BluetoothAdvertisement> advertisement) {
+ DVLOG(2) << "Advertisement registered.";
+ advertisements_.emplace(client_eid, std::move(advertisement));
+ RecordAdvertisementResult(true /* is_success */);
+}
+
+void FidoCableDiscovery::OnAdvertisementRegisterError(
+ BluetoothAdvertisement::ErrorCode error_code) {
+ DLOG(ERROR) << "Failed to register advertisement: " << error_code;
+ RecordAdvertisementResult(false /* is_success */);
+}
+
+void FidoCableDiscovery::RecordAdvertisementResult(bool is_success) {
+ is_success ? ++advertisement_success_counter_
+ : ++advertisement_failure_counter_;
+
+ // Wait until all advertisements are sent out.
+ if (advertisement_success_counter_ + advertisement_failure_counter_ !=
+ discovery_data_.size()) {
+ return;
+ }
+
+ // No advertisements succeeded, no point in starting scanning.
+ if (!advertisement_success_counter_) {
+ NotifyDiscoveryStarted(false);
+ return;
+ }
+
+ // At least one advertisement succeeded and all advertisement has been
+ // processed. Start scanning.
+ adapter()->StartDiscoverySessionWithFilter(
+ std::make_unique<BluetoothDiscoveryFilter>(
+ BluetoothTransport::BLUETOOTH_TRANSPORT_LE),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySessionWithFilter,
+ weak_factory_.GetWeakPtr())),
+ base::AdaptCallbackForRepeating(
+ base::BindOnce(&FidoCableDiscovery::OnStartDiscoverySessionError,
+ weak_factory_.GetWeakPtr())));
+}
+
+void FidoCableDiscovery::CableDeviceFound(BluetoothAdapter* adapter,
+ BluetoothDevice* device) {
+ const auto* found_cable_device_data = GetFoundCableDiscoveryData(device);
+ if (!found_cable_device_data)
+ return;
+
+ DVLOG(2) << "Found new Cable device.";
+ // Nonce is embedded as first 8 bytes of client EID.
+ std::array<uint8_t, 8> nonce;
+ bool extract_success = fido_parsing_utils::ExtractArray(
+ found_cable_device_data->client_eid, 0, &nonce);
+ if (!extract_success)
+ return;
+
+ AddDevice(std::make_unique<FidoCableDevice>(
+ device->GetAddress(),
+ std::string(found_cable_device_data->session_key.begin(),
+ found_cable_device_data->session_key.end()),
+ nonce));
+}
+
+const FidoCableDiscovery::CableDiscoveryData*
+FidoCableDiscovery::GetFoundCableDiscoveryData(
+ const BluetoothDevice* device) const {
+ const auto* service_data =
+ device->GetServiceDataForUUID(CableAdvertisementUUID());
+ DCHECK(service_data);
+
+ EidArray received_authenticator_eid;
+ bool extract_success = fido_parsing_utils::ExtractArray(
+ *service_data, 8, &received_authenticator_eid);
+ if (!extract_success)
+ return nullptr;
+
+ auto discovery_data_iterator = std::find_if(
+ discovery_data_.begin(), discovery_data_.end(),
+ [&received_authenticator_eid](const auto& data) {
+ return received_authenticator_eid == data.authenticator_eid;
+ });
+
+ return discovery_data_iterator != discovery_data_.end()
+ ? &(*discovery_data_iterator)
+ : nullptr;
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_cable_discovery.h b/chromium/device/fido/fido_cable_discovery.h
new file mode 100644
index 00000000000..a5f9f1749be
--- /dev/null
+++ b/chromium/device/fido/fido_cable_discovery.h
@@ -0,0 +1,100 @@
+// 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_CABLE_DISCOVERY_H_
+#define DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_
+
+#include <stdint.h>
+
+#include <array>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "device/fido/fido_ble_discovery_base.h"
+
+namespace device {
+
+class BluetoothDevice;
+class BluetoothAdvertisement;
+
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableDiscovery
+ : public FidoBleDiscoveryBase {
+ public:
+ static constexpr size_t kEphemeralIdSize = 16;
+ static constexpr size_t kSessionKeySize = 32;
+ using EidArray = std::array<uint8_t, kEphemeralIdSize>;
+ using SessionKeyArray = std::array<uint8_t, kSessionKeySize>;
+
+ // Encapsulates information required to discover Cable device per single
+ // credential. When multiple credentials are enrolled to a single account
+ // (i.e. more than one phone has been enrolled to an user account as a
+ // security key), then FidoCableDiscovery must advertise for all of the client
+ // EID received from the relying party.
+ // TODO(hongjunchoi): Add discovery data required for MakeCredential request.
+ // See: https://crbug.com/837088
+ struct COMPONENT_EXPORT(DEVICE_FIDO) CableDiscoveryData {
+ CableDiscoveryData(uint8_t version,
+ const EidArray& client_eid,
+ const EidArray& authenticator_eid,
+ const SessionKeyArray& session_key);
+ CableDiscoveryData(const CableDiscoveryData& data);
+ CableDiscoveryData& operator=(const CableDiscoveryData& other);
+ ~CableDiscoveryData();
+
+ uint8_t version;
+ EidArray client_eid;
+ EidArray authenticator_eid;
+ SessionKeyArray session_key;
+ };
+
+ FidoCableDiscovery(std::vector<CableDiscoveryData> discovery_data);
+ ~FidoCableDiscovery() override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
+ TestUnregisterAdvertisementUponDestruction);
+
+ // BluetoothAdapter::Observer:
+ void DeviceAdded(BluetoothAdapter* adapter, BluetoothDevice* device) override;
+ void DeviceChanged(BluetoothAdapter* adapter,
+ BluetoothDevice* device) override;
+ void DeviceRemoved(BluetoothAdapter* adapter,
+ BluetoothDevice* device) override;
+
+ // FidoBleDiscoveryBase:
+ void OnSetPowered() override;
+
+ void StartAdvertisement();
+ void OnAdvertisementRegistered(
+ const EidArray& client_eid,
+ scoped_refptr<BluetoothAdvertisement> advertisement);
+ void OnAdvertisementRegisterError(
+ BluetoothAdvertisement::ErrorCode error_code);
+ // Keeps a counter of success/failure of advertisements done by the client.
+ // If all advertisements fail, then immediately stop discovery process and
+ // invoke NotifyDiscoveryStarted(false). Otherwise kick off discovery session
+ // once all advertisements has been processed.
+ void RecordAdvertisementResult(bool is_success);
+ void CableDeviceFound(BluetoothAdapter* adapter, BluetoothDevice* device);
+ const CableDiscoveryData* GetFoundCableDiscoveryData(
+ const BluetoothDevice* device) const;
+
+ std::vector<CableDiscoveryData> discovery_data_;
+ size_t advertisement_success_counter_ = 0;
+ size_t advertisement_failure_counter_ = 0;
+ std::map<EidArray, scoped_refptr<BluetoothAdvertisement>> advertisements_;
+ base::WeakPtrFactory<FidoCableDiscovery> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FidoCableDiscovery);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_CABLE_DISCOVERY_H_
diff --git a/chromium/device/fido/fido_cable_discovery_unittest.cc b/chromium/device/fido/fido_cable_discovery_unittest.cc
new file mode 100644
index 00000000000..920f7d8e289
--- /dev/null
+++ b/chromium/device/fido/fido_cable_discovery_unittest.cc
@@ -0,0 +1,390 @@
+// 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_cable_discovery.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/stl_util.h"
+#include "build/build_config.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_advertisement.h"
+#include "device/bluetooth/test/bluetooth_test.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/fido/fido_ble_device.h"
+#include "device/fido/fido_ble_uuids.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/mock_fido_discovery_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::NiceMock;
+
+namespace device {
+
+namespace {
+
+constexpr uint8_t kTestCableVersionNumber = 0x01;
+
+// Constants required for discovering and constructing a Cable device that
+// are given by the relying party via an extension.
+constexpr FidoCableDiscovery::EidArray kClientEid = {
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15}};
+
+constexpr char kUuidFormattedClientEid[] =
+ "00010203-0405-0607-0809-101112131415";
+
+constexpr FidoCableDiscovery::EidArray kAuthenticatorEid = {
+ {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01}};
+
+constexpr FidoCableDiscovery::EidArray kInvalidAuthenticatorEid = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00}};
+
+constexpr FidoCableDiscovery::SessionKeyArray kTestSessionKey = {
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
+
+constexpr FidoCableDiscovery::EidArray kSecondaryClientEid = {
+ {0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00}};
+
+constexpr char kUuidFormattedSecondaryClientEid[] =
+ "15141312-1110-0908-0706-050403020100";
+
+constexpr FidoCableDiscovery::EidArray kSecondaryAuthenticatorEid = {
+ {0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
+ 0xee, 0xee, 0xee, 0xee}};
+
+constexpr FidoCableDiscovery::SessionKeyArray kSecondarySessionKey = {
+ {0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd}};
+
+// Below constants are used to construct MockBluetoothDevice for testing.
+constexpr char kTestBleDeviceAddress[] = "11:12:13:14:15:16";
+
+constexpr char kTestBleDeviceName[] = "test_cable_device";
+
+std::unique_ptr<MockBluetoothDevice> CreateTestBluetoothDevice() {
+ return std::make_unique<testing::NiceMock<MockBluetoothDevice>>(
+ nullptr /* adapter */, 0 /* bluetooth_class */, kTestBleDeviceName,
+ kTestBleDeviceAddress, true /* paired */, true /* connected */);
+}
+
+// Matcher to compare the content of advertisement data received from the
+// client.
+MATCHER_P2(IsAdvertisementContent,
+ expected_client_eid,
+ expected_uuid_formatted_client_eid,
+ "") {
+#if defined(OS_MACOSX)
+ const auto uuid_list = arg->service_uuids();
+ return std::any_of(uuid_list->begin(), uuid_list->end(),
+ [this](const auto& uuid) {
+ return uuid == expected_uuid_formatted_client_eid;
+ });
+
+#elif defined(OS_WIN)
+ const auto manufacturer_data = arg->manufacturer_data();
+ const auto manufacturer_data_value = manufacturer_data->find(0xFFFD);
+
+ if (manufacturer_data_value == manufacturer_data->end())
+ return false;
+
+ return fido_parsing_utils::ExtractSuffixSpan(manufacturer_data_value->second,
+ 2) == expected_client_eid;
+
+#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+ const auto service_data = arg->service_data();
+ const auto service_data_with_uuid =
+ service_data->find(kCableAdvertisementUUID);
+
+ if (service_data_with_uuid == service_data->end())
+ return false;
+
+ const auto& service_data_value = service_data_with_uuid->second;
+ return service_data_value[0] == kTestCableVersionNumber &&
+ service_data_value.size() == 24u &&
+ base::make_span(service_data_value).subspan(8) == expected_client_eid;
+
+#endif
+
+ return true;
+}
+
+class CableMockBluetoothAdvertisement : public BluetoothAdvertisement {
+ public:
+ MOCK_METHOD2(Unregister,
+ void(const SuccessCallback& success_callback,
+ const ErrorCallback& error_callback));
+
+ private:
+ ~CableMockBluetoothAdvertisement() override = default;
+};
+
+// Mock BLE adapter that abstracts out authenticator logic with the following
+// logic:
+// - Responds to BluetoothAdapter::RegisterAdvertisement() by always invoking
+// success callback.
+// - Responds to BluetoothAdapter::StartDiscoverySessionWithFilter() by
+// invoking BluetoothAdapter::Observer::DeviceAdded() on a test bluetooth
+// device that includes service data containing authenticator EID.
+class CableMockAdapter : public MockBluetoothAdapter {
+ public:
+ MOCK_METHOD3(RegisterAdvertisement,
+ void(std::unique_ptr<BluetoothAdvertisement::Data>,
+ const CreateAdvertisementCallback&,
+ const AdvertisementErrorCallback&));
+
+ void AddNewTestBluetoothDevice(
+ base::span<const uint8_t, FidoCableDiscovery::kEphemeralIdSize>
+ authenticator_eid) {
+ auto mock_device = CreateTestBluetoothDevice();
+
+ std::vector<uint8_t> service_data(8);
+ fido_parsing_utils::Append(&service_data, authenticator_eid);
+ BluetoothDevice::ServiceDataMap service_data_map;
+ service_data_map.emplace(kCableAdvertisementUUID, std::move(service_data));
+
+ mock_device->UpdateAdvertisementData(
+ 1 /* rssi */, BluetoothDevice::UUIDList(), std::move(service_data_map),
+ BluetoothDevice::ManufacturerDataMap(), nullptr /* tx_power*/);
+
+ auto* mock_device_ptr = mock_device.get();
+ AddMockDevice(std::move(mock_device));
+
+ for (auto& observer : GetObservers())
+ observer.DeviceAdded(this, mock_device_ptr);
+ }
+
+ void ExpectRegisterAdvertisementWithResponse(
+ bool simulate_success,
+ base::span<const uint8_t> expected_client_eid,
+ base::StringPiece expected_uuid_formatted_client_eid,
+ scoped_refptr<CableMockBluetoothAdvertisement> advertisement_ptr =
+ nullptr) {
+ if (!advertisement_ptr)
+ advertisement_ptr =
+ base::MakeRefCounted<CableMockBluetoothAdvertisement>();
+
+ EXPECT_CALL(*this,
+ RegisterAdvertisement(
+ IsAdvertisementContent(expected_client_eid,
+ expected_uuid_formatted_client_eid),
+ _, _))
+ .WillOnce(::testing::WithArgs<1, 2>(
+ [simulate_success, advertisement_ptr](
+ const auto& success_callback, const auto& failure_callback) {
+ simulate_success
+ ? success_callback.Run(advertisement_ptr)
+ : failure_callback.Run(BluetoothAdvertisement::ErrorCode::
+ INVALID_ADVERTISEMENT_ERROR_CODE);
+ }));
+ }
+
+ void ExpectSuccessCallbackToSetPowered() {
+ EXPECT_CALL(*this, SetPowered(true, _, _))
+ .WillOnce(::testing::WithArg<1>(
+ [](const auto& callback) { callback.Run(); }));
+ }
+
+ protected:
+ ~CableMockAdapter() override = default;
+};
+
+} // namespace
+
+class FidoCableDiscoveryTest : public ::testing::Test {
+ public:
+ std::unique_ptr<FidoCableDiscovery> CreateDiscovery() {
+ std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
+ discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
+ kAuthenticatorEid, kTestSessionKey);
+ return std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+// Tests regular successful discovery flow for Cable device.
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsNewDevice) {
+ auto cable_discovery = CreateDiscovery();
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer, DeviceAdded(_, _));
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ ::testing::InSequence testing_sequence;
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
+ EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
+ .WillOnce(::testing::WithArg<1>([&mock_adapter](const auto& callback) {
+ mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
+ callback.Run(nullptr);
+ }));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+// Tests a scenario where upon broadcasting advertisement and scanning, client
+// discovers a device with an incorrect authenticator EID. Observer::AddDevice()
+// must not be called.
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryFindsIncorrectDevice) {
+ auto cable_discovery = CreateDiscovery();
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer, DeviceAdded(_, _)).Times(0);
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ ::testing::InSequence testing_sequence;
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
+ EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
+ .WillOnce(::testing::WithArg<1>([&mock_adapter](const auto& callback) {
+ mock_adapter->AddNewTestBluetoothDevice(kInvalidAuthenticatorEid);
+ callback.Run(nullptr);
+ }));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+// Tests Cable discovery flow when multiple(2) sets of client/authenticator EIDs
+// are passed on from the relying party. We should expect 2 invocations of
+// BluetoothAdapter::RegisterAdvertisement().
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithMultipleEids) {
+ std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
+ discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
+ kAuthenticatorEid, kTestSessionKey);
+ discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ kSecondaryAuthenticatorEid, kSecondarySessionKey);
+ auto cable_discovery =
+ std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer, DeviceAdded(_, _));
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ ::testing::InSequence testing_sequence;
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kSecondaryClientEid,
+ kUuidFormattedSecondaryClientEid);
+ EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
+ .WillOnce(::testing::WithArg<1>([&mock_adapter](const auto& callback) {
+ mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
+ callback.Run(nullptr);
+ }));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+// Tests a scenario where only one of the two client EID's are advertised
+// successfully. Since at least one advertisement are successfully processed,
+// scanning process should be invoked.
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithPartialAdvertisementSuccess) {
+ std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
+ discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
+ kAuthenticatorEid, kTestSessionKey);
+ discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ kSecondaryAuthenticatorEid, kSecondarySessionKey);
+ auto cable_discovery =
+ std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer, DeviceAdded(_, _));
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ ::testing::InSequence testing_sequence;
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kClientEid, kUuidFormattedClientEid);
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ false /* simulate_success */, kSecondaryClientEid,
+ kUuidFormattedSecondaryClientEid);
+ EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
+ .WillOnce(::testing::WithArg<1>([&mock_adapter](const auto& callback) {
+ mock_adapter->AddNewTestBluetoothDevice(kAuthenticatorEid);
+ callback.Run(nullptr);
+ }));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+// Test the scenario when all advertisement for client EID's fails.
+TEST_F(FidoCableDiscoveryTest, TestDiscoveryWithAdvertisementFailures) {
+ std::vector<FidoCableDiscovery::CableDiscoveryData> discovery_data;
+ discovery_data.emplace_back(kTestCableVersionNumber, kClientEid,
+ kAuthenticatorEid, kTestSessionKey);
+ discovery_data.emplace_back(kTestCableVersionNumber, kSecondaryClientEid,
+ kSecondaryAuthenticatorEid, kSecondarySessionKey);
+ auto cable_discovery =
+ std::make_unique<FidoCableDiscovery>(std::move(discovery_data));
+
+ NiceMock<MockFidoDiscoveryObserver> mock_observer;
+ EXPECT_CALL(mock_observer, DeviceAdded(_, _)).Times(0);
+ cable_discovery->set_observer(&mock_observer);
+
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ ::testing::InSequence testing_sequence;
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ false /* simulate_success */, kClientEid, kUuidFormattedClientEid);
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ false /* simulate_success */, kSecondaryClientEid,
+ kUuidFormattedSecondaryClientEid);
+ EXPECT_CALL(*mock_adapter, StartDiscoverySessionWithFilterRaw(_, _, _))
+ .Times(0);
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_F(FidoCableDiscoveryTest, TestUnregisterAdvertisementUponDestruction) {
+ auto cable_discovery = CreateDiscovery();
+ CableMockBluetoothAdvertisement* advertisement =
+ new CableMockBluetoothAdvertisement();
+ EXPECT_CALL(*advertisement, Unregister(_, _)).Times(1);
+
+ ::testing::InSequence testing_sequence;
+ auto mock_adapter =
+ base::MakeRefCounted<::testing::NiceMock<CableMockAdapter>>();
+ mock_adapter->ExpectSuccessCallbackToSetPowered();
+ mock_adapter->ExpectRegisterAdvertisementWithResponse(
+ true /* simulate_success */, kClientEid, kUuidFormattedClientEid,
+ base::WrapRefCounted(advertisement));
+
+ BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+ cable_discovery->Start();
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_EQ(1u, cable_discovery->advertisements_.size());
+ cable_discovery.reset();
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_constants.cc b/chromium/device/fido/fido_constants.cc
index 20de24e51a8..4c61c7e8abb 100644
--- a/chromium/device/fido/fido_constants.cc
+++ b/chromium/device/fido/fido_constants.cc
@@ -43,11 +43,6 @@ const uint8_t kP1IndividualAttestation = 0x80;
const size_t kMaxKeyHandleLength = 255;
const size_t kU2fParameterLength = 32;
-const std::array<uint8_t, 2> kLegacyVersionSuffix = {0x00, 0x00};
-
-const std::array<uint8_t, 6> kU2fVersionResponse = {'U', '2', 'F',
- '_', 'V', '2'};
-
const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(3);
const base::TimeDelta kHidKeepAliveDelay =
base::TimeDelta::FromMilliseconds(100);
@@ -59,4 +54,13 @@ const char kNoneAttestationValue[] = "none";
const char kPublicKey[] = "public-key";
+const char* CredentialTypeToString(CredentialType type) {
+ switch (type) {
+ case CredentialType::kPublicKey:
+ return kPublicKey;
+ }
+ NOTREACHED();
+ return kPublicKey;
+}
+
} // namespace device
diff --git a/chromium/device/fido/fido_constants.h b/chromium/device/fido/fido_constants.h
index 3ec3d1dd52b..2d4040651f2 100644
--- a/chromium/device/fido/fido_constants.h
+++ b/chromium/device/fido/fido_constants.h
@@ -212,6 +212,19 @@ enum class UserVerificationRequirement {
kDiscouraged,
};
+// Enumerates the two types of application parameter values used: the
+// "primary" value is the hash of the relying party ID[1] and is always
+// provided. The "alternative" value is the hash of a U2F AppID, specified in
+// an extension[2], for compatibility with keys that were registered with the
+// old API.
+//
+// [1] https://w3c.github.io/webauthn/#rp-id
+// [2] https://w3c.github.io/webauthn/#sctn-appid-extension
+enum class ApplicationParameterType {
+ kPrimary,
+ kAlternative,
+};
+
// Parameters for fake U2F registration used to check for user presence.
COMPONENT_EXPORT(DEVICE_FIDO)
extern const std::array<uint8_t, 32> kBogusAppParam;
@@ -261,15 +274,6 @@ COMPONENT_EXPORT(DEVICE_FIDO) extern const uint8_t kP1IndividualAttestation;
COMPONENT_EXPORT(DEVICE_FIDO) extern const size_t kMaxKeyHandleLength;
COMPONENT_EXPORT(DEVICE_FIDO) extern const size_t kU2fParameterLength;
-// Suffix added to APDU encoded command for legacy version request.
-COMPONENT_EXPORT(DEVICE_FIDO)
-extern const std::array<uint8_t, 2> kLegacyVersionSuffix;
-
-// Expected response data for version request from U2F device.
-// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#getversion-request-and-response---u2f_version
-COMPONENT_EXPORT(DEVICE_FIDO)
-extern const std::array<uint8_t, 6> kU2fVersionResponse;
-
// Maximum wait time before client error outs on device.
COMPONENT_EXPORT(DEVICE_FIDO) extern const base::TimeDelta kDeviceTimeout;
@@ -290,14 +294,7 @@ COMPONENT_EXPORT(DEVICE_FIDO) extern const char kNoneAttestationValue[];
COMPONENT_EXPORT(DEVICE_FIDO)
extern const char kPublicKey[];
-constexpr const char* to_string(CredentialType type) {
- switch (type) {
- case CredentialType::kPublicKey:
- return kPublicKey;
- }
- NOTREACHED();
- return kPublicKey;
-}
+const char* CredentialTypeToString(CredentialType type);
} // namespace device
diff --git a/chromium/device/fido/fido_device.h b/chromium/device/fido/fido_device.h
index b22900d5e69..28ffef7f692 100644
--- a/chromium/device/fido/fido_device.h
+++ b/chromium/device/fido/fido_device.h
@@ -25,7 +25,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDevice {
public:
using WinkCallback = base::OnceClosure;
using DeviceCallback =
- base::OnceCallback<void(base::Optional<std::vector<uint8_t>> response)>;
+ base::OnceCallback<void(base::Optional<std::vector<uint8_t>>)>;
// Internal state machine states.
enum class State { kInit, kConnected, kBusy, kReady, kDeviceError };
diff --git a/chromium/device/fido/fido_device_authenticator.cc b/chromium/device/fido/fido_device_authenticator.cc
new file mode 100644
index 00000000000..c8aa469918e
--- /dev/null
+++ b/chromium/device/fido/fido_device_authenticator.cc
@@ -0,0 +1,56 @@
+// 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_device_authenticator.h"
+
+#include <utility>
+
+#include "device/fido/authenticator_selection_criteria.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/fido_device.h"
+#include "device/fido/get_assertion_task.h"
+#include "device/fido/make_credential_task.h"
+
+namespace device {
+
+FidoDeviceAuthenticator::FidoDeviceAuthenticator(FidoDevice* device)
+ : device_(device) {}
+FidoDeviceAuthenticator::~FidoDeviceAuthenticator() = default;
+
+void FidoDeviceAuthenticator::MakeCredential(
+ AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) {
+ DCHECK(!task_);
+ // 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>(
+ device_, std::move(request), std::move(authenticator_selection_criteria),
+ std::move(callback));
+}
+
+void FidoDeviceAuthenticator::GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) {
+ task_ = std::make_unique<GetAssertionTask>(device_, std::move(request),
+ std::move(callback));
+}
+
+void FidoDeviceAuthenticator::Cancel() {
+ if (!task_)
+ return;
+
+ task_->CancelTask();
+}
+
+std::string FidoDeviceAuthenticator::GetId() const {
+ return device_->GetId();
+}
+
+void FidoDeviceAuthenticator::SetTaskForTesting(
+ std::unique_ptr<FidoTask> task) {
+ task_ = std::move(task);
+}
+
+} // namespace device
diff --git a/chromium/device/fido/fido_device_authenticator.h b/chromium/device/fido/fido_device_authenticator.h
new file mode 100644
index 00000000000..29db9d814f5
--- /dev/null
+++ b/chromium/device/fido/fido_device_authenticator.h
@@ -0,0 +1,63 @@
+// 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_DEVICE_AUTHENTICATOR_H_
+#define DEVICE_FIDO_FIDO_DEVICE_AUTHENTICATOR_H_
+
+#include <string>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "device/fido/fido_authenticator.h"
+
+namespace device {
+
+class AuthenticatorSelectionCriteria;
+class CtapGetAssertionRequest;
+class CtapMakeCredentialRequest;
+class FidoDevice;
+class FidoTask;
+
+// Adaptor class from a |FidoDevice| to the |FidoAuthenticator| interface.
+// Responsible for translating WebAuthn-level requests into serializations that
+// can be passed to the device for transport.
+class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
+ : public FidoAuthenticator {
+ public:
+ FidoDeviceAuthenticator(FidoDevice* device);
+ ~FidoDeviceAuthenticator() override;
+
+ // FidoAuthenticator:
+ void MakeCredential(
+ AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) override;
+ void GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) override;
+ void Cancel() override;
+ std::string GetId() const override;
+
+ protected:
+ void OnCtapMakeCredentialResponseReceived(
+ MakeCredentialCallback callback,
+ base::Optional<std::vector<uint8_t>> response_data);
+ void OnCtapGetAssertionResponseReceived(
+ GetAssertionCallback callback,
+ base::Optional<std::vector<uint8_t>> response_data);
+
+ FidoDevice* device() { return device_; }
+ void SetTaskForTesting(std::unique_ptr<FidoTask> task);
+
+ private:
+ FidoDevice* const device_;
+ std::unique_ptr<FidoTask> task_;
+
+ DISALLOW_COPY_AND_ASSIGN(FidoDeviceAuthenticator);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_FIDO_DEVICE_AUTHENTICATOR_H_
diff --git a/chromium/device/fido/fido_discovery.cc b/chromium/device/fido/fido_discovery.cc
index 8e941b65032..299bbf058c7 100644
--- a/chromium/device/fido/fido_discovery.cc
+++ b/chromium/device/fido/fido_discovery.cc
@@ -33,11 +33,21 @@ std::unique_ptr<FidoDiscovery> CreateFidoDiscoveryImpl(
#endif // !defined(OS_ANDROID)
case FidoTransportProtocol::kBluetoothLowEnergy:
return std::make_unique<FidoBleDiscovery>();
+ // FidoCaBleDiscovery is not constructed using FidoDiscovery factory
+ // function and instead constructed in FidoGetAssertionRequestHandler as it
+ // requires extensions passed on from the relying party.
+ case FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy:
+ NOTREACHED()
+ << "Cable discovery is not constructed using 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();
+ NOTREACHED() << "Unhandled transport type";
return nullptr;
}
@@ -64,9 +74,10 @@ FidoDiscovery::~FidoDiscovery() = default;
void FidoDiscovery::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();
- // StartInternal should never synchronously call NotifyStarted().
- DCHECK_EQ(state_, State::kStarting);
}
void FidoDiscovery::NotifyDiscoveryStarted(bool success) {
diff --git a/chromium/device/fido/fido_hid_device.cc b/chromium/device/fido/fido_hid_device.cc
index 89652ed41c4..d2104f564b9 100644
--- a/chromium/device/fido/fido_hid_device.cc
+++ b/chromium/device/fido/fido_hid_device.cc
@@ -148,13 +148,13 @@ void FidoHidDevice::AllocateChannel(std::vector<uint8_t> command,
void FidoHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce,
std::vector<uint8_t> command,
DeviceCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> message) {
+ base::Optional<FidoHidMessage> message) {
if (state_ == State::kDeviceError)
return;
+
timeout_callback_.Cancel();
- if (!success || !message) {
+ if (!message) {
state_ = State::kDeviceError;
Transition(std::vector<uint8_t>(), std::move(callback));
return;
@@ -198,11 +198,11 @@ void FidoHidDevice::OnAllocateChannel(std::vector<uint8_t> nonce,
Transition(std::move(command), std::move(callback));
}
-void FidoHidDevice::WriteMessage(std::unique_ptr<FidoHidMessage> message,
+void FidoHidDevice::WriteMessage(base::Optional<FidoHidMessage> message,
bool response_expected,
HidMessageCallback callback) {
if (!connection_ || !message || message->NumPackets() == 0) {
- std::move(callback).Run(false, nullptr);
+ std::move(callback).Run(base::nullopt);
return;
}
const auto& packet = message->PopNextPacket();
@@ -213,7 +213,7 @@ void FidoHidDevice::WriteMessage(std::unique_ptr<FidoHidMessage> message,
std::move(callback)));
}
-void FidoHidDevice::PacketWritten(std::unique_ptr<FidoHidMessage> message,
+void FidoHidDevice::PacketWritten(base::Optional<FidoHidMessage> message,
bool response_expected,
HidMessageCallback callback,
bool success) {
@@ -222,13 +222,13 @@ void FidoHidDevice::PacketWritten(std::unique_ptr<FidoHidMessage> message,
} else if (success && response_expected) {
ReadMessage(std::move(callback));
} else {
- std::move(callback).Run(success, nullptr);
+ std::move(callback).Run(base::nullopt);
}
}
void FidoHidDevice::ReadMessage(HidMessageCallback callback) {
if (!connection_) {
- std::move(callback).Run(false, nullptr);
+ std::move(callback).Run(base::nullopt);
return;
}
@@ -241,14 +241,14 @@ void FidoHidDevice::OnRead(HidMessageCallback callback,
uint8_t report_id,
const base::Optional<std::vector<uint8_t>>& buf) {
if (!success) {
- std::move(callback).Run(success, nullptr);
+ std::move(callback).Run(base::nullopt);
return;
}
DCHECK(buf);
auto read_message = FidoHidMessage::CreateFromSerializedData(*buf);
if (!read_message) {
- std::move(callback).Run(false, nullptr);
+ std::move(callback).Run(base::nullopt);
return;
}
@@ -261,7 +261,7 @@ void FidoHidDevice::OnRead(HidMessageCallback callback,
}
if (read_message->MessageComplete()) {
- std::move(callback).Run(success, std::move(read_message));
+ std::move(callback).Run(std::move(read_message));
return;
}
@@ -272,20 +272,20 @@ void FidoHidDevice::OnRead(HidMessageCallback callback,
}
void FidoHidDevice::OnReadContinuation(
- std::unique_ptr<FidoHidMessage> message,
+ base::Optional<FidoHidMessage> message,
HidMessageCallback callback,
bool success,
uint8_t report_id,
const base::Optional<std::vector<uint8_t>>& buf) {
if (!success) {
- std::move(callback).Run(success, nullptr);
+ std::move(callback).Run(base::nullopt);
return;
}
DCHECK(buf);
message->AddContinuationPacket(*buf);
if (message->MessageComplete()) {
- std::move(callback).Run(success, std::move(message));
+ std::move(callback).Run(std::move(message));
return;
}
connection_->Read(base::BindOnce(&FidoHidDevice::OnReadContinuation,
@@ -294,13 +294,12 @@ void FidoHidDevice::OnReadContinuation(
}
void FidoHidDevice::MessageReceived(DeviceCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> message) {
+ base::Optional<FidoHidMessage> message) {
if (state_ == State::kDeviceError)
return;
timeout_callback_.Cancel();
- if (!success || !message) {
+ if (!message) {
state_ = State::kDeviceError;
Transition(std::vector<uint8_t>(), std::move(callback));
return;
@@ -329,8 +328,8 @@ void FidoHidDevice::MessageReceived(DeviceCallback callback,
state_ = State::kReady;
base::WeakPtr<FidoHidDevice> self = weak_factory_.GetWeakPtr();
std::move(callback).Run(
- (success && message) ? base::make_optional(message->GetMessagePayload())
- : base::nullopt);
+ message ? base::make_optional(message->GetMessagePayload())
+ : base::nullopt);
// Executing |callback| may have freed |this|. Check |self| first.
if (self && !pending_transactions_.empty()) {
@@ -366,8 +365,7 @@ void FidoHidDevice::OnKeepAlive(DeviceCallback callback) {
}
void FidoHidDevice::OnWink(WinkCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> response) {
+ base::Optional<FidoHidMessage> response) {
std::move(callback).Run();
}
diff --git a/chromium/device/fido/fido_hid_device.h b/chromium/device/fido/fido_hid_device.h
index 57dd5f65185..f1e4865b50e 100644
--- a/chromium/device/fido/fido_hid_device.h
+++ b/chromium/device/fido/fido_hid_device.h
@@ -5,7 +5,6 @@
#ifndef DEVICE_FIDO_FIDO_HID_DEVICE_H_
#define DEVICE_FIDO_FIDO_HID_DEVICE_H_
-#include <memory>
#include <queue>
#include <string>
#include <utility>
@@ -15,6 +14,7 @@
#include "base/cancelable_callback.h"
#include "base/component_export.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h"
#include "device/fido/fido_device.h"
@@ -58,7 +58,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDevice : public FidoDevice {
static constexpr uint32_t kBroadcastChannel = 0xffffffff;
using HidMessageCallback =
- base::OnceCallback<void(bool, std::unique_ptr<FidoHidMessage>)>;
+ base::OnceCallback<void(base::Optional<FidoHidMessage>)>;
using ConnectCallback = device::mojom::HidManager::ConnectCallback;
// Open a connection to this device.
@@ -71,35 +71,31 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidDevice : public FidoDevice {
void OnAllocateChannel(std::vector<uint8_t> nonce,
std::vector<uint8_t> command,
DeviceCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> message);
+ base::Optional<FidoHidMessage> message);
void Transition(std::vector<uint8_t> command, DeviceCallback callback);
// Write all message packets to device, and read response if expected.
- void WriteMessage(std::unique_ptr<FidoHidMessage> message,
+ void WriteMessage(base::Optional<FidoHidMessage> message,
bool response_expected,
HidMessageCallback callback);
- void PacketWritten(std::unique_ptr<FidoHidMessage> message,
+ void PacketWritten(base::Optional<FidoHidMessage> message,
bool response_expected,
HidMessageCallback callback,
bool success);
// Read all response message packets from device.
void ReadMessage(HidMessageCallback callback);
void MessageReceived(DeviceCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> message);
+ base::Optional<FidoHidMessage> message);
void OnRead(HidMessageCallback callback,
bool success,
uint8_t report_id,
const base::Optional<std::vector<uint8_t>>& buf);
- void OnReadContinuation(std::unique_ptr<FidoHidMessage> message,
+ void OnReadContinuation(base::Optional<FidoHidMessage> message,
HidMessageCallback callback,
bool success,
uint8_t report_id,
const base::Optional<std::vector<uint8_t>>& buf);
void OnKeepAlive(DeviceCallback callback);
- void OnWink(WinkCallback callback,
- bool success,
- std::unique_ptr<FidoHidMessage> response);
+ void OnWink(WinkCallback callback, base::Optional<FidoHidMessage> response);
void ArmTimeout(DeviceCallback callback);
void OnTimeout(DeviceCallback callback);
diff --git a/chromium/device/fido/fido_hid_device_unittest.cc b/chromium/device/fido/fido_hid_device_unittest.cc
index 0b95f705219..e52e1b5382a 100644
--- a/chromium/device/fido/fido_hid_device_unittest.cc
+++ b/chromium/device/fido/fido_hid_device_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "device/fido/fido_hid_device.h"
+
+#include <memory>
#include <tuple>
#include "base/bind.h"
@@ -11,14 +14,10 @@
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "components/apdu/apdu_command.h"
-#include "components/apdu/apdu_response.h"
#include "device/fido/fake_hid_impl_for_testing.h"
#include "device/fido/fido_constants.h"
-#include "device/fido/fido_hid_device.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
-#include "device/fido/u2f_request.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/device/public/cpp/hid/hid_device_filter.h"
@@ -33,10 +32,17 @@ using ::testing::Invoke;
namespace {
-// HID_MSG(83), followed by payload length(0008), followed by 'U2F_V2', followed
-// by APDU response code(9000).
-constexpr uint8_t kMockVersionResponseSuffix[] = {
- 0x83, 0x00, 0x08, 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00};
+// HID_MSG(83), followed by payload length(000b), followed by response data
+// "MOCK_DATA", followed by APDU SW_NO_ERROR response code(9000).
+constexpr uint8_t kU2fMockResponseMessage[] = {
+ 0x83, 0x00, 0x0b, 0x4d, 0x4f, 0x43, 0x4b,
+ 0x5f, 0x44, 0x41, 0x54, 0x41, 0x90, 0x00,
+};
+
+// APDU encoded success response with data "MOCK_DATA" followed by a SW_NO_ERROR
+// APDU response code(9000).
+constexpr uint8_t kU2fMockResponseData[] = {0x4d, 0x4f, 0x43, 0x4b, 0x5f, 0x44,
+ 0x41, 0x54, 0x41, 0x90, 0x00};
// HID_KEEP_ALIVE(bb), followed by payload length(0001), followed by
// status processing(01) byte.
@@ -49,13 +55,17 @@ constexpr uint8_t kInitResponsePrefix[] = {
0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11,
};
+// Mock APDU encoded U2F request with empty data and mock P1 parameter(0x04).
+constexpr uint8_t kMockU2fRequest[] = {0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x00, 0x00};
+
// Returns HID_INIT request to send to device with mock connection.
std::vector<uint8_t> CreateMockInitResponse(
base::span<const uint8_t> nonce,
base::span<const uint8_t> channel_id) {
- auto init_response = u2f_parsing_utils::Materialize(kInitResponsePrefix);
- u2f_parsing_utils::Append(&init_response, nonce);
- u2f_parsing_utils::Append(&init_response, channel_id);
+ auto init_response = fido_parsing_utils::Materialize(kInitResponsePrefix);
+ fido_parsing_utils::Append(&init_response, nonce);
+ fido_parsing_utils::Append(&init_response, channel_id);
init_response.resize(64);
return init_response;
}
@@ -63,28 +73,25 @@ std::vector<uint8_t> CreateMockInitResponse(
// Returns HID keep alive message encoded into HID packet format.
std::vector<uint8_t> GetKeepAliveHidMessage(
base::span<const uint8_t> channel_id) {
- auto response = u2f_parsing_utils::Materialize(channel_id);
- u2f_parsing_utils::Append(&response, kMockKeepAliveResponseSuffix);
+ auto response = fido_parsing_utils::Materialize(channel_id);
+ fido_parsing_utils::Append(&response, kMockKeepAliveResponseSuffix);
response.resize(64);
return response;
}
// Returns "U2F_v2" as a mock response to version request with given channel id.
-std::vector<uint8_t> CreateMockResponse(
+std::vector<uint8_t> CreateMockResponseWithChannelId(
base::span<const uint8_t> channel_id,
base::span<const uint8_t> response_buffer) {
- auto response = u2f_parsing_utils::Materialize(channel_id);
- u2f_parsing_utils::Append(&response, response_buffer);
+ auto response = fido_parsing_utils::Materialize(channel_id);
+ fido_parsing_utils::Append(&response, response_buffer);
response.resize(64);
return response;
}
-// Returns U2F_V2 version response formatted in APDU response encoding.
-std::vector<uint8_t> GetValidU2fVersionResponse() {
- return apdu::ApduResponse(std::vector<uint8_t>(kU2fVersionResponse.begin(),
- kU2fVersionResponse.end()),
- apdu::ApduResponse::Status::SW_NO_ERROR)
- .GetEncodedResponse();
+// Returns a APDU encoded U2F version request for testing.
+std::vector<uint8_t> GetMockDeviceRequest() {
+ return fido_parsing_utils::Materialize(kMockU2fRequest);
}
device::mojom::HidDeviceInfoPtr TestHidDevice() {
@@ -131,7 +138,7 @@ class FidoDeviceEnumerateCallbackReceiver
};
using TestDeviceCallbackReceiver =
- ::device::test::TestCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
+ ::device::test::ValueCallbackReceiver<base::Optional<std::vector<uint8_t>>>;
} // namespace
@@ -170,20 +177,19 @@ TEST_F(FidoHidDeviceTest, TestConnectionFailure) {
// Add pending transactions manually and ensure they are processed.
TestDeviceCallbackReceiver receiver_1;
- device->pending_transactions_.emplace(U2fRequest::GetU2fVersionApduCommand(),
+ device->pending_transactions_.emplace(GetMockDeviceRequest(),
receiver_1.callback());
TestDeviceCallbackReceiver receiver_2;
- device->pending_transactions_.emplace(U2fRequest::GetU2fVersionApduCommand(),
+ device->pending_transactions_.emplace(GetMockDeviceRequest(),
receiver_2.callback());
TestDeviceCallbackReceiver receiver_3;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
- receiver_3.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), receiver_3.callback());
EXPECT_EQ(FidoDevice::State::kDeviceError, device->state_);
- EXPECT_FALSE(std::get<0>(*receiver_1.result()));
- EXPECT_FALSE(std::get<0>(*receiver_2.result()));
- EXPECT_FALSE(std::get<0>(*receiver_3.result()));
+ EXPECT_FALSE(receiver_1.value());
+ EXPECT_FALSE(receiver_2.value());
+ EXPECT_FALSE(receiver_3.value());
}
TEST_F(FidoHidDeviceTest, TestDeviceError) {
@@ -206,27 +212,25 @@ TEST_F(FidoHidDeviceTest, TestDeviceError) {
device->state_ = FidoDevice::State::kReady;
TestDeviceCallbackReceiver receiver_0;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
- receiver_0.callback());
- EXPECT_FALSE(std::get<0>(*receiver_0.result()));
+ device->DeviceTransact(GetMockDeviceRequest(), receiver_0.callback());
+ EXPECT_FALSE(receiver_0.value());
EXPECT_EQ(FidoDevice::State::kDeviceError, device->state_);
// Add pending transactions manually and ensure they are processed.
TestDeviceCallbackReceiver receiver_1;
- device->pending_transactions_.emplace(U2fRequest::GetU2fVersionApduCommand(),
+ device->pending_transactions_.emplace(GetMockDeviceRequest(),
receiver_1.callback());
TestDeviceCallbackReceiver receiver_2;
- device->pending_transactions_.emplace(U2fRequest::GetU2fVersionApduCommand(),
+ device->pending_transactions_.emplace(GetMockDeviceRequest(),
receiver_2.callback());
TestDeviceCallbackReceiver receiver_3;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(),
- receiver_3.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), receiver_3.callback());
FakeHidConnection::mock_connection_error_ = false;
EXPECT_EQ(FidoDevice::State::kDeviceError, device->state_);
- EXPECT_FALSE(std::get<0>(*receiver_1.result()));
- EXPECT_FALSE(std::get<0>(*receiver_2.result()));
- EXPECT_FALSE(std::get<0>(*receiver_3.result()));
+ EXPECT_FALSE(receiver_1.value());
+ EXPECT_FALSE(receiver_2.value());
+ EXPECT_FALSE(receiver_3.value());
}
TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
@@ -240,9 +244,9 @@ TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
device::mojom::HidConnectionPtr connection_client;
- MockHidConnection mock_connection(hid_device.Clone(),
- mojo::MakeRequest(&connection_client),
- u2f_parsing_utils::Materialize(kChannelId));
+ MockHidConnection mock_connection(
+ hid_device.Clone(), mojo::MakeRequest(&connection_client),
+ fido_parsing_utils::Materialize(kChannelId));
// Initial write for establishing a channel ID.
mock_connection.ExpectWriteHidInit();
@@ -270,10 +274,10 @@ TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
// Version response from the authenticator.
.WillOnce(Invoke(
[&mock_connection](device::mojom::HidConnection::ReadCallback* cb) {
- std::move(*cb).Run(
- true, 0,
- CreateMockResponse(mock_connection.connection_channel_id(),
- kMockVersionResponseSuffix));
+ std::move(*cb).Run(true, 0,
+ CreateMockResponseWithChannelId(
+ mock_connection.connection_channel_id(),
+ kU2fMockResponseMessage));
}));
// Add device and set mock connection to fake hid manager.
@@ -289,13 +293,12 @@ TEST_F(FidoHidDeviceTest, TestRetryChannelAllocation) {
auto& device = u2f_devices.front();
TestDeviceCallbackReceiver cb;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
- cb.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), cb.callback());
cb.WaitForCallback();
- const auto& result = std::get<0>(*cb.result());
- ASSERT_TRUE(result);
- EXPECT_THAT(*result, testing::ElementsAreArray(GetValidU2fVersionResponse()));
+ const auto& value = cb.value();
+ ASSERT_TRUE(value);
+ EXPECT_THAT(*value, testing::ElementsAreArray(kU2fMockResponseData));
}
TEST_F(FidoHidDeviceTest, TestKeepAliveMessage) {
@@ -306,9 +309,9 @@ TEST_F(FidoHidDeviceTest, TestKeepAliveMessage) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
device::mojom::HidConnectionPtr connection_client;
- MockHidConnection mock_connection(hid_device.Clone(),
- mojo::MakeRequest(&connection_client),
- u2f_parsing_utils::Materialize(kChannelId));
+ MockHidConnection mock_connection(
+ hid_device.Clone(), mojo::MakeRequest(&connection_client),
+ fido_parsing_utils::Materialize(kChannelId));
// Initial write for establishing channel ID.
mock_connection.ExpectWriteHidInit();
@@ -337,10 +340,10 @@ TEST_F(FidoHidDeviceTest, TestKeepAliveMessage) {
kDeviceTimeout - base::TimeDelta::FromMicroseconds(1);
scoped_task_environment_.FastForwardBy(almost_time_out);
- std::move(*cb).Run(
- true, 0,
- CreateMockResponse(mock_connection.connection_channel_id(),
- kMockVersionResponseSuffix));
+ std::move(*cb).Run(true, 0,
+ CreateMockResponseWithChannelId(
+ mock_connection.connection_channel_id(),
+ kU2fMockResponseMessage));
}));
// Add device and set mock connection to fake hid manager.
@@ -359,12 +362,11 @@ TEST_F(FidoHidDeviceTest, TestKeepAliveMessage) {
// Keep alive message handling is only supported for CTAP HID device.
device->set_supported_protocol(ProtocolVersion::kCtap);
TestDeviceCallbackReceiver cb;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
- cb.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), cb.callback());
cb.WaitForCallback();
- const auto result = std::get<0>(*cb.result());
- ASSERT_TRUE(result);
- EXPECT_THAT(*result, testing::ElementsAreArray(GetValidU2fVersionResponse()));
+ const auto& value = cb.value();
+ ASSERT_TRUE(value);
+ EXPECT_THAT(*value, testing::ElementsAreArray(kU2fMockResponseData));
}
TEST_F(FidoHidDeviceTest, TestDeviceTimeoutAfterKeepAliveMessage) {
@@ -375,9 +377,9 @@ TEST_F(FidoHidDeviceTest, TestDeviceTimeoutAfterKeepAliveMessage) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
device::mojom::HidConnectionPtr connection_client;
- MockHidConnection mock_connection(hid_device.Clone(),
- mojo::MakeRequest(&connection_client),
- u2f_parsing_utils::Materialize(kChannelId));
+ MockHidConnection mock_connection(
+ hid_device.Clone(), mojo::MakeRequest(&connection_client),
+ fido_parsing_utils::Materialize(kChannelId));
// Initial write for establishing channel ID.
mock_connection.ExpectWriteHidInit();
@@ -403,10 +405,10 @@ TEST_F(FidoHidDeviceTest, TestDeviceTimeoutAfterKeepAliveMessage) {
// is invoked only after 3 seconds, which should cause device to timeout.
.WillOnce(Invoke([&](device::mojom::HidConnection::ReadCallback* cb) {
scoped_task_environment_.FastForwardBy(kDeviceTimeout);
- std::move(*cb).Run(
- true, 0,
- CreateMockResponse(mock_connection.connection_channel_id(),
- kMockVersionResponseSuffix));
+ std::move(*cb).Run(true, 0,
+ CreateMockResponseWithChannelId(
+ mock_connection.connection_channel_id(),
+ kU2fMockResponseMessage));
}));
// Add device and set mock connection to fake hid manager.
@@ -425,11 +427,10 @@ TEST_F(FidoHidDeviceTest, TestDeviceTimeoutAfterKeepAliveMessage) {
// Keep alive message handling is only supported for CTAP HID device.
device->set_supported_protocol(ProtocolVersion::kCtap);
TestDeviceCallbackReceiver cb;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
- cb.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), cb.callback());
cb.WaitForCallback();
- const auto result = std::get<0>(*cb.result());
- EXPECT_FALSE(result);
+ const auto& value = cb.value();
+ EXPECT_FALSE(value);
EXPECT_EQ(FidoDevice::State::kDeviceError, device->state());
}
@@ -441,9 +442,9 @@ TEST_F(FidoHidDeviceTest, TestCancel) {
// Replace device HID connection with custom client connection bound to mock
// server-side mojo connection.
device::mojom::HidConnectionPtr connection_client;
- MockHidConnection mock_connection(hid_device.Clone(),
- mojo::MakeRequest(&connection_client),
- u2f_parsing_utils::Materialize(kChannelId));
+ MockHidConnection mock_connection(
+ hid_device.Clone(), mojo::MakeRequest(&connection_client),
+ fido_parsing_utils::Materialize(kChannelId));
// Initial write for establishing channel ID.
mock_connection.ExpectWriteHidInit();
@@ -467,10 +468,10 @@ TEST_F(FidoHidDeviceTest, TestCancel) {
auto delay = base::TimeDelta::FromSeconds(2);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
- base::BindOnce(
- std::move(*cb), true, 0,
- CreateMockResponse(mock_connection.connection_channel_id(),
- kMockVersionResponseSuffix)),
+ base::BindOnce(std::move(*cb), true, 0,
+ CreateMockResponseWithChannelId(
+ mock_connection.connection_channel_id(),
+ kU2fMockResponseMessage)),
delay);
}));
@@ -490,8 +491,7 @@ TEST_F(FidoHidDeviceTest, TestCancel) {
// Keep alive message handling is only supported for CTAP HID device.
device->set_supported_protocol(ProtocolVersion::kCtap);
TestDeviceCallbackReceiver cb;
- device->DeviceTransact(U2fRequest::GetU2fVersionApduCommand(false),
- cb.callback());
+ device->DeviceTransact(GetMockDeviceRequest(), cb.callback());
device->Cancel();
scoped_task_environment_.FastForwardUntilNoTasksRemain();
}
diff --git a/chromium/device/fido/fido_hid_message.cc b/chromium/device/fido/fido_hid_message.cc
index b72f86feba1..d95598c4a62 100644
--- a/chromium/device/fido/fido_hid_message.cc
+++ b/chromium/device/fido/fido_hid_message.cc
@@ -10,17 +10,17 @@
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
// static
-std::unique_ptr<FidoHidMessage> FidoHidMessage::Create(
+base::Optional<FidoHidMessage> FidoHidMessage::Create(
uint32_t channel_id,
FidoHidDeviceCommand type,
base::span<const uint8_t> data) {
if (data.size() > kHidMaxMessageSize)
- return nullptr;
+ return base::nullopt;
switch (type) {
case FidoHidDeviceCommand::kPing:
@@ -28,53 +28,56 @@ std::unique_ptr<FidoHidMessage> FidoHidMessage::Create(
case FidoHidDeviceCommand::kMsg:
case FidoHidDeviceCommand::kCbor: {
if (data.empty())
- return nullptr;
+ return base::nullopt;
break;
}
case FidoHidDeviceCommand::kCancel:
case FidoHidDeviceCommand::kWink: {
if (!data.empty())
- return nullptr;
+ return base::nullopt;
break;
}
case FidoHidDeviceCommand::kLock: {
if (data.size() != 1 || data[0] > kHidMaxLockSeconds)
- return nullptr;
+ return base::nullopt;
break;
}
case FidoHidDeviceCommand::kInit: {
if (data.size() != 8)
- return nullptr;
+ return base::nullopt;
break;
}
case FidoHidDeviceCommand::kKeepAlive:
case FidoHidDeviceCommand::kError:
if (data.size() != 1)
- return nullptr;
+ return base::nullopt;
}
- return base::WrapUnique(new FidoHidMessage(channel_id, type, data));
+ return FidoHidMessage(channel_id, type, data);
}
// static
-std::unique_ptr<FidoHidMessage> FidoHidMessage::CreateFromSerializedData(
+base::Optional<FidoHidMessage> FidoHidMessage::CreateFromSerializedData(
base::span<const uint8_t> serialized_data) {
size_t remaining_size = 0;
if (serialized_data.size() > kHidPacketSize ||
serialized_data.size() < kHidInitPacketHeaderSize)
- return nullptr;
+ return base::nullopt;
auto init_packet = FidoHidInitPacket::CreateFromSerializedData(
serialized_data, &remaining_size);
if (init_packet == nullptr)
- return nullptr;
+ return base::nullopt;
- return base::WrapUnique(
- new FidoHidMessage(std::move(init_packet), remaining_size));
+ return FidoHidMessage(std::move(init_packet), remaining_size);
}
+FidoHidMessage::FidoHidMessage(FidoHidMessage&& that) = default;
+
+FidoHidMessage& FidoHidMessage::operator=(FidoHidMessage&& other) = default;
+
FidoHidMessage::~FidoHidMessage() = default;
bool FidoHidMessage::MessageComplete() const {
@@ -137,9 +140,9 @@ FidoHidMessage::FidoHidMessage(uint32_t channel_id,
data = data.subspan(init_data.size());
for (auto cont_data :
- u2f_parsing_utils::SplitSpan(data, kHidContinuationPacketDataSize)) {
+ fido_parsing_utils::SplitSpan(data, kHidContinuationPacketDataSize)) {
packets_.push_back(std::make_unique<FidoHidContinuationPacket>(
- channel_id, sequence++, u2f_parsing_utils::Materialize(cont_data)));
+ channel_id, sequence++, fido_parsing_utils::Materialize(cont_data)));
}
}
diff --git a/chromium/device/fido/fido_hid_message.h b/chromium/device/fido/fido_hid_message.h
index 529aa00634e..ecf386cd39e 100644
--- a/chromium/device/fido/fido_hid_message.h
+++ b/chromium/device/fido/fido_hid_message.h
@@ -17,6 +17,7 @@
#include "base/containers/queue.h"
#include "base/containers/span.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_hid_packet.h"
@@ -27,14 +28,16 @@ namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) FidoHidMessage {
public:
// Static functions to create CTAP/U2F HID commands.
- static std::unique_ptr<FidoHidMessage> Create(uint32_t channel_id,
- FidoHidDeviceCommand cmd,
- base::span<const uint8_t> data);
+ static base::Optional<FidoHidMessage> Create(uint32_t channel_id,
+ FidoHidDeviceCommand cmd,
+ base::span<const uint8_t> data);
// Reconstruct a message from serialized message data.
- static std::unique_ptr<FidoHidMessage> CreateFromSerializedData(
+ static base::Optional<FidoHidMessage> CreateFromSerializedData(
base::span<const uint8_t> serialized_data);
+ FidoHidMessage(FidoHidMessage&& that);
+ FidoHidMessage& operator=(FidoHidMessage&& other);
~FidoHidMessage();
bool MessageComplete() const;
diff --git a/chromium/device/fido/fido_hid_message_unittest.cc b/chromium/device/fido/fido_hid_message_unittest.cc
index cc7ab4fef97..b819454dbe5 100644
--- a/chromium/device/fido/fido_hid_message_unittest.cc
+++ b/chromium/device/fido/fido_hid_message_unittest.cc
@@ -160,7 +160,7 @@ TEST(FidoHidMessageTest, TestMaxSize) {
std::vector<uint8_t> data(kHidMaxMessageSize + 1);
auto oversize_message =
FidoHidMessage::Create(channel_id, FidoHidDeviceCommand::kPing, data);
- EXPECT_EQ(nullptr, oversize_message);
+ EXPECT_FALSE(oversize_message);
}
TEST(FidoHidMessageTest, TestDeconstruct) {
diff --git a/chromium/device/fido/u2f_parsing_utils.cc b/chromium/device/fido/fido_parsing_utils.cc
index 2da8ba0b628..54daf0940e4 100644
--- a/chromium/device/fido/u2f_parsing_utils.cc
+++ b/chromium/device/fido/fido_parsing_utils.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
#include "base/logging.h"
+#include "crypto/sha2.h"
namespace device {
-namespace u2f_parsing_utils {
+namespace fido_parsing_utils {
namespace {
@@ -79,5 +80,11 @@ std::vector<base::span<const uint8_t>> SplitSpan(base::span<const uint8_t> span,
return chunks;
}
-} // namespace u2f_parsing_utils
+std::vector<uint8_t> CreateSHA256Hash(base::StringPiece data) {
+ std::vector<uint8_t> hashed_data(crypto::kSHA256Length);
+ crypto::SHA256HashString(data, hashed_data.data(), hashed_data.size());
+ return hashed_data;
+}
+
+} // namespace fido_parsing_utils
} // namespace device
diff --git a/chromium/device/fido/u2f_parsing_utils.h b/chromium/device/fido/fido_parsing_utils.h
index 15ca8c7f95f..ace50c5cd7f 100644
--- a/chromium/device/fido/u2f_parsing_utils.h
+++ b/chromium/device/fido/fido_parsing_utils.h
@@ -2,21 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef DEVICE_FIDO_U2F_PARSING_UTILS_H_
-#define DEVICE_FIDO_U2F_PARSING_UTILS_H_
+#ifndef DEVICE_FIDO_FIDO_PARSING_UTILS_H_
+#define DEVICE_FIDO_FIDO_PARSING_UTILS_H_
#include <stddef.h>
#include <stdint.h>
+
#include <algorithm>
#include <array>
+#include <utility>
#include <vector>
#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/optional.h"
+#include "base/strings/string_piece.h"
namespace device {
-namespace u2f_parsing_utils {
+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 {
+ 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 is_transparent = void;
+};
// U2FResponse offsets. The format of a U2F response is defined in
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success
@@ -81,7 +97,10 @@ COMPONENT_EXPORT(DEVICE_FIDO)
std::vector<base::span<const uint8_t>> SplitSpan(base::span<const uint8_t> span,
size_t max_chunk_size);
-} // namespace u2f_parsing_utils
+COMPONENT_EXPORT(DEVICE_FIDO)
+std::vector<uint8_t> CreateSHA256Hash(base::StringPiece data);
+
+} // namespace fido_parsing_utils
} // namespace device
-#endif // DEVICE_FIDO_U2F_PARSING_UTILS_H_
+#endif // DEVICE_FIDO_FIDO_PARSING_UTILS_H_
diff --git a/chromium/device/fido/u2f_parsing_utils_unittest.cc b/chromium/device/fido/fido_parsing_utils_unittest.cc
index 7dffb524f72..b84cb6d9265 100644
--- a/chromium/device/fido/u2f_parsing_utils_unittest.cc
+++ b/chromium/device/fido/fido_parsing_utils_unittest.cc
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "device/fido/u2f_parsing_utils.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/fido_test_data.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
-namespace u2f_parsing_utils {
+namespace fido_parsing_utils {
namespace {
constexpr uint8_t kOne[] = {0x01};
@@ -19,6 +20,66 @@ constexpr uint8_t kThree[] = {0x03};
constexpr uint8_t kOneTwoThree[] = {0x01, 0x02, 0x03};
} // namespace
+TEST(U2fParsingUtils, SpanLess) {
+ 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));
+}
+
TEST(U2fParsingUtils, Materialize) {
const std::vector<uint8_t> empty;
EXPECT_THAT(Materialize(empty), ::testing::IsEmpty());
@@ -188,5 +249,10 @@ TEST(U2fParsingUtils, SplitSpan) {
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwoThree)));
}
-} // namespace u2f_parsing_utils
+TEST(U2fParsingUtils, CreateSHA256Hash) {
+ EXPECT_THAT(CreateSHA256Hash("acme.com"),
+ ::testing::ElementsAreArray(test_data::kApplicationParameter));
+}
+
+} // namespace fido_parsing_utils
} // namespace device
diff --git a/chromium/device/fido/fido_request_handler.h b/chromium/device/fido/fido_request_handler.h
index 3b46f9039aa..a81327cdd2f 100644
--- a/chromium/device/fido/fido_request_handler.h
+++ b/chromium/device/fido/fido_request_handler.h
@@ -13,6 +13,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/optional.h"
+#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_transport_protocol.h"
@@ -41,11 +42,11 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
bool is_complete() const { return completion_callback_.is_null(); }
protected:
- // Converts device response code received from CTAP1/CTAP2 device into
+ // Converts authenticator response code received from CTAP1/CTAP2 device into
// FidoReturnCode and passes response data to webauth::mojom::Authenticator.
- void OnDeviceResponse(FidoDevice* device,
- CtapDeviceResponseCode device_response_code,
- base::Optional<Response> response_data) {
+ void OnAuthenticatorResponse(FidoAuthenticator* authenticator,
+ CtapDeviceResponseCode device_response_code,
+ base::Optional<Response> response_data) {
if (is_complete()) {
DVLOG(2)
<< "Response from authenticator received after request is complete.";
@@ -54,14 +55,18 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
const auto return_code = ConvertDeviceResponseCodeToFidoReturnCode(
device_response_code, response_data.has_value());
+
+ // Any authenticator response codes that do not result from user consent
+ // imply that the authenticator should be dropped and that other on-going
+ // requests should continue until timeout is reached.
if (!return_code) {
- ongoing_tasks().erase(device->GetId());
+ active_authenticators().erase(authenticator->GetId());
return;
}
// Once response has been passed to the relying party, cancel all other on
// going requests.
- CancelOngoingTasks(device->GetId());
+ CancelOngoingTasks(authenticator->GetId());
std::move(completion_callback_).Run(*return_code, std::move(response_data));
}
@@ -77,7 +82,7 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
: FidoReturnCode::kAuthenticatorResponseInvalid;
// These errors are only returned after the user interacted with the
- // device.
+ // authenticator.
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
return FidoReturnCode::kUserConsentButCredentialExcluded;
case CtapDeviceResponseCode::kCtap2ErrNoCredentials:
diff --git a/chromium/device/fido/fido_request_handler_base.cc b/chromium/device/fido/fido_request_handler_base.cc
index 156f61c3b13..f3b5b7bf93b 100644
--- a/chromium/device/fido/fido_request_handler_base.cc
+++ b/chromium/device/fido/fido_request_handler_base.cc
@@ -7,16 +7,31 @@
#include <utility>
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_task.h"
#include "services/service_manager/public/cpp/connector.h"
+#if defined(OS_MACOSX)
+#include "device/fido/mac/authenticator.h"
+#endif
+
namespace device {
FidoRequestHandlerBase::FidoRequestHandlerBase(
service_manager::Connector* connector,
const base::flat_set<FidoTransportProtocol>& transports) {
for (const auto transport : transports) {
+ // Construction of CaBleDiscovery is handled by the implementing class as it
+ // requires an extension passed on from the relying party.
+ if (transport == FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy)
+ continue;
+
+ if (transport == FidoTransportProtocol::kInternal) {
+ use_platform_authenticator_ = true;
+ continue;
+ }
+
auto discovery = FidoDiscovery::Create(transport, connector);
if (discovery == nullptr) {
// This can occur in tests when a ScopedVirtualU2fDevice is in effect and
@@ -24,7 +39,6 @@ FidoRequestHandlerBase::FidoRequestHandlerBase(
continue;
}
discovery->set_observer(this);
- discovery->Start();
discoveries_.push_back(std::move(discovery));
}
}
@@ -33,30 +47,56 @@ FidoRequestHandlerBase::~FidoRequestHandlerBase() = default;
void FidoRequestHandlerBase::CancelOngoingTasks(
base::StringPiece exclude_device_id) {
- for (auto task_it = ongoing_tasks_.begin();
- task_it != ongoing_tasks_.end();) {
+ for (auto task_it = active_authenticators_.begin();
+ task_it != active_authenticators_.end();) {
DCHECK(!task_it->first.empty());
if (task_it->first != exclude_device_id) {
DCHECK(task_it->second);
- task_it->second->CancelTask();
- task_it = ongoing_tasks_.erase(task_it);
+ task_it->second->Cancel();
+ task_it = active_authenticators_.erase(task_it);
} else {
++task_it;
}
}
}
+void FidoRequestHandlerBase::Start() {
+ for (const auto& discovery : discoveries_) {
+ discovery->Start();
+ }
+ if (use_platform_authenticator_) {
+ MaybeAddPlatformAuthenticator();
+ }
+}
+
+void FidoRequestHandlerBase::MaybeAddPlatformAuthenticator() {
+#if defined(OS_MACOSX)
+ if (__builtin_available(macOS 10.12.2, *)) {
+ auto authenticator = fido::mac::TouchIdAuthenticator::CreateIfAvailable();
+ if (!authenticator) {
+ return;
+ }
+ AddAuthenticator(std::move(authenticator));
+ }
+#endif
+}
+
void FidoRequestHandlerBase::DiscoveryStarted(FidoDiscovery* discovery,
bool success) {}
void FidoRequestHandlerBase::DeviceAdded(FidoDiscovery* discovery,
FidoDevice* device) {
- DCHECK(!base::ContainsKey(ongoing_tasks(), device->GetId()));
+ DCHECK(!base::ContainsKey(active_authenticators(), device->GetId()));
// All devices are initially assumed to support CTAP protocol and thus
// AuthenticatorGetInfo command is sent to all connected devices. If device
// errors out, then it is assumed to support U2F protocol.
device->set_supported_protocol(ProtocolVersion::kCtap);
- ongoing_tasks_.emplace(device->GetId(), CreateTaskForNewDevice(device));
+ AddAuthenticator(CreateAuthenticatorFromDevice(device));
+}
+
+std::unique_ptr<FidoDeviceAuthenticator>
+FidoRequestHandlerBase::CreateAuthenticatorFromDevice(FidoDevice* device) {
+ return std::make_unique<FidoDeviceAuthenticator>(device);
}
void FidoRequestHandlerBase::DeviceRemoved(FidoDiscovery* discovery,
@@ -66,7 +106,16 @@ void FidoRequestHandlerBase::DeviceRemoved(FidoDiscovery* discovery,
// ongoing_tasks_.erase() will have no effect for the devices that have been
// already removed due to processing error or due to invocation of
// CancelOngoingTasks().
- ongoing_tasks_.erase(device->GetId());
+ active_authenticators_.erase(device->GetId());
+}
+
+void FidoRequestHandlerBase::AddAuthenticator(
+ std::unique_ptr<FidoAuthenticator> authenticator) {
+ DCHECK(!base::ContainsKey(active_authenticators(), authenticator->GetId()));
+ FidoAuthenticator* authenticator_ptr = authenticator.get();
+ active_authenticators_.emplace(authenticator->GetId(),
+ std::move(authenticator));
+ DispatchRequest(authenticator_ptr);
}
} // namespace device
diff --git a/chromium/device/fido/fido_request_handler_base.h b/chromium/device/fido/fido_request_handler_base.h
index 8c010f01c78..65e494a7225 100644
--- a/chromium/device/fido/fido_request_handler_base.h
+++ b/chromium/device/fido/fido_request_handler_base.h
@@ -15,6 +15,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/strings/string_piece_forward.h"
+#include "device/fido/fido_device_authenticator.h"
#include "device/fido/fido_discovery.h"
#include "device/fido/fido_transport_protocol.h"
@@ -24,6 +25,7 @@ class Connector;
namespace device {
+class FidoAuthenticator;
class FidoDevice;
class FidoTask;
@@ -35,7 +37,8 @@ class FidoTask;
class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
: public FidoDiscovery::Observer {
public:
- using TaskMap = std::map<std::string, std::unique_ptr<FidoTask>, std::less<>>;
+ using AuthenticatorMap =
+ std::map<std::string, std::unique_ptr<FidoAuthenticator>, std::less<>>;
FidoRequestHandlerBase(
service_manager::Connector* connector,
@@ -55,9 +58,21 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
void CancelOngoingTasks(base::StringPiece exclude_device_id = nullptr);
protected:
- virtual std::unique_ptr<FidoTask> CreateTaskForNewDevice(FidoDevice*) = 0;
+ // Subclasses implement this method to dispatch their request onto the given
+ // FidoAuthenticator. The FidoAuthenticator is owned by this
+ // FidoRequestHandler and stored in active_authenticators().
+ virtual void DispatchRequest(FidoAuthenticator*) = 0;
- TaskMap& ongoing_tasks() { return ongoing_tasks_; }
+ void Start();
+
+ // Testing seam to allow unit tests to inject a fake authenticator.
+ virtual std::unique_ptr<FidoDeviceAuthenticator>
+ CreateAuthenticatorFromDevice(FidoDevice* device);
+
+ AuthenticatorMap& active_authenticators() { return active_authenticators_; }
+ std::vector<std::unique_ptr<FidoDiscovery>>& discoveries() {
+ return discoveries_;
+ }
private:
// FidoDiscovery::Observer
@@ -65,9 +80,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoRequestHandlerBase
void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) final;
void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) final;
- TaskMap ongoing_tasks_;
+ void AddAuthenticator(std::unique_ptr<FidoAuthenticator> authenticator);
+
+ void MaybeAddPlatformAuthenticator();
+
+ AuthenticatorMap active_authenticators_;
std::vector<std::unique_ptr<FidoDiscovery>> discoveries_;
+ // If set to true at any point before calling Start(), the request handler
+ // will try to create a platform authenticator to handle the request
+ // (currently only TouchIdAuthenticator on macOS).
+ bool use_platform_authenticator_ = false;
+
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 f96a7bfe281..2d5dce3822b 100644
--- a/chromium/device/fido/fido_request_handler_unittest.cc
+++ b/chromium/device/fido/fido_request_handler_unittest.cc
@@ -6,6 +6,7 @@
#include <utility>
#include <vector>
+#include "base/bind.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "device/fido/fake_fido_discovery.h"
@@ -83,6 +84,16 @@ class FakeFidoTask : public FidoTask {
base::WeakPtrFactory<FakeFidoTask> weak_factory_;
};
+class FakeFidoAuthenticator : public FidoDeviceAuthenticator {
+ public:
+ FakeFidoAuthenticator(FidoDevice* device) : FidoDeviceAuthenticator(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,
@@ -90,18 +101,24 @@ class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
: FidoRequestHandler(nullptr /* connector */,
protocols,
std::move(callback)),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ Start();
+ }
~FakeFidoRequestHandler() override = default;
- std::unique_ptr<FidoTask> CreateTaskForNewDevice(
+ void DispatchRequest(FidoAuthenticator* authenticator) override {
+ static_cast<FakeFidoAuthenticator*>(authenticator)
+ ->RunFakeTask(
+ base::BindOnce(&FakeFidoRequestHandler::OnAuthenticatorResponse,
+ weak_factory_.GetWeakPtr(), authenticator));
+ }
+
+ std::unique_ptr<FidoDeviceAuthenticator> CreateAuthenticatorFromDevice(
FidoDevice* device) override {
- return std::make_unique<FakeFidoTask>(
- device, base::BindOnce(&FakeFidoRequestHandler::OnDeviceResponse,
- weak_factory_.GetWeakPtr(), device));
+ return std::make_unique<FakeFidoAuthenticator>(device);
}
private:
- FakeHandlerCallback callback_;
base::WeakPtrFactory<FakeFidoRequestHandler> weak_factory_;
};
diff --git a/chromium/device/fido/fido_test_data.h b/chromium/device/fido/fido_test_data.h
index 88838d45826..ba23b8ed792 100644
--- a/chromium/device/fido/fido_test_data.h
+++ b/chromium/device/fido/fido_test_data.h
@@ -28,6 +28,13 @@ constexpr uint8_t kApplicationParameter[] = {
0x7B, 0xCF, 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE,
};
+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};
+
+constexpr uint8_t kUserId[] = {0x10, 0x98, 0x23, 0x72, 0x35, 0x40, 0x98, 0x72};
+
constexpr char kRelyingPartyId[] = "example.com";
constexpr uint8_t kU2fRegisterCommandApduWithIndividualAttestation[] = {
@@ -299,6 +306,8 @@ constexpr uint8_t kU2fFakeRegisterCommand[] = {
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
+ // Maximum response length
+ 0x00, 0x00,
};
// U2F response blob produced by a U2F registration request used in example 6
@@ -788,6 +797,326 @@ constexpr uint8_t kTestGetAssertionResponseWithIncorrectRpIdHash[] = {
0x30, 0x36, 0x59, 0xC9, 0xCD, 0x92,
};
+// Below |kCtap2MakeCredentialCertificate|, |kCtap2MakeCredentialAuthData|, and
+// |kCtap2MakeCredentialSignature| leverage example 4 of the CTAP spec.
+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html
+constexpr uint8_t kCtap2MakeCredentialCertificate[] = {
+ 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29,
+ 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+ 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73,
+ 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19,
+ 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f,
+ 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31,
+ 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x32,
+ 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59,
+ 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22,
+ 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74,
+ 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41,
+ 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59,
+ 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
+ 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52, 0xe5, 0x3a, 0xd5, 0xdf, 0xed,
+ 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf, 0x8f, 0x22,
+ 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04,
+ 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c,
+ 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60,
+ 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30,
+ 0x46, 0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25,
+ 0xf7, 0x37, 0x3e, 0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94,
+ 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7,
+ 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43,
+ 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9,
+ 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3};
+
+constexpr uint8_t kCtap2MakeCredentialAuthData[] = {
+ 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
+ 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
+ 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 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};
+
+constexpr uint8_t kCtap2MakeCredentialSignature[] = {
+ 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c,
+ 0xc1, 0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4,
+ 0x62, 0xd5, 0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89,
+ 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5,
+ 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7,
+ 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29};
+
+constexpr uint8_t kCtap2MakeCredentialCredentialId[] = {
+ 0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16,
+ 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f,
+};
+
+constexpr uint8_t kNoneAttestationResponse[] = {
+ // map(3)
+ 0xa3,
+ // Format - text(3)
+ 0x63,
+ // "fmt"
+ 0x66, 0x6D, 0x74,
+ // text(4)
+ 0x64,
+ // "none"
+ 0x6E, 0x6F, 0x6E, 0x65,
+ // Attestation statement
+ 0x67,
+ // text(7) - "attStmt"
+ 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74,
+ // Empty CBOR Map
+ 0xa0,
+ // Authenticator data
+ 0x68,
+ // text(8) - "authData"
+ 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61,
+ // bytes(154)
+ 0x58, 0x9a,
+ // byte data
+ 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
+ 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
+ 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 0x41, 0x00, 0x00, 0x00,
+ 0x0b,
+ // Replaced device AAGUID
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ // Credential information
+ 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,
+};
+
+const uint8_t kDeviceMakeCredentialResponse[] = {
+ // Success response code
+ 0x00,
+ // map(3)
+ 0xa3,
+ // unsigned(1)
+ 0x01,
+ // text(6)
+ 0x66,
+ // "packed"
+ 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64,
+ // unsigned(2)
+ 0x02,
+ // bytes(154)
+ 0x58, 0x9a,
+ // auth data
+ 0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4,
+ 0x2d, 0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6,
+ 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, 0x05, 0x1d, 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,
+ // unsigned(3)
+ 0x03,
+ // map(3)
+ 0xa3,
+ // text(3)
+ 0x63,
+ // "alg"
+ 0x61, 0x6c, 0x67,
+ // 7
+ 0x07,
+ // text(3)
+ 0x63,
+ // "sig"
+ 0x73, 0x69, 0x67,
+ // bytes(71)
+ 0x58, 0x47,
+ // signature
+ 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c,
+ 0xc1, 0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4,
+ 0x62, 0xd5, 0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89,
+ 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5,
+ 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7,
+ 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29,
+ // text(3)
+ 0x63,
+ // "x5c"
+ 0x78, 0x35, 0x63,
+ // array(1)
+ 0x81,
+ // bytes(407)
+ 0x59, 0x01, 0x97,
+ // certificate
+ 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29,
+ 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+ 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a,
+ 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73,
+ 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19,
+ 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f,
+ 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f,
+ 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31,
+ 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36, 0x31, 0x32,
+ 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
+ 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59,
+ 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22,
+ 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74,
+ 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41,
+ 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59,
+ 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06,
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00,
+ 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52, 0xe5, 0x3a, 0xd5, 0xdf, 0xed,
+ 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf, 0x8f, 0x22,
+ 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04,
+ 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c,
+ 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60,
+ 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
+ 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30,
+ 0x46, 0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25,
+ 0xf7, 0x37, 0x3e, 0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94,
+ 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7,
+ 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43,
+ 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9,
+ 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3};
+
+constexpr uint8_t kCtap2GetAssertionAuthData[] = {
+ 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b,
+ 0xba, 0x8c, 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5,
+ 0x03, 0xd9, 0x11, 0x4a, 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0,
+ 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x11};
+
+constexpr uint8_t kCtap2GetAssertionSignature[] = {
+ 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
+ 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
+ 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
+ 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
+ 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
+ 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
+};
+
+constexpr uint8_t kDeviceGetAssertionResponse[] = {
+ // Success response code
+ 0x00,
+ // map(5)
+ 0xa5,
+ // unsigned(1) - Credential
+ 0x01,
+ // map(2)
+ 0xa2,
+ // text(2)
+ 0x62,
+ // "id"
+ 0x69, 0x64,
+ // bytes(64)
+ 0x58, 0x40,
+ // credential id
+ 0xf2, 0x20, 0x06, 0xde, 0x4f, 0x90, 0x5a, 0xf6, 0x8a, 0x43, 0x94, 0x2f,
+ 0x02, 0x4f, 0x2a, 0x5e, 0xce, 0x60, 0x3d, 0x9c, 0x6d, 0x4b, 0x3d, 0xf8,
+ 0xbe, 0x08, 0xed, 0x01, 0xfc, 0x44, 0x26, 0x46, 0xd0, 0x34, 0x85, 0x8a,
+ 0xc7, 0x5b, 0xed, 0x3f, 0xd5, 0x80, 0xbf, 0x98, 0x08, 0xd9, 0x4f, 0xcb,
+ 0xee, 0x82, 0xb9, 0xb2, 0xef, 0x66, 0x77, 0xaf, 0x0a, 0xdc, 0xc3, 0x58,
+ 0x52, 0xea, 0x6b, 0x9e,
+ // text(4)
+ 0x64,
+ // "type"
+ 0x74, 0x79, 0x70, 0x65,
+ // text(10)
+ 0x6a,
+ // "public-key"
+ 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79,
+ // unsigned(2) - Auth data
+ 0x02,
+ // bytes(37)
+ 0x58, 0x25,
+ // auth data
+ 0x62, 0x5d, 0xda, 0xdf, 0x74, 0x3f, 0x57, 0x27, 0xe6, 0x6b, 0xba, 0x8c,
+ 0x2e, 0x38, 0x79, 0x22, 0xd1, 0xaf, 0x43, 0xc5, 0x03, 0xd9, 0x11, 0x4a,
+ 0x8f, 0xba, 0x10, 0x4d, 0x84, 0xd0, 0x2b, 0xfa, 0x01, 0x00, 0x00, 0x00,
+ 0x11,
+ // unsigned(3) - signature
+ 0x03,
+ // bytes(71)
+ 0x58, 0x47,
+ // signature
+ 0x30, 0x45, 0x02, 0x20, 0x4a, 0x5a, 0x9d, 0xd3, 0x92, 0x98, 0x14, 0x9d,
+ 0x90, 0x47, 0x69, 0xb5, 0x1a, 0x45, 0x14, 0x33, 0x00, 0x6f, 0x18, 0x2a,
+ 0x34, 0xfb, 0xdf, 0x66, 0xde, 0x5f, 0xc7, 0x17, 0xd7, 0x5f, 0xb3, 0x50,
+ 0x02, 0x21, 0x00, 0xa4, 0x6b, 0x8e, 0xa3, 0xc3, 0xb9, 0x33, 0x82, 0x1c,
+ 0x6e, 0x7f, 0x5e, 0xf9, 0xda, 0xae, 0x94, 0xab, 0x47, 0xf1, 0x8d, 0xb4,
+ 0x74, 0xc7, 0x47, 0x90, 0xea, 0xab, 0xb1, 0x44, 0x11, 0xe7, 0xa0,
+ // unsigned(4) - publicKeyCredentialUserEntity
+ 0x04,
+ // map(4)
+ 0xa4,
+ // text(2)
+ 0x62,
+ // "id"
+ 0x69, 0x64,
+ // bytes(32) - user id
+ 0x58, 0x20,
+ // user id
+ 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01,
+ 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02,
+ 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82,
+ // text(4)
+ 0x64,
+ // "icon"
+ 0x69, 0x63, 0x6f, 0x6e,
+ // text(40)
+ 0x78, 0x28,
+ // "https://pics.acme.com/00/p/aBjjjpqPb.png"
+ 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x70, 0x69, 0x63, 0x73,
+ 0x2e, 0x61, 0x63, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x30,
+ 0x2f, 0x70, 0x2f, 0x61, 0x42, 0x6a, 0x6a, 0x6a, 0x70, 0x71, 0x50, 0x62,
+ 0x2e, 0x70, 0x6e, 0x67,
+ // text(4)
+ 0x64,
+ // "name"
+ 0x6e, 0x61, 0x6d, 0x65,
+ // text(22)
+ 0x76,
+ // "johnpsmith@example.com"
+ 0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74, 0x68, 0x40, 0x65,
+ 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+ // text(11)
+ 0x6b,
+ // "displayName"
+ 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65,
+ // text(13)
+ 0x6d,
+ // "John P. Smith"
+ 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x50, 0x2e, 0x20, 0x53, 0x6d, 0x69, 0x74,
+ 0x68,
+ // unsigned(5) - number of credentials
+ 0x05,
+ // 1
+ 0x01,
+};
+
} // namespace test_data
} // namespace device
diff --git a/chromium/device/fido/fido_transport_protocol.h b/chromium/device/fido/fido_transport_protocol.h
index 87bae5792e0..71b09d95902 100644
--- a/chromium/device/fido/fido_transport_protocol.h
+++ b/chromium/device/fido/fido_transport_protocol.h
@@ -13,6 +13,8 @@ enum class FidoTransportProtocol {
kUsbHumanInterfaceDevice,
kNearFieldCommunication,
kBluetoothLowEnergy,
+ kCloudAssistedBluetoothLowEnergy,
+ kInternal,
};
} // namespace device
diff --git a/chromium/device/fido/get_assertion_handler_unittest.cc b/chromium/device/fido/get_assertion_handler_unittest.cc
index e8a2d7b63cc..7dba2d677be 100644
--- a/chromium/device/fido/get_assertion_handler_unittest.cc
+++ b/chromium/device/fido/get_assertion_handler_unittest.cc
@@ -10,12 +10,12 @@
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/fake_fido_discovery.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/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -42,10 +42,10 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
ForgeNextHidDiscovery();
CtapGetAssertionRequest request_param(
- kRpId, u2f_parsing_utils::Materialize(kClientDataHash));
+ kRpId, fido_parsing_utils::Materialize(kClientDataHash));
request_param.SetAllowList(
- {{to_string(CredentialType::kPublicKey),
- u2f_parsing_utils::Materialize(
+ {{CredentialType::kPublicKey,
+ fido_parsing_utils::Materialize(
test_data::kTestGetAssertionCredentialId)}});
return std::make_unique<GetAssertionRequestHandler>(
diff --git a/chromium/device/fido/get_assertion_request_handler.cc b/chromium/device/fido/get_assertion_request_handler.cc
index 119a417b70b..722deacae64 100644
--- a/chromium/device/fido/get_assertion_request_handler.cc
+++ b/chromium/device/fido/get_assertion_request_handler.cc
@@ -8,7 +8,8 @@
#include "base/bind.h"
#include "device/fido/authenticator_get_assertion_response.h"
-#include "device/fido/fido_device.h"
+#include "device/fido/fido_authenticator.h"
+#include "device/fido/fido_cable_discovery.h"
#include "device/fido/get_assertion_task.h"
namespace device {
@@ -20,16 +21,27 @@ GetAssertionRequestHandler::GetAssertionRequestHandler(
SignResponseCallback completion_callback)
: FidoRequestHandler(connector, protocols, std::move(completion_callback)),
request_(std::move(request)),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ if (base::ContainsKey(
+ protocols, FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) &&
+ request_.cable_extension()) {
+ auto discovery =
+ std::make_unique<FidoCableDiscovery>(*request_.cable_extension());
+ discovery->set_observer(this);
+ discoveries().push_back(std::move(discovery));
+ }
+
+ Start();
+}
GetAssertionRequestHandler::~GetAssertionRequestHandler() = default;
-std::unique_ptr<FidoTask> GetAssertionRequestHandler::CreateTaskForNewDevice(
- FidoDevice* device) {
- return std::make_unique<GetAssertionTask>(
- device, request_,
- base::BindOnce(&GetAssertionRequestHandler::OnDeviceResponse,
- weak_factory_.GetWeakPtr(), device));
+void GetAssertionRequestHandler::DispatchRequest(
+ FidoAuthenticator* authenticator) {
+ authenticator->GetAssertion(
+ request_,
+ base::BindOnce(&GetAssertionRequestHandler::OnAuthenticatorResponse,
+ weak_factory_.GetWeakPtr(), authenticator));
}
} // namespace device
diff --git a/chromium/device/fido/get_assertion_request_handler.h b/chromium/device/fido/get_assertion_request_handler.h
index 191a6ad6ce2..4f318334895 100644
--- a/chromium/device/fido/get_assertion_request_handler.h
+++ b/chromium/device/fido/get_assertion_request_handler.h
@@ -22,13 +22,12 @@ class Connector;
namespace device {
-class FidoDevice;
-class FidoTask;
+class FidoAuthenticator;
class AuthenticatorGetAssertionResponse;
-using SignResponseCallback = base::OnceCallback<void(
- FidoReturnCode status_code,
- base::Optional<AuthenticatorGetAssertionResponse> response_data)>;
+using SignResponseCallback =
+ base::OnceCallback<void(FidoReturnCode,
+ base::Optional<AuthenticatorGetAssertionResponse>)>;
class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
: public FidoRequestHandler<AuthenticatorGetAssertionResponse> {
@@ -42,7 +41,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
private:
// FidoRequestHandlerBase:
- std::unique_ptr<FidoTask> CreateTaskForNewDevice(FidoDevice* device) override;
+ void DispatchRequest(FidoAuthenticator* authenticator) override;
CtapGetAssertionRequest request_;
base::WeakPtrFactory<GetAssertionRequestHandler> weak_factory_;
diff --git a/chromium/device/fido/get_assertion_task.h b/chromium/device/fido/get_assertion_task.h
index 22ef34ed8d8..3f90a21b8e7 100644
--- a/chromium/device/fido/get_assertion_task.h
+++ b/chromium/device/fido/get_assertion_task.h
@@ -27,8 +27,8 @@ class AuthenticatorGetAssertionResponse;
class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionTask : public FidoTask {
public:
using GetAssertionTaskCallback = base::OnceCallback<void(
- CtapDeviceResponseCode return_code,
- base::Optional<AuthenticatorGetAssertionResponse> response_data)>;
+ CtapDeviceResponseCode,
+ base::Optional<AuthenticatorGetAssertionResponse>)>;
GetAssertionTask(FidoDevice* device,
CtapGetAssertionRequest request,
diff --git a/chromium/device/fido/get_assertion_task_unittest.cc b/chromium/device/fido/get_assertion_task_unittest.cc
index 311f0b89c24..d126d035b7c 100644
--- a/chromium/device/fido/get_assertion_task_unittest.cc
+++ b/chromium/device/fido/get_assertion_task_unittest.cc
@@ -14,10 +14,10 @@
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -58,9 +58,9 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAssertionSuccess) {
test_data::kTestGetAssertionResponse);
CtapGetAssertionRequest request_param(
- kRpId, u2f_parsing_utils::Materialize(kClientDataHash));
- request_param.SetAllowList({{to_string(CredentialType::kPublicKey),
- u2f_parsing_utils::Materialize(
+ kRpId, fido_parsing_utils::Materialize(kClientDataHash));
+ request_param.SetAllowList({{CredentialType::kPublicKey,
+ fido_parsing_utils::Materialize(
test_data::kTestGetAssertionCredentialId)}});
auto task = std::make_unique<GetAssertionTask>(
@@ -90,7 +90,7 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAssertionInvalidCredential) {
auto task = std::make_unique<GetAssertionTask>(
device.get(),
CtapGetAssertionRequest(kRpId,
- u2f_parsing_utils::Materialize(kClientDataHash)),
+ fido_parsing_utils::Materialize(kClientDataHash)),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
@@ -116,7 +116,7 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAsserionIncorrectUserEntity) {
auto task = std::make_unique<GetAssertionTask>(
device.get(),
CtapGetAssertionRequest(kRpId,
- u2f_parsing_utils::Materialize(kClientDataHash)),
+ fido_parsing_utils::Materialize(kClientDataHash)),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
@@ -140,7 +140,7 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAsserionIncorrectRpIdHash) {
auto task = std::make_unique<GetAssertionTask>(
device.get(),
CtapGetAssertionRequest(kRpId,
- u2f_parsing_utils::Materialize(kClientDataHash)),
+ fido_parsing_utils::Materialize(kClientDataHash)),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
@@ -163,7 +163,7 @@ TEST_F(FidoGetAssertionTaskTest, TestIncorrectGetAssertionResponse) {
auto task = std::make_unique<GetAssertionTask>(
device.get(),
CtapGetAssertionRequest(kRpId,
- u2f_parsing_utils::Materialize(kClientDataHash)),
+ fido_parsing_utils::Materialize(kClientDataHash)),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
@@ -182,7 +182,7 @@ TEST_F(FidoGetAssertionTaskTest, TestIncompatibleUserVerificationSetting) {
test_data::kTestGetInfoResponseWithoutUvSupport);
auto request = CtapGetAssertionRequest(
- kRpId, u2f_parsing_utils::Materialize(kClientDataHash));
+ kRpId, fido_parsing_utils::Materialize(kClientDataHash));
request.SetUserVerification(UserVerificationRequirement::kRequired);
auto task = std::make_unique<GetAssertionTask>(
diff --git a/chromium/device/fido/mac/authenticator.h b/chromium/device/fido/mac/authenticator.h
new file mode 100644
index 00000000000..bedc1e08373
--- /dev/null
+++ b/chromium/device/fido/mac/authenticator.h
@@ -0,0 +1,68 @@
+// 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_MAC_AUTHENTICATOR_H_
+#define DEVICE_FIDO_MAC_AUTHENTICATOR_H_
+
+#include "base/mac/availability.h"
+#include "base/macros.h"
+#include "base/strings/string_piece_forward.h"
+#include "device/fido/fido_authenticator.h"
+#include "device/fido/mac/operation.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+class API_AVAILABLE(macosx(10.12.2)) TouchIdAuthenticator
+ : public FidoAuthenticator {
+ public:
+ // IsAvailable returns true iff Touch ID is enabled and enrolled on the
+ // current device.
+ static bool IsAvailable();
+
+ // CreateIfAvailable returns a TouchIdAuthenticator if IsAvailable() returns
+ // true and nullptr otherwise.
+ static std::unique_ptr<TouchIdAuthenticator> CreateIfAvailable();
+
+ ~TouchIdAuthenticator() override;
+
+ // TouchIdAuthenticator
+ void MakeCredential(
+ AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) override;
+ void GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) override;
+ void Cancel() override;
+
+ std::string GetId() const override;
+
+ private:
+ TouchIdAuthenticator();
+
+ // The profile ID identifies the user profile from which the request
+ // originates. It is used to scope credentials to the profile under which they
+ // were created.
+ base::StringPiece GetOrInitializeProfileId();
+
+ // The keychain access group is a string value related to the Apple developer
+ // ID under which the binary gets signed that the Keychain Services API use
+ // for access control. See
+ // https://developer.apple.com/documentation/security/ksecattraccessgroup?language=objc.
+ base::StringPiece keychain_access_group() {
+ return "EQHXZ8M8AV.com.google.chrome.webauthn";
+ }
+
+ std::unique_ptr<Operation> operation_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TouchIdAuthenticator);
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_AUTHENTICATOR_H_
diff --git a/chromium/device/fido/mac/authenticator.mm b/chromium/device/fido/mac/authenticator.mm
new file mode 100644
index 00000000000..351e3e94c49
--- /dev/null
+++ b/chromium/device/fido/mac/authenticator.mm
@@ -0,0 +1,84 @@
+// 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.
+
+#include "device/fido/mac/authenticator.h"
+
+#import <LocalAuthentication/LocalAuthentication.h>
+
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "device/fido/authenticator_selection_criteria.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/mac/get_assertion_operation.h"
+#include "device/fido/mac/make_credential_operation.h"
+#include "device/fido/mac/util.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// static
+// NOTE(martinkr): This is currently only called from |CreateIfAvailable| but
+// will also be needed for the implementation of
+// IsUserVerifyingPlatformAuthenticatorAvailable() (see
+// https://www.w3.org/TR/webauthn/#isUserVerifyingPlatformAuthenticatorAvailable).
+bool TouchIdAuthenticator::IsAvailable() {
+ base::scoped_nsobject<LAContext> context([[LAContext alloc] init]);
+ return
+ [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
+ error:nil];
+}
+
+// static
+std::unique_ptr<TouchIdAuthenticator>
+TouchIdAuthenticator::CreateIfAvailable() {
+ return IsAvailable() ? base::WrapUnique(new TouchIdAuthenticator()) : nullptr;
+}
+
+TouchIdAuthenticator::~TouchIdAuthenticator() = default;
+
+void TouchIdAuthenticator::MakeCredential(
+ AuthenticatorSelectionCriteria authenticator_selection_criteria,
+ CtapMakeCredentialRequest request,
+ MakeCredentialCallback callback) {
+ DCHECK(!operation_);
+ operation_ = std::make_unique<MakeCredentialOperation>(
+ std::move(request), GetOrInitializeProfileId().as_string(),
+ keychain_access_group().as_string(), std::move(callback));
+ operation_->Run();
+}
+
+void TouchIdAuthenticator::GetAssertion(CtapGetAssertionRequest request,
+ GetAssertionCallback callback) {
+ DCHECK(!operation_);
+ operation_ = std::make_unique<GetAssertionOperation>(
+ std::move(request), GetOrInitializeProfileId().as_string(),
+ keychain_access_group().as_string(), std::move(callback));
+ operation_->Run();
+}
+
+void TouchIdAuthenticator::Cancel() {
+ // If there is an operation pending, delete it, which will clean up any
+ // pending callbacks, e.g. if the operation is waiting for a response from
+ // the Touch ID prompt. Note that we cannot cancel the actual prompt once it
+ // has been shown.
+ operation_.reset();
+}
+
+std::string TouchIdAuthenticator::GetId() const {
+ return "TouchIdAuthenticator";
+}
+
+TouchIdAuthenticator::TouchIdAuthenticator() = default;
+
+base::StringPiece TouchIdAuthenticator::GetOrInitializeProfileId() {
+ // TODO(martinkr): Implement.
+ return "TODO";
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/get_assertion_operation.h b/chromium/device/fido/mac/get_assertion_operation.h
new file mode 100644
index 00000000000..a36e2dd09d8
--- /dev/null
+++ b/chromium/device/fido/mac/get_assertion_operation.h
@@ -0,0 +1,52 @@
+// 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_MAC_GET_ASSERTION_OPERATION_H_
+#define DEVICE_FIDO_MAC_GET_ASSERTION_OPERATION_H_
+
+#include "base/component_export.h"
+#include "base/mac/availability.h"
+#include "base/macros.h"
+#include "device/fido/authenticator_get_assertion_response.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/mac/operation_base.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// GetAssertionOperation implements the authenticatorGetAssertion operation. The
+// operation can be invoked via its |Run| method, which must only be called
+// once.
+//
+// It prompts the user for consent via Touch ID, then looks up a key pair
+// matching the request in the keychain and generates an assertion.
+//
+// For documentation on the keychain item metadata, see
+// |MakeCredentialOperation|.
+class API_AVAILABLE(macosx(10.12.2))
+ COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionOperation
+ : public OperationBase<CtapGetAssertionRequest,
+ AuthenticatorGetAssertionResponse> {
+ public:
+ GetAssertionOperation(CtapGetAssertionRequest request,
+ std::string profile_id,
+ std::string keychain_access_group,
+ Callback callback);
+ ~GetAssertionOperation() override;
+
+ void Run() override;
+
+ private:
+ const std::string& RpId() const override;
+ void PromptTouchIdDone(bool success, NSError* err) override;
+
+ DISALLOW_COPY_AND_ASSIGN(GetAssertionOperation);
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_GET_ASSERTION_OPERATION_H_
diff --git a/chromium/device/fido/mac/get_assertion_operation.mm b/chromium/device/fido/mac/get_assertion_operation.mm
new file mode 100644
index 00000000000..a7a5572c0a0
--- /dev/null
+++ b/chromium/device/fido/mac/get_assertion_operation.mm
@@ -0,0 +1,157 @@
+// 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/mac/get_assertion_operation.h"
+
+#include <set>
+#include <string>
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_number_conversions.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/mac/keychain.h"
+#include "device/fido/mac/util.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+using base::ScopedCFTypeRef;
+
+GetAssertionOperation::GetAssertionOperation(CtapGetAssertionRequest request,
+ std::string profile_id,
+ std::string keychain_access_group,
+ Callback callback)
+ : OperationBase<CtapGetAssertionRequest, AuthenticatorGetAssertionResponse>(
+ std::move(request),
+ std::move(profile_id),
+ std::move(keychain_access_group),
+ std::move(callback)) {}
+GetAssertionOperation::~GetAssertionOperation() = default;
+
+const std::string& GetAssertionOperation::RpId() const {
+ return request().rp_id();
+}
+
+void GetAssertionOperation::Run() {
+ // Prompt the user for consent.
+ // TODO(martinkr): Localize reason strings.
+ PromptTouchId("sign in to " + RpId());
+}
+
+void GetAssertionOperation::PromptTouchIdDone(bool success, NSError* err) {
+ if (!success) {
+ // err is autoreleased.
+ CHECK(err != nil);
+ DVLOG(1) << "Touch ID prompt failed: " << base::mac::NSToCFCast(err);
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOperationDenied, base::nullopt);
+ return;
+ }
+
+ // Collect the credential ids from allowList. If allowList is absent, we will
+ // just pick the first available credential for the RP below.
+ std::set<std::vector<uint8_t>> allowed_credential_ids;
+ if (request().allow_list()) {
+ for (const PublicKeyCredentialDescriptor& desc : *request().allow_list()) {
+ if (desc.credential_type() != CredentialType::kPublicKey) {
+ continue;
+ }
+ allowed_credential_ids.insert(desc.id());
+ }
+ }
+
+ // Fetch credentials for RP from the request and current user profile.
+ ScopedCFTypeRef<CFArrayRef> keychain_items;
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> query = DefaultKeychainQuery();
+ CFDictionarySetValue(query, kSecUseAuthenticationContext,
+ authentication_context());
+ CFDictionarySetValue(query, kSecReturnRef, @YES);
+ CFDictionarySetValue(query, kSecReturnAttributes, @YES);
+ CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll);
+
+ OSStatus status = Keychain::GetInstance().ItemCopyMatching(
+ query, reinterpret_cast<CFTypeRef*>(keychain_items.InitializeInto()));
+ if (status == errSecItemNotFound) {
+ DVLOG(1) << "no credentials found for RP";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, base::nullopt);
+ return;
+ }
+ if (status != errSecSuccess) {
+ OSSTATUS_DLOG(ERROR, status) << "SecItemCopyMatching failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ SecKeyRef private_key = nil; // Owned by |keychain_items|.
+ std::vector<uint8_t> credential_id;
+ for (CFIndex i = 0; i < CFArrayGetCount(keychain_items); ++i) {
+ CFDictionaryRef attributes = base::mac::CFCast<CFDictionaryRef>(
+ CFArrayGetValueAtIndex(keychain_items, i));
+ CFDataRef application_label = base::mac::GetValueFromDictionary<CFDataRef>(
+ attributes, kSecAttrApplicationLabel);
+ SecKeyRef key =
+ base::mac::GetValueFromDictionary<SecKeyRef>(attributes, kSecValueRef);
+ if (!application_label || !key) {
+ // Corrupted keychain?
+ DLOG(ERROR) << "could not find application label or key ref: "
+ << attributes;
+ continue;
+ }
+ std::vector<uint8_t> cid(CFDataGetBytePtr(application_label),
+ CFDataGetBytePtr(application_label) +
+ CFDataGetLength(application_label));
+ if (allowed_credential_ids.empty() ||
+ allowed_credential_ids.find(cid) != allowed_credential_ids.end()) {
+ private_key = key;
+ credential_id = std::move(cid);
+ break;
+ }
+ }
+ if (!private_key) {
+ DVLOG(1) << "no allowed credential found";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrNoCredentials, base::nullopt);
+ return;
+ }
+ base::ScopedCFTypeRef<SecKeyRef> public_key(
+ Keychain::GetInstance().KeyCopyPublicKey(private_key));
+ if (!public_key) {
+ DLOG(ERROR) << "failed to get public key for credential id "
+ << base::HexEncode(credential_id.data(), credential_id.size());
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+
+ base::Optional<AuthenticatorData> authenticator_data =
+ MakeAuthenticatorData(RpId(), std::move(credential_id), public_key);
+ if (!authenticator_data) {
+ DLOG(ERROR) << "MakeAuthenticatorData failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ base::Optional<std::vector<uint8_t>> signature = GenerateSignature(
+ *authenticator_data, request().client_data_hash(), private_key);
+ if (!signature) {
+ DLOG(ERROR) << "GenerateSignature failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kSuccess,
+ AuthenticatorGetAssertionResponse(std::move(*authenticator_data),
+ std::move(*signature)));
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm b/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm
new file mode 100644
index 00000000000..d0bcc7fbcce
--- /dev/null
+++ b/chromium/device/fido/mac/get_assertion_operation_unittest_mac.mm
@@ -0,0 +1,82 @@
+// 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/mac/get_assertion_operation.h"
+
+#include <Foundation/Foundation.h>
+#include <Security/Security.h>
+
+#include "base/strings/string_number_conversions.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "device/fido/mac/make_credential_operation.h"
+#include "device/fido/test_callback_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+namespace {
+
+using test::TestCallbackReceiver;
+
+const std::vector<uint8_t> kClientDataHash = {1, 2, 3, 4, 5};
+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);
+}
+
+bool MakeCredential() API_AVAILABLE(macos(10.12.2)) {
+ TestCallbackReceiver<CtapDeviceResponseCode,
+ base::Optional<AuthenticatorMakeCredentialResponse>>
+ callback_receiver;
+ auto request = CtapMakeCredentialRequest(
+ kClientDataHash, PublicKeyCredentialRpEntity(kRpId),
+ PublicKeyCredentialUserEntity(kUserId),
+ PublicKeyCredentialParams(
+ {{PublicKeyCredentialParams::
+ CredentialInfo() /* defaults to ES-256 */}}));
+ MakeCredentialOperation op(request, "test-profile", kKeychainAccessGroup,
+ callback_receiver.callback());
+
+ op.Run();
+ callback_receiver.WaitForCallback();
+ auto result = callback_receiver.TakeResult();
+ CtapDeviceResponseCode error = std::get<0>(result);
+ auto opt_response = std::move(std::get<1>(result));
+ return error == CtapDeviceResponseCode::kSuccess && opt_response;
+}
+
+// For demo purposes only. This test does a Touch ID user prompt. It will fail
+// on incompatible hardware and crash if not code signed or lacking the
+// keychain-access-group entitlement.
+TEST(GetAssertionOperationTest, DISABLED_TestRun)
+API_AVAILABLE(macos(10.12.2)) {
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+ ASSERT_TRUE(MakeCredential());
+
+ TestCallbackReceiver<CtapDeviceResponseCode,
+ base::Optional<AuthenticatorGetAssertionResponse>>
+ callback_receiver;
+ auto request = MakeTestRequest();
+ GetAssertionOperation op(request, "test-profile", kKeychainAccessGroup,
+ callback_receiver.callback());
+
+ op.Run();
+ callback_receiver.WaitForCallback();
+ auto result = callback_receiver.TakeResult();
+ CtapDeviceResponseCode error = std::get<0>(result);
+ EXPECT_EQ(CtapDeviceResponseCode::kSuccess, error);
+ auto opt_response = std::move(std::get<1>(result));
+ ASSERT_TRUE(opt_response);
+};
+}
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/keychain.h b/chromium/device/fido/mac/keychain.h
new file mode 100644
index 00000000000..0b627798868
--- /dev/null
+++ b/chromium/device/fido/mac/keychain.h
@@ -0,0 +1,62 @@
+// 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_MAC_KEYCHAIN_H_
+#define DEVICE_FIDO_MAC_KEYCHAIN_H_
+
+#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// Keychain wraps some operations from the macOS Security framework to work with
+// keys and keychain items.
+//
+// The Touch ID authenticator creates keychain items in the "iOS-style"
+// keychain, which scopes item access based on the application-identifer or
+// keychain-access-group entitlements, and therefore requires code signing with
+// a real Apple developer ID. We therefore group these function here, so they
+// can be mocked out in testing.
+class API_AVAILABLE(macosx(10.12.2)) Keychain {
+ public:
+ static const Keychain& GetInstance();
+
+ // KeyCreateRandomKey wraps the |SecKeyCreateRandomKey| function.
+ virtual base::ScopedCFTypeRef<SecKeyRef> KeyCreateRandomKey(
+ CFDictionaryRef params,
+ CFErrorRef* error) const;
+ // KeyCreateSignature wraps the |SecKeyCreateSignature| function.
+ virtual base::ScopedCFTypeRef<CFDataRef> KeyCreateSignature(
+ SecKeyRef key,
+ SecKeyAlgorithm algorithm,
+ CFDataRef data,
+ CFErrorRef* error) const;
+ // KeyCopyPublicKey wraps the |SecKeyCopyPublicKey| function.
+ virtual base::ScopedCFTypeRef<SecKeyRef> KeyCopyPublicKey(
+ SecKeyRef key) const;
+
+ // ItemCopyMatching wraps the |SecItemCopyMatching| function.
+ virtual OSStatus ItemCopyMatching(CFDictionaryRef query,
+ CFTypeRef* result) const;
+ // ItemDelete wraps the |SecItemDelete| function.
+ virtual OSStatus ItemDelete(CFDictionaryRef query) const;
+
+ private:
+ friend class base::NoDestructor<Keychain>;
+ Keychain();
+
+ DISALLOW_COPY_AND_ASSIGN(Keychain);
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_KEYCHAIN_H_
diff --git a/chromium/device/fido/mac/keychain.mm b/chromium/device/fido/mac/keychain.mm
new file mode 100644
index 00000000000..692b7c8a776
--- /dev/null
+++ b/chromium/device/fido/mac/keychain.mm
@@ -0,0 +1,50 @@
+// 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/mac/keychain.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// static
+const Keychain& Keychain::GetInstance() {
+ static const base::NoDestructor<Keychain> k;
+ return *k;
+}
+
+Keychain::Keychain() = default;
+
+base::ScopedCFTypeRef<SecKeyRef> Keychain::KeyCreateRandomKey(
+ CFDictionaryRef params,
+ CFErrorRef* error) const {
+ return base::ScopedCFTypeRef<SecKeyRef>(SecKeyCreateRandomKey(params, error));
+}
+
+base::ScopedCFTypeRef<CFDataRef> Keychain::KeyCreateSignature(
+ SecKeyRef key,
+ SecKeyAlgorithm algorithm,
+ CFDataRef data,
+ CFErrorRef* error) const {
+ return base::ScopedCFTypeRef<CFDataRef>(
+ SecKeyCreateSignature(key, algorithm, data, error));
+}
+
+base::ScopedCFTypeRef<SecKeyRef> Keychain::KeyCopyPublicKey(
+ SecKeyRef key) const {
+ return base::ScopedCFTypeRef<SecKeyRef>(SecKeyCopyPublicKey(key));
+}
+
+OSStatus Keychain::ItemCopyMatching(CFDictionaryRef query,
+ CFTypeRef* result) const {
+ return SecItemCopyMatching(query, result);
+}
+
+OSStatus Keychain::ItemDelete(CFDictionaryRef query) const {
+ return SecItemDelete(query);
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/make_credential_operation.h b/chromium/device/fido/mac/make_credential_operation.h
new file mode 100644
index 00000000000..f8d59652cb6
--- /dev/null
+++ b/chromium/device/fido/mac/make_credential_operation.h
@@ -0,0 +1,67 @@
+// 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_MAC_MAKE_CREDENTIAL_OPERATION_H_
+#define DEVICE_FIDO_MAC_MAKE_CREDENTIAL_OPERATION_H_
+
+#include "base/component_export.h"
+#include "base/mac/availability.h"
+#include "base/macros.h"
+#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/mac/operation_base.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// MakeCredentialOperation implements the authenticatorMakeCredential operation.
+// The operation can be invoked via its |Run| method, which must only be called
+// once.
+//
+// It prompts the user for consent via Touch ID and then generates a key pair
+// in the secure enclave. A reference to the private key is stored as a
+// keychain item in the macOS keychain for later lookup. The actual private key
+// cannot be extracted from the secure enclave. Each keychain item stores the
+// following metadata:
+//
+// - The item's application label (kSecAttrApplicationLabel), which must be
+// unique, contains the credential identifier, which is computed as the CBOR
+// encoding of (rp_id, user_id).
+//
+// - The application tag (kSecAttrApplicationTag) holds an identifier for the
+// associated Chrome user profile, in order to separate credentials from
+// different profiles.
+//
+// - The label (kSecAttrLabel) stores the RP ID, to allow iteration over all
+// keys by a given RP.
+//
+// Keychain items are stored with the access group (kSecAttrAccessGroup) set
+// to a value that identifies them as Chrome WebAuthn credentials
+// (keychain_access_group_), so that they are logically
+// separate from any other data that Chrome may store in the keychain in
+// the future.
+class API_AVAILABLE(macosx(10.12.2))
+ COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialOperation
+ : public OperationBase<CtapMakeCredentialRequest,
+ AuthenticatorMakeCredentialResponse> {
+ public:
+ MakeCredentialOperation(CtapMakeCredentialRequest request,
+ std::string profile_id,
+ std::string keychain_access_group,
+ Callback callback);
+ ~MakeCredentialOperation() override;
+
+ void Run() override;
+
+ private:
+ const std::string& RpId() const override;
+ void PromptTouchIdDone(bool success, NSError* err) override;
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_MAKE_CREDENTIAL_OPERATION_H_
diff --git a/chromium/device/fido/mac/make_credential_operation.mm b/chromium/device/fido/mac/make_credential_operation.mm
new file mode 100644
index 00000000000..36e11ff5429
--- /dev/null
+++ b/chromium/device/fido/mac/make_credential_operation.mm
@@ -0,0 +1,192 @@
+// 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/mac/make_credential_operation.h"
+
+#include <string>
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "device/fido/fido_attestation_statement.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/mac/keychain.h"
+#include "device/fido/mac/util.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+using base::ScopedCFTypeRef;
+
+MakeCredentialOperation::MakeCredentialOperation(
+ CtapMakeCredentialRequest request,
+ std::string profile_id,
+ std::string keychain_access_group,
+ Callback callback)
+ : OperationBase<CtapMakeCredentialRequest,
+ AuthenticatorMakeCredentialResponse>(
+ std::move(request),
+ std::move(profile_id),
+ std::move(keychain_access_group),
+ std::move(callback)) {}
+MakeCredentialOperation::~MakeCredentialOperation() = default;
+
+const std::string& MakeCredentialOperation::RpId() const {
+ return request().rp().rp_id();
+}
+
+void MakeCredentialOperation::Run() {
+ // Verify pubKeyCredParams contains ES-256, which is the only algorithm we
+ // support.
+ auto is_es256 =
+ [](const PublicKeyCredentialParams::CredentialInfo& cred_info) {
+ return cred_info.algorithm ==
+ static_cast<int>(CoseAlgorithmIdentifier::kCoseEs256);
+ };
+ const auto& key_params =
+ request().public_key_credential_params().public_key_credential_params();
+ if (!std::any_of(key_params.begin(), key_params.end(), is_es256)) {
+ DVLOG(1) << "No supported algorithm found.";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrUnsupportedAlgorithms,
+ base::nullopt);
+ return;
+ }
+
+ // Prompt the user for consent.
+ // TODO(martinkr): Localize reason strings.
+ PromptTouchId("register with " + RpId());
+}
+
+void MakeCredentialOperation::PromptTouchIdDone(bool success, NSError* err) {
+ if (!success) {
+ // err is autoreleased.
+ CHECK(err != nil);
+ DVLOG(1) << "Touch ID prompt failed: " << base::mac::NSToCFCast(err);
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOperationDenied, base::nullopt);
+ return;
+ }
+
+ // Evaluate that excludeList does not contain any credentials stored by this
+ // authenticator.
+ if (request().exclude_list()) {
+ for (auto& credential : *request().exclude_list()) {
+ ScopedCFTypeRef<CFMutableDictionaryRef> query = DefaultKeychainQuery();
+ CFDictionarySetValue(query, kSecAttrApplicationLabel,
+ [NSData dataWithBytes:credential.id().data()
+ length:credential.id().size()]);
+ OSStatus status = SecItemCopyMatching(query, nullptr);
+ if (status == errSecSuccess) {
+ // Excluded item found.
+ DVLOG(1) << "credential from excludeList found";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrCredentialExcluded,
+ base::nullopt);
+ return;
+ }
+ if (status != errSecItemNotFound) {
+ // Unexpected keychain error.
+ OSSTATUS_DLOG(ERROR, status)
+ << "failed to check for excluded credential";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ }
+ }
+
+ // Delete the key pair for this RP + user handle if one already exists.
+ const std::vector<uint8_t> keychain_item_id =
+ KeychainItemIdentifier(RpId(), request().user().user_id());
+ {
+ ScopedCFTypeRef<CFMutableDictionaryRef> query = DefaultKeychainQuery();
+ CFDictionarySetValue(query, kSecAttrApplicationLabel,
+ [NSData dataWithBytes:keychain_item_id.data()
+ length:keychain_item_id.size()]);
+ OSStatus status = Keychain::GetInstance().ItemDelete(query);
+ if (status != errSecSuccess && status != errSecItemNotFound) {
+ // Internal keychain error.
+ OSSTATUS_DLOG(ERROR, status) << "SecItemDelete failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ }
+
+ // Generate the new key pair.
+ ScopedCFTypeRef<CFMutableDictionaryRef> params(
+ CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
+ CFDictionarySetValue(params, kSecAttrKeyType,
+ kSecAttrKeyTypeECSECPrimeRandom);
+ CFDictionarySetValue(params, kSecAttrKeySizeInBits, @256);
+ CFDictionarySetValue(params, kSecAttrSynchronizable, @NO);
+ CFDictionarySetValue(params, kSecAttrTokenID, kSecAttrTokenIDSecureEnclave);
+
+ ScopedCFTypeRef<CFMutableDictionaryRef> private_key_params =
+ DefaultKeychainQuery();
+ CFDictionarySetValue(params, kSecPrivateKeyAttrs, private_key_params);
+ CFDictionarySetValue(private_key_params, kSecAttrIsPermanent, @YES);
+ CFDictionarySetValue(private_key_params, kSecAttrAccessControl,
+ access_control());
+ CFDictionarySetValue(private_key_params, kSecUseAuthenticationContext,
+ authentication_context());
+ CFDictionarySetValue(private_key_params, kSecAttrApplicationLabel,
+ [NSData dataWithBytes:keychain_item_id.data()
+ length:keychain_item_id.size()]);
+
+ ScopedCFTypeRef<CFErrorRef> cferr;
+ ScopedCFTypeRef<SecKeyRef> private_key(
+ Keychain::GetInstance().KeyCreateRandomKey(params,
+ cferr.InitializeInto()));
+ if (!private_key) {
+ DLOG(ERROR) << "SecKeyCreateRandomKey failed: " << cferr;
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ ScopedCFTypeRef<SecKeyRef> public_key(
+ Keychain::GetInstance().KeyCopyPublicKey(private_key));
+ if (!public_key) {
+ DLOG(ERROR) << "SecKeyCopyPublicKey failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+
+ // Create attestation object. There is no separate attestation key pair, so
+ // we perform self-attestation.
+ base::Optional<AuthenticatorData> authenticator_data =
+ MakeAuthenticatorData(RpId(), keychain_item_id, public_key);
+ if (!authenticator_data) {
+ DLOG(ERROR) << "MakeAuthenticatorData failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ base::Optional<std::vector<uint8_t>> signature = GenerateSignature(
+ *authenticator_data, request().client_data_hash(), private_key);
+ if (!signature) {
+ DLOG(ERROR) << "MakeSignature failed";
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kCtap2ErrOther, base::nullopt);
+ return;
+ }
+ std::vector<std::vector<uint8_t>> no_certificates;
+ AuthenticatorMakeCredentialResponse response(AttestationObject(
+ std::move(*authenticator_data),
+ // TODO(martinkr): Add a PackedAttestationStatement for self-attestation.
+ std::make_unique<FidoAttestationStatement>(std::move(*signature),
+ std::move(no_certificates))));
+ std::move(callback())
+ .Run(CtapDeviceResponseCode::kSuccess, std::move(response));
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm b/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm
new file mode 100644
index 00000000000..39d7aa9b65e
--- /dev/null
+++ b/chromium/device/fido/mac/make_credential_operation_unittest_mac.mm
@@ -0,0 +1,64 @@
+// 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/mac/make_credential_operation.h"
+
+#include <Foundation/Foundation.h>
+#include <Security/Security.h>
+
+#include "base/strings/string_number_conversions.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "device/fido/test_callback_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+namespace {
+
+using test::TestCallbackReceiver;
+
+const std::vector<uint8_t> kClientDataHash = {1, 2, 3, 4, 5};
+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";
+
+CtapMakeCredentialRequest MakeTestRequest() {
+ return CtapMakeCredentialRequest(
+ kClientDataHash, PublicKeyCredentialRpEntity(kRpId),
+ PublicKeyCredentialUserEntity(kUserId),
+ PublicKeyCredentialParams(
+ {{PublicKeyCredentialParams::
+ CredentialInfo() /* defaults to ES-256 */}}));
+}
+
+// For demo purposes only. This test does a Touch ID user prompt. It will fail
+// on incompatible hardware and crash if not code signed or lacking the
+// keychain-access-group entitlement.
+TEST(MakeCredentialOperationTest, DISABLED_TestRun)
+API_AVAILABLE(macosx(10.12.2)) {
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+ TestCallbackReceiver<CtapDeviceResponseCode,
+ base::Optional<AuthenticatorMakeCredentialResponse>>
+ callback_receiver;
+ auto request = MakeTestRequest();
+ MakeCredentialOperation op(request, "test-profile", kKeychainAccessGroup,
+ callback_receiver.callback());
+
+ op.Run();
+ callback_receiver.WaitForCallback();
+ auto result = callback_receiver.TakeResult();
+ CtapDeviceResponseCode error = std::get<0>(result);
+ EXPECT_EQ(CtapDeviceResponseCode::kSuccess, error);
+ auto opt_response = std::move(std::get<1>(result));
+ ASSERT_TRUE(opt_response);
+};
+
+} // namespace
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/operation.h b/chromium/device/fido/mac/operation.h
new file mode 100644
index 00000000000..191a2dbe192
--- /dev/null
+++ b/chromium/device/fido/mac/operation.h
@@ -0,0 +1,31 @@
+// 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_MAC_OPERATION_H_
+#define DEVICE_FIDO_MAC_OPERATION_H_
+
+#include "base/macros.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// Operation is the interface to OperationBase.
+class Operation {
+ public:
+ virtual ~Operation() = default;
+ virtual void Run() = 0;
+
+ protected:
+ Operation() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Operation);
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_OPERATION_H_
diff --git a/chromium/device/fido/mac/operation_base.h b/chromium/device/fido/mac/operation_base.h
new file mode 100644
index 00000000000..5112cbf8017
--- /dev/null
+++ b/chromium/device/fido/mac/operation_base.h
@@ -0,0 +1,101 @@
+// 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_MAC_OPERATION_BASE_H_
+#define DEVICE_FIDO_MAC_OPERATION_BASE_H_
+
+#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/strings/sys_string_conversions.h"
+#include "device/fido/mac/operation.h"
+#include "device/fido/mac/touch_id_context.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// OperationBase abstracts behavior common to both concrete Operations,
+// |MakeCredentialOperation| and |GetAssertionOperation|.
+template <class Request, class Response>
+class API_AVAILABLE(macosx(10.12.2)) OperationBase : public Operation {
+ public:
+ using Callback = base::OnceCallback<void(CtapDeviceResponseCode,
+ base::Optional<Response>)>;
+
+ OperationBase(Request request,
+ std::string profile_id,
+ std::string keychain_access_group,
+ Callback callback)
+ : request_(std::move(request)),
+ profile_id_(std::move(profile_id)),
+ keychain_access_group_(std::move(keychain_access_group)),
+ callback_(std::move(callback)),
+ touch_id_context_(std::make_unique<TouchIdContext>()) {}
+ ~OperationBase() override = default;
+
+ protected:
+ // PromptTouchId triggers a Touch ID consent dialog with the given reason
+ // string. Subclasses implement the PromptTouchIdDone callback to receive the
+ // result.
+ void PromptTouchId(std::string reason) {
+ // The callback passed to TouchIdContext::Prompt will not fire if the
+ // TouchIdContext itself has been deleted. Since that it is owned by this
+ // class, there is no need to bind the callback to a weak ref here.
+ touch_id_context_->PromptTouchId(
+ std::move(reason), base::BindOnce(&OperationBase::PromptTouchIdDone,
+ base::Unretained(this)));
+ }
+
+ // Callback for |PromptTouchId|. Any NSError that gets passed is autoreleased.
+ virtual void PromptTouchIdDone(bool success, NSError* err) = 0;
+
+ // Subclasses override RpId to return the RP ID from the type-specific
+ // request.
+ virtual const std::string& RpId() const = 0;
+
+ LAContext* authentication_context() const {
+ return touch_id_context_->authentication_context();
+ }
+ SecAccessControlRef access_control() const {
+ return touch_id_context_->access_control();
+ }
+
+ // DefaultKeychainQuery returns a default keychain query dictionary that has
+ // the keychain item class, profile ID and RP ID filled out (but not the
+ // credential ID). More fields can be set on the return value to refine the
+ // query.
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> DefaultKeychainQuery() const {
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> query(
+ CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr));
+ CFDictionarySetValue(query, kSecClass, kSecClassKey);
+ CFDictionarySetValue(query, kSecAttrAccessGroup,
+ base::SysUTF8ToNSString(keychain_access_group_));
+ CFDictionarySetValue(query, kSecAttrLabel, base::SysUTF8ToNSString(RpId()));
+ CFDictionarySetValue(query, kSecAttrApplicationTag,
+ base::SysUTF8ToNSString(profile_id_));
+ return query;
+ }
+
+ const Request& request() const { return request_; }
+ Callback& callback() { return callback_; }
+
+ private:
+ Request request_;
+ std::string profile_id_;
+ std::string keychain_access_group_;
+ Callback callback_;
+
+ std::unique_ptr<TouchIdContext> touch_id_context_;
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_OPERATION_BASE_H_
diff --git a/chromium/device/fido/mac/touch_id_context.h b/chromium/device/fido/mac/touch_id_context.h
new file mode 100644
index 00000000000..29133b482d2
--- /dev/null
+++ b/chromium/device/fido/mac/touch_id_context.h
@@ -0,0 +1,59 @@
+// 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_MAC_TOUCH_ID_CONTEXT_H_
+#define DEVICE_FIDO_MAC_TOUCH_ID_CONTEXT_H_
+
+#import <LocalAuthentication/LocalAuthentication.h>
+#import <Security/Security.h>
+
+#include "base/callback.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// TouchIdContext wraps a macOS Touch ID consent prompt for signing with a
+// secure enclave key.
+class API_AVAILABLE(macosx(10.12.2)) TouchIdContext {
+ public:
+ // The callback is invoked when the Touch ID prompt completes. It receives a
+ // boolean indicating success and an autoreleased NSError if the prompt was
+ // denied or failed.
+ using Callback = base::OnceCallback<void(bool, NSError*)>;
+
+ TouchIdContext();
+ ~TouchIdContext();
+
+ // PromptTouchId displays a Touch ID consent prompt with the provided reason
+ // string to the user. On completion or error, the provided callback is
+ // invoked, unless the TouchIdContext instance has been destroyed in the
+ // meantime (in which case nothing happens).
+ void PromptTouchId(std::string reason, Callback callback);
+
+ // authentication_context returns the LAContext used for the Touch ID prompt.
+ LAContext* authentication_context() const { return context_; }
+
+ // access_control returns a reference to the SecAccessControl object that was
+ // evaluated/authorized in the Touch ID prompt.
+ SecAccessControlRef access_control() const { return access_control_; }
+
+ private:
+ base::scoped_nsobject<LAContext> context_;
+ base::ScopedCFTypeRef<SecAccessControlRef> access_control_;
+ Callback callback_;
+ base::WeakPtrFactory<TouchIdContext> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TouchIdContext);
+};
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_TOUCH_ID_CONTEXT_H_
diff --git a/chromium/device/fido/mac/touch_id_context.mm b/chromium/device/fido/mac/touch_id_context.mm
new file mode 100644
index 00000000000..8a31f2bca26
--- /dev/null
+++ b/chromium/device/fido/mac/touch_id_context.mm
@@ -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.
+
+#include "device/fido/mac/touch_id_context.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/strings/sys_string_conversions.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+namespace {
+API_AVAILABLE(macosx(10.12.2))
+base::ScopedCFTypeRef<SecAccessControlRef> DefaultAccessControl() {
+ return base::ScopedCFTypeRef<SecAccessControlRef>(
+ SecAccessControlCreateWithFlags(
+ kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
+ kSecAccessControlPrivateKeyUsage | kSecAccessControlTouchIDAny,
+ nullptr));
+}
+} // namespace
+
+TouchIdContext::TouchIdContext()
+ : context_([[LAContext alloc] init]),
+ access_control_(DefaultAccessControl()),
+ callback_(),
+ weak_ptr_factory_(this) {}
+
+TouchIdContext::~TouchIdContext() = default;
+
+void TouchIdContext::PromptTouchId(std::string reason, Callback callback) {
+ callback_ = std::move(callback);
+ auto weak_self = weak_ptr_factory_.GetWeakPtr();
+ // If evaluation succeeds (i.e. user provides a fingerprint), |context_| can
+ // be used for one signing operation. N.B. even in |MakeCredentialOperation|,
+ // we need to perform a signature for the attestation statement, so we need
+ // the sign bit there.
+ [context_ evaluateAccessControl:access_control_
+ operation:LAAccessControlOperationUseKeySign
+ localizedReason:base::SysUTF8ToNSString(reason)
+ reply:^(BOOL success, NSError* error) {
+ if (!weak_self) {
+ return;
+ }
+ std::move(callback_).Run(success, error);
+ }];
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/mac/util.h b/chromium/device/fido/mac/util.h
new file mode 100644
index 00000000000..fe0935ccc35
--- /dev/null
+++ b/chromium/device/fido/mac/util.h
@@ -0,0 +1,51 @@
+// 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_MAC_UTIL_H_
+#define DEVICE_FIDO_MAC_UTIL_H_
+
+#include <string>
+#include <vector>
+
+#import <Security/Security.h>
+
+#include "base/callback.h"
+#include "base/mac/availability.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+// KeychainItemIdentifier returns the unique identifier for a key pair, derived
+// from an RP ID and user handle. It is stored in the keychain items
+// kSecAttrApplicationLabel attribute and can be used for lookup.
+std::vector<uint8_t> KeychainItemIdentifier(std::string rp_id,
+ std::vector<uint8_t> user_id);
+
+// MakeAuthenticatorData returns an AuthenticatorData instance for the Touch ID
+// authenticator with the given Relying Party ID, credential ID and public key.
+// It returns |base::nullopt| on failure.
+base::Optional<AuthenticatorData> MakeAuthenticatorData(
+ const std::string& rp_id,
+ std::vector<uint8_t> credential_id,
+ SecKeyRef public_key) API_AVAILABLE(macosx(10.12.2));
+
+// GenerateSignature signs the concatenation of the serialization of the given
+// authenticator data and the given client data hash, as required for
+// (self-)attestation and assertion. Returns |base::nullopt| if the operation
+// fails.
+base::Optional<std::vector<uint8_t>> GenerateSignature(
+ const AuthenticatorData& authenticator_data,
+ const std::vector<uint8_t>& client_data_hash,
+ SecKeyRef private_key) API_AVAILABLE(macosx(10.12.2));
+
+std::vector<uint8_t> TouchIdAaguid();
+
+} // namespace mac
+} // namespace fido
+} // namespace device
+
+#endif // DEVICE_FIDO_MAC_UTIL_H_
diff --git a/chromium/device/fido/mac/util.mm b/chromium/device/fido/mac/util.mm
new file mode 100644
index 00000000000..38b71a5556d
--- /dev/null
+++ b/chromium/device/fido/mac/util.mm
@@ -0,0 +1,142 @@
+// 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/mac/get_assertion_operation.h"
+
+#include <array>
+#include <set>
+#include <string>
+
+#import <Foundation/Foundation.h>
+
+#include "base/bind.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#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 "device/fido/ec_public_key.h"
+#include "device/fido/fido_attestation_statement.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "device/fido/mac/keychain.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+using base::ScopedCFTypeRef;
+using base::scoped_nsobject;
+using cbor::CBORWriter;
+using cbor::CBORValue;
+
+// The authenticator AAGUID value.
+constexpr std::array<uint8_t, 16> kAaguid = {0xad, 0xce, 0x00, 0x02, 0x35, 0xbc,
+ 0xc6, 0x0a, 0x64, 0x8b, 0x0b, 0x25,
+ 0xf1, 0xf0, 0x55, 0x03};
+
+std::vector<uint8_t> TouchIdAaguid() {
+ return std::vector<uint8_t>(kAaguid.begin(), kAaguid.end());
+}
+
+namespace {
+
+// MakeECPublicKey converts a SecKeyRef for a public key into an equivalent
+// |ECPublicKey| instance. It returns |nullptr| if the key cannot be converted.
+std::unique_ptr<ECPublicKey> MakeECPublicKey(SecKeyRef public_key_ref)
+ API_AVAILABLE(macosx(10.12.2)) {
+ CHECK(public_key_ref);
+ ScopedCFTypeRef<CFErrorRef> err;
+ ScopedCFTypeRef<CFDataRef> data_ref(
+ SecKeyCopyExternalRepresentation(public_key_ref, err.InitializeInto()));
+ if (!data_ref) {
+ LOG(ERROR) << "SecCopyExternalRepresentation failed: " << err;
+ return nullptr;
+ }
+ base::span<const uint8_t> key_data =
+ base::make_span(CFDataGetBytePtr(data_ref), CFDataGetLength(data_ref));
+ auto key =
+ ECPublicKey::ParseX962Uncompressed(fido_parsing_utils::kEs256, key_data);
+ if (!key) {
+ LOG(ERROR) << "Unexpected public key format: "
+ << base::HexEncode(key_data.data(), key_data.size());
+ return nullptr;
+ }
+ return key;
+}
+
+} // namespace
+
+// KeychainItemIdentifier returns the unique identifier for a given RP ID
+// and user handle. It is stored in the keychain items Application Label and
+// used for later lookup.
+std::vector<uint8_t> KeychainItemIdentifier(std::string rp_id,
+ std::vector<uint8_t> user_id) {
+ std::vector<CBORValue> array;
+ array.emplace_back(CBORValue(rp_id));
+ array.emplace_back(CBORValue(user_id));
+ auto value = CBORWriter::Write(CBORValue(std::move(array)));
+ CHECK(value);
+ return *value;
+}
+
+base::Optional<AuthenticatorData> MakeAuthenticatorData(
+ const std::string& rp_id,
+ std::vector<uint8_t> credential_id,
+ SecKeyRef public_key) API_AVAILABLE(macosx(10.12.2)) {
+ if (credential_id.size() > 255) {
+ LOG(ERROR) << "credential id too long: "
+ << base::HexEncode(credential_id.data(), credential_id.size());
+ return base::nullopt;
+ }
+ std::array<uint8_t, 2> encoded_credential_id_length = {
+ 0, static_cast<uint8_t>(credential_id.size())};
+ constexpr uint8_t flags =
+ static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserVerification) |
+ static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
+ std::vector<uint8_t> counter = {0, 0, 0, 0}; // implement
+ auto ec_public_key = MakeECPublicKey(public_key);
+ if (!ec_public_key) {
+ LOG(ERROR) << "MakeECPublicKey failed";
+ return base::nullopt;
+ }
+ return AuthenticatorData(
+ fido_parsing_utils::CreateSHA256Hash(rp_id), flags, counter,
+ AttestedCredentialData(kAaguid, encoded_credential_id_length,
+ std::move(credential_id),
+ std::move(ec_public_key)));
+}
+
+base::Optional<std::vector<uint8_t>> GenerateSignature(
+ const AuthenticatorData& authenticator_data,
+ const std::vector<uint8_t>& client_data_hash,
+ SecKeyRef private_key) API_AVAILABLE(macosx(10.12.2)) {
+ const std::vector<uint8_t> serialized_authenticator_data =
+ authenticator_data.SerializeToByteArray();
+ size_t capacity =
+ serialized_authenticator_data.size() + client_data_hash.size();
+ ScopedCFTypeRef<CFMutableDataRef> sig_input(
+ CFDataCreateMutable(kCFAllocatorDefault, capacity));
+ CFDataAppendBytes(sig_input, serialized_authenticator_data.data(),
+ serialized_authenticator_data.size());
+ CFDataAppendBytes(sig_input, client_data_hash.data(),
+ client_data_hash.size());
+ ScopedCFTypeRef<CFErrorRef> err;
+ ScopedCFTypeRef<CFDataRef> sig_data(
+ Keychain::GetInstance().KeyCreateSignature(
+ private_key, kSecKeyAlgorithmECDSASignatureMessageX962SHA256,
+ sig_input, err.InitializeInto()));
+ if (!sig_data) {
+ LOG(ERROR) << "SecKeyCreateSignature failed: " << err;
+ return base::nullopt;
+ }
+ return std::vector<uint8_t>(
+ CFDataGetBytePtr(sig_data),
+ CFDataGetBytePtr(sig_data) + CFDataGetLength(sig_data));
+}
+
+} // namespace mac
+} // namespace fido
+} // namespace device
diff --git a/chromium/device/fido/make_credential_handler_unittest.cc b/chromium/device/fido/make_credential_handler_unittest.cc
index 736408b47e2..7f8bee04a48 100644
--- a/chromium/device/fido/make_credential_handler_unittest.cc
+++ b/chromium/device/fido/make_credential_handler_unittest.cc
@@ -12,12 +12,12 @@
#include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device.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/make_credential_request_handler.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -46,12 +46,13 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
std::unique_ptr<MakeCredentialRequestHandler> CreateMakeCredentialHandler() {
ForgeNextHidDiscovery();
PublicKeyCredentialRpEntity rp(kRpId);
- PublicKeyCredentialUserEntity user(u2f_parsing_utils::Materialize(kUserId));
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(kUserId));
PublicKeyCredentialParams credential_params(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1));
auto request_parameter = CtapMakeCredentialRequest(
- u2f_parsing_utils::Materialize(kClientDataHash), std::move(rp),
+ fido_parsing_utils::Materialize(kClientDataHash), std::move(rp),
std::move(user), std::move(credential_params));
return std::make_unique<MakeCredentialRequestHandler>(
diff --git a/chromium/device/fido/make_credential_request_handler.cc b/chromium/device/fido/make_credential_request_handler.cc
index fe72f26a1a8..f9c16af664c 100644
--- a/chromium/device/fido/make_credential_request_handler.cc
+++ b/chromium/device/fido/make_credential_request_handler.cc
@@ -8,7 +8,7 @@
#include "base/bind.h"
#include "device/fido/authenticator_make_credential_response.h"
-#include "device/fido/fido_device.h"
+#include "device/fido/fido_authenticator.h"
#include "device/fido/make_credential_task.h"
#include "services/service_manager/public/cpp/connector.h"
@@ -24,16 +24,18 @@ MakeCredentialRequestHandler::MakeCredentialRequestHandler(
request_parameter_(std::move(request_parameter)),
authenticator_selection_criteria_(
std::move(authenticator_selection_criteria)),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ Start();
+}
MakeCredentialRequestHandler::~MakeCredentialRequestHandler() = default;
-std::unique_ptr<FidoTask> MakeCredentialRequestHandler::CreateTaskForNewDevice(
- FidoDevice* device) {
- return std::make_unique<MakeCredentialTask>(
- device, request_parameter_, authenticator_selection_criteria_,
- base::BindOnce(&MakeCredentialRequestHandler::OnDeviceResponse,
- weak_factory_.GetWeakPtr(), device));
+void MakeCredentialRequestHandler::DispatchRequest(
+ FidoAuthenticator* authenticator) {
+ return authenticator->MakeCredential(
+ authenticator_selection_criteria_, request_parameter_,
+ base::BindOnce(&MakeCredentialRequestHandler::OnAuthenticatorResponse,
+ weak_factory_.GetWeakPtr(), authenticator));
}
} // namespace device
diff --git a/chromium/device/fido/make_credential_request_handler.h b/chromium/device/fido/make_credential_request_handler.h
index f0ac0d6e99a..23cc5b6178f 100644
--- a/chromium/device/fido/make_credential_request_handler.h
+++ b/chromium/device/fido/make_credential_request_handler.h
@@ -24,13 +24,11 @@ class Connector;
namespace device {
-class FidoDevice;
-class FidoTask;
+class FidoAuthenticator;
class AuthenticatorMakeCredentialResponse;
-using RegisterResponseCallback = base::OnceCallback<void(
- FidoReturnCode status_code,
- base::Optional<AuthenticatorMakeCredentialResponse> response_data)>;
+using RegisterResponseCallback = base::OnceCallback<
+ void(FidoReturnCode, base::Optional<AuthenticatorMakeCredentialResponse>)>;
class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
: public FidoRequestHandler<AuthenticatorMakeCredentialResponse> {
@@ -45,7 +43,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
private:
// FidoRequestHandlerBase:
- std::unique_ptr<FidoTask> CreateTaskForNewDevice(FidoDevice* device) final;
+ void DispatchRequest(FidoAuthenticator* authenticator) final;
CtapMakeCredentialRequest request_parameter_;
AuthenticatorSelectionCriteria authenticator_selection_criteria_;
diff --git a/chromium/device/fido/make_credential_task.cc b/chromium/device/fido/make_credential_task.cc
index acefe073c02..4c966ebd331 100644
--- a/chromium/device/fido/make_credential_task.cc
+++ b/chromium/device/fido/make_credential_task.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "device/fido/ctap_empty_authenticator_request.h"
+#include "device/fido/ctap_register_operation.h"
#include "device/fido/device_response_converter.h"
namespace device {
@@ -40,10 +41,11 @@ void MakeCredentialTask::MakeCredential() {
return;
}
- device()->DeviceTransact(
- request_parameter_.EncodeAsCBOR(),
+ register_operation_ = std::make_unique<CtapRegisterOperation>(
+ device(), &request_parameter_,
base::BindOnce(&MakeCredentialTask::OnCtapMakeCredentialResponseReceived,
weak_factory_.GetWeakPtr()));
+ register_operation_->Start();
}
void MakeCredentialTask::U2fRegister() {
@@ -56,28 +58,21 @@ void MakeCredentialTask::U2fRegister() {
}
void MakeCredentialTask::OnCtapMakeCredentialResponseReceived(
- base::Optional<std::vector<uint8_t>> device_response) {
- if (!device_response) {
- std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
- base::nullopt);
- return;
- }
-
- auto response_code = GetResponseCode(*device_response);
- if (response_code != CtapDeviceResponseCode::kSuccess) {
- std::move(callback_).Run(response_code, base::nullopt);
+ CtapDeviceResponseCode return_code,
+ base::Optional<AuthenticatorMakeCredentialResponse> response_data) {
+ if (return_code != CtapDeviceResponseCode::kSuccess) {
+ std::move(callback_).Run(return_code, base::nullopt);
return;
}
- auto parsed_response = ReadCTAPMakeCredentialResponse(*device_response);
- if (!parsed_response ||
- !parsed_response->CheckRpIdHash(request_parameter_.rp().rp_id())) {
+ if (!response_data ||
+ !response_data->CheckRpIdHash(request_parameter_.rp().rp_id())) {
std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
base::nullopt);
return;
}
- std::move(callback_).Run(response_code, std::move(parsed_response));
+ std::move(callback_).Run(return_code, std::move(response_data));
}
bool MakeCredentialTask::CheckIfAuthenticatorSelectionCriteriaAreSatisfied() {
diff --git a/chromium/device/fido/make_credential_task.h b/chromium/device/fido/make_credential_task.h
index 8e87f975d15..25025892edf 100644
--- a/chromium/device/fido/make_credential_task.h
+++ b/chromium/device/fido/make_credential_task.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include <memory>
#include <vector>
#include "base/callback.h"
@@ -17,6 +18,7 @@
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/authenticator_selection_criteria.h"
#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/ctap_register_operation.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_task.h"
@@ -27,8 +29,8 @@ namespace device {
class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialTask : public FidoTask {
public:
using MakeCredentialTaskCallback = base::OnceCallback<void(
- CtapDeviceResponseCode return_code,
- base::Optional<AuthenticatorMakeCredentialResponse> response_data)>;
+ CtapDeviceResponseCode,
+ base::Optional<AuthenticatorMakeCredentialResponse>)>;
MakeCredentialTask(FidoDevice* device,
CtapMakeCredentialRequest request_parameter,
@@ -43,7 +45,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialTask : public FidoTask {
void MakeCredential();
void U2fRegister();
void OnCtapMakeCredentialResponseReceived(
- base::Optional<std::vector<uint8_t>> device_response);
+ CtapDeviceResponseCode return_code,
+ base::Optional<AuthenticatorMakeCredentialResponse> response_data);
// Invoked after retrieving response to AuthenticatorGetInfo request. Filters
// out authenticators based on |authenticator_selection_criteria_| constraints
@@ -53,8 +56,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialTask : public FidoTask {
CtapMakeCredentialRequest request_parameter_;
AuthenticatorSelectionCriteria authenticator_selection_criteria_;
+ std::unique_ptr<CtapRegisterOperation> register_operation_;
MakeCredentialTaskCallback callback_;
-
base::WeakPtrFactory<MakeCredentialTask> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MakeCredentialTask);
diff --git a/chromium/device/fido/make_credential_task_unittest.cc b/chromium/device/fido/make_credential_task_unittest.cc
index 2ce00b9f5f3..24cc98701ae 100644
--- a/chromium/device/fido/make_credential_task_unittest.cc
+++ b/chromium/device/fido/make_credential_task_unittest.cc
@@ -13,11 +13,11 @@
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/make_credential_task.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,11 +47,12 @@ class FidoMakeCredentialTaskTest : public testing::Test {
std::unique_ptr<MakeCredentialTask> CreateMakeCredentialTask(
FidoDevice* device) {
PublicKeyCredentialRpEntity rp(kRpId);
- PublicKeyCredentialUserEntity user(u2f_parsing_utils::Materialize(kUserId));
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(kUserId));
return std::make_unique<MakeCredentialTask>(
device,
CtapMakeCredentialRequest(
- u2f_parsing_utils::Materialize(kClientDataHash), std::move(rp),
+ fido_parsing_utils::Materialize(kClientDataHash), std::move(rp),
std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1))),
@@ -63,11 +64,12 @@ class FidoMakeCredentialTaskTest : public testing::Test {
FidoDevice* device,
AuthenticatorSelectionCriteria criteria) {
PublicKeyCredentialRpEntity rp(kRpId);
- PublicKeyCredentialUserEntity user(u2f_parsing_utils::Materialize(kUserId));
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(kUserId));
return std::make_unique<MakeCredentialTask>(
device,
CtapMakeCredentialRequest(
- u2f_parsing_utils::Materialize(kClientDataHash), std::move(rp),
+ fido_parsing_utils::Materialize(kClientDataHash), std::move(rp),
std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1))),
diff --git a/chromium/device/fido/mock_fido_device.cc b/chromium/device/fido/mock_fido_device.cc
index 4b91df55b47..42d61e8c835 100644
--- a/chromium/device/fido/mock_fido_device.cc
+++ b/chromium/device/fido/mock_fido_device.cc
@@ -11,8 +11,8 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/apdu/apdu_response.h"
#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
-#include "device/fido/u2f_parsing_utils.h"
namespace device {
@@ -74,16 +74,6 @@ void MockFidoDevice::NoErrorRegister(const std::vector<uint8_t>& command,
}
// static
-void MockFidoDevice::NoErrorVersion(const std::vector<uint8_t>& command,
- DeviceCallback& cb) {
- std::move(cb).Run(
- apdu::ApduResponse(std::vector<uint8_t>(kU2fVersionResponse.cbegin(),
- kU2fVersionResponse.cend()),
- apdu::ApduResponse::Status::SW_NO_ERROR)
- .GetEncodedResponse());
-}
-
-// static
void MockFidoDevice::SignWithCorruptedResponse(
const std::vector<uint8_t>& command,
DeviceCallback& cb) {
@@ -109,7 +99,7 @@ void MockFidoDevice::ExpectCtap2CommandAndRespondWith(
CtapRequestCommand command,
base::Optional<base::span<const uint8_t>> response,
base::TimeDelta delay) {
- auto data = u2f_parsing_utils::MaterializeOrNull(response);
+ auto data = fido_parsing_utils::MaterializeOrNull(response);
auto send_response = [ data(std::move(data)), delay ](DeviceCallback & cb) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
@@ -123,13 +113,13 @@ void MockFidoDevice::ExpectRequestAndRespondWith(
base::span<const uint8_t> request,
base::Optional<base::span<const uint8_t>> response,
base::TimeDelta delay) {
- auto data = u2f_parsing_utils::MaterializeOrNull(response);
+ auto data = fido_parsing_utils::MaterializeOrNull(response);
auto send_response = [ data(std::move(data)), delay ](DeviceCallback & cb) {
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, base::BindOnce(std::move(cb), std::move(data)), delay);
};
- auto request_as_vector = u2f_parsing_utils::Materialize(request);
+ auto request_as_vector = fido_parsing_utils::Materialize(request);
EXPECT_CALL(*this,
DeviceTransactPtr(std::move(request_as_vector), ::testing::_))
.WillOnce(::testing::WithArg<1>(::testing::Invoke(send_response)));
@@ -142,7 +132,7 @@ void MockFidoDevice::ExpectCtap2CommandAndDoNotRespond(
void MockFidoDevice::ExpectRequestAndDoNotRespond(
base::span<const uint8_t> request) {
- auto request_as_vector = u2f_parsing_utils::Materialize(request);
+ auto request_as_vector = fido_parsing_utils::Materialize(request);
EXPECT_CALL(*this,
DeviceTransactPtr(std::move(request_as_vector), ::testing::_));
}
diff --git a/chromium/device/fido/mock_fido_device.h b/chromium/device/fido/mock_fido_device.h
index 9e17e2e2ed4..e8afa2c4e47 100644
--- a/chromium/device/fido/mock_fido_device.h
+++ b/chromium/device/fido/mock_fido_device.h
@@ -51,8 +51,6 @@ class MockFidoDevice : public FidoDevice {
DeviceCallback& cb);
static void NoErrorRegister(const std::vector<uint8_t>& command,
DeviceCallback& cb);
- static void NoErrorVersion(const std::vector<uint8_t>& command,
- DeviceCallback& cb);
static void SignWithCorruptedResponse(const std::vector<uint8_t>& command,
DeviceCallback& cb);
static void WinkDoNothing(WinkCallback& cb);
diff --git a/chromium/device/fido/public_key_credential_descriptor.cc b/chromium/device/fido/public_key_credential_descriptor.cc
index 007897f6ee1..af48eebcf34 100644
--- a/chromium/device/fido/public_key_credential_descriptor.cc
+++ b/chromium/device/fido/public_key_credential_descriptor.cc
@@ -26,21 +26,22 @@ PublicKeyCredentialDescriptor::CreateFromCBORValue(
const cbor::CBORValue::MapValue& map = cbor.GetMap();
auto type = map.find(cbor::CBORValue(kCredentialTypeKey));
- if (type == map.end() || !type->second.is_string())
+ if (type == map.end() || !type->second.is_string() ||
+ type->second.GetString() != kPublicKey)
return base::nullopt;
auto id = map.find(cbor::CBORValue(kCredentialIdKey));
if (id == map.end() || !id->second.is_bytestring())
return base::nullopt;
- return PublicKeyCredentialDescriptor(type->second.GetString(),
+ return PublicKeyCredentialDescriptor(CredentialType::kPublicKey,
id->second.GetBytestring());
}
PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor(
- std::string credential_type,
+ CredentialType credential_type,
std::vector<uint8_t> id)
- : credential_type_(std::move(credential_type)), id_(std::move(id)) {}
+ : credential_type_(credential_type), id_(std::move(id)) {}
PublicKeyCredentialDescriptor::PublicKeyCredentialDescriptor(
const PublicKeyCredentialDescriptor& other) = default;
@@ -60,7 +61,7 @@ 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(credential_type_);
+ cbor::CBORValue(CredentialTypeToString(credential_type_));
return cbor::CBORValue(std::move(cbor_descriptor_map));
}
diff --git a/chromium/device/fido/public_key_credential_descriptor.h b/chromium/device/fido/public_key_credential_descriptor.h
index bcd369fa2b0..02bc4389a37 100644
--- a/chromium/device/fido/public_key_credential_descriptor.h
+++ b/chromium/device/fido/public_key_credential_descriptor.h
@@ -12,6 +12,7 @@
#include "base/component_export.h"
#include "base/optional.h"
#include "components/cbor/cbor_values.h"
+#include "device/fido/fido_constants.h"
namespace device {
@@ -24,7 +25,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialDescriptor {
static base::Optional<PublicKeyCredentialDescriptor> CreateFromCBORValue(
const cbor::CBORValue& cbor);
- PublicKeyCredentialDescriptor(std::string credential_type,
+ PublicKeyCredentialDescriptor(CredentialType credential_type,
std::vector<uint8_t> id);
PublicKeyCredentialDescriptor(const PublicKeyCredentialDescriptor& other);
PublicKeyCredentialDescriptor(PublicKeyCredentialDescriptor&& other);
@@ -36,11 +37,11 @@ class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialDescriptor {
cbor::CBORValue ConvertToCBOR() const;
- const std::string& credential_type() const { return credential_type_; }
+ CredentialType credential_type() const { return credential_type_; }
const std::vector<uint8_t>& id() const { return id_; }
private:
- std::string credential_type_;
+ CredentialType credential_type_;
std::vector<uint8_t> id_;
};
diff --git a/chromium/device/fido/public_key_credential_params.cc b/chromium/device/fido/public_key_credential_params.cc
index d0d575d557c..4b7e53f2bb5 100644
--- a/chromium/device/fido/public_key_credential_params.cc
+++ b/chromium/device/fido/public_key_credential_params.cc
@@ -33,7 +33,7 @@ cbor::CBORValue PublicKeyCredentialParams::ConvertToCBOR() const {
for (const auto& credential : public_key_credential_params_) {
cbor::CBORValue::MapValue cbor_credential_map;
cbor_credential_map[cbor::CBORValue("type")] =
- cbor::CBORValue(to_string(credential.type));
+ cbor::CBORValue(CredentialTypeToString(credential.type));
cbor_credential_map[cbor::CBORValue("alg")] =
cbor::CBORValue(credential.algorithm);
credential_param_array.emplace_back(std::move(cbor_credential_map));
diff --git a/chromium/device/fido/response_data.cc b/chromium/device/fido/response_data.cc
index 829adcef82e..09f3e4e4632 100644
--- a/chromium/device/fido/response_data.cc
+++ b/chromium/device/fido/response_data.cc
@@ -8,7 +8,7 @@
#include "base/base64url.h"
#include "base/strings/string_piece.h"
-#include "crypto/sha2.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
@@ -33,11 +33,7 @@ std::string ResponseData::GetId() const {
}
bool ResponseData::CheckRpIdHash(const std::string& rp_id) const {
- const auto& response_rp_id_hash = GetRpIdHash();
- std::vector<uint8_t> request_rp_id_hash(crypto::kSHA256Length);
- crypto::SHA256HashString(rp_id, request_rp_id_hash.data(),
- request_rp_id_hash.size());
- return response_rp_id_hash == request_rp_id_hash;
+ return GetRpIdHash() == fido_parsing_utils::CreateSHA256Hash(rp_id);
}
} // namespace device
diff --git a/chromium/device/fido/scoped_virtual_fido_device.cc b/chromium/device/fido/scoped_virtual_fido_device.cc
index db7fc515882..d5afaf87a4a 100644
--- a/chromium/device/fido/scoped_virtual_fido_device.cc
+++ b/chromium/device/fido/scoped_virtual_fido_device.cc
@@ -11,6 +11,7 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "device/fido/virtual_u2f_device.h"
namespace device {
namespace test {
@@ -26,7 +27,7 @@ class VirtualFidoDeviceDiscovery : public FidoDiscovery {
protected:
void StartInternal() override {
- auto device = std::make_unique<VirtualFidoDevice>(state_);
+ auto device = std::make_unique<VirtualU2fDevice>(state_);
AddDevice(std::move(device));
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
diff --git a/chromium/device/fido/test_callback_receiver.h b/chromium/device/fido/test_callback_receiver.h
index 1a93bc5c22a..90363783a03 100644
--- a/chromium/device/fido/test_callback_receiver.h
+++ b/chromium/device/fido/test_callback_receiver.h
@@ -40,8 +40,7 @@ namespace test {
template <class... CallbackArgs>
class TestCallbackReceiver {
public:
- using TupleOfNonReferenceArgs =
- std::tuple<typename std::decay_t<CallbackArgs>...>;
+ using TupleOfNonReferenceArgs = std::tuple<std::decay_t<CallbackArgs>...>;
TestCallbackReceiver() = default;
~TestCallbackReceiver() = default;
@@ -82,7 +81,7 @@ class TestCallbackReceiver {
private:
void ReceiverMethod(CallbackArgs... args) {
- result_.emplace(std::move(args)...);
+ result_.emplace(std::forward<CallbackArgs>(args)...);
was_called_ = true;
wait_for_callback_loop_.Quit();
}
@@ -94,11 +93,11 @@ class TestCallbackReceiver {
DISALLOW_COPY_AND_ASSIGN(TestCallbackReceiver);
};
-template <class Status>
-class StatusCallbackReceiver : public TestCallbackReceiver<Status> {
+template <class Value>
+class ValueCallbackReceiver : public TestCallbackReceiver<Value> {
public:
- const Status& status() const {
- return std::get<0>(*TestCallbackReceiver<Status>::result());
+ const Value& value() const {
+ return std::get<0>(*TestCallbackReceiver<Value>::result());
}
};
diff --git a/chromium/device/fido/test_callback_receiver_unittest.cc b/chromium/device/fido/test_callback_receiver_unittest.cc
index dc31f78fb41..4197776840c 100644
--- a/chromium/device/fido/test_callback_receiver_unittest.cc
+++ b/chromium/device/fido/test_callback_receiver_unittest.cc
@@ -4,6 +4,10 @@
#include "device/fido/test_callback_receiver.h"
+#include <memory>
+#include <tuple>
+#include <utility>
+
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -12,6 +16,31 @@
namespace device {
namespace test {
+namespace {
+
+// Simple class that resets a boolean flag when moved out from.
+class MoveResets {
+ public:
+ MoveResets() = default;
+ MoveResets(bool value) : value_(value) {} // NOLINT(runtime/explicit)
+ MoveResets(const MoveResets&) = default;
+ MoveResets(MoveResets&& other) : value_(std::exchange(other.value_, false)) {}
+ MoveResets& operator=(const MoveResets&) = default;
+ MoveResets& operator=(MoveResets&& other) {
+ value_ = std::exchange(other.value_, false);
+ return *this;
+ }
+
+ ~MoveResets() = default;
+
+ bool value() const { return value_; }
+
+ private:
+ bool value_ = false;
+};
+
+} // namespace
+
TEST(TestCallbackReceiver, BasicClosure) {
base::test::ScopedTaskEnvironment task_environment;
TestCallbackReceiver<> closure_receiver;
@@ -64,22 +93,24 @@ TEST(TestCallbackReceiver, MoveOnlyArgumentIsMoved) {
TEST(TestCallbackReceiver, ReferenceArgumentIsCopied) {
base::test::ScopedTaskEnvironment task_environment;
- TestCallbackReceiver<int&> callback_receiver;
+ TestCallbackReceiver<MoveResets&> callback_receiver;
- int passed_in_value = 42;
+ MoveResets passed_in_value = true;
auto callback = callback_receiver.callback();
EXPECT_FALSE(callback_receiver.result().has_value());
+ // Make sure |passed_in_value| is not moved from.
std::move(callback).Run(passed_in_value);
-
+ EXPECT_TRUE(passed_in_value.value());
EXPECT_TRUE(callback_receiver.result().has_value());
- const int& received_value = std::get<0>(*callback_receiver.result());
- EXPECT_EQ(passed_in_value, received_value);
+ const MoveResets& received_value = std::get<0>(*callback_receiver.result());
+ EXPECT_EQ(passed_in_value.value(), received_value.value());
- passed_in_value = 43;
- EXPECT_NE(passed_in_value, received_value);
+ // Make sure |received_value| is not a reference to |passed_in_value|.
+ passed_in_value = false;
+ EXPECT_NE(passed_in_value.value(), received_value.value());
callback_receiver.TakeResult();
EXPECT_FALSE(callback_receiver.result().has_value());
diff --git a/chromium/device/fido/u2f_command_constructor.cc b/chromium/device/fido/u2f_command_constructor.cc
new file mode 100644
index 00000000000..2b4fb1172ec
--- /dev/null
+++ b/chromium/device/fido/u2f_command_constructor.cc
@@ -0,0 +1,130 @@
+// 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/u2f_command_constructor.h"
+
+#include <string>
+#include <utility>
+
+#include "components/apdu/apdu_command.h"
+#include "device/fido/fido_parsing_utils.h"
+
+namespace device {
+
+bool IsConvertibleToU2fRegisterCommand(
+ const CtapMakeCredentialRequest& request) {
+ if (request.user_verification_required() || request.resident_key_supported())
+ return false;
+
+ const auto& public_key_credential_info =
+ request.public_key_credential_params().public_key_credential_params();
+ return std::any_of(
+ public_key_credential_info.begin(), public_key_credential_info.end(),
+ [](const auto& credential_info) {
+ return credential_info.algorithm ==
+ base::strict_cast<int>(CoseAlgorithmIdentifier::kCoseEs256);
+ });
+}
+
+bool IsConvertibleToU2fSignCommand(const CtapGetAssertionRequest& request) {
+ const auto& allow_list = request.allow_list();
+ return request.user_verification() !=
+ UserVerificationRequirement::kRequired &&
+ allow_list && !allow_list->empty();
+}
+
+base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
+ const CtapMakeCredentialRequest& request) {
+ if (!IsConvertibleToU2fRegisterCommand(request))
+ return base::nullopt;
+
+ return ConstructU2fRegisterCommand(
+ fido_parsing_utils::CreateSHA256Hash(request.rp().rp_id()),
+ request.client_data_hash());
+}
+
+base::Optional<std::vector<uint8_t>> ConvertToU2fCheckOnlySignCommand(
+ const CtapMakeCredentialRequest& request,
+ const PublicKeyCredentialDescriptor& key_handle) {
+ if (key_handle.credential_type() != CredentialType::kPublicKey)
+ return base::nullopt;
+
+ return ConstructU2fSignCommand(
+ fido_parsing_utils::CreateSHA256Hash(request.rp().rp_id()),
+ request.client_data_hash(), key_handle.id(), true /* check_only */);
+}
+
+base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
+ const CtapGetAssertionRequest& request,
+ ApplicationParameterType application_parameter_type,
+ base::span<const uint8_t> key_handle,
+ bool check_only) {
+ if (!IsConvertibleToU2fSignCommand(request))
+ return base::nullopt;
+
+ auto application_parameter =
+ application_parameter_type == ApplicationParameterType::kPrimary
+ ? fido_parsing_utils::CreateSHA256Hash(request.rp_id())
+ : std::vector<uint8_t>();
+
+ return ConstructU2fSignCommand(std::move(application_parameter),
+ request.client_data_hash(), key_handle,
+ check_only);
+}
+
+base::Optional<std::vector<uint8_t>> ConstructU2fRegisterCommand(
+ base::span<const uint8_t> application_parameter,
+ base::span<const uint8_t> challenge_parameter,
+ bool is_individual_attestation) {
+ if (application_parameter.size() != kU2fParameterLength ||
+ challenge_parameter.size() != kU2fParameterLength) {
+ return base::nullopt;
+ }
+
+ std::vector<uint8_t> data;
+ data.reserve(challenge_parameter.size() + application_parameter.size());
+ fido_parsing_utils::Append(&data, challenge_parameter);
+ fido_parsing_utils::Append(&data, application_parameter);
+
+ apdu::ApduCommand command;
+ command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kRegister));
+ command.set_p1(kP1TupRequiredConsumed |
+ (is_individual_attestation ? kP1IndividualAttestation : 0));
+ command.set_data(std::move(data));
+ command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
+ return command.GetEncodedCommand();
+}
+
+base::Optional<std::vector<uint8_t>> ConstructU2fSignCommand(
+ base::span<const uint8_t> application_parameter,
+ base::span<const uint8_t> challenge_parameter,
+ base::span<const uint8_t> key_handle,
+ bool check_only) {
+ if (application_parameter.size() != kU2fParameterLength ||
+ challenge_parameter.size() != kU2fParameterLength ||
+ key_handle.size() > kMaxKeyHandleLength) {
+ return base::nullopt;
+ }
+
+ std::vector<uint8_t> data;
+ data.reserve(challenge_parameter.size() + application_parameter.size() + 1 +
+ key_handle.size());
+ fido_parsing_utils::Append(&data, challenge_parameter);
+ fido_parsing_utils::Append(&data, application_parameter);
+ data.push_back(static_cast<uint8_t>(key_handle.size()));
+ fido_parsing_utils::Append(&data, key_handle);
+
+ apdu::ApduCommand command;
+ command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kSign));
+ command.set_p1(check_only ? kP1CheckOnly : kP1TupRequiredConsumed);
+ command.set_data(std::move(data));
+ command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
+ return command.GetEncodedCommand();
+}
+
+base::Optional<std::vector<uint8_t>> ConstructBogusU2fRegistrationCommand() {
+ return ConstructU2fRegisterCommand(kBogusAppParam, kBogusChallenge);
+}
+
+} // namespace device
diff --git a/chromium/device/fido/u2f_command_constructor.h b/chromium/device/fido/u2f_command_constructor.h
new file mode 100644
index 00000000000..69161d110cc
--- /dev/null
+++ b/chromium/device/fido/u2f_command_constructor.h
@@ -0,0 +1,79 @@
+// 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_U2F_COMMAND_CONSTRUCTOR_H_
+#define DEVICE_FIDO_U2F_COMMAND_CONSTRUCTOR_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/span.h"
+#include "base/optional.h"
+#include "device/fido/ctap_get_assertion_request.h"
+#include "device/fido/ctap_make_credential_request.h"
+#include "device/fido/fido_constants.h"
+
+namespace device {
+
+// Checks whether the request can be translated to valid U2F request
+// parameter. Namely, U2F request does not support resident key and
+// user verification, and ES256 algorithm must be used for public key
+// credential.
+// 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
+COMPONENT_EXPORT(DEVICE_FIDO)
+bool IsConvertibleToU2fRegisterCommand(
+ const CtapMakeCredentialRequest& request);
+
+// Checks whether user verification is not required and that allow list is
+// not empty.
+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#using-the-ctap2-authenticatorgetassertion-command-with-ctap1-u2f-authenticators
+COMPONENT_EXPORT(DEVICE_FIDO)
+bool IsConvertibleToU2fSignCommand(const CtapGetAssertionRequest& request);
+
+// Extracts APDU encoded U2F register command from CtapMakeCredentialRequest.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConvertToU2fRegisterCommand(
+ const CtapMakeCredentialRequest& request);
+
+// Extracts APDU encoded U2F check only sign command from
+// CtapMakeCredentialRequest. Invoked when U2F register operation includes key
+// handles in exclude list.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConvertToU2fCheckOnlySignCommand(
+ const CtapMakeCredentialRequest& request,
+ const PublicKeyCredentialDescriptor& key_handle);
+
+// Extracts APDU encoded U2F sign command from CtapGetAssertionRequest.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConvertToU2fSignCommand(
+ const CtapGetAssertionRequest& request,
+ ApplicationParameterType application_parameter_type,
+ base::span<const uint8_t> key_handle,
+ bool check_only = false);
+
+// TODO(hongjunchoi): Move this logic inside ConvertToU2fRegisterCommand()
+// once U2fRegister is removed.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConstructU2fRegisterCommand(
+ base::span<const uint8_t> application_parameter,
+ base::span<const uint8_t> challenge_parameter,
+ bool is_individual_attestation = false);
+
+// TODO(hongjunchoi): Move this logic inside ConvertToU2fSignCommand() once
+// U2fSign is deleted.
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConstructU2fSignCommand(
+ base::span<const uint8_t> application_parameter,
+ base::span<const uint8_t> challenge_parameter,
+ base::span<const uint8_t> key_handle,
+ bool check_only = false);
+
+COMPONENT_EXPORT(DEVICE_FIDO)
+base::Optional<std::vector<uint8_t>> ConstructBogusU2fRegistrationCommand();
+
+} // namespace device
+
+#endif // DEVICE_FIDO_U2F_COMMAND_CONSTRUCTOR_H_
diff --git a/chromium/device/fido/u2f_command_constructor_unittest.cc b/chromium/device/fido/u2f_command_constructor_unittest.cc
new file mode 100644
index 00000000000..2824ba44fc8
--- /dev/null
+++ b/chromium/device/fido/u2f_command_constructor_unittest.cc
@@ -0,0 +1,240 @@
+// 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/u2f_command_constructor.h"
+
+#include <utility>
+
+#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_parsing_utils.h"
+#include "device/fido/fido_test_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+CtapMakeCredentialRequest ConstructMakeCredentialRequest() {
+ PublicKeyCredentialRpEntity rp("acme.com");
+ rp.SetRpName("acme.com");
+
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(test_data::kUserId));
+ user.SetUserName("johnpsmith@example.com")
+ .SetDisplayName("John P. Smith")
+ .SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+
+ return CtapMakeCredentialRequest(
+ fido_parsing_utils::Materialize(test_data::kClientDataHash),
+ std::move(rp), std::move(user),
+ PublicKeyCredentialParams(PublicKeyCredentialParams(
+ std::vector<PublicKeyCredentialParams::CredentialInfo>(1))));
+}
+
+CtapGetAssertionRequest ConstructGetAssertionRequest() {
+ return CtapGetAssertionRequest(
+ "acme.com", fido_parsing_utils::Materialize(test_data::kClientDataHash));
+}
+
+} // namespace
+
+TEST(U2fCommandConstructorTest, TestCreateU2fRegisterCommand) {
+ const auto& register_command_without_individual_attestation =
+ ConstructU2fRegisterCommand(test_data::kApplicationParameter,
+ test_data::kChallengeParameter,
+ false /* is_individual_attestation */);
+
+ ASSERT_TRUE(register_command_without_individual_attestation);
+ EXPECT_THAT(*register_command_without_individual_attestation,
+ ::testing::ElementsAreArray(test_data::kU2fRegisterCommandApdu));
+
+ const auto& register_command_with_individual_attestation =
+ ConstructU2fRegisterCommand(test_data::kApplicationParameter,
+ test_data::kChallengeParameter,
+ true /* is_individual_attestation */);
+
+ ASSERT_TRUE(register_command_with_individual_attestation);
+ EXPECT_THAT(*register_command_with_individual_attestation,
+ ::testing::ElementsAreArray(
+ test_data::kU2fRegisterCommandApduWithIndividualAttestation));
+}
+
+TEST(U2fCommandConstructorTest, TestCreateRegisterWithIncorrectParameters) {
+ std::vector<uint8_t> application_parameter(kU2fParameterLength, 0x01);
+ std::vector<uint8_t> challenge_parameter(kU2fParameterLength, 0xff);
+
+ const auto& register_command_without_individual_attestation =
+ ConstructU2fRegisterCommand(application_parameter, challenge_parameter,
+ false /* is_individual_attestation */);
+
+ ASSERT_TRUE(register_command_without_individual_attestation);
+ ASSERT_LE(3u, register_command_without_individual_attestation->size());
+ // Individual attestation bit should be cleared.
+ EXPECT_EQ(0, (*register_command_without_individual_attestation)[2] & 0x80);
+
+ const auto register_request_with_individual_attestation =
+ ConstructU2fRegisterCommand(application_parameter, challenge_parameter,
+ true /* is_individual_attestation */);
+
+ ASSERT_TRUE(register_request_with_individual_attestation);
+ ASSERT_LE(3u, register_request_with_individual_attestation->size());
+ // Individual attestation bit should be set.
+ EXPECT_EQ(0x80, (*register_request_with_individual_attestation)[2] & 0x80);
+
+ // Expect null result with incorrectly sized application_parameter.
+ application_parameter.push_back(0xff);
+ auto incorrect_register_cmd =
+ ConstructU2fRegisterCommand(application_parameter, challenge_parameter,
+ false /* is_individual_attestation */);
+
+ EXPECT_FALSE(incorrect_register_cmd);
+ application_parameter.pop_back();
+
+ // Expect null result with incorrectly sized challenge.
+ challenge_parameter.push_back(0xff);
+ incorrect_register_cmd =
+ ConstructU2fRegisterCommand(application_parameter, challenge_parameter,
+ false /* is_individual_attestation */);
+
+ EXPECT_FALSE(incorrect_register_cmd);
+}
+
+TEST(U2fCommandConstructorTest, TestConvertCtapMakeCredentialToU2fRegister) {
+ const auto make_credential_param = ConstructMakeCredentialRequest();
+
+ EXPECT_TRUE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+
+ const auto u2f_register_command =
+ ConvertToU2fRegisterCommand(make_credential_param);
+ ASSERT_TRUE(u2f_register_command);
+ EXPECT_THAT(*u2f_register_command,
+ ::testing::ElementsAreArray(test_data::kU2fRegisterCommandApdu));
+}
+
+TEST(U2fCommandConstructorTest,
+ TestConvertCtapMakeCredentialToU2fCheckOnlySign) {
+ auto make_credential_param = ConstructMakeCredentialRequest();
+ PublicKeyCredentialDescriptor credential_descriptor(
+ CredentialType::kPublicKey,
+ fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle));
+ std::vector<PublicKeyCredentialDescriptor> exclude_list;
+ exclude_list.push_back(credential_descriptor);
+ make_credential_param.SetExcludeList(std::move(exclude_list));
+ EXPECT_TRUE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+
+ const auto u2f_check_only_sign = ConvertToU2fCheckOnlySignCommand(
+ make_credential_param, credential_descriptor);
+
+ ASSERT_TRUE(u2f_check_only_sign);
+ EXPECT_THAT(
+ *u2f_check_only_sign,
+ ::testing::ElementsAreArray(test_data::kU2fCheckOnlySignCommandApdu));
+}
+
+TEST(U2fCommandConstructorTest,
+ TestConvertCtapMakeCredentialToU2fCheckOnlySignWithInvalidCredentialType) {
+ auto make_credential_param = ConstructMakeCredentialRequest();
+ PublicKeyCredentialDescriptor credential_descriptor(
+ // Purposefully construct an invalid CredentialType.
+ static_cast<CredentialType>(-1),
+ fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle));
+ std::vector<PublicKeyCredentialDescriptor> exclude_list;
+ exclude_list.push_back(credential_descriptor);
+ make_credential_param.SetExcludeList(std::move(exclude_list));
+ EXPECT_TRUE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+
+ const auto u2f_check_only_sign = ConvertToU2fCheckOnlySignCommand(
+ make_credential_param, credential_descriptor);
+
+ EXPECT_FALSE(u2f_check_only_sign);
+}
+
+TEST(U2fCommandConstructorTest, TestU2fRegisterCredentialAlgorithmRequirement) {
+ PublicKeyCredentialRpEntity rp("acme.com");
+ rp.SetRpName("acme.com");
+
+ PublicKeyCredentialUserEntity user(
+ fido_parsing_utils::Materialize(test_data::kUserId));
+ user.SetUserName("johnpsmith@example.com")
+ .SetDisplayName("John P. Smith")
+ .SetIconUrl(GURL("https://pics.acme.com/00/p/aBjjjpqPb.png"));
+
+ CtapMakeCredentialRequest make_credential_param(
+ fido_parsing_utils::Materialize(test_data::kClientDataHash),
+ std::move(rp), std::move(user),
+ PublicKeyCredentialParams({{CredentialType::kPublicKey, -257}}));
+
+ EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+}
+
+TEST(U2fCommandConstructorTest, TestU2fRegisterUserVerificationRequirement) {
+ auto make_credential_param = ConstructMakeCredentialRequest();
+ make_credential_param.SetUserVerificationRequired(true);
+
+ EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+}
+
+TEST(U2fCommandConstructorTest, TestU2fRegisterResidentKeyRequirement) {
+ auto make_credential_param = ConstructMakeCredentialRequest();
+ make_credential_param.SetResidentKeySupported(true);
+
+ EXPECT_FALSE(IsConvertibleToU2fRegisterCommand(make_credential_param));
+}
+
+TEST(U2fCommandConstructorTest, TestCreateSignApduCommand) {
+ const auto& encoded_sign = ConstructU2fSignCommand(
+ test_data::kApplicationParameter, test_data::kChallengeParameter,
+ test_data::kU2fSignKeyHandle);
+ ASSERT_TRUE(encoded_sign);
+ EXPECT_THAT(*encoded_sign,
+ ::testing::ElementsAreArray(test_data::kU2fSignCommandApdu));
+
+ const auto encoded_sign_check_only = ConstructU2fSignCommand(
+ test_data::kApplicationParameter, test_data::kChallengeParameter,
+ test_data::kU2fSignKeyHandle, true /* check_only */);
+ ASSERT_TRUE(encoded_sign_check_only);
+ EXPECT_THAT(
+ *encoded_sign_check_only,
+ ::testing::ElementsAreArray(test_data::kU2fCheckOnlySignCommandApdu));
+}
+
+TEST(U2fCommandConstructorTest, TestConvertCtapGetAssertionToU2fSignRequest) {
+ auto get_assertion_req = ConstructGetAssertionRequest();
+ std::vector<PublicKeyCredentialDescriptor> allowed_list;
+ allowed_list.push_back(PublicKeyCredentialDescriptor(
+ CredentialType::kPublicKey,
+ fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
+ get_assertion_req.SetAllowList(std::move(allowed_list));
+
+ const auto u2f_sign_command = ConvertToU2fSignCommand(
+ get_assertion_req, ApplicationParameterType::kPrimary,
+ fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle));
+
+ EXPECT_TRUE(IsConvertibleToU2fSignCommand(get_assertion_req));
+ ASSERT_TRUE(u2f_sign_command);
+ EXPECT_THAT(*u2f_sign_command,
+ ::testing::ElementsAreArray(test_data::kU2fSignCommandApdu));
+}
+
+TEST(U2fCommandConstructorTest, TestU2fSignAllowListRequirement) {
+ auto get_assertion_req = ConstructGetAssertionRequest();
+ EXPECT_FALSE(IsConvertibleToU2fSignCommand(get_assertion_req));
+}
+
+TEST(U2fCommandConstructorTest, TestU2fSignUserVerificationRequirement) {
+ auto get_assertion_req = ConstructGetAssertionRequest();
+ std::vector<PublicKeyCredentialDescriptor> allowed_list;
+ allowed_list.push_back(PublicKeyCredentialDescriptor(
+ CredentialType::kPublicKey,
+ fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
+ get_assertion_req.SetAllowList(std::move(allowed_list));
+ get_assertion_req.SetUserVerification(UserVerificationRequirement::kRequired);
+
+ EXPECT_FALSE(IsConvertibleToU2fSignCommand(get_assertion_req));
+}
+
+} // namespace device
diff --git a/chromium/device/fido/u2f_register.cc b/chromium/device/fido/u2f_register.cc
index 4f6557cff85..a05818eaffc 100644
--- a/chromium/device/fido/u2f_register.cc
+++ b/chromium/device/fido/u2f_register.cc
@@ -10,6 +10,7 @@
#include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h"
#include "device/fido/authenticator_make_credential_response.h"
+#include "device/fido/u2f_command_constructor.h"
#include "services/service_manager/public/cpp/connector.h"
namespace device {
@@ -82,7 +83,7 @@ void U2fRegister::OnTryCheckRegistration(
// Duplicate registration found. Call bogus registration to check for
// user presence (touch) and terminate the registration process.
InitiateDeviceTransaction(
- U2fRequest::GetBogusRegisterCommand(),
+ ConstructBogusU2fRegistrationCommand(),
base::BindOnce(&U2fRegister::OnTryDevice, weak_factory_.GetWeakPtr(),
true /* is_duplicate_registration */));
break;
diff --git a/chromium/device/fido/u2f_register_unittest.cc b/chromium/device/fido/u2f_register_unittest.cc
index af6edcaac50..b29834525d9 100644
--- a/chromium/device/fido/u2f_register_unittest.cc
+++ b/chromium/device/fido/u2f_register_unittest.cc
@@ -9,21 +9,15 @@
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
-#include "components/cbor/cbor_writer.h"
-#include "device/fido/attestation_object.h"
-#include "device/fido/attested_credential_data.h"
-#include "device/fido/authenticator_data.h"
#include "device/fido/authenticator_make_credential_response.h"
-#include "device/fido/ec_public_key.h"
#include "device/fido/fake_fido_discovery.h"
-#include "device/fido/fido_attestation_statement.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/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
-#include "device/fido/virtual_fido_device.h"
+#include "device/fido/virtual_u2f_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,129 +27,8 @@ using ::testing::_;
namespace {
-constexpr bool kNoIndividualAttestation = false;
-constexpr bool kIndividualAttestation = true;
-
-// The attested credential data, excluding the public key bytes. Append
-// with kTestECPublicKeyCOSE to get the complete attestation data.
-constexpr uint8_t kTestAttestedCredentialDataPrefix[] = {
- // clang-format off
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // 16-byte aaguid
- 0x00, 0x40, // 2-byte length
- 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C,
- 0x26, 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17,
- 0x36, 0xC3, 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54,
- 0xD7, 0xFF, 0x94, 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B,
- 0xDD, 0x39, 0x6B, 0x64, 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00,
- 0xCC, 0xD4, 0x15, 0xCD, 0x08, 0xFE, 0x42, 0x00, 0x38, // 64-byte key handle
- // clang-format on
-};
-
-// The authenticator data, excluding the attested credential data bytes. Append
-// with attested credential data to get the complete authenticator data.
-constexpr uint8_t kTestAuthenticatorDataPrefix[] = {
- // clang-format off
- // sha256 hash of rp id.
- 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, // flags (TUP and AT bits set)
- 0x00, 0x00, 0x00, 0x00 // counter
- // clang-format on
-};
-
-// Components of the CBOR needed to form an authenticator object.
-// Combined diagnostic notation:
-// {"fmt": "fido-u2f", "attStmt": {"sig": h'30...}, "authData": h'D4C9D9...'}
-constexpr uint8_t kFormatFidoU2fCBOR[] = {
- // clang-format off
- 0xA3, // map(3)
- 0x63, // text(3)
- 0x66, 0x6D, 0x74, // "fmt"
- 0x68, // text(8)
- 0x66, 0x69, 0x64, 0x6F, 0x2D, 0x75, 0x32, 0x66 // "fido-u2f"
- // clang-format on
-};
-
-constexpr uint8_t kAttStmtCBOR[] = {
- // clang-format off
- 0x67, // text(7)
- 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74 // "attStmt"
- // clang-format on
-};
-
-constexpr uint8_t kAuthDataCBOR[] = {
- // clang-format off
- 0x68, // text(8)
- 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, // "authData"
- 0x58, 0xC4 // bytes(196). i.e.,the authenticator_data bytearray
- // clang-format on
-};
-
-// Helpers for testing U2f register responses.
-std::vector<uint8_t> GetTestECPublicKeyCOSE() {
- return u2f_parsing_utils::Materialize(test_data::kTestECPublicKeyCOSE);
-}
-
-std::vector<uint8_t> GetTestRegisterResponse() {
- return u2f_parsing_utils::Materialize(test_data::kTestU2fRegisterResponse);
-}
-
std::vector<uint8_t> GetTestRegisterRequest() {
- return u2f_parsing_utils::Materialize(test_data::kU2fRegisterCommandApdu);
-}
-
-std::vector<uint8_t> GetTestCredentialRawIdBytes() {
- return u2f_parsing_utils::Materialize(test_data::kU2fSignKeyHandle);
-}
-
-std::vector<uint8_t> GetU2fAttestationStatementCBOR() {
- return u2f_parsing_utils::Materialize(
- test_data::kU2fAttestationStatementCBOR);
-}
-
-std::vector<uint8_t> GetTestAttestedCredentialDataBytes() {
- // Combine kTestAttestedCredentialDataPrefix and kTestECPublicKeyCOSE.
- auto test_attested_data =
- u2f_parsing_utils::Materialize(kTestAttestedCredentialDataPrefix);
- test_attested_data.insert(test_attested_data.end(),
- std::begin(test_data::kTestECPublicKeyCOSE),
- std::end(test_data::kTestECPublicKeyCOSE));
- return test_attested_data;
-}
-
-std::vector<uint8_t> GetTestAuthenticatorDataBytes() {
- // Build the test authenticator data.
- auto test_authenticator_data =
- u2f_parsing_utils::Materialize(kTestAuthenticatorDataPrefix);
- std::vector<uint8_t> test_attested_data =
- GetTestAttestedCredentialDataBytes();
- test_authenticator_data.insert(test_authenticator_data.end(),
- test_attested_data.begin(),
- test_attested_data.end());
- return test_authenticator_data;
-}
-
-std::vector<uint8_t> GetTestAttestationObjectBytes() {
- auto test_authenticator_object =
- u2f_parsing_utils::Materialize(kFormatFidoU2fCBOR);
- test_authenticator_object.insert(test_authenticator_object.end(),
- std::begin(kAttStmtCBOR),
- std::end(kAttStmtCBOR));
- test_authenticator_object.insert(
- test_authenticator_object.end(),
- std::begin(test_data::kU2fAttestationStatementCBOR),
- std::end(test_data::kU2fAttestationStatementCBOR));
- test_authenticator_object.insert(test_authenticator_object.end(),
- std::begin(kAuthDataCBOR),
- std::end(kAuthDataCBOR));
- std::vector<uint8_t> test_authenticator_data =
- GetTestAuthenticatorDataBytes();
- test_authenticator_object.insert(test_authenticator_object.end(),
- test_authenticator_data.begin(),
- test_authenticator_data.end());
- return test_authenticator_object;
+ return fido_parsing_utils::Materialize(test_data::kU2fRegisterCommandApdu);
}
using TestRegisterCallback = ::device::test::StatusAndValueCallbackReceiver<
@@ -185,22 +58,20 @@ class U2fRegisterTest : public ::testing::Test {
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
registered_keys,
- u2f_parsing_utils::Materialize(test_data::kChallengeParameter),
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- kNoIndividualAttestation, register_callback_receiver_.callback());
+ fido_parsing_utils::Materialize(test_data::kChallengeParameter),
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ false /* is_individual_attestation */,
+ register_callback_receiver_.callback());
}
test::FakeFidoDiscovery* discovery() const { return discovery_; }
+
TestRegisterCallback& register_callback_receiver() {
return register_callback_receiver_;
}
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
- std::vector<uint8_t> application_parameter_ =
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter);
- std::vector<uint8_t> challenge_parameter_ =
- u2f_parsing_utils::Materialize(test_data::kChallengeParameter);
std::vector<std::vector<uint8_t>> key_handles_;
base::flat_set<FidoTransportProtocol> protocols_;
test::ScopedFakeFidoDiscoveryFactory scoped_fake_discovery_factory_;
@@ -208,69 +79,6 @@ class U2fRegisterTest : public ::testing::Test {
TestRegisterCallback register_callback_receiver_;
};
-TEST_F(U2fRegisterTest, TestCreateU2fRegisterCommand) {
- U2fRegister register_request(nullptr /* connector */, protocols_,
- key_handles_, challenge_parameter_,
- application_parameter_, kNoIndividualAttestation,
- register_callback_receiver().callback());
-
- const auto register_command_without_individual_attestation =
- register_request.GetU2fRegisterApduCommand(kNoIndividualAttestation);
-
- ASSERT_TRUE(register_command_without_individual_attestation);
- EXPECT_THAT(*register_command_without_individual_attestation,
- ::testing::ElementsAreArray(test_data::kU2fRegisterCommandApdu));
-
- const auto register_command_with_individual_attestation =
- register_request.GetU2fRegisterApduCommand(kIndividualAttestation);
- ASSERT_TRUE(register_command_with_individual_attestation);
- EXPECT_THAT(*register_command_with_individual_attestation,
- ::testing::ElementsAreArray(
- test_data::kU2fRegisterCommandApduWithIndividualAttestation));
-}
-
-TEST_F(U2fRegisterTest, TestCreateRegisterWithIncorrectParameters) {
- std::vector<uint8_t> application_parameter(kU2fParameterLength, 0x01);
- std::vector<uint8_t> challenge_parameter(kU2fParameterLength, 0xff);
-
- U2fRegister register_request(nullptr, protocols_, key_handles_,
- challenge_parameter, application_parameter,
- kNoIndividualAttestation,
- register_callback_receiver().callback());
- const auto register_without_individual_attestation =
- register_request.GetU2fRegisterApduCommand(kNoIndividualAttestation);
-
- ASSERT_TRUE(register_without_individual_attestation);
- ASSERT_LE(3u, register_without_individual_attestation->size());
- // Individual attestation bit should be cleared.
- EXPECT_EQ(0, (*register_without_individual_attestation)[2] & 0x80);
-
- const auto register_request_with_individual_attestation =
- register_request.GetU2fRegisterApduCommand(kIndividualAttestation);
- ASSERT_TRUE(register_request_with_individual_attestation);
- ASSERT_LE(3u, register_request_with_individual_attestation->size());
- // Individual attestation bit should be set.
- EXPECT_EQ(0x80, (*register_request_with_individual_attestation)[2] & 0x80);
-
- // Expect null result with incorrectly sized application_parameter.
- application_parameter.push_back(0xff);
- auto incorrect_register_cmd =
- U2fRegister(nullptr, protocols_, key_handles_, challenge_parameter,
- application_parameter, kNoIndividualAttestation,
- register_callback_receiver().callback())
- .GetU2fRegisterApduCommand(kNoIndividualAttestation);
- EXPECT_FALSE(incorrect_register_cmd);
- application_parameter.pop_back();
-
- // Expect null result with incorrectly sized challenge.
- challenge_parameter.push_back(0xff);
- incorrect_register_cmd =
- U2fRegister(nullptr, protocols_, key_handles_, challenge_parameter,
- application_parameter, kNoIndividualAttestation,
- register_callback_receiver().callback())
- .GetU2fRegisterApduCommand(kNoIndividualAttestation);
- EXPECT_FALSE(incorrect_register_cmd);
-}
TEST_F(U2fRegisterTest, TestRegisterSuccess) {
auto request = CreateRegisterRequest();
@@ -288,8 +96,8 @@ TEST_F(U2fRegisterTest, TestRegisterSuccess) {
register_callback_receiver().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(),
- register_callback_receiver().value()->raw_credential_id());
+ EXPECT_THAT(register_callback_receiver().value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
TEST_F(U2fRegisterTest, TestRegisterSuccessWithFake) {
@@ -297,7 +105,7 @@ TEST_F(U2fRegisterTest, TestRegisterSuccessWithFake) {
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
- auto device = std::make_unique<VirtualFidoDevice>();
+ auto device = std::make_unique<VirtualU2fDevice>();
discovery()->AddDevice(std::move(device));
register_callback_receiver().WaitForCallback();
@@ -328,8 +136,8 @@ TEST_F(U2fRegisterTest, TestDelayedSuccess) {
register_callback_receiver().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(),
- register_callback_receiver().value()->raw_credential_id());
+ EXPECT_THAT(register_callback_receiver().value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
TEST_F(U2fRegisterTest, TestMultipleDevices) {
@@ -359,8 +167,8 @@ TEST_F(U2fRegisterTest, TestMultipleDevices) {
register_callback_receiver().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(),
- register_callback_receiver().value()->raw_credential_id());
+ EXPECT_THAT(register_callback_receiver().value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
// Tests a scenario where a single device is connected and registration call
@@ -369,8 +177,8 @@ TEST_F(U2fRegisterTest, TestMultipleDevices) {
TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithExclusionList) {
// Simulate three unknown key handles.
auto request = CreateRegisterRequestWithRegisteredKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta)});
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta)});
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -383,14 +191,14 @@ TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithExclusionList) {
// call, MockFidoDevice::NoErrorRegister will be invoked after registration.
EXPECT_CALL(*device.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -409,8 +217,8 @@ TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithExclusionList) {
register_callback_receiver().WaitForCallback();
ASSERT_TRUE(register_callback_receiver().value());
EXPECT_EQ(FidoReturnCode::kSuccess, register_callback_receiver().status());
- EXPECT_EQ(GetTestCredentialRawIdBytes(),
- register_callback_receiver().value()->raw_credential_id());
+ EXPECT_THAT(register_callback_receiver().value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
// Tests a scenario where two devices are connected and registration call is
@@ -419,9 +227,9 @@ TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithExclusionList) {
TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
// Simulate three unknown key handles.
auto request = CreateRegisterRequestWithRegisteredKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
request->Start();
auto device0 = std::make_unique<MockFidoDevice>();
@@ -432,21 +240,21 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
// MockFidoDevice::NotSatisfied.
EXPECT_CALL(*device0.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device0.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device0.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyGamma),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -468,21 +276,21 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
// successful registration.
EXPECT_CALL(*device1.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device1.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device1.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyGamma),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -501,8 +309,8 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
register_callback_receiver().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(),
- register_callback_receiver().value()->raw_credential_id());
+ EXPECT_THAT(register_callback_receiver().value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
// Tests a scenario where single device is connected and registration is called
@@ -513,9 +321,9 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithExclusionList) {
TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithDuplicateHandle) {
// Simulate three unknown key handles followed by a duplicate key.
auto request = CreateRegisterRequestWithRegisteredKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -528,27 +336,27 @@ TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithDuplicateHandle) {
// MockFidoDevice::NoErrorRegister.
EXPECT_CALL(*device.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyGamma),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NoErrorSign));
EXPECT_CALL(*device.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fFakeRegisterCommand),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NoErrorRegister));
@@ -572,9 +380,9 @@ TEST_F(U2fRegisterTest, TestSingleDeviceRegistrationWithDuplicateHandle) {
TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithDuplicateHandle) {
// Simulate two unknown key handles followed by a duplicate key.
auto request = CreateRegisterRequestWithRegisteredKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleGamma)});
request->Start();
// Since the first device did not create any of the key handles provided in
@@ -585,21 +393,21 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithDuplicateHandle) {
EXPECT_CALL(*device0, GetId()).WillRepeatedly(testing::Return("device0"));
EXPECT_CALL(*device0.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device0.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device0.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyGamma),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -618,27 +426,27 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithDuplicateHandle) {
EXPECT_CALL(*device1, GetId()).WillRepeatedly(::testing::Return("device1"));
EXPECT_CALL(*device1.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(
*device1.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device1.get(),
DeviceTransactPtr(
- u2f_parsing_utils::Materialize(
+ fido_parsing_utils::Materialize(
test_data::kU2fCheckOnlySignCommandApduWithKeyGamma),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NoErrorSign));
EXPECT_CALL(*device1.get(),
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fFakeRegisterCommand),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NoErrorRegister));
@@ -654,100 +462,6 @@ TEST_F(U2fRegisterTest, TestMultipleDeviceRegistrationWithDuplicateHandle) {
EXPECT_FALSE(register_callback_receiver().value());
}
-// These test the parsing of the U2F raw bytes of the registration response.
-// Test that an EC public key serializes to CBOR properly.
-TEST_F(U2fRegisterTest, TestSerializedPublicKey) {
- std::unique_ptr<ECPublicKey> public_key =
- ECPublicKey::ExtractFromU2fRegistrationResponse(
- u2f_parsing_utils::kEs256, GetTestRegisterResponse());
- EXPECT_EQ(GetTestECPublicKeyCOSE(), public_key->EncodeAsCOSEKey());
-}
-
-// Test that the attestation statement cbor map is constructed properly.
-TEST_F(U2fRegisterTest, TestU2fAttestationStatementCBOR) {
- std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
- FidoAttestationStatement::CreateFromU2fRegisterResponse(
- GetTestRegisterResponse());
- auto cbor = cbor::CBORWriter::Write(
- cbor::CBORValue(fido_attestation_statement->GetAsCBORMap()));
- ASSERT_TRUE(cbor);
- EXPECT_EQ(GetU2fAttestationStatementCBOR(), *cbor);
-}
-
-// Tests that well-formed attested credential data serializes properly.
-TEST_F(U2fRegisterTest, TestAttestedCredentialData) {
- std::unique_ptr<ECPublicKey> public_key =
- ECPublicKey::ExtractFromU2fRegistrationResponse(
- u2f_parsing_utils::kEs256, GetTestRegisterResponse());
- base::Optional<AttestedCredentialData> attested_data =
- AttestedCredentialData::CreateFromU2fRegisterResponse(
- GetTestRegisterResponse(), std::move(public_key));
-
- EXPECT_EQ(GetTestAttestedCredentialDataBytes(),
- attested_data->SerializeAsBytes());
-}
-
-// Tests that well-formed authenticator data serializes properly.
-TEST_F(U2fRegisterTest, TestAuthenticatorData) {
- std::unique_ptr<ECPublicKey> public_key =
- ECPublicKey::ExtractFromU2fRegistrationResponse(
- u2f_parsing_utils::kEs256, GetTestRegisterResponse());
- base::Optional<AttestedCredentialData> attested_data =
- AttestedCredentialData::CreateFromU2fRegisterResponse(
- GetTestRegisterResponse(), std::move(public_key));
-
- constexpr uint8_t flags =
- static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
- static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
-
- AuthenticatorData authenticator_data(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter), flags,
- std::vector<uint8_t>(4) /* counter */, std::move(attested_data));
-
- EXPECT_EQ(GetTestAuthenticatorDataBytes(),
- authenticator_data.SerializeToByteArray());
-}
-
-// Tests that a U2F attestation object serializes properly.
-TEST_F(U2fRegisterTest, TestU2fAttestationObject) {
- std::unique_ptr<ECPublicKey> public_key =
- ECPublicKey::ExtractFromU2fRegistrationResponse(
- u2f_parsing_utils::kEs256, GetTestRegisterResponse());
- base::Optional<AttestedCredentialData> attested_data =
- AttestedCredentialData::CreateFromU2fRegisterResponse(
- GetTestRegisterResponse(), std::move(public_key));
-
- constexpr uint8_t flags =
- static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
- static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
- AuthenticatorData authenticator_data(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter), flags,
- std::vector<uint8_t>(4) /* counter */, std::move(attested_data));
-
- // Construct the attestation statement.
- std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
- FidoAttestationStatement::CreateFromU2fRegisterResponse(
- GetTestRegisterResponse());
-
- // Construct the attestation object.
- auto attestation_object = std::make_unique<AttestationObject>(
- std::move(authenticator_data), std::move(fido_attestation_statement));
-
- EXPECT_EQ(GetTestAttestationObjectBytes(),
- attestation_object->SerializeToCBOREncodedBytes());
-}
-
-// Test that a U2F register response is properly parsed.
-TEST_F(U2fRegisterTest, TestRegisterResponseData) {
- base::Optional<AuthenticatorMakeCredentialResponse> response =
- AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- GetTestRegisterResponse());
- EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_credential_id());
- EXPECT_EQ(GetTestAttestationObjectBytes(),
- response->GetCBOREncodedAttestationObject());
-}
-
MATCHER_P(IndicatesIndividualAttestation, expected, "") {
return arg.size() > 2 && ((arg[2] & 0x80) == 0x80) == expected;
}
@@ -764,7 +478,9 @@ TEST_F(U2fRegisterTest, TestIndividualAttestation) {
nullptr /* connector */,
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}) /* transports */,
- key_handles_, challenge_parameter_, application_parameter_,
+ key_handles_,
+ fido_parsing_utils::Materialize(test_data::kChallengeParameter),
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
individual_attestation, cb.callback());
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -782,7 +498,8 @@ TEST_F(U2fRegisterTest, TestIndividualAttestation) {
cb.WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, cb.status());
ASSERT_TRUE(cb.value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(), cb.value()->raw_credential_id());
+ EXPECT_THAT(cb.value()->raw_credential_id(),
+ ::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
}
diff --git a/chromium/device/fido/u2f_request.cc b/chromium/device/fido/u2f_request.cc
index f5fb0f26d2e..fd81c6cc2fa 100644
--- a/chromium/device/fido/u2f_request.cc
+++ b/chromium/device/fido/u2f_request.cc
@@ -13,7 +13,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/apdu/apdu_command.h"
-#include "components/apdu/apdu_response.h"
+#include "device/fido/u2f_command_constructor.h"
#include "services/service_manager/public/cpp/connector.h"
namespace device {
@@ -50,73 +50,18 @@ void U2fRequest::Start() {
}
}
-// static
-std::vector<uint8_t> U2fRequest::GetBogusRegisterCommand() {
- apdu::ApduCommand command;
- std::vector<uint8_t> data(kBogusChallenge.cbegin(), kBogusChallenge.cend());
- data.insert(data.end(), kBogusAppParam.cbegin(), kBogusAppParam.cend());
- command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kRegister));
- command.set_p1(kP1TupRequiredConsumed);
- command.set_data(data);
- return command.GetEncodedCommand();
-}
-
-// static
-std::vector<uint8_t> U2fRequest::GetU2fVersionApduCommand(
- bool is_legacy_version) {
- apdu::ApduCommand command;
- command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kVersion));
- // Set maximum expected response length to maximum length possible.
- command.set_response_length(kU2fMaxResponseSize);
- // Early U2F drafts defined the U2F version command a format
- // incompatible with ISO 7816-4, so 2 additional 0x0 bytes are necessary.
- // https://fidoalliance.org/specs/fido-u2f-v1.1-id-20160915/fido-u2f-raw-message-formats-v1.1-id-20160915.html#implementation-considerations
- auto version_cmd = command.GetEncodedCommand();
- if (is_legacy_version)
- version_cmd.insert(version_cmd.end(), kLegacyVersionSuffix.cbegin(),
- kLegacyVersionSuffix.cend());
-
- return version_cmd;
-}
-
base::Optional<std::vector<uint8_t>> U2fRequest::GetU2fSignApduCommand(
const std::vector<uint8_t>& application_parameter,
const std::vector<uint8_t>& key_handle,
bool is_check_only_sign) const {
- if (application_parameter.size() != kU2fParameterLength ||
- challenge_digest_.size() != kU2fParameterLength ||
- key_handle.size() > kMaxKeyHandleLength) {
- return base::nullopt;
- }
- apdu::ApduCommand command;
- std::vector<uint8_t> data(challenge_digest_.begin(), challenge_digest_.end());
- data.insert(data.end(), application_parameter.begin(),
- application_parameter.end());
- data.push_back(static_cast<uint8_t>(key_handle.size()));
- data.insert(data.end(), key_handle.begin(), key_handle.end());
- command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kSign));
- command.set_p1(is_check_only_sign ? kP1CheckOnly : kP1TupRequiredConsumed);
- command.set_data(data);
- command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
- return command.GetEncodedCommand();
+ return ConstructU2fSignCommand(application_parameter, challenge_digest_,
+ key_handle, is_check_only_sign);
}
base::Optional<std::vector<uint8_t>> U2fRequest::GetU2fRegisterApduCommand(
bool is_individual_attestation) const {
- if (application_parameter_.size() != kU2fParameterLength ||
- challenge_digest_.size() != kU2fParameterLength) {
- return base::nullopt;
- }
- apdu::ApduCommand command;
- std::vector<uint8_t> data(challenge_digest_.begin(), challenge_digest_.end());
- data.insert(data.end(), application_parameter_.begin(),
- application_parameter_.end());
- command.set_ins(base::strict_cast<uint8_t>(U2fApduInstruction::kRegister));
- command.set_p1(kP1TupRequiredConsumed |
- (is_individual_attestation ? kP1IndividualAttestation : 0));
- command.set_data(data);
- command.set_response_length(apdu::ApduCommand::kApduMaxResponseLength);
- return command.GetEncodedCommand();
+ return ConstructU2fRegisterCommand(application_parameter_, challenge_digest_,
+ is_individual_attestation);
}
void U2fRequest::Transition() {
@@ -151,31 +96,6 @@ void U2fRequest::InitiateDeviceTransaction(
current_device_->DeviceTransact(std::move(*cmd), std::move(callback));
}
-void U2fRequest::OnDeviceVersionRequest(
- VersionCallback callback,
- base::WeakPtr<FidoDevice> device,
- bool legacy,
- base::Optional<std::vector<uint8_t>> response) {
- const auto apdu_response =
- response ? apdu::ApduResponse::CreateFromMessage(std::move(*response))
- : base::nullopt;
- if (apdu_response &&
- apdu_response->status() == apdu::ApduResponse::Status::SW_NO_ERROR &&
- std::equal(apdu_response->data().cbegin(), apdu_response->data().cend(),
- kU2fVersionResponse.cbegin(), kU2fVersionResponse.cend())) {
- std::move(callback).Run(ProtocolVersion::kU2f);
- } else if (!legacy) {
- // Standard GetVersion failed, attempt legacy GetVersion command.
- device->DeviceTransact(
- GetU2fVersionApduCommand(true),
- base::BindOnce(&U2fRequest::OnDeviceVersionRequest,
- weak_factory_.GetWeakPtr(), std::move(callback), device,
- true /* legacy */));
- } else {
- std::move(callback).Run(ProtocolVersion::kUnknown);
- }
-}
-
void U2fRequest::AbandonCurrentDeviceAndTransition() {
DCHECK_NE(nullptr, current_device_);
abandoned_devices_.emplace_back(std::exchange(current_device_, nullptr));
diff --git a/chromium/device/fido/u2f_request.h b/chromium/device/fido/u2f_request.h
index 2ed0157a5f4..e8717f0fa7f 100644
--- a/chromium/device/fido/u2f_request.h
+++ b/chromium/device/fido/u2f_request.h
@@ -52,12 +52,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fRequest
// registration process. That is, check-only sign command is sent during
// registration to prevent duplicate registration.
//
- // Returns bogus register command to be used to verify user presence.
- static std::vector<uint8_t> GetBogusRegisterCommand();
- // Returns APDU formatted U2F version request command. If |is_legacy_version|
- // is set to true, suffix {0x00, 0x00} is added at the end.
- static std::vector<uint8_t> GetU2fVersionApduCommand(
- bool is_legacy_version = false);
// Returns APDU U2F request commands. Null optional is returned for
// incorrectly formatted parameter.
base::Optional<std::vector<uint8_t>> GetU2fSignApduCommand(
@@ -83,12 +77,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fRequest
// |current_device_|.
void InitiateDeviceTransaction(base::Optional<std::vector<uint8_t>> cmd,
FidoDevice::DeviceCallback callback);
- // Callback function to U2F version request. If non-legacy version request
- // fails, retry with legacy version request.
- void OnDeviceVersionRequest(VersionCallback callback,
- base::WeakPtr<FidoDevice> device,
- bool legacy,
- base::Optional<std::vector<uint8_t>> response);
virtual void TryDevice() = 0;
diff --git a/chromium/device/fido/u2f_request_unittest.cc b/chromium/device/fido/u2f_request_unittest.cc
index b4b9d930ca7..33124f01557 100644
--- a/chromium/device/fido/u2f_request_unittest.cc
+++ b/chromium/device/fido/u2f_request_unittest.cc
@@ -37,7 +37,7 @@ class FakeU2fRequest : public U2fRequest {
};
using TestVersionCallback =
- ::device::test::TestCallbackReceiver<ProtocolVersion>;
+ ::device::test::ValueCallbackReceiver<ProtocolVersion>;
} // namespace
@@ -361,48 +361,4 @@ TEST_F(U2fRequestTest, TestMultipleDiscoveriesWithFailures) {
}
}
-TEST_F(U2fRequestTest, TestEncodeVersionRequest) {
- constexpr uint8_t kEncodedU2fVersionRequest[] = {0x00, 0x03, 0x00, 0x00,
- 0x00, 0x00, 0x00};
- EXPECT_THAT(U2fRequest::GetU2fVersionApduCommand(),
- ::testing::ElementsAreArray(kEncodedU2fVersionRequest));
-
- // Legacy version command contains 2 extra null bytes compared to ISO 7816-4
- // format.
- constexpr uint8_t kEncodedU2fLegacyVersionRequest[] = {
- 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- EXPECT_THAT(U2fRequest::GetU2fVersionApduCommand(true),
- ::testing::ElementsAreArray(kEncodedU2fLegacyVersionRequest));
-}
-
-// Test a scenario when version request is sent to legacy U2F token.
-// After non-legacy version requests fails, legacy version request should be
-// sent to device as a retry.
-TEST_F(U2fRequestTest, TestLegacyVersionRequest) {
- auto* discovery = discovery_factory().ForgeNextHidDiscovery();
- FakeU2fRequest request({FidoTransportProtocol::kUsbHumanInterfaceDevice});
- request.Start();
-
- auto device0 = std::make_unique<MockFidoDevice>();
- EXPECT_CALL(*device0, GetId()).WillRepeatedly(::testing::Return("device0"));
- EXPECT_CALL(*device0,
- DeviceTransactPtr(U2fRequest::GetU2fVersionApduCommand(true), _))
- // Success response for legacy version request after retry.
- .WillOnce(testing::Invoke(MockFidoDevice::NoErrorVersion));
-
- auto* device_ptr = device0.get();
- discovery->AddDevice(std::move(device0));
-
- // Represents version callback received from legacy U2F token on initial
- // version request. Device responses with invalid protocol version (in this
- // case, empty byte array). Retry version request with legacy bit is expected
- // to be issued afterwards.
- request.OnDeviceVersionRequest(version_callback_receiver().callback(),
- device_ptr->GetWeakPtr(), false /* legacy */,
- std::vector<uint8_t>());
-
- EXPECT_EQ(ProtocolVersion::kU2f,
- std::get<0>(*version_callback_receiver().result()));
-}
-
} // namespace device
diff --git a/chromium/device/fido/u2f_sign.cc b/chromium/device/fido/u2f_sign.cc
index fd7b44df8e3..1cad2c8c8fa 100644
--- a/chromium/device/fido/u2f_sign.cc
+++ b/chromium/device/fido/u2f_sign.cc
@@ -8,6 +8,7 @@
#include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h"
+#include "device/fido/u2f_command_constructor.h"
#include "services/service_manager/public/cpp/connector.h"
namespace device {
@@ -137,7 +138,7 @@ void U2fSign::OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator it,
// it's not registered. Once the user consents to use the device,
// the relying party can inform them that it hasn't been registered.
InitiateDeviceTransaction(
- U2fRequest::GetBogusRegisterCommand(),
+ ConstructBogusU2fRegistrationCommand(),
base::BindOnce(&U2fSign::OnTryDevice, weak_factory_.GetWeakPtr(),
registered_keys_.cend(),
ApplicationParameterType::kPrimary));
diff --git a/chromium/device/fido/u2f_sign.h b/chromium/device/fido/u2f_sign.h
index 6dccad0afaa..10cad3e122b 100644
--- a/chromium/device/fido/u2f_sign.h
+++ b/chromium/device/fido/u2f_sign.h
@@ -49,19 +49,6 @@ class COMPONENT_EXPORT(DEVICE_FIDO) U2fSign : public U2fRequest {
~U2fSign() override;
private:
- // Enumerates the two types of |application_parameter| values used: the
- // "primary" value is the hash of the relying party ID[1] and is always
- // provided. The "alternative" value is the hash of a U2F AppID, specified in
- // an extension[2], for compatibility with keys that were registered with the
- // old API.
- //
- // [1] https://w3c.github.io/webauthn/#rp-id
- // [2] https://w3c.github.io/webauthn/#sctn-appid-extension
- enum class ApplicationParameterType {
- kPrimary,
- kAlternative,
- };
-
void TryDevice() override;
void OnTryDevice(std::vector<std::vector<uint8_t>>::const_iterator it,
ApplicationParameterType application_parameter_type,
diff --git a/chromium/device/fido/u2f_sign_unittest.cc b/chromium/device/fido/u2f_sign_unittest.cc
index 44c51211fda..23b972ddcc0 100644
--- a/chromium/device/fido/u2f_sign_unittest.cc
+++ b/chromium/device/fido/u2f_sign_unittest.cc
@@ -9,17 +9,15 @@
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "crypto/ec_private_key.h"
-#include "crypto/sha2.h"
-#include "device/fido/authenticator_data.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/fake_fido_discovery.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/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
-#include "device/fido/u2f_parsing_utils.h"
-#include "device/fido/virtual_fido_device.h"
+#include "device/fido/virtual_u2f_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,34 +28,11 @@ namespace device {
namespace {
std::vector<uint8_t> GetTestCredentialRawIdBytes() {
- return u2f_parsing_utils::Materialize(test_data::kU2fSignKeyHandle);
+ return fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle);
}
std::vector<uint8_t> GetU2fSignCommandWithCorrectCredential() {
- return u2f_parsing_utils::Materialize(test_data::kU2fSignCommandApdu);
-}
-
-std::vector<uint8_t> GetTestSignResponse() {
- return u2f_parsing_utils::Materialize(test_data::kTestU2fSignResponse);
-}
-
-std::vector<uint8_t> GetTestAuthenticatorData() {
- return u2f_parsing_utils::Materialize(test_data::kTestSignAuthenticatorData);
-}
-
-std::vector<uint8_t> GetTestAssertionSignature() {
- return u2f_parsing_utils::Materialize(test_data::kU2fSignature);
-}
-
-std::vector<uint8_t> GetTestSignatureCounter() {
- return u2f_parsing_utils::Materialize(test_data::kTestSignatureCounter);
-}
-
-// Get a subset of the response for testing error handling.
-std::vector<uint8_t> GetTestCorruptedSignResponse(size_t length) {
- DCHECK_LE(length, arraysize(test_data::kTestU2fSignResponse));
- return u2f_parsing_utils::Materialize(u2f_parsing_utils::ExtractSpan(
- test_data::kTestU2fSignResponse, 0, length));
+ return fido_parsing_utils::Materialize(test_data::kU2fSignCommandApdu);
}
using TestSignCallback = ::device::test::StatusAndValueCallbackReceiver<
@@ -87,8 +62,10 @@ class U2fSignTest : public ::testing::Test {
nullptr /* connector */,
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
- std::move(registered_keys), challenge_parameter_,
- application_parameter_, base::nullopt,
+ std::move(registered_keys),
+ fido_parsing_utils::Materialize(test_data::kChallengeParameter),
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ base::nullopt /* alt_application_parameter*/,
sign_callback_receiver_.callback());
}
@@ -97,32 +74,12 @@ class U2fSignTest : public ::testing::Test {
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
- std::vector<uint8_t> application_parameter_ =
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter);
- std::vector<uint8_t> challenge_parameter_ =
- u2f_parsing_utils::Materialize(test_data::kChallengeParameter);
test::ScopedFakeFidoDiscoveryFactory scoped_fake_discovery_factory_;
test::FakeFidoDiscovery* discovery_;
TestSignCallback sign_callback_receiver_;
base::flat_set<FidoTransportProtocol> protocols_;
};
-TEST_F(U2fSignTest, TestCreateSignApduCommand) {
- const auto u2f_sign = CreateSignRequest();
- const auto encoded_sign = u2f_sign->GetU2fSignApduCommand(
- application_parameter_, GetTestCredentialRawIdBytes());
- ASSERT_TRUE(encoded_sign);
- EXPECT_THAT(*encoded_sign,
- ::testing::ElementsAreArray(test_data::kU2fSignCommandApdu));
-
- const auto encoded_sign_check_only = u2f_sign->GetU2fSignApduCommand(
- application_parameter_, GetTestCredentialRawIdBytes(), true);
- ASSERT_TRUE(encoded_sign_check_only);
- EXPECT_THAT(
- *encoded_sign_check_only,
- ::testing::ElementsAreArray(test_data::kU2fCheckOnlySignCommandApdu));
-}
-
TEST_F(U2fSignTest, TestSignSuccess) {
auto request = CreateSignRequest();
request->Start();
@@ -141,8 +98,8 @@ TEST_F(U2fSignTest, TestSignSuccess) {
EXPECT_EQ(FidoReturnCode::kSuccess, sign_callback_receiver().status());
// Correct key was sent so a sign response is expected.
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
// Verify that we get the key handle used for signing.
EXPECT_THAT(GetTestCredentialRawIdBytes(),
@@ -154,18 +111,20 @@ TEST_F(U2fSignTest, TestSignSuccessWithFake) {
auto private_key = crypto::ECPrivateKey::Create();
std::string public_key;
private_key->ExportRawPublicKey(&public_key);
- std::vector<uint8_t> key_handle(32);
- crypto::SHA256HashString(public_key, key_handle.data(), key_handle.size());
+ auto key_handle = fido_parsing_utils::CreateSHA256Hash(public_key);
std::vector<std::vector<uint8_t>> handles{key_handle};
auto request = CreateSignRequestWithKeys(handles);
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
- auto device = std::make_unique<VirtualFidoDevice>();
+ auto device = std::make_unique<VirtualU2fDevice>();
device->mutable_state()->registrations.emplace(
- key_handle, VirtualFidoDevice::RegistrationData(
- std::move(private_key), application_parameter_, 42));
+ key_handle,
+ VirtualFidoDevice::RegistrationData(
+ std::move(private_key),
+ fido_parsing_utils::Materialize(test_data::kApplicationParameter),
+ 42));
discovery()->AddDevice(std::move(device));
sign_callback_receiver().WaitForCallback();
@@ -210,8 +169,8 @@ TEST_F(U2fSignTest, TestDelayedSuccess) {
EXPECT_EQ(FidoReturnCode::kSuccess, sign_callback_receiver().status());
// Correct key was sent so a sign response is expected.
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
// Verify that we get the key handle used for signing.
EXPECT_THAT(GetTestCredentialRawIdBytes(),
@@ -224,8 +183,8 @@ TEST_F(U2fSignTest, TestMultipleHandles) {
// tested first.
const auto correct_key_handle = GetTestCredentialRawIdBytes();
auto request = CreateSignRequestWithKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta),
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta),
correct_key_handle});
request->Start();
discovery()->WaitForCallToStartAndSimulateSuccess();
@@ -234,12 +193,12 @@ TEST_F(U2fSignTest, TestMultipleHandles) {
// Wrong key would respond with SW_WRONG_DATA.
EXPECT_CALL(*device, GetId()).WillRepeatedly(::testing::Return("device"));
EXPECT_CALL(*device,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -257,9 +216,8 @@ TEST_F(U2fSignTest, TestMultipleHandles) {
EXPECT_EQ(FidoReturnCode::kSuccess, sign_callback_receiver().status());
// Correct key was sent so a sign response is expected.
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
-
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
// Verify that we get the key handle used for signing.
EXPECT_EQ(correct_key_handle,
sign_callback_receiver().value()->raw_credential_id());
@@ -269,7 +227,7 @@ TEST_F(U2fSignTest, TestMultipleDevices) {
const auto correct_key_handle = GetTestCredentialRawIdBytes();
auto request = CreateSignRequestWithKeys(
{GetTestCredentialRawIdBytes(),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha)});
+ fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha)});
request->Start();
auto device0 = std::make_unique<MockFidoDevice>();
@@ -278,7 +236,7 @@ TEST_F(U2fSignTest, TestMultipleDevices) {
DeviceTransactPtr(GetU2fSignCommandWithCorrectCredential(), _))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device0,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NotSatisfied));
@@ -304,8 +262,8 @@ TEST_F(U2fSignTest, TestMultipleDevices) {
EXPECT_EQ(FidoReturnCode::kSuccess, sign_callback_receiver().status());
// Correct key was sent so a sign response is expected.
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
// Verify that we get the key handle used for signing.
EXPECT_EQ(correct_key_handle,
@@ -314,19 +272,19 @@ TEST_F(U2fSignTest, TestMultipleDevices) {
TEST_F(U2fSignTest, TestFakeEnroll) {
auto request = CreateSignRequestWithKeys(
- {u2f_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
- u2f_parsing_utils::Materialize(test_data::kKeyHandleBeta)});
+ {fido_parsing_utils::Materialize(test_data::kKeyHandleAlpha),
+ fido_parsing_utils::Materialize(test_data::kKeyHandleBeta)});
request->Start();
auto device0 = std::make_unique<MockFidoDevice>();
EXPECT_CALL(*device0,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device0,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NotSatisfied));
@@ -340,17 +298,17 @@ TEST_F(U2fSignTest, TestFakeEnroll) {
EXPECT_CALL(*device1, GetId()).WillRepeatedly(::testing::Return("device1"));
// Both keys will be tried, when both fail, register is tried on that device.
EXPECT_CALL(*device1,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyAlpha),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device1,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fSignCommandApduWithKeyBeta),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device1,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fFakeRegisterCommand),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::NoErrorRegister));
@@ -380,7 +338,7 @@ TEST_F(U2fSignTest, TestFakeEnrollErroringOut) {
DeviceTransactPtr(GetU2fSignCommandWithCorrectCredential(), _))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
EXPECT_CALL(*device0,
- DeviceTransactPtr(u2f_parsing_utils::Materialize(
+ DeviceTransactPtr(fido_parsing_utils::Materialize(
test_data::kU2fFakeRegisterCommand),
_))
.WillOnce(::testing::Invoke(MockFidoDevice::WrongData));
@@ -403,65 +361,8 @@ TEST_F(U2fSignTest, TestFakeEnrollErroringOut) {
// Correct key was sent so a sign response is expected.
sign_callback_receiver().WaitForCallback();
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
-}
-
-TEST_F(U2fSignTest, TestAuthenticatorDataForSign) {
- constexpr uint8_t flags =
- static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
-
- EXPECT_EQ(GetTestAuthenticatorData(),
- AuthenticatorData(u2f_parsing_utils::Materialize(
- test_data::kApplicationParameter),
- flags, GetTestSignatureCounter(), base::nullopt)
- .SerializeToByteArray());
-}
-
-TEST_F(U2fSignTest, TestSignResponseData) {
- base::Optional<AuthenticatorGetAssertionResponse> response =
- AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- GetTestSignResponse(), GetTestCredentialRawIdBytes());
- ASSERT_TRUE(response.has_value());
- EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_credential_id());
- EXPECT_EQ(GetTestAuthenticatorData(),
- response->auth_data().SerializeToByteArray());
- EXPECT_EQ(GetTestAssertionSignature(), response->signature());
-}
-
-TEST_F(U2fSignTest, TestNullKeyHandle) {
- base::Optional<AuthenticatorGetAssertionResponse> response =
- AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- GetTestSignResponse(), std::vector<uint8_t>());
- EXPECT_FALSE(response);
-}
-
-TEST_F(U2fSignTest, TestNullResponse) {
- base::Optional<AuthenticatorGetAssertionResponse> response =
- AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- std::vector<uint8_t>(), GetTestCredentialRawIdBytes());
- EXPECT_FALSE(response);
-}
-
-TEST_F(U2fSignTest, TestCorruptedCounter) {
- // A sign response of less than 5 bytes.
- base::Optional<AuthenticatorGetAssertionResponse> response =
- AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- GetTestCorruptedSignResponse(3), GetTestCredentialRawIdBytes());
- EXPECT_FALSE(response);
-}
-
-TEST_F(U2fSignTest, TestCorruptedSignature) {
- // A sign response no more than 5 bytes.
- base::Optional<AuthenticatorGetAssertionResponse> response =
- AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse(
- u2f_parsing_utils::Materialize(test_data::kApplicationParameter),
- GetTestCorruptedSignResponse(5), GetTestCredentialRawIdBytes());
- EXPECT_FALSE(response);
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
}
// Device returns success, but the response is unparse-able.
@@ -538,8 +439,8 @@ TEST_F(U2fSignTest, TestAlternativeApplicationParameter) {
sign_callback_receiver().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, sign_callback_receiver().status());
- EXPECT_EQ(GetTestAssertionSignature(),
- sign_callback_receiver().value()->signature());
+ EXPECT_THAT(sign_callback_receiver().value()->signature(),
+ ::testing::ElementsAreArray(test_data::kU2fSignature));
EXPECT_EQ(signing_key_handle,
sign_callback_receiver().value()->raw_credential_id());
}
diff --git a/chromium/device/fido/virtual_fido_device.cc b/chromium/device/fido/virtual_fido_device.cc
index aef7dc80d4e..38a6112ef44 100644
--- a/chromium/device/fido/virtual_fido_device.cc
+++ b/chromium/device/fido/virtual_fido_device.cc
@@ -7,30 +7,14 @@
#include <tuple>
#include <utility>
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/apdu/apdu_command.h"
-#include "components/apdu/apdu_response.h"
#include "crypto/ec_private_key.h"
#include "crypto/ec_signature_creator.h"
-#include "crypto/sha2.h"
-#include "device/fido/fido_constants.h"
-#include "device/fido/u2f_parsing_utils.h"
-#include "net/cert/x509_util.h"
+#include "device/fido/fido_parsing_utils.h"
namespace device {
-
namespace {
-// First byte of registration response is 0x05 for historical reasons
-// not detailed in the spec.
-constexpr uint8_t kU2fRegistrationResponseHeader = 0x05;
-
// The example attestation private key from the U2F spec at
// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-example
//
@@ -49,24 +33,6 @@ constexpr uint8_t kAttestationKey[]{
0xd7, 0x86, 0x2f, 0x23, 0xab, 0xaf, 0x02, 0x03, 0xb4, 0xb8, 0x91, 0x1b,
0xa0, 0x56, 0x99, 0x94, 0xe1, 0x01};
-std::vector<uint8_t> GetAttestationKey() {
- return std::vector<uint8_t>(std::begin(kAttestationKey),
- std::end(kAttestationKey));
-}
-
-// Small helper to make the code below more readable.
-template <class T>
-void AppendTo(std::vector<uint8_t>* dst, const T& src) {
- dst->insert(dst->end(), std::begin(src), std::end(src));
-}
-
-// Returns an error response with the given status.
-base::Optional<std::vector<uint8_t>> ErrorStatus(
- apdu::ApduResponse::Status status) {
- return apdu::ApduResponse(std::vector<uint8_t>(), status)
- .GetEncodedResponse();
-}
-
} // namespace
// VirtualFidoDevice::RegistrationData ----------------------------------------
@@ -96,14 +62,12 @@ VirtualFidoDevice::State::~State() = default;
bool VirtualFidoDevice::State::InjectRegistration(
const std::vector<uint8_t>& credential_id,
const std::string& relying_party_id) {
- std::vector<uint8_t> application_parameter(crypto::kSHA256Length);
- crypto::SHA256HashString(relying_party_id, application_parameter.data(),
- application_parameter.size());
-
+ auto application_parameter =
+ fido_parsing_utils::CreateSHA256Hash(relying_party_id);
auto private_key = crypto::ECPrivateKey::Create();
- if (!private_key) {
+ if (!private_key)
return false;
- }
+
RegistrationData registration(std::move(private_key),
std::move(application_parameter),
0 /* signature counter */);
@@ -114,126 +78,33 @@ bool VirtualFidoDevice::State::InjectRegistration(
return was_inserted;
}
-VirtualFidoDevice::VirtualFidoDevice()
- : state_(new State), weak_factory_(this) {}
+VirtualFidoDevice::VirtualFidoDevice() = default;
// VirtualFidoDevice ----------------------------------------------------------
VirtualFidoDevice::VirtualFidoDevice(scoped_refptr<State> state)
- : state_(std::move(state)), weak_factory_(this) {}
+ : state_(std::move(state)) {}
VirtualFidoDevice::~VirtualFidoDevice() = default;
-void VirtualFidoDevice::TryWink(WinkCallback cb) {
- std::move(cb).Run();
+// static
+std::vector<uint8_t> VirtualFidoDevice::GetAttestationKey() {
+ return fido_parsing_utils::Materialize(kAttestationKey);
}
-// Cancel operation is not supported on U2F devices.
-void VirtualFidoDevice::Cancel() {}
-
-std::string VirtualFidoDevice::GetId() const {
- // Use our heap address to get a unique-ish number. (0xffe1 is a prime).
- return "VirtualFidoDevice-" + std::to_string((size_t)this % 0xffe1);
+// static
+bool VirtualFidoDevice::Sign(crypto::ECPrivateKey* private_key,
+ base::span<const uint8_t> sign_buffer,
+ std::vector<uint8_t>* signature) {
+ auto signer = crypto::ECSignatureCreator::Create(private_key);
+ return signer->Sign(sign_buffer.data(), sign_buffer.size(), signature);
}
-void VirtualFidoDevice::DeviceTransact(std::vector<uint8_t> command,
- DeviceCallback cb) {
- // Note, here we are using the code-under-test in this fake.
- auto parsed_command = apdu::ApduCommand::CreateFromMessage(command);
-
- // If malformed U2F request is received, respond with error immediately.
- if (!parsed_command) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- std::move(cb),
- ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED)));
- return;
- }
-
- base::Optional<std::vector<uint8_t>> response;
-
- switch (parsed_command->ins()) {
- case base::strict_cast<uint8_t>(U2fApduInstruction::kVersion):
- break;
- case base::strict_cast<uint8_t>(U2fApduInstruction::kRegister):
- response = DoRegister(parsed_command->ins(), parsed_command->p1(),
- parsed_command->p2(), parsed_command->data());
- break;
- case base::strict_cast<uint8_t>(U2fApduInstruction::kSign):
- response = DoSign(parsed_command->ins(), parsed_command->p1(),
- parsed_command->p2(), parsed_command->data());
- break;
- default:
- response = ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
- }
-
- // Call |callback| via the |MessageLoop| because |AuthenticatorImpl| doesn't
- // support callback hairpinning.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(cb), std::move(response)));
-}
-
-base::WeakPtr<FidoDevice> VirtualFidoDevice::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
-base::Optional<std::vector<uint8_t>> VirtualFidoDevice::DoRegister(
- uint8_t ins,
- uint8_t p1,
- uint8_t p2,
- base::span<const uint8_t> data) {
- if (data.size() != 64) {
- return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
- }
-
- if (mutable_state()->simulate_press_callback) {
- mutable_state()->simulate_press_callback.Run();
- }
-
- const bool individual_attestation_requested = p1 & kP1IndividualAttestation;
- // The spec says that the other bits of P1 should be zero. However, Chrome
- // sends Test User Presence (0x03) so we ignore those bits.
-
- auto challenge_param = data.first(32);
- auto application_parameter = data.last(32);
-
- // Create key to register.
- // Note: Non-deterministic, you need to mock this out if you rely on
- // deterministic behavior.
- auto private_key = crypto::ECPrivateKey::Create();
- std::string public_key;
- bool status = private_key->ExportRawPublicKey(&public_key);
- DCHECK(status);
- public_key.insert(0, 1, 0x04);
- DCHECK_EQ(public_key.size(), 65ul);
-
- // Our key handles are simple hashes of the public key.
- std::vector<uint8_t> key_handle(32);
- crypto::SHA256HashString(public_key, key_handle.data(), key_handle.size());
-
- // Data to be signed.
- std::vector<uint8_t> sign_buffer;
- sign_buffer.reserve(1 + application_parameter.size() +
- challenge_param.size() + key_handle.size() +
- public_key.size());
- sign_buffer.push_back(0x00);
- AppendTo(&sign_buffer, application_parameter);
- AppendTo(&sign_buffer, challenge_param);
- AppendTo(&sign_buffer, key_handle);
- AppendTo(&sign_buffer, public_key);
-
- // Sign with attestation key.
- // Note: Non-deterministic, you need to mock this out if you rely on
- // deterministic behavior.
- std::vector<uint8_t> sig;
+base::Optional<std::vector<uint8_t>>
+VirtualFidoDevice::GenerateAttestationCertificate(
+ bool individual_attestation_requested) const {
std::unique_ptr<crypto::ECPrivateKey> attestation_private_key =
crypto::ECPrivateKey::CreateFromPrivateKeyInfo(GetAttestationKey());
- auto signer =
- crypto::ECSignatureCreator::Create(attestation_private_key.get());
- status = signer->Sign(sign_buffer.data(), sign_buffer.size(), &sig);
- DCHECK(status);
-
constexpr uint32_t kAttestationCertSerialNumber = 1;
std::string attestation_cert;
if (!net::x509_util::CreateSelfSignedCert(
@@ -244,105 +115,19 @@ base::Optional<std::vector<uint8_t>> VirtualFidoDevice::DoRegister(
kAttestationCertSerialNumber, base::Time::FromTimeT(1500000000),
base::Time::FromTimeT(1500000000), &attestation_cert)) {
DVLOG(2) << "Failed to create attestation certificate";
- return ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
+ return base::nullopt;
}
- // U2F response data.
- std::vector<uint8_t> response;
- response.reserve(1 + public_key.size() + 1 + key_handle.size() +
- attestation_cert.size() + sig.size());
- response.push_back(kU2fRegistrationResponseHeader);
- AppendTo(&response, public_key);
- response.push_back(key_handle.size());
- AppendTo(&response, key_handle);
- AppendTo(&response, attestation_cert);
- AppendTo(&response, sig);
-
- // Store the registration. Because the key handle is the hashed public key we
- // just generated, no way this should already be registered.
- bool did_insert = false;
- std::tie(std::ignore, did_insert) = state_->registrations.emplace(
- std::move(key_handle),
- RegistrationData(std::move(private_key),
- u2f_parsing_utils::Materialize(application_parameter),
- 1));
- DCHECK(did_insert);
-
- return apdu::ApduResponse(std::move(response),
- apdu::ApduResponse::Status::SW_NO_ERROR)
- .GetEncodedResponse();
+ return std::vector<uint8_t>(attestation_cert.begin(), attestation_cert.end());
}
-base::Optional<std::vector<uint8_t>> VirtualFidoDevice::DoSign(
- uint8_t ins,
- uint8_t p1,
- uint8_t p2,
- base::span<const uint8_t> data) {
- if (!(p1 == kP1CheckOnly || p1 == kP1TupRequiredConsumed ||
- p1 == kP1IndividualAttestation) ||
- p2 != 0) {
- return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
- }
-
- if (mutable_state()->simulate_press_callback) {
- mutable_state()->simulate_press_callback.Run();
- }
-
- auto challenge_param = data.first(32);
- auto application_parameter = data.subspan(32, 32);
- size_t key_handle_length = data[64];
- if (data.size() != 32 + 32 + 1 + key_handle_length) {
- return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
- }
- auto key_handle = data.last(key_handle_length);
-
- // Check if this is our key_handle and it's for this appId.
- auto it = state_->registrations.find(
- std::vector<uint8_t>(key_handle.cbegin(), key_handle.cend()));
-
- if (it == state_->registrations.end()) {
- return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
- }
-
- base::span<const uint8_t> registered_app_id_hash =
- base::make_span(it->second.application_parameter);
- if (application_parameter != registered_app_id_hash) {
- // It's important this error looks identical to the previous one, as
- // tokens should not reveal the existence of keyHandles to unrelated appIds.
- return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
- }
-
- auto& registration = it->second;
- ++registration.counter;
-
- // First create the part of the response that gets signed over.
- std::vector<uint8_t> response;
- response.push_back(0x01); // Always pretend we got a touch.
- response.push_back(registration.counter >> 24);
- response.push_back(registration.counter >> 16);
- response.push_back(registration.counter >> 8);
- response.push_back(registration.counter);
-
- std::vector<uint8_t> sign_buffer;
- sign_buffer.reserve(application_parameter.size() + response.size() +
- challenge_param.size());
- AppendTo(&sign_buffer, application_parameter);
- AppendTo(&sign_buffer, response);
- AppendTo(&sign_buffer, challenge_param);
-
- // Sign with credential key.
- std::vector<uint8_t> sig;
- auto signer =
- crypto::ECSignatureCreator::Create(registration.private_key.get());
- bool status = signer->Sign(sign_buffer.data(), sign_buffer.size(), &sig);
- DCHECK(status);
-
- // Add signature for full response.
- AppendTo(&response, sig);
+void VirtualFidoDevice::TryWink(WinkCallback cb) {
+ std::move(cb).Run();
+}
- return apdu::ApduResponse(std::move(response),
- apdu::ApduResponse::Status::SW_NO_ERROR)
- .GetEncodedResponse();
+std::string VirtualFidoDevice::GetId() const {
+ // Use our heap address to get a unique-ish number. (0xffe1 is a prime).
+ return "VirtualFidoDevice-" + std::to_string((size_t)this % 0xffe1);
}
} // namespace device
diff --git a/chromium/device/fido/virtual_fido_device.h b/chromium/device/fido/virtual_fido_device.h
index f10e7dbc80c..66bc161ffb0 100644
--- a/chromium/device/fido/virtual_fido_device.h
+++ b/chromium/device/fido/virtual_fido_device.h
@@ -17,7 +17,10 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
#include "device/fido/fido_device.h"
+#include "device/fido/fido_parsing_utils.h"
+#include "net/cert/x509_util.h"
namespace crypto {
class ECPrivateKey;
@@ -49,7 +52,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
// Stores the state of the device. Since |U2fDevice| objects only persist for
// the lifetime of a single request, keeping state in an external object is
- // neccessary in order to provide continuity between requests.
+ // necessary in order to provide continuity between requests.
class COMPONENT_EXPORT(DEVICE_FIDO) State : public base::RefCounted<State> {
public:
State();
@@ -62,12 +65,18 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
std::string individual_attestation_cert_common_name;
// Registered keys. Keyed on key handle (a.k.a. "credential ID").
- std::map<std::vector<uint8_t>, RegistrationData> registrations;
+ std::map<std::vector<uint8_t>,
+ RegistrationData,
+ fido_parsing_utils::SpanLess>
+ registrations;
// If set, this callback is called whenever a "press" is required. It allows
// tests to change the state of the world during processing.
base::RepeatingCallback<void(void)> simulate_press_callback;
+ // If true, causes the response from the device to be invalid.
+ bool simulate_invalid_response = false;
+
// 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").
@@ -97,27 +106,24 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
State* mutable_state() { return state_.get(); }
protected:
+ static std::vector<uint8_t> GetAttestationKey();
+
+ static bool Sign(crypto::ECPrivateKey* private_key,
+ base::span<const uint8_t> sign_buffer,
+ std::vector<uint8_t>* signature);
+
+ // Constructs certificate encoded in X.509 format to be used for packed
+ // attestation statement and FIDO-U2F attestation statement.
+ // https://w3c.github.io/webauthn/#defined-attestation-formats
+ base::Optional<std::vector<uint8_t>> GenerateAttestationCertificate(
+ bool individual_attestation_requested) const;
+
// FidoDevice:
void TryWink(WinkCallback cb) override;
- void Cancel() override;
std::string GetId() const override;
- void DeviceTransact(std::vector<uint8_t> command, DeviceCallback cb) override;
- base::WeakPtr<FidoDevice> GetWeakPtr() override;
private:
- base::Optional<std::vector<uint8_t>> DoRegister(
- uint8_t ins,
- uint8_t p1,
- uint8_t p2,
- base::span<const uint8_t> data);
-
- base::Optional<std::vector<uint8_t>> DoSign(uint8_t ins,
- uint8_t p1,
- uint8_t p2,
- base::span<const uint8_t> data);
-
- scoped_refptr<State> state_;
- base::WeakPtrFactory<FidoDevice> weak_factory_;
+ scoped_refptr<State> state_ = base::MakeRefCounted<State>();
DISALLOW_COPY_AND_ASSIGN(VirtualFidoDevice);
};
diff --git a/chromium/device/fido/virtual_u2f_device.cc b/chromium/device/fido/virtual_u2f_device.cc
new file mode 100644
index 00000000000..fa38b41b215
--- /dev/null
+++ b/chromium/device/fido/virtual_u2f_device.cc
@@ -0,0 +1,261 @@
+// 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/virtual_u2f_device.h"
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/apdu/apdu_command.h"
+#include "components/apdu/apdu_response.h"
+#include "crypto/ec_private_key.h"
+#include "device/fido/fido_constants.h"
+#include "device/fido/fido_parsing_utils.h"
+
+namespace device {
+
+using fido_parsing_utils::Append;
+
+namespace {
+
+// First byte of registration response is 0x05 for historical reasons
+// not detailed in the spec.
+constexpr uint8_t kU2fRegistrationResponseHeader = 0x05;
+
+// Returns an error response with the given status.
+base::Optional<std::vector<uint8_t>> ErrorStatus(
+ apdu::ApduResponse::Status status) {
+ return apdu::ApduResponse(std::vector<uint8_t>(), status)
+ .GetEncodedResponse();
+}
+
+} // namespace
+
+VirtualU2fDevice::VirtualU2fDevice()
+ : VirtualFidoDevice(), weak_factory_(this) {}
+
+// VirtualU2fDevice ----------------------------------------------------------
+
+VirtualU2fDevice::VirtualU2fDevice(scoped_refptr<State> state)
+ : VirtualFidoDevice(std::move(state)), weak_factory_(this) {}
+
+VirtualU2fDevice::~VirtualU2fDevice() = default;
+
+// Cancel operation is not supported on U2F devices.
+void VirtualU2fDevice::Cancel() {}
+
+void VirtualU2fDevice::DeviceTransact(std::vector<uint8_t> command,
+ DeviceCallback cb) {
+ // Note, here we are using the code-under-test in this fake.
+ auto parsed_command = apdu::ApduCommand::CreateFromMessage(command);
+
+ // If malformed U2F request is received, respond with error immediately.
+ if (!parsed_command) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ std::move(cb),
+ ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED)));
+ return;
+ }
+
+ if (mutable_state()->simulate_invalid_response) {
+ std::vector<uint8_t> nonsense = {1, 2, 3};
+ auto response = apdu::ApduResponse(std::move(nonsense),
+ apdu::ApduResponse::Status::SW_NO_ERROR)
+ .GetEncodedResponse();
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(cb), std::move(response)));
+ return;
+ }
+
+ base::Optional<std::vector<uint8_t>> response;
+
+ switch (parsed_command->ins()) {
+ // Version request is defined by the U2F spec, but is never used in
+ // production code.
+ case base::strict_cast<uint8_t>(U2fApduInstruction::kVersion):
+ break;
+ case base::strict_cast<uint8_t>(U2fApduInstruction::kRegister):
+ response = DoRegister(parsed_command->ins(), parsed_command->p1(),
+ parsed_command->p2(), parsed_command->data());
+ break;
+ case base::strict_cast<uint8_t>(U2fApduInstruction::kSign):
+ response = DoSign(parsed_command->ins(), parsed_command->p1(),
+ parsed_command->p2(), parsed_command->data());
+ break;
+ default:
+ response = ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
+ }
+
+ // Call |callback| via the |MessageLoop| because |AuthenticatorImpl| doesn't
+ // support callback hairpinning.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(cb), std::move(response)));
+}
+
+base::WeakPtr<FidoDevice> VirtualU2fDevice::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+base::Optional<std::vector<uint8_t>> VirtualU2fDevice::DoRegister(
+ uint8_t ins,
+ uint8_t p1,
+ uint8_t p2,
+ base::span<const uint8_t> data) {
+ if (data.size() != 64) {
+ return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
+ }
+
+ if (mutable_state()->simulate_press_callback) {
+ mutable_state()->simulate_press_callback.Run();
+ }
+
+ auto challenge_param = data.first(32);
+ auto application_parameter = data.last(32);
+
+ // Create key to register.
+ // Note: Non-deterministic, you need to mock this out if you rely on
+ // deterministic behavior.
+ auto private_key = crypto::ECPrivateKey::Create();
+ std::string public_key;
+ bool status = private_key->ExportRawPublicKey(&public_key);
+ DCHECK(status);
+ public_key.insert(0, 1, 0x04);
+ DCHECK_EQ(public_key.size(), 65ul);
+
+ // Our key handles are simple hashes of the public key.
+ auto key_handle = fido_parsing_utils::CreateSHA256Hash(public_key);
+
+ // Data to be signed.
+ std::vector<uint8_t> sign_buffer;
+ sign_buffer.reserve(1 + application_parameter.size() +
+ challenge_param.size() + key_handle.size() +
+ public_key.size());
+ sign_buffer.push_back(0x00);
+ Append(&sign_buffer, application_parameter);
+ Append(&sign_buffer, challenge_param);
+ Append(&sign_buffer, key_handle);
+ Append(&sign_buffer, base::as_bytes(base::make_span(public_key)));
+
+ // Sign with attestation key.
+ // Note: Non-deterministic, you need to mock this out if you rely on
+ // deterministic behavior.
+ std::vector<uint8_t> sig;
+ std::unique_ptr<crypto::ECPrivateKey> attestation_private_key =
+ crypto::ECPrivateKey::CreateFromPrivateKeyInfo(GetAttestationKey());
+ status = Sign(attestation_private_key.get(), sign_buffer, &sig);
+ DCHECK(status);
+
+ // The spec says that the other bits of P1 should be zero. However, Chrome
+ // sends Test User Presence (0x03) so we ignore those bits.
+ bool individual_attestation_requested = p1 & kP1IndividualAttestation;
+ const auto attestation_cert =
+ GenerateAttestationCertificate(individual_attestation_requested);
+ if (!attestation_cert)
+ return ErrorStatus(apdu::ApduResponse::Status::SW_INS_NOT_SUPPORTED);
+
+ // U2F response data.
+ std::vector<uint8_t> response;
+ response.reserve(1 + public_key.size() + 1 + key_handle.size() +
+ attestation_cert->size() + sig.size());
+ response.push_back(kU2fRegistrationResponseHeader);
+ Append(&response, base::as_bytes(base::make_span(public_key)));
+ response.push_back(key_handle.size());
+ Append(&response, key_handle);
+ Append(&response, *attestation_cert);
+ Append(&response, sig);
+
+ // Store the registration. Because the key handle is the hashed public key we
+ // just generated, no way this should already be registered.
+ bool did_insert = false;
+ std::tie(std::ignore, did_insert) = mutable_state()->registrations.emplace(
+ std::move(key_handle),
+ RegistrationData(std::move(private_key),
+ fido_parsing_utils::Materialize(application_parameter),
+ 1));
+ DCHECK(did_insert);
+
+ return apdu::ApduResponse(std::move(response),
+ apdu::ApduResponse::Status::SW_NO_ERROR)
+ .GetEncodedResponse();
+}
+
+base::Optional<std::vector<uint8_t>> VirtualU2fDevice::DoSign(
+ uint8_t ins,
+ uint8_t p1,
+ uint8_t p2,
+ base::span<const uint8_t> data) {
+ if (!(p1 == kP1CheckOnly || p1 == kP1TupRequiredConsumed ||
+ p1 == kP1IndividualAttestation) ||
+ p2 != 0) {
+ return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
+ }
+
+ if (mutable_state()->simulate_press_callback) {
+ mutable_state()->simulate_press_callback.Run();
+ }
+
+ auto challenge_param = data.first(32);
+ auto application_parameter = data.subspan(32, 32);
+ size_t key_handle_length = data[64];
+ if (data.size() != 32 + 32 + 1 + key_handle_length) {
+ return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_LENGTH);
+ }
+ auto key_handle = data.last(key_handle_length);
+
+ // Check if this is our key_handle and it's for this appId.
+ auto it = mutable_state()->registrations.find(key_handle);
+ if (it == mutable_state()->registrations.end()) {
+ return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
+ }
+
+ base::span<const uint8_t> registered_app_id_hash =
+ base::make_span(it->second.application_parameter);
+ if (application_parameter != registered_app_id_hash) {
+ // It's important this error looks identical to the previous one, as
+ // tokens should not reveal the existence of keyHandles to unrelated appIds.
+ return ErrorStatus(apdu::ApduResponse::Status::SW_WRONG_DATA);
+ }
+
+ auto& registration = it->second;
+ ++registration.counter;
+
+ // First create the part of the response that gets signed over.
+ std::vector<uint8_t> response;
+ response.push_back(0x01); // Always pretend we got a touch.
+ response.push_back(registration.counter >> 24);
+ response.push_back(registration.counter >> 16);
+ response.push_back(registration.counter >> 8);
+ response.push_back(registration.counter);
+
+ std::vector<uint8_t> sign_buffer;
+ sign_buffer.reserve(application_parameter.size() + response.size() +
+ challenge_param.size());
+ Append(&sign_buffer, application_parameter);
+ Append(&sign_buffer, response);
+ Append(&sign_buffer, challenge_param);
+
+ // Sign with credential key.
+ std::vector<uint8_t> sig;
+ bool status = Sign(registration.private_key.get(), sign_buffer, &sig);
+ DCHECK(status);
+
+ // Add signature for full response.
+ Append(&response, sig);
+
+ return apdu::ApduResponse(std::move(response),
+ apdu::ApduResponse::Status::SW_NO_ERROR)
+ .GetEncodedResponse();
+}
+
+} // namespace device
diff --git a/chromium/device/fido/virtual_u2f_device.h b/chromium/device/fido/virtual_u2f_device.h
new file mode 100644
index 00000000000..aa47d4c9ada
--- /dev/null
+++ b/chromium/device/fido/virtual_u2f_device.h
@@ -0,0 +1,51 @@
+// 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_VIRTUAL_U2F_DEVICE_H_
+#define DEVICE_FIDO_VIRTUAL_U2F_DEVICE_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "device/fido/virtual_fido_device.h"
+
+namespace device {
+
+class COMPONENT_EXPORT(DEVICE_FIDO) VirtualU2fDevice
+ : public VirtualFidoDevice {
+ public:
+ VirtualU2fDevice();
+ explicit VirtualU2fDevice(scoped_refptr<State> state);
+ ~VirtualU2fDevice() override;
+
+ // FidoDevice:
+ void Cancel() override;
+ void DeviceTransact(std::vector<uint8_t> command, DeviceCallback cb) override;
+ base::WeakPtr<FidoDevice> GetWeakPtr() override;
+
+ private:
+ base::Optional<std::vector<uint8_t>> DoRegister(
+ uint8_t ins,
+ uint8_t p1,
+ uint8_t p2,
+ base::span<const uint8_t> data);
+
+ base::Optional<std::vector<uint8_t>> DoSign(uint8_t ins,
+ uint8_t p1,
+ uint8_t p2,
+ base::span<const uint8_t> data);
+
+ base::WeakPtrFactory<FidoDevice> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(VirtualU2fDevice);
+};
+
+} // namespace device
+
+#endif // DEVICE_FIDO_VIRTUAL_U2F_DEVICE_H_
diff --git a/chromium/device/gamepad/gamepad_platform_data_fetcher_win.h b/chromium/device/gamepad/gamepad_platform_data_fetcher_win.h
index 9925ca3dcec..fbf9afbd9c2 100644
--- a/chromium/device/gamepad/gamepad_platform_data_fetcher_win.h
+++ b/chromium/device/gamepad/gamepad_platform_data_fetcher_win.h
@@ -21,7 +21,6 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/scoped_native_library.h"
#include "device/gamepad/gamepad_data_fetcher.h"
#include "device/gamepad/gamepad_standard_mappings.h"
diff --git a/chromium/device/geolocation/geolocation_provider_impl_unittest.cc b/chromium/device/geolocation/geolocation_provider_impl_unittest.cc
index ce9524ba581..9f5f44a4458 100644
--- a/chromium/device/geolocation/geolocation_provider_impl_unittest.cc
+++ b/chromium/device/geolocation/geolocation_provider_impl_unittest.cc
@@ -13,7 +13,6 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
@@ -151,7 +150,7 @@ bool GeolocationProviderTest::ProvidersStarted() {
FROM_HERE,
base::BindOnce(&GeolocationProviderTest::GetProvidersStarted,
base::Unretained(this)),
- base::MessageLoop::QuitWhenIdleClosure());
+ base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
base::RunLoop().Run();
return is_started_;
}
diff --git a/chromium/device/media_transfer_protocol/BUILD.gn b/chromium/device/media_transfer_protocol/BUILD.gn
deleted file mode 100644
index 1cee23d7eca..00000000000
--- a/chromium/device/media_transfer_protocol/BUILD.gn
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2014 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.
-
-import("//build/config/features.gni")
-import("//third_party/protobuf/proto_library.gni")
-
-assert(is_chromeos)
-assert(use_dbus)
-
-proto_library("mtp_file_entry_proto") {
- sources = [
- "//third_party/cros_system_api/dbus/mtp_file_entry.proto",
- ]
- proto_out_dir = "device/media_transfer_protocol"
-}
-
-proto_library("mtp_storage_info_proto") {
- sources = [
- "//third_party/cros_system_api/dbus/mtp_storage_info.proto",
- ]
- proto_out_dir = "device/media_transfer_protocol"
-}
-
-static_library("media_transfer_protocol") {
- sources = [
- "media_transfer_protocol_daemon_client.cc",
- "media_transfer_protocol_daemon_client.h",
- "media_transfer_protocol_manager.cc",
- "media_transfer_protocol_manager.h",
- ]
-
- public_deps = [
- ":mtp_file_entry_proto",
- ":mtp_storage_info_proto",
- "//base",
- "//device/media_transfer_protocol/public/mojom",
- ]
- deps = [
- "//chromeos",
- "//dbus",
- ]
-}
diff --git a/chromium/device/media_transfer_protocol/DEPS b/chromium/device/media_transfer_protocol/DEPS
deleted file mode 100644
index b9845a38d93..00000000000
--- a/chromium/device/media_transfer_protocol/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
- # The media transfer protocol daemon uses D-Bus.
- "+dbus",
- "+chromeos/dbus",
- "+third_party/cros_system_api/dbus",
-]
diff --git a/chromium/device/media_transfer_protocol/OWNERS b/chromium/device/media_transfer_protocol/OWNERS
deleted file mode 100644
index 7f803eb8544..00000000000
--- a/chromium/device/media_transfer_protocol/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-satorux@chromium.org
-thestig@chromium.org
-
-# COMPONENT: Platform>Apps>FileManager
diff --git a/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
deleted file mode 100644
index 097fa5e67c1..00000000000
--- a/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
+++ /dev/null
@@ -1,554 +0,0 @@
-// Copyright (c) 2012 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/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "dbus/bus.h"
-#include "dbus/message.h"
-#include "dbus/object_path.h"
-#include "dbus/object_proxy.h"
-#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
-#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-
-namespace device {
-
-namespace {
-
-const char kInvalidResponseMsg[] = "Invalid Response: ";
-uint32_t kMaxChunkSize = 1024 * 1024; // D-Bus has message size limits.
-
-mojom::MtpFileEntry GetMojoMtpFileEntryFromProtobuf(
- const MtpFileEntry& entry) {
- return mojom::MtpFileEntry(
- entry.item_id(),
- entry.parent_id(),
- entry.file_name(),
- entry.file_size(),
- entry.modification_time(),
- static_cast<mojom::MtpFileEntry::FileType>(entry.file_type()));
-}
-
-mojom::MtpStorageInfo GetMojoMtpStorageInfoFromProtobuf(
- const MtpStorageInfo& protobuf) {
- return mojom::MtpStorageInfo(
- protobuf.storage_name(),
- protobuf.vendor(),
- protobuf.vendor_id(),
- protobuf.product(),
- protobuf.product_id(),
- protobuf.device_flags(),
- protobuf.storage_type(),
- protobuf.filesystem_type(),
- protobuf.access_capability(),
- protobuf.max_capacity(),
- protobuf.free_space_in_bytes(),
- protobuf.free_space_in_objects(),
- protobuf.storage_description(),
- protobuf.volume_identifier());
-}
-
-// The MediaTransferProtocolDaemonClient implementation.
-class MediaTransferProtocolDaemonClientImpl
- : public MediaTransferProtocolDaemonClient {
- public:
- explicit MediaTransferProtocolDaemonClientImpl(dbus::Bus* bus)
- : proxy_(bus->GetObjectProxy(
- mtpd::kMtpdServiceName,
- dbus::ObjectPath(mtpd::kMtpdServicePath))),
- listen_for_changes_called_(false),
- weak_ptr_factory_(this) {
- }
-
- // MediaTransferProtocolDaemonClient override.
- void EnumerateStorages(const EnumerateStoragesCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface,
- mtpd::kEnumerateStorages);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void GetStorageInfo(const std::string& storage_name,
- const GetStorageInfoCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetStorageInfo);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(storage_name);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
- weak_ptr_factory_.GetWeakPtr(),
- storage_name,
- callback,
- error_callback));
- }
-
- void GetStorageInfoFromDevice(const std::string& storage_name,
- const GetStorageInfoCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface,
- mtpd::kGetStorageInfoFromDevice);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(storage_name);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
- weak_ptr_factory_.GetWeakPtr(), storage_name, callback,
- error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void OpenStorage(const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(storage_name);
- DCHECK(mode == mtpd::kReadOnlyMode || mode == mtpd::kReadWriteMode);
- writer.AppendString(mode);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void CloseStorage(const std::string& handle,
- const CloseStorageCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCloseStorage);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- void CreateDirectory(const std::string& handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCreateDirectory);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendUint32(parent_id);
- writer.AppendString(directory_name);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCreateDirectory,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void ReadDirectoryEntryIds(const std::string& handle,
- uint32_t file_id,
- const ReadDirectoryEntryIdsCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface,
- mtpd::kReadDirectoryEntryIds);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendUint32(file_id);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectoryIds,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- void GetFileInfo(const std::string& handle,
- const std::vector<uint32_t>& file_ids,
- size_t offset,
- size_t entries_to_read,
- const GetFileInfoCallback& callback,
- const ErrorCallback& error_callback) override {
- if (offset >= file_ids.size()) {
- error_callback.Run();
- return;
- }
-
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfo);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- {
- dbus::MessageWriter array_writer(nullptr);
- writer.OpenArray("u", &array_writer);
-
- size_t end_offset = file_ids.size();
- if (offset <= SIZE_MAX - entries_to_read)
- end_offset = std::min(end_offset, offset + entries_to_read);
- for (size_t i = offset; i < end_offset; ++i)
- array_writer.AppendUint32(file_ids[i]);
-
- writer.CloseContainer(&array_writer);
- }
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void ReadFileChunk(const std::string& handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t bytes_to_read,
- const ReadFileCallback& callback,
- const ErrorCallback& error_callback) override {
- DCHECK_LE(bytes_to_read, kMaxChunkSize);
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kReadFileChunk);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendUint32(file_id);
- writer.AppendUint32(offset);
- writer.AppendUint32(bytes_to_read);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
- weak_ptr_factory_.GetWeakPtr(),
- callback,
- error_callback));
- }
-
- void RenameObject(const std::string& handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kRenameObject);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendUint32(object_id);
- writer.AppendString(new_name);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnRenameObject,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
- }
-
- void CopyFileFromLocal(const std::string& handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface,
- mtpd::kCopyFileFromLocal);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendFileDescriptor(source_file_descriptor);
- writer.AppendUint32(parent_id);
- writer.AppendString(file_name);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_INFINITE,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCopyFileFromLocal,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
- }
-
- void DeleteObject(const std::string& handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback,
- const ErrorCallback& error_callback) override {
- dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kDeleteObject);
- dbus::MessageWriter writer(&method_call);
- writer.AppendString(handle);
- writer.AppendUint32(object_id);
- proxy_->CallMethod(
- &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnDeleteObject,
- weak_ptr_factory_.GetWeakPtr(), callback, error_callback));
- }
-
- // MediaTransferProtocolDaemonClient override.
- void ListenForChanges(const MTPStorageEventHandler& handler) override {
- DCHECK(!listen_for_changes_called_);
- listen_for_changes_called_ = true;
-
- static const SignalEventTuple kSignalEventTuples[] = {
- { mtpd::kMTPStorageAttached, true },
- { mtpd::kMTPStorageDetached, false },
- };
- for (const auto& event : kSignalEventTuples) {
- proxy_->ConnectToSignal(
- mtpd::kMtpdInterface, event.signal_name,
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal,
- weak_ptr_factory_.GetWeakPtr(), handler, event.is_attach),
- base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected,
- weak_ptr_factory_.GetWeakPtr()));
- }
- }
-
- private:
- // A struct to contain a pair of signal name and attachment event type.
- // Used by SetUpConnections.
- struct SignalEventTuple {
- const char* signal_name;
- bool is_attach;
- };
-
- // Handles the result of EnumerateStorages and calls |callback| or
- // |error_callback|.
- void OnEnumerateStorages(const EnumerateStoragesCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
- dbus::MessageReader reader(response);
- std::vector<std::string> storage_names;
- if (!reader.PopArrayOfStrings(&storage_names)) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
- callback.Run(storage_names);
- }
-
- // Handles the result of GetStorageInfo and calls |callback| or
- // |error_callback|.
- void OnGetStorageInfo(const std::string& storage_name,
- const GetStorageInfoCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- dbus::MessageReader reader(response);
- MtpStorageInfo protobuf;
- if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
- callback.Run(GetMojoMtpStorageInfoFromProtobuf(protobuf));
- }
-
- // Handles the result of OpenStorage and calls |callback| or |error_callback|.
- void OnOpenStorage(const OpenStorageCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
- dbus::MessageReader reader(response);
- std::string handle;
- if (!reader.PopString(&handle)) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
- callback.Run(handle);
- }
-
- // Handles the result of CloseStorage and calls |callback| or
- // |error_callback|.
- void OnCloseStorage(const CloseStorageCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
- callback.Run();
- }
-
- void OnCreateDirectory(const CreateDirectoryCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
- callback.Run();
- }
-
- // Handles the result of ReadDirectoryEntryIds and calls |callback| or
- // |error_callback|.
- void OnReadDirectoryIds(const ReadDirectoryEntryIdsCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- dbus::MessageReader reader(response);
- dbus::MessageReader array_reader(nullptr);
- if (!reader.PopArray(&array_reader) || reader.HasMoreData()) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
-
- std::vector<uint32_t> file_ids;
- while (array_reader.HasMoreData()) {
- uint32_t file_id;
- if (!array_reader.PopUint32(&file_id)) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
- file_ids.push_back(file_id);
- }
- callback.Run(file_ids);
- }
-
- // Handles the result of GetFileInfo and calls |callback| or |error_callback|.
- void OnGetFileInfo(const GetFileInfoCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- dbus::MessageReader reader(response);
- MtpFileEntries entries_protobuf;
- if (!reader.PopArrayOfBytesAsProto(&entries_protobuf)) {
- LOG(ERROR) << kInvalidResponseMsg << response->ToString();
- error_callback.Run();
- return;
- }
-
- std::vector<mojom::MtpFileEntry> file_entries;
- file_entries.reserve(entries_protobuf.file_entries_size());
- for (int i = 0; i < entries_protobuf.file_entries_size(); ++i) {
- const auto& entry = entries_protobuf.file_entries(i);
- file_entries.push_back(
- GetMojoMtpFileEntryFromProtobuf(entry));
- }
- callback.Run(file_entries);
- }
-
- // Handles the result of ReadFileChunk and calls |callback| or
- // |error_callback|.
- void OnReadFile(const ReadFileCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- const uint8_t* data_bytes = nullptr;
- size_t data_length = 0;
- dbus::MessageReader reader(response);
- if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) {
- error_callback.Run();
- return;
- }
- std::string data(reinterpret_cast<const char*>(data_bytes), data_length);
- callback.Run(data);
- }
-
- void OnRenameObject(const RenameObjectCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- callback.Run();
- }
-
- void OnCopyFileFromLocal(const CopyFileFromLocalCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- callback.Run();
- }
-
- void OnDeleteObject(const DeleteObjectCallback& callback,
- const ErrorCallback& error_callback,
- dbus::Response* response) {
- if (!response) {
- error_callback.Run();
- return;
- }
-
- callback.Run();
- }
-
- // Handles MTPStorageAttached/Dettached signals and calls |handler|.
- void OnMTPStorageSignal(MTPStorageEventHandler handler,
- bool is_attach,
- dbus::Signal* signal) {
- dbus::MessageReader reader(signal);
- std::string storage_name;
- if (!reader.PopString(&storage_name)) {
- LOG(ERROR) << "Invalid signal: " << signal->ToString();
- return;
- }
- DCHECK(!storage_name.empty());
- handler.Run(is_attach, storage_name);
- }
-
-
- // Handles the result of signal connection setup.
- void OnSignalConnected(const std::string& interface,
- const std::string& signal,
- bool succeeded) {
- LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
- << signal << " failed.";
- }
-
- dbus::ObjectProxy* const proxy_;
-
- bool listen_for_changes_called_;
-
- // Note: This should remain the last member so it'll be destroyed and
- // invalidate its weak pointers before any other members are destroyed.
- base::WeakPtrFactory<MediaTransferProtocolDaemonClientImpl> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl);
-};
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// MediaTransferProtocolDaemonClient
-
-MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() =
- default;
-
-MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() =
- default;
-
-// static
-std::unique_ptr<MediaTransferProtocolDaemonClient>
-MediaTransferProtocolDaemonClient::Create(dbus::Bus* bus) {
- return std::make_unique<MediaTransferProtocolDaemonClientImpl>(bus);
-}
-
-} // namespace device
diff --git a/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
deleted file mode 100644
index e9ac3aadc52..00000000000
--- a/chromium/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2012 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.
-
-// Client code to talk to the Media Transfer Protocol daemon. The MTP daemon is
-// responsible for communicating with PTP / MTP capable devices like cameras
-// and smartphones.
-
-#ifndef DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
-#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "build/build_config.h"
-#include "device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom.h"
-#include "device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom.h"
-
-#if !defined(OS_CHROMEOS)
-#error "Only used on ChromeOS"
-#endif
-
-namespace dbus {
-class Bus;
-}
-
-namespace device {
-
-// A class to make the actual DBus calls for mtpd service.
-// This class only makes calls, result/error handling should be done
-// by callbacks.
-class MediaTransferProtocolDaemonClient {
- public:
- // A callback to be called when DBus method call fails.
- using ErrorCallback = base::Closure;
-
- // A callback to handle the result of EnumerateAutoMountableDevices.
- // The argument is the enumerated storage names.
- using EnumerateStoragesCallback =
- base::Callback<void(const std::vector<std::string>& storage_names)>;
-
- // A callback to handle the result of GetStorageInfo.
- // The argument is the information about the specified storage.
- using GetStorageInfoCallback =
- base::Callback<void(const mojom::MtpStorageInfo& storage_info)>;
-
- // A callback to handle the result of OpenStorage.
- // The argument is the returned handle.
- using OpenStorageCallback = base::Callback<void(const std::string& handle)>;
-
- // A callback to handle the result of CloseStorage.
- using CloseStorageCallback = base::Closure;
-
- // A callback to handle the result of CreateDirectory.
- using CreateDirectoryCallback = base::Closure;
-
- // A callback to handle the result of ReadDirectoryEntryIds.
- // The argument is a vector of file ids.
- using ReadDirectoryEntryIdsCallback =
- base::Callback<void(const std::vector<uint32_t>& file_ids)>;
-
- // A callback to handle the result of GetFileInfo.
- // The argument is a vector of file entries.
- using GetFileInfoCallback =
- base::Callback<void(const std::vector<mojom::MtpFileEntry>& file_entries)>;
-
- // A callback to handle the result of ReadFileChunkById.
- // The argument is a string containing the file data.
- using ReadFileCallback = base::Callback<void(const std::string& data)>;
-
- // A callback to handle the result of RenameObject.
- using RenameObjectCallback = base::Closure;
-
- // A callback to handle the result of CopyFileFromLocal.
- using CopyFileFromLocalCallback = base::Closure;
-
- // A callback to handle the result of DeleteObject.
- using DeleteObjectCallback = base::Closure;
-
- // A callback to handle storage attach/detach events.
- // The first argument is true for attach, false for detach.
- // The second argument is the storage name.
- using MTPStorageEventHandler =
- base::Callback<void(bool is_attach, const std::string& storage_name)>;
-
- virtual ~MediaTransferProtocolDaemonClient();
-
- // Calls EnumerateStorages method. |callback| is called after the
- // method call succeeds, otherwise, |error_callback| is called.
- virtual void EnumerateStorages(
- const EnumerateStoragesCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls GetStorageInfo method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- virtual void GetStorageInfo(const std::string& storage_name,
- const GetStorageInfoCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls GetStorageInfoFromDevice method. |callback| is called after the
- // method call succeeds, otherwise, |error_callback| is called.
- virtual void GetStorageInfoFromDevice(
- const std::string& storage_name,
- const GetStorageInfoCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls OpenStorage method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // OpenStorage returns a handle in |callback|.
- virtual void OpenStorage(const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls CloseStorage method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |handle| comes from a OpenStorageCallback.
- virtual void CloseStorage(const std::string& handle,
- const CloseStorageCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls CreateDirectory method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |parent_id| is an id of the parent directory.
- // |directory_name| is name of new directory.
- virtual void CreateDirectory(const std::string& handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls ReadDirectoryEntryIds method. |callback| is called after the method
- // call succeeds, otherwise, |error_callback| is called.
- // |file_id| is a MTP-device specific id for a file.
- virtual void ReadDirectoryEntryIds(
- const std::string& handle,
- uint32_t file_id,
- const ReadDirectoryEntryIdsCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls GetFileInfo method. |callback| is called after the method
- // call succeeds, otherwise, |error_callback| is called.
- // |file_ids| is a list of MTP-device specific file ids.
- // |offset| is the index into |file_ids| to read from.
- // |entries_to_read| is the maximum number of file entries to read.
- virtual void GetFileInfo(const std::string& handle,
- const std::vector<uint32_t>& file_ids,
- size_t offset,
- size_t entries_to_read,
- const GetFileInfoCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls ReadFileChunk method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |file_id| is a MTP-device specific id for a file.
- // |offset| is the offset into the file.
- // |bytes_to_read| cannot exceed 1 MiB.
- virtual void ReadFileChunk(const std::string& handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t bytes_to_read,
- const ReadFileCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls RenameObject method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |object_is| is an id of object to be renamed.
- // |new_name| is new name of the object.
- virtual void RenameObject(const std::string& handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls CopyFileFromLocal method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |source_file_descriptor| is a file descriptor of source file.
- // |parent_id| is a object id of a target directory.
- // |file_name| is a file name of a target file.
- virtual void CopyFileFromLocal(const std::string& handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Calls DeleteObject method. |callback| is called after the method call
- // succeeds, otherwise, |error_callback| is called.
- // |object_id| is an object id of a file or directory which is deleted.
- virtual void DeleteObject(const std::string& handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback,
- const ErrorCallback& error_callback) = 0;
-
- // Registers given callback for events. Should only be called once.
- // |storage_event_handler| is called when a mtp storage attach or detach
- // signal is received.
- virtual void ListenForChanges(const MTPStorageEventHandler& handler) = 0;
-
- // Factory function, creates a new instance.
- static std::unique_ptr<MediaTransferProtocolDaemonClient> Create(
- dbus::Bus* bus);
-
- protected:
- // Create() should be used instead.
- MediaTransferProtocolDaemonClient();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClient);
-};
-
-} // namespace device
-
-#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
diff --git a/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.cc b/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.cc
deleted file mode 100644
index c3a9ef0f4a0..00000000000
--- a/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.cc
+++ /dev/null
@@ -1,707 +0,0 @@
-// Copyright (c) 2012 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/media_transfer_protocol/media_transfer_protocol_manager.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/containers/flat_map.h"
-#include "base/containers/flat_set.h"
-#include "base/containers/queue.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/sequenced_task_runner.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_checker.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "dbus/bus.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
-#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
-#include "third_party/cros_system_api/dbus/service_constants.h"
-
-namespace device {
-
-namespace {
-
-#if DCHECK_IS_ON()
-MediaTransferProtocolManager* g_media_transfer_protocol_manager = nullptr;
-#endif
-
-// When reading directory entries, this is the number of entries for
-// GetFileInfo() to read in one operation. If set too low, efficiency goes down
-// slightly due to the overhead of D-Bus calls. If set too high, then slow
-// devices may trigger a D-Bus timeout.
-// The value below is a good initial estimate.
-const size_t kFileInfoToFetchChunkSize = 25;
-
-// On the first call to GetFileInfo, the offset to use is 0.
-const size_t kInitialOffset = 0;
-
-// The MediaTransferProtocolManager implementation.
-class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
- public:
- MediaTransferProtocolManagerImpl()
- : bus_(chromeos::DBusThreadManager::Get()->GetSystemBus()),
- weak_ptr_factory_(this) {
- // Listen for future mtpd service owner changes, in case it is not
- // available right now. There is no guarantee that mtpd is running already.
- mtpd_owner_changed_callback_ =
- base::Bind(&MediaTransferProtocolManagerImpl::FinishSetupOnOriginThread,
- weak_ptr_factory_.GetWeakPtr());
- if (bus_) {
- bus_->ListenForServiceOwnerChange(mtpd::kMtpdServiceName,
- mtpd_owner_changed_callback_);
- bus_->GetServiceOwner(mtpd::kMtpdServiceName,
- mtpd_owner_changed_callback_);
- }
- }
-
- ~MediaTransferProtocolManagerImpl() override {
-#if DCHECK_IS_ON()
- DCHECK(g_media_transfer_protocol_manager);
- g_media_transfer_protocol_manager = nullptr;
-#endif
- if (bus_) {
- bus_->UnlistenForServiceOwnerChange(mtpd::kMtpdServiceName,
- mtpd_owner_changed_callback_);
- }
-
- VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
- }
-
- // MediaTransferProtocolManager override.
- void AddObserverAndEnumerateStorages(
- Observer* observer,
- EnumerateStoragesCallback callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- // Return all available storage info.
- std::vector<const mojom::MtpStorageInfo*> storage_info_list;
- storage_info_list.reserve(storage_info_map_.size());
- for (const auto& info : storage_info_map_)
- storage_info_list.push_back(&info.second);
- std::move(callback).Run(std::move(storage_info_list));
-
- observers_.AddObserver(observer);
- }
-
- // MediaTransferProtocolManager override.
- void RemoveObserver(Observer* observer) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- observers_.RemoveObserver(observer);
- }
-
- // MediaTransferProtocolManager override.
- void GetStorages(GetStoragesCallback callback) const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- std::vector<std::string> storages;
- storages.reserve(storage_info_map_.size());
- for (const auto& info : storage_info_map_)
- storages.push_back(info.first);
- std::move(callback).Run(storages);
- }
-
- // MediaTransferProtocolManager override.
- void GetStorageInfo(const std::string& storage_name,
- GetStorageInfoCallback callback) const override {
- DCHECK(thread_checker_.CalledOnValidThread());
- const auto it = storage_info_map_.find(storage_name);
- const auto* storage_info =
- it != storage_info_map_.end() ? &it->second : nullptr;
- std::move(callback).Run(storage_info);
- }
-
- // MediaTransferProtocolManager override.
- void GetStorageInfoFromDevice(
- const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(storage_info_map_, storage_name) || !mtp_client_) {
- mojom::MtpStorageInfo info;
- callback.Run(info, true /* error */);
- return;
- }
- get_storage_info_from_device_callbacks_.push(callback);
- mtp_client_->GetStorageInfoFromDevice(
- storage_name,
- base::Bind(
- &MediaTransferProtocolManagerImpl::OnGetStorageInfoFromDevice,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(
- &MediaTransferProtocolManagerImpl::OnGetStorageInfoFromDeviceError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- // MediaTransferProtocolManager override.
- void OpenStorage(const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(storage_info_map_, storage_name) || !mtp_client_) {
- callback.Run(std::string(), true);
- return;
- }
- open_storage_callbacks_.push(callback);
- mtp_client_->OpenStorage(
- storage_name,
- mode,
- base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- // MediaTransferProtocolManager override.
- void CloseStorage(const std::string& storage_handle,
- const CloseStorageCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(true);
- return;
- }
- close_storage_callbacks_.push(std::make_pair(callback, storage_handle));
- mtp_client_->CloseStorage(
- storage_handle,
- base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void CreateDirectory(const std::string& storage_handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(true /* error */);
- return;
- }
- create_directory_callbacks_.push(callback);
- mtp_client_->CreateDirectory(
- storage_handle, parent_id, directory_name,
- base::Bind(&MediaTransferProtocolManagerImpl::OnCreateDirectory,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnCreateDirectoryError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- // MediaTransferProtocolManager override.
- void ReadDirectory(const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(std::vector<mojom::MtpFileEntry>(),
- false /* no more entries */,
- true /* error */);
- return;
- }
- read_directory_callbacks_.push(callback);
- mtp_client_->ReadDirectoryEntryIds(
- storage_handle, file_id,
- base::Bind(&MediaTransferProtocolManagerImpl::
- OnReadDirectoryEntryIdsToReadDirectory,
- weak_ptr_factory_.GetWeakPtr(), storage_handle, max_size),
- base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- // MediaTransferProtocolManager override.
- void ReadFileChunk(const std::string& storage_handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t count,
- const ReadFileCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(std::string(), true);
- return;
- }
- read_file_callbacks_.push(callback);
- mtp_client_->ReadFileChunk(
- storage_handle, file_id, offset, count,
- base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void GetFileInfo(const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(mojom::MtpFileEntry(), true);
- return;
- }
- std::vector<uint32_t> file_ids;
- file_ids.push_back(file_id);
- get_file_info_callbacks_.push(callback);
- mtp_client_->GetFileInfo(
- storage_handle,
- file_ids,
- kInitialOffset,
- file_ids.size(),
- base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void RenameObject(const std::string& storage_handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(true /* error */);
- return;
- }
- rename_object_callbacks_.push(callback);
- mtp_client_->RenameObject(
- storage_handle, object_id, new_name,
- base::Bind(&MediaTransferProtocolManagerImpl::OnRenameObject,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnRenameObjectError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void CopyFileFromLocal(const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(true /* error */);
- return;
- }
- copy_file_from_local_callbacks_.push(callback);
- mtp_client_->CopyFileFromLocal(
- storage_handle, source_file_descriptor, parent_id, file_name,
- base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocal,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocalError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void DeleteObject(const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) override {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, storage_handle) || !mtp_client_) {
- callback.Run(true /* error */);
- return;
- }
- delete_object_callbacks_.push(callback);
- mtp_client_->DeleteObject(
- storage_handle, object_id,
- base::Bind(&MediaTransferProtocolManagerImpl::OnDeleteObject,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&MediaTransferProtocolManagerImpl::OnDeleteObjectError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- private:
- // Map of storage names to storage info.
- using GetStorageInfoFromDeviceCallbackQueue =
- base::queue<GetStorageInfoFromDeviceCallback>;
- // Callback queues - DBus communication is in-order, thus callbacks are
- // received in the same order as the requests.
- using OpenStorageCallbackQueue = base::queue<OpenStorageCallback>;
- // (callback, handle)
- using CloseStorageCallbackQueue =
- base::queue<std::pair<CloseStorageCallback, std::string>>;
- using CreateDirectoryCallbackQueue = base::queue<CreateDirectoryCallback>;
- using ReadDirectoryCallbackQueue = base::queue<ReadDirectoryCallback>;
- using ReadFileCallbackQueue = base::queue<ReadFileCallback>;
- using GetFileInfoCallbackQueue = base::queue<GetFileInfoCallback>;
- using RenameObjectCallbackQueue = base::queue<RenameObjectCallback>;
- using CopyFileFromLocalCallbackQueue = base::queue<CopyFileFromLocalCallback>;
- using DeleteObjectCallbackQueue = base::queue<DeleteObjectCallback>;
-
- void OnStorageAttached(const std::string& storage_name) {
- DCHECK(thread_checker_.CalledOnValidThread());
- mtp_client_->GetStorageInfo(
- storage_name,
- base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
- weak_ptr_factory_.GetWeakPtr()),
- base::DoNothing());
- }
-
- void OnStorageDetached(const std::string& storage_name) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (storage_info_map_.erase(storage_name) == 0) {
- // This can happen for a storage where
- // MediaTransferProtocolDaemonClient::GetStorageInfo() failed.
- // Return to avoid giving observers phantom detach events.
- return;
- }
- for (auto& observer : observers_)
- observer.StorageDetached(storage_name);
- }
-
- void OnStorageChanged(bool is_attach, const std::string& storage_name) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(mtp_client_);
- if (is_attach)
- OnStorageAttached(storage_name);
- else
- OnStorageDetached(storage_name);
- }
-
- void OnEnumerateStorages(const std::vector<std::string>& storage_names) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(mtp_client_);
- for (const auto& name : storage_names) {
- if (base::ContainsKey(storage_info_map_, name)) {
- // OnStorageChanged() might have gotten called first.
- continue;
- }
- OnStorageAttached(name);
- }
- }
-
- void OnGetStorageInfo(const mojom::MtpStorageInfo& storage_info) {
- DCHECK(thread_checker_.CalledOnValidThread());
- const std::string& storage_name = storage_info.storage_name;
- if (base::ContainsKey(storage_info_map_, storage_name)) {
- // This should not happen, since MediaTransferProtocolManagerImpl should
- // only call EnumerateStorages() once, which populates |storage_info_map_|
- // with the already-attached devices.
- // After that, all incoming signals are either for new storage
- // attachments, which should not be in |storage_info_map_|, or for
- // storage detachments, which do not add to |storage_info_map_|.
- // Return to avoid giving observers phantom detach events.
- NOTREACHED();
- return;
- }
-
- // New storage. Add it and let the observers know.
- storage_info_map_.insert(std::make_pair(storage_name, storage_info));
-
- for (auto& observer : observers_)
- observer.StorageAttached(storage_info);
- }
-
- void OnGetStorageInfoFromDevice(const mojom::MtpStorageInfo& storage_info) {
- get_storage_info_from_device_callbacks_.front().Run(storage_info,
- false /* no error */);
- get_storage_info_from_device_callbacks_.pop();
- }
-
- void OnGetStorageInfoFromDeviceError() {
- mojom::MtpStorageInfo info;
- get_storage_info_from_device_callbacks_.front().Run(info, true /* error */);
- get_storage_info_from_device_callbacks_.pop();
- }
-
- void OnOpenStorage(const std::string& handle) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!base::ContainsKey(handles_, handle)) {
- handles_.insert(handle);
- open_storage_callbacks_.front().Run(handle, false);
- } else {
- NOTREACHED();
- open_storage_callbacks_.front().Run(std::string(), true);
- }
- open_storage_callbacks_.pop();
- }
-
- void OnOpenStorageError() {
- open_storage_callbacks_.front().Run(std::string(), true);
- open_storage_callbacks_.pop();
- }
-
- void OnCloseStorage() {
- DCHECK(thread_checker_.CalledOnValidThread());
- const std::string& handle = close_storage_callbacks_.front().second;
- if (base::ContainsKey(handles_, handle)) {
- handles_.erase(handle);
- close_storage_callbacks_.front().first.Run(false);
- } else {
- NOTREACHED();
- close_storage_callbacks_.front().first.Run(true);
- }
- close_storage_callbacks_.pop();
- }
-
- void OnCloseStorageError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- close_storage_callbacks_.front().first.Run(true);
- close_storage_callbacks_.pop();
- }
-
- void OnCreateDirectory() {
- DCHECK(thread_checker_.CalledOnValidThread());
- create_directory_callbacks_.front().Run(false /* no error */);
- create_directory_callbacks_.pop();
- }
-
- void OnCreateDirectoryError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- create_directory_callbacks_.front().Run(true /* error */);
- create_directory_callbacks_.pop();
- }
-
- void OnReadDirectoryEntryIdsToReadDirectory(
- const std::string& storage_handle,
- const size_t max_size,
- const std::vector<uint32_t>& file_ids) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (file_ids.empty()) {
- OnGotDirectoryEntries(storage_handle, file_ids, kInitialOffset, max_size,
- file_ids, std::vector<mojom::MtpFileEntry>());
- return;
- }
-
- std::vector<uint32_t> sorted_file_ids = file_ids;
- std::sort(sorted_file_ids.begin(), sorted_file_ids.end());
-
- const size_t chunk_size =
- max_size == 0 ? kFileInfoToFetchChunkSize
- : std::min(max_size, kFileInfoToFetchChunkSize);
-
- mtp_client_->GetFileInfo(
- storage_handle, file_ids, kInitialOffset, chunk_size,
- base::Bind(&MediaTransferProtocolManagerImpl::OnGotDirectoryEntries,
- weak_ptr_factory_.GetWeakPtr(), storage_handle, file_ids,
- kInitialOffset, max_size, sorted_file_ids),
- base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
- weak_ptr_factory_.GetWeakPtr()));
- }
-
- void OnGotDirectoryEntries(
- const std::string& storage_handle,
- const std::vector<uint32_t>& file_ids,
- const size_t offset,
- const size_t max_size,
- const std::vector<uint32_t>& sorted_file_ids,
- const std::vector<mojom::MtpFileEntry>& file_entries) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(file_ids.size(), sorted_file_ids.size());
-
- // Use |sorted_file_ids| to sanity check and make sure the results are a
- // subset of the requested file ids.
- for (const auto& entry : file_entries) {
- std::vector<uint32_t>::const_iterator it = std::lower_bound(
- sorted_file_ids.begin(), sorted_file_ids.end(), entry.item_id);
- if (it == sorted_file_ids.end()) {
- OnReadDirectoryError();
- return;
- }
- }
-
- const size_t directory_size =
- max_size == 0 ? file_ids.size() : std::min(file_ids.size(), max_size);
- size_t next_offset = directory_size;
- if (offset < SIZE_MAX - kFileInfoToFetchChunkSize)
- next_offset = std::min(next_offset, offset + kFileInfoToFetchChunkSize);
- bool has_more = next_offset < directory_size;
- read_directory_callbacks_.front().Run(file_entries,
- has_more,
- false /* no error */);
-
- if (has_more) {
- const size_t chunk_size =
- std::min(directory_size - next_offset, kFileInfoToFetchChunkSize);
-
- mtp_client_->GetFileInfo(
- storage_handle, file_ids, next_offset, chunk_size,
- base::Bind(&MediaTransferProtocolManagerImpl::OnGotDirectoryEntries,
- weak_ptr_factory_.GetWeakPtr(), storage_handle, file_ids,
- next_offset, max_size, sorted_file_ids),
- base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
- weak_ptr_factory_.GetWeakPtr()));
- return;
- }
- read_directory_callbacks_.pop();
- }
-
- void OnReadDirectoryError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- read_directory_callbacks_.front().Run(std::vector<mojom::MtpFileEntry>(),
- false /* no more entries */,
- true /* error */);
- read_directory_callbacks_.pop();
- }
-
- void OnReadFile(const std::string& data) {
- DCHECK(thread_checker_.CalledOnValidThread());
- read_file_callbacks_.front().Run(data, false);
- read_file_callbacks_.pop();
- }
-
- void OnReadFileError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- read_file_callbacks_.front().Run(std::string(), true);
- read_file_callbacks_.pop();
- }
-
- void OnGetFileInfo(const std::vector<mojom::MtpFileEntry>& entries) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (entries.size() == 1) {
- get_file_info_callbacks_.front().Run(entries[0], false /* no error */);
- get_file_info_callbacks_.pop();
- } else {
- OnGetFileInfoError();
- }
- }
-
- void OnGetFileInfoError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- get_file_info_callbacks_.front().Run(mojom::MtpFileEntry(), true);
- get_file_info_callbacks_.pop();
- }
-
- void OnRenameObject() {
- DCHECK(thread_checker_.CalledOnValidThread());
- rename_object_callbacks_.front().Run(false /* no error */);
- rename_object_callbacks_.pop();
- }
-
- void OnRenameObjectError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- rename_object_callbacks_.front().Run(true /* error */);
- rename_object_callbacks_.pop();
- }
-
- void OnCopyFileFromLocal() {
- DCHECK(thread_checker_.CalledOnValidThread());
- copy_file_from_local_callbacks_.front().Run(false /* no error */);
- copy_file_from_local_callbacks_.pop();
- }
-
- void OnCopyFileFromLocalError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- copy_file_from_local_callbacks_.front().Run(true /* error */);
- copy_file_from_local_callbacks_.pop();
- }
-
- void OnDeleteObject() {
- DCHECK(thread_checker_.CalledOnValidThread());
- delete_object_callbacks_.front().Run(false /* no error */);
- delete_object_callbacks_.pop();
- }
-
- void OnDeleteObjectError() {
- DCHECK(thread_checker_.CalledOnValidThread());
- delete_object_callbacks_.front().Run(true /* error */);
- delete_object_callbacks_.pop();
- }
-
- // Callback to finish initialization after figuring out if the mtpd service
- // has an owner, or if the service owner has changed.
- // |mtpd_service_owner| contains the name of the current owner, if any.
- void FinishSetupOnOriginThread(const std::string& mtpd_service_owner) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (mtpd_service_owner == current_mtpd_owner_)
- return;
-
- // In the case of a new service owner, clear |storage_info_map_|.
- // Assume all storages have been disconnected. If there is a new service
- // owner, reconnecting to it will reconnect all the storages as well.
-
- // Save a copy of |storage_info_map_| keys as |storage_info_map_| can
- // change in OnStorageDetached().
- std::vector<std::string> storage_names;
- storage_names.reserve(storage_info_map_.size());
- for (const auto& info : storage_info_map_)
- storage_names.push_back(info.first);
-
- for (const auto& name : storage_names)
- OnStorageDetached(name);
-
- if (mtpd_service_owner.empty()) {
- current_mtpd_owner_.clear();
- mtp_client_.reset();
- return;
- }
-
- current_mtpd_owner_ = mtpd_service_owner;
-
- // |bus_| must be valid here. Otherwise, how did this method get called as a
- // callback in the first place?
- DCHECK(bus_);
- mtp_client_ = MediaTransferProtocolDaemonClient::Create(bus_.get());
-
- // Set up signals and start initializing |storage_info_map_|.
- mtp_client_->ListenForChanges(
- base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged,
- weak_ptr_factory_.GetWeakPtr()));
- mtp_client_->EnumerateStorages(
- base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages,
- weak_ptr_factory_.GetWeakPtr()),
- base::DoNothing());
- }
-
- // Mtpd DBus client.
- std::unique_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
-
- // And a D-Bus session for talking to mtpd. Note: In production, this is never
- // a nullptr, but in tests it oftentimes is. It may be too much work for
- // DBusThreadManager to provide a bus in unit tests.
- scoped_refptr<dbus::Bus> const bus_;
-
- // Device attachment / detachment observers.
- base::ObserverList<Observer> observers_;
-
- // Map to keep track of attached storages by name.
- base::flat_map<std::string, mojom::MtpStorageInfo> storage_info_map_;
-
- // Set of open storage handles.
- base::flat_set<std::string> handles_;
-
- dbus::Bus::GetServiceOwnerCallback mtpd_owner_changed_callback_;
-
- std::string current_mtpd_owner_;
-
- // Queued callbacks.
- GetStorageInfoFromDeviceCallbackQueue get_storage_info_from_device_callbacks_;
- OpenStorageCallbackQueue open_storage_callbacks_;
- CloseStorageCallbackQueue close_storage_callbacks_;
- CreateDirectoryCallbackQueue create_directory_callbacks_;
- ReadDirectoryCallbackQueue read_directory_callbacks_;
- ReadFileCallbackQueue read_file_callbacks_;
- GetFileInfoCallbackQueue get_file_info_callbacks_;
- RenameObjectCallbackQueue rename_object_callbacks_;
- CopyFileFromLocalCallbackQueue copy_file_from_local_callbacks_;
- DeleteObjectCallbackQueue delete_object_callbacks_;
-
- base::ThreadChecker thread_checker_;
-
- base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
-};
-
-} // namespace
-
-// static
-std::unique_ptr<MediaTransferProtocolManager>
-MediaTransferProtocolManager::Initialize() {
- auto manager = std::make_unique<MediaTransferProtocolManagerImpl>();
-
- VLOG(1) << "MediaTransferProtocolManager initialized";
-
-#if DCHECK_IS_ON()
- DCHECK(!g_media_transfer_protocol_manager);
- g_media_transfer_protocol_manager = manager.get();
-#endif
-
- return manager;
-}
-
-} // namespace device
diff --git a/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.h b/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.h
deleted file mode 100644
index dde53322a8b..00000000000
--- a/chromium/device/media_transfer_protocol/media_transfer_protocol_manager.h
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright (c) 2012 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_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
-#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-#include "device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom.h"
-#include "device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom.h"
-
-#if !defined(OS_CHROMEOS)
-#error "Only used on ChromeOS"
-#endif
-
-namespace device {
-
-// This class handles the interaction with mtpd.
-// Other classes can add themselves as observers.
-class MediaTransferProtocolManager {
- public:
- // A callback to handle the result of AddObserverAndEnumerateStorages().
- // The argument is the returned vector of available MTP storages info.
- // The pointers in the vector are guaranteed to be non-NULL.
- using EnumerateStoragesCallback = base::OnceCallback<void(
- std::vector<const mojom::MtpStorageInfo*> storage_info_list)>;
-
- // A callback to handle the result of GetStorages().
- // The argument is the returned vector of available MTP storage names.
- using GetStoragesCallback =
- base::OnceCallback<void(const std::vector<std::string>& storages)>;
-
- // A callback to receive the result of GetStorageInfo().
- // On success, the |storage_info| argument contains the storage metadata.
- // Otherwise, |storage_info| is a nullptr.
- using GetStorageInfoCallback =
- base::OnceCallback<void(const mojom::MtpStorageInfo* storage_info)>;
-
- // A callback to handle the result of GetStorageInfoFromDevice.
- // The first argument is the returned storage info.
- // The second argument is true if there was an error.
- using GetStorageInfoFromDeviceCallback =
- base::Callback<void(const mojom::MtpStorageInfo& storage_info,
- const bool error)>;
-
- // A callback to handle the result of OpenStorage.
- // The first argument is the returned handle.
- // The second argument is true if there was an error.
- using OpenStorageCallback =
- base::Callback<void(const std::string& handle, bool error)>;
-
- // A callback to handle the result of CloseStorage.
- // The argument is true if there was an error.
- using CloseStorageCallback = base::Callback<void(bool error)>;
-
- // A callback to handle the result of CreateDirectory.
- // The first argument is true if there was an error.
- using CreateDirectoryCallback = base::Callback<void(bool error)>;
-
- // A callback to handle the result of ReadDirectory.
- // The first argument is a vector of file entries.
- // The second argument is true if there are more file entries.
- // The third argument is true if there was an error.
- using ReadDirectoryCallback =
- base::Callback<void(const std::vector<mojom::MtpFileEntry>& file_entries,
- bool has_more,
- bool error)>;
-
- // A callback to handle the result of ReadFileChunk.
- // The first argument is a string containing the file data.
- // The second argument is true if there was an error.
- using ReadFileCallback =
- base::Callback<void(const std::string& data, bool error)>;
-
- // A callback to handle the result of GetFileInfo.
- // The first argument is a file entry.
- // The second argument is true if there was an error.
- using GetFileInfoCallback =
- base::Callback<void(const mojom::MtpFileEntry& file_entry, bool error)>;
-
- // A callback to handle the result of RenameObject.
- // The first argument is true if there was an error.
- using RenameObjectCallback = base::Callback<void(bool error)>;
-
- // A callback to handle the result of CopyFileFromLocal.
- // The first argument is true if there was an error.
- using CopyFileFromLocalCallback = base::Callback<void(bool error)>;
-
- // A callback to handle the result of DeleteObject.
- // The first argument is true if there was an error.
- using DeleteObjectCallback = base::Callback<void(bool error)>;
-
- // Implement this interface to be notified about MTP storage
- // attachment / detachment events.
- class Observer {
- public:
- virtual ~Observer() {}
-
- // Functions called after a MTP storage has been attached / detached.
- virtual void StorageAttached(
- const device::mojom::MtpStorageInfo& storage_info) = 0;
- virtual void StorageDetached(const std::string& storage_name) = 0;
- };
-
- virtual ~MediaTransferProtocolManager() {}
-
- // Adds an observer and runs |callback| with a list of existing storages.
- virtual void AddObserverAndEnumerateStorages(
- Observer* observer,
- EnumerateStoragesCallback callback) = 0;
-
- // Removes an observer.
- virtual void RemoveObserver(Observer* observer) = 0;
-
- // Gets all available MTP storages and runs |callback|.
- virtual void GetStorages(GetStoragesCallback callback) const = 0;
-
- // Gets the metadata for |storage_name| and runs |callback| synchronously.
- virtual void GetStorageInfo(const std::string& storage_name,
- GetStorageInfoCallback callback) const = 0;
-
- // Read the metadata of |storage_name| from device and runs |callback|.
- virtual void GetStorageInfoFromDevice(
- const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) = 0;
-
- // Opens |storage_name| in |mode| and runs |callback|.
- virtual void OpenStorage(const std::string& storage_name,
- const std::string& mode,
- const OpenStorageCallback& callback) = 0;
-
- // Close |storage_handle| and runs |callback|.
- virtual void CloseStorage(const std::string& storage_handle,
- const CloseStorageCallback& callback) = 0;
-
- // Creates |directory_name| in |parent_id|.
- virtual void CreateDirectory(const std::string& storage_handle,
- const uint32_t parent_id,
- const std::string& directory_name,
- const CreateDirectoryCallback& callback) = 0;
-
- // Reads directory entries from |file_id| on |storage_handle| and runs
- // |callback|. |max_size| is a maximum number of files to be read.
- virtual void ReadDirectory(const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) = 0;
-
- // Reads file data from |file_id| on |storage_handle| and runs |callback|.
- // Reads |count| bytes of data starting at |offset|.
- virtual void ReadFileChunk(const std::string& storage_handle,
- uint32_t file_id,
- uint32_t offset,
- uint32_t count,
- const ReadFileCallback& callback) = 0;
-
- // Gets the file metadata for |file_id| on |storage_handle| and runs
- // |callback|.
- virtual void GetFileInfo(const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) = 0;
-
- // Renames |object_id| to |new_name|.
- virtual void RenameObject(const std::string& storage_handle,
- const uint32_t object_id,
- const std::string& new_name,
- const RenameObjectCallback& callback) = 0;
-
- // Copies the file from |source_file_descriptor| to |file_name| on
- // |parent_id|.
- virtual void CopyFileFromLocal(const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
- const std::string& file_name,
- const CopyFileFromLocalCallback& callback) = 0;
-
- // Deletes |object_id|.
- virtual void DeleteObject(const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) = 0;
-
- // Creates and returns the global MediaTransferProtocolManager instance.
- static std::unique_ptr<MediaTransferProtocolManager> Initialize();
-};
-
-} // namespace device
-
-#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
diff --git a/chromium/device/media_transfer_protocol/public/mojom/BUILD.gn b/chromium/device/media_transfer_protocol/public/mojom/BUILD.gn
deleted file mode 100644
index 444a0ce1a64..00000000000
--- a/chromium/device/media_transfer_protocol/public/mojom/BUILD.gn
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2017 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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojom") {
- sources = [
- "mtp_file_entry.mojom",
- "mtp_storage_info.mojom",
- ]
-}
diff --git a/chromium/device/media_transfer_protocol/public/mojom/OWNERS b/chromium/device/media_transfer_protocol/public/mojom/OWNERS
deleted file mode 100644
index 08850f42120..00000000000
--- a/chromium/device/media_transfer_protocol/public/mojom/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom b/chromium/device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom
deleted file mode 100644
index 3d65bb8a9c0..00000000000
--- a/chromium/device/media_transfer_protocol/public/mojom/mtp_file_entry.mojom
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 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.
-
-module device.mojom;
-
-// This is a mojo counterpart of the MtpFileEntry protobuf message from
-// //src/third_party/cros_system_api/dbus/mtp_file_entry.proto
-// See discussion on https://crbug.com/769630.
-struct MtpFileEntry {
- enum FileType {
- FILE_TYPE_FOLDER = 0,
- FILE_TYPE_JPEG = 14,
- FILE_TYPE_JFIF = 15,
- FILE_TYPE_TIFF = 16,
- FILE_TYPE_BMP = 17,
- FILE_TYPE_GIF = 18,
- FILE_TYPE_PICT = 19,
- FILE_TYPE_PNG = 20,
- FILE_TYPE_WINDOWSIMAGEFORMAT = 25,
- FILE_TYPE_JP2 = 40,
- FILE_TYPE_JPX = 41,
- FILE_TYPE_UNKNOWN = 44,
- FILE_TYPE_OTHER = 9999
- };
-
- uint32 item_id = 0xFFFFFFFF;
- uint32 parent_id = 0XFFFFFFFF;
- string file_name;
- uint64 file_size = 0;
- int64 modification_time = 0;
- FileType file_type = FileType.FILE_TYPE_UNKNOWN;
-};
diff --git a/chromium/device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom b/chromium/device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom
deleted file mode 100644
index dcdb9175d7e..00000000000
--- a/chromium/device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 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.
-
-module device.mojom;
-
-// This is a mojo counterpart of the MtpStorageInfo protobuf message from
-// //src/third_party/cros_system_api/dbus/mtp_storage_info.proto
-// See discussion on https://crbug.com/769630.
-struct MtpStorageInfo {
- string storage_name;
- string vendor;
- uint32 vendor_id = 0;
- string product;
- uint32 product_id = 0;
- uint32 device_flags = 0;
- uint32 storage_type = 0;
- uint32 filesystem_type = 0;
- uint32 access_capability = 0;
- uint64 max_capacity = 0;
- uint64 free_space_in_bytes = 0;
- uint64 free_space_in_objects = 0;
- string storage_description;
- string volume_identifier;
-};
diff --git a/chromium/device/serial/BUILD.gn b/chromium/device/serial/BUILD.gn
index fa48ed0c977..77132bfc86d 100644
--- a/chromium/device/serial/BUILD.gn
+++ b/chromium/device/serial/BUILD.gn
@@ -38,8 +38,6 @@ if (is_win || is_linux || is_mac) {
"serial_device_enumerator_win.h",
"serial_io_handler.cc",
"serial_io_handler.h",
- "serial_io_handler_posix.cc",
- "serial_io_handler_posix.h",
"serial_io_handler_win.cc",
"serial_io_handler_win.h",
]
@@ -58,6 +56,12 @@ if (is_win || is_linux || is_mac) {
"//third_party/re2",
]
+ if (is_posix) {
+ sources += [
+ "serial_io_handler_posix.cc",
+ "serial_io_handler_posix.h",
+ ]
+ }
if (use_udev) {
deps += [ "//device/udev_linux" ]
}
diff --git a/chromium/device/serial/serial_device_enumerator_unittest.cc b/chromium/device/serial/serial_device_enumerator_unittest.cc
new file mode 100644
index 00000000000..4f0f55ac7d0
--- /dev/null
+++ b/chromium/device/serial/serial_device_enumerator_unittest.cc
@@ -0,0 +1,23 @@
+// 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/serial/serial_device_enumerator.h"
+
+#include <memory>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+TEST(SerialDeviceEnumeratorTest, GetDevices) {
+ // There is no guarantee that a test machine will have a serial device
+ // available. The purpose of this test is to ensure that the process of
+ // attempting to enumerate devices does not cause a crash.
+ auto enumerator = SerialDeviceEnumerator::Create();
+ ASSERT_TRUE(enumerator);
+ std::vector<mojom::SerialDeviceInfoPtr> devices = enumerator->GetDevices();
+}
+
+} // namespace device
diff --git a/chromium/device/serial/serial_io_handler_win.cc b/chromium/device/serial/serial_io_handler_win.cc
index 2f5c2da4528..26efe2c9081 100644
--- a/chromium/device/serial/serial_io_handler_win.cc
+++ b/chromium/device/serial/serial_io_handler_win.cc
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/scoped_observer.h"
#include "base/sequence_checker.h"
#include "device/base/device_info_query_win.h"
@@ -237,8 +237,8 @@ bool SerialIoHandlerWin::PostOpen() {
DCHECK(!read_context_);
DCHECK(!write_context_);
- base::MessageLoopForIO::current()->RegisterIOHandler(file().GetPlatformFile(),
- this);
+ base::MessageLoopCurrentForIO::Get()->RegisterIOHandler(
+ file().GetPlatformFile(), this);
comm_context_.reset(new base::MessagePumpForIO::IOContext());
read_context_.reset(new base::MessagePumpForIO::IOContext());
diff --git a/chromium/device/usb/mock_usb_device.h b/chromium/device/usb/mock_usb_device.h
index f03954e392c..ef09b0a19dd 100644
--- a/chromium/device/usb/mock_usb_device.h
+++ b/chromium/device/usb/mock_usb_device.h
@@ -44,7 +44,7 @@ class MockUsbDevice : public UsbDevice {
const std::string& serial_number,
const std::vector<UsbConfigDescriptor>& configurations);
- void Open(OpenCallback callback) { OpenInternal(callback); }
+ void Open(OpenCallback callback) override { OpenInternal(callback); }
MOCK_METHOD1(OpenInternal, void(OpenCallback&));
void AddMockConfig(const UsbConfigDescriptor& config);
diff --git a/chromium/device/usb/mojo/BUILD.gn b/chromium/device/usb/mojo/BUILD.gn
index f31975ddede..0a556a864c5 100644
--- a/chromium/device/usb/mojo/BUILD.gn
+++ b/chromium/device/usb/mojo/BUILD.gn
@@ -19,7 +19,6 @@ source_set("mojo") {
"//device/usb",
"//device/usb/public/cpp",
"//device/usb/public/mojom",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//net",
]
diff --git a/chromium/device/usb/mojo/DEPS b/chromium/device/usb/mojo/DEPS
deleted file mode 100644
index 6cfa565faca..00000000000
--- a/chromium/device/usb/mojo/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
- "+mojo/common",
-]
diff --git a/chromium/device/usb/mojo/device_manager_impl_unittest.cc b/chromium/device/usb/mojo/device_manager_impl_unittest.cc
index edb46481f7e..ed3ed79e95e 100644
--- a/chromium/device/usb/mojo/device_manager_impl_unittest.cc
+++ b/chromium/device/usb/mojo/device_manager_impl_unittest.cc
@@ -71,7 +71,7 @@ class USBDeviceManagerImplTest : public testing::Test {
class MockDeviceManagerClient : public mojom::UsbDeviceManagerClient {
public:
MockDeviceManagerClient() : binding_(this) {}
- ~MockDeviceManagerClient() = default;
+ ~MockDeviceManagerClient() override = default;
UsbDeviceManagerClientPtr CreateInterfacePtrAndBind() {
UsbDeviceManagerClientPtr client;
@@ -80,12 +80,12 @@ class MockDeviceManagerClient : public mojom::UsbDeviceManagerClient {
}
MOCK_METHOD1(DoOnDeviceAdded, void(mojom::UsbDeviceInfo*));
- void OnDeviceAdded(UsbDeviceInfoPtr device_info) {
+ void OnDeviceAdded(UsbDeviceInfoPtr device_info) override {
DoOnDeviceAdded(device_info.get());
}
MOCK_METHOD1(DoOnDeviceRemoved, void(mojom::UsbDeviceInfo*));
- void OnDeviceRemoved(UsbDeviceInfoPtr device_info) {
+ void OnDeviceRemoved(UsbDeviceInfoPtr device_info) override {
DoOnDeviceRemoved(device_info.get());
}
diff --git a/chromium/device/usb/public/mojom/BUILD.gn b/chromium/device/usb/public/mojom/BUILD.gn
index 56bb553f541..1c496ed638a 100644
--- a/chromium/device/usb/public/mojom/BUILD.gn
+++ b/chromium/device/usb/public/mojom/BUILD.gn
@@ -12,7 +12,6 @@ mojom("mojom") {
]
deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
]
diff --git a/chromium/device/usb/usb_device_handle_unittest.cc b/chromium/device/usb/usb_device_handle_unittest.cc
index 070003d017a..db4ffeba7cf 100644
--- a/chromium/device/usb/usb_device_handle_unittest.cc
+++ b/chromium/device/usb/usb_device_handle_unittest.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
diff --git a/chromium/device/vr/BUILD.gn b/chromium/device/vr/BUILD.gn
index ea806c5c9c0..7a50c06d5d6 100644
--- a/chromium/device/vr/BUILD.gn
+++ b/chromium/device/vr/BUILD.gn
@@ -65,16 +65,21 @@ if (enable_vr) {
"android/gvr/gvr_gamepad_data_provider.h",
]
+ if (enable_arcore) {
+ sources += [
+ "android/arcore/arcore_device_provider_factory.cc",
+ "android/arcore/arcore_device_provider_factory.h",
+ ]
+ }
+
deps += [
":jni_headers",
"//device/gamepad",
"//device/gamepad/public/cpp:shared_with_blink",
"//third_party/blink/public:blink_headers",
+ "//third_party/gvr-android-sdk:gvr_shim",
]
ldflags = [ "-landroid" ]
- libs = [
- "//third_party/gvr-android-sdk/libgvr_shim_static_${current_cpu}.a",
- ]
configs += [ "//third_party/gvr-android-sdk:libgvr_config" ]
}
diff --git a/chromium/device/vr/android/arcore/arcore_device_provider_factory.cc b/chromium/device/vr/android/arcore/arcore_device_provider_factory.cc
new file mode 100644
index 00000000000..16da7db4e01
--- /dev/null
+++ b/chromium/device/vr/android/arcore/arcore_device_provider_factory.cc
@@ -0,0 +1,33 @@
+// 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/arcore/arcore_device_provider_factory.h"
+
+#include "base/logging.h"
+#include "device/vr/vr_device_provider.h"
+
+namespace device {
+
+namespace {
+ARCoreDeviceProviderFactory* g_arcore_device_provider_factory = nullptr;
+} // namespace
+
+// static
+std::unique_ptr<device::VRDeviceProvider>
+ARCoreDeviceProviderFactory::Create() {
+ if (!g_arcore_device_provider_factory)
+ return nullptr;
+ return g_arcore_device_provider_factory->CreateDeviceProvider();
+}
+
+// static
+void ARCoreDeviceProviderFactory::Install(
+ std::unique_ptr<ARCoreDeviceProviderFactory> factory) {
+ DCHECK_NE(g_arcore_device_provider_factory, factory.get());
+ if (g_arcore_device_provider_factory)
+ delete g_arcore_device_provider_factory;
+ g_arcore_device_provider_factory = factory.release();
+}
+
+} // namespace device
diff --git a/chromium/device/vr/android/arcore/arcore_device_provider_factory.h b/chromium/device/vr/android/arcore/arcore_device_provider_factory.h
new file mode 100644
index 00000000000..2b29ec2828a
--- /dev/null
+++ b/chromium/device/vr/android/arcore/arcore_device_provider_factory.h
@@ -0,0 +1,34 @@
+// 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_ARCORE_ARCORE_DEVICE_PROVIDER_FACTORY_H_
+#define DEVICE_VR_ANDROID_ARCORE_ARCORE_DEVICE_PROVIDER_FACTORY_H_
+
+#include <memory>
+#include "base/macros.h"
+#include "device/vr/vr_export.h"
+
+namespace device {
+
+class VRDeviceProvider;
+
+class DEVICE_VR_EXPORT ARCoreDeviceProviderFactory {
+ public:
+ static std::unique_ptr<device::VRDeviceProvider> Create();
+ static void Install(std::unique_ptr<ARCoreDeviceProviderFactory> factory);
+
+ virtual ~ARCoreDeviceProviderFactory() = default;
+
+ protected:
+ ARCoreDeviceProviderFactory() = default;
+
+ virtual std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ARCoreDeviceProviderFactory);
+};
+
+} // namespace device
+
+#endif // DEVICE_VR_ANDROID_ARCORE_ARCORE_DEVICE_PROVIDER_FACTORY_H_
diff --git a/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.cc b/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.cc
index 033fec4f65c..0cc3e09f1eb 100644
--- a/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.cc
+++ b/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.cc
@@ -4,6 +4,8 @@
#include "device/vr/android/gvr/gvr_delegate_provider_factory.h"
+#include "base/logging.h"
+
namespace device {
namespace {
@@ -18,11 +20,14 @@ GvrDelegateProvider* GvrDelegateProviderFactory::Create() {
}
// static
-void GvrDelegateProviderFactory::Install(GvrDelegateProviderFactory* f) {
- if (g_gvr_delegate_provider_factory == f)
- return;
- delete g_gvr_delegate_provider_factory;
- g_gvr_delegate_provider_factory = f;
+void GvrDelegateProviderFactory::Install(
+ std::unique_ptr<GvrDelegateProviderFactory> factory) {
+ DCHECK_NE(g_gvr_delegate_provider_factory, factory.get());
+ if (g_gvr_delegate_provider_factory)
+ delete g_gvr_delegate_provider_factory;
+ g_gvr_delegate_provider_factory = factory.release();
}
+GvrDevice* GvrDelegateProviderFactory::device_ = nullptr;
+
} // namespace device
diff --git a/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.h b/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.h
index 3db30037ecb..88e2ffebdee 100644
--- a/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.h
+++ b/chromium/device/vr/android/gvr/gvr_delegate_provider_factory.h
@@ -5,6 +5,8 @@
#ifndef DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_FACTORY_H_
#define DEVICE_VR_ANDROID_GVR_DELEGATE_PROVIDER_FACTORY_H_
+#include <memory>
+
#include "base/macros.h"
#include "device/vr/vr_export.h"
@@ -12,18 +14,24 @@
namespace device {
class GvrDelegateProvider;
+class GvrDevice;
class DEVICE_VR_EXPORT GvrDelegateProviderFactory {
public:
static GvrDelegateProvider* Create();
- static void Install(GvrDelegateProviderFactory* factory);
+ static void Install(std::unique_ptr<GvrDelegateProviderFactory> factory);
+ static void SetDevice(GvrDevice* device) { device_ = device; }
+ static GvrDevice* GetDevice() { return device_; }
+
+ virtual ~GvrDelegateProviderFactory() = default;
protected:
GvrDelegateProviderFactory() = default;
- virtual ~GvrDelegateProviderFactory() = default;
virtual GvrDelegateProvider* CreateGvrDelegateProvider() = 0;
+ static GvrDevice* device_;
+
private:
DISALLOW_COPY_AND_ASSIGN(GvrDelegateProviderFactory);
};
diff --git a/chromium/device/vr/android/gvr/gvr_device.cc b/chromium/device/vr/android/gvr/gvr_device.cc
index bc5db81cae0..b713ae1b532 100644
--- a/chromium/device/vr/android/gvr/gvr_device.cc
+++ b/chromium/device/vr/android/gvr/gvr_device.cc
@@ -155,9 +155,11 @@ GvrDevice::GvrDevice() : weak_ptr_factory_(this) {
env, non_presenting_context_);
gvr_api_ = gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId()));
+ GvrDelegateProviderFactory::SetDevice(this);
}
GvrDevice::~GvrDevice() {
+ GvrDelegateProviderFactory::SetDevice(nullptr);
if (!non_presenting_context_.obj())
return;
JNIEnv* env = base::android::AttachCurrentThread();
@@ -165,7 +167,6 @@ GvrDevice::~GvrDevice() {
}
void GvrDevice::RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
@@ -182,17 +183,15 @@ void GvrDevice::RequestPresent(
std::move(submit_client), std::move(request), GetVRDisplayInfo(),
std::move(present_options),
base::BindOnce(&GvrDevice::OnRequestPresentResult,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback),
- base::Unretained(display)));
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void GvrDevice::OnRequestPresentResult(
mojom::VRDisplayHost::RequestPresentCallback callback,
- VRDisplayImpl* display,
bool result,
mojom::VRDisplayFrameTransportOptionsPtr transport_options) {
if (result)
- SetPresentingDisplay(display);
+ SetIsPresenting();
std::move(callback).Run(result, std::move(transport_options));
}
diff --git a/chromium/device/vr/android/gvr/gvr_device.h b/chromium/device/vr/android/gvr/gvr_device.h
index e362ce270c2..3376beff589 100644
--- a/chromium/device/vr/android/gvr/gvr_device.h
+++ b/chromium/device/vr/android/gvr/gvr_device.h
@@ -17,7 +17,6 @@
namespace device {
class GvrDelegateProvider;
-class VRDisplayImpl;
// TODO(mthiesse, crbug.com/769373): Remove DEVICE_VR_EXPORT.
class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase {
@@ -27,7 +26,6 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase {
// VRDeviceBase
void RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
@@ -51,7 +49,6 @@ class DEVICE_VR_EXPORT GvrDevice : public VRDeviceBase {
void OnRequestPresentResult(
mojom::VRDisplayHost::RequestPresentCallback callback,
- VRDisplayImpl* display,
bool result,
mojom::VRDisplayFrameTransportOptionsPtr transport_options);
diff --git a/chromium/device/vr/buildflags/BUILD.gn b/chromium/device/vr/buildflags/BUILD.gn
index 51c05d325c8..fa4c3d95ca4 100644
--- a/chromium/device/vr/buildflags/BUILD.gn
+++ b/chromium/device/vr/buildflags/BUILD.gn
@@ -9,6 +9,7 @@ import("//build/buildflag_header.gni")
buildflag_header("buildflags") {
header = "buildflags.h"
flags = [
+ "ENABLE_ARCORE=$enable_arcore",
"ENABLE_VR=$enable_vr",
"ENABLE_OPENVR=$enable_openvr",
"ENABLE_OCULUS_VR=$enable_oculus_vr",
diff --git a/chromium/device/vr/buildflags/buildflags.gni b/chromium/device/vr/buildflags/buildflags.gni
index 905d9e799df..368caa16284 100644
--- a/chromium/device/vr/buildflags/buildflags.gni
+++ b/chromium/device/vr/buildflags/buildflags.gni
@@ -5,6 +5,7 @@
import("//build/config/chrome_build.gni")
import("//build/config/chromecast_build.gni")
import("//build/config/gclient_args.gni")
+import("//chrome/android/channel.gni")
declare_args() {
# TODO(733935): Enable for other Android architectures too. Currently we only
@@ -29,4 +30,17 @@ declare_args() {
# Whether to include VR extras like test APKs in non-VR-specific targets
include_vr_data = false
+
+ # TODO(crbug.com/837999, crbug.com/841389): We currently only support arm and
+ # we are limiting to canary and dev until binary size issues are resolved.
+ # TODO(crbug.com/845080): add android_channel == "dev" || "canary"
+ package_arcore = is_android && !is_chromecast && current_cpu == "arm" &&
+ android_channel == "default"
+
+ # TODO(crbug.com/841389): We should eventually have a single flag for
+ # enabling arcore, but we currently don't support ARCore in 64bit, and we do
+ # not support all channels. This flag governs the inclusion of code that must
+ # be identical across configs.
+ enable_arcore = is_android && !is_chromecast &&
+ (current_cpu == "arm" || current_cpu == "arm64")
}
diff --git a/chromium/device/vr/oculus/oculus_device.cc b/chromium/device/vr/oculus/oculus_device.cc
index 769489c0a7d..9819906c7e2 100644
--- a/chromium/device/vr/oculus/oculus_device.cc
+++ b/chromium/device/vr/oculus/oculus_device.cc
@@ -95,7 +95,6 @@ OculusDevice::OculusDevice(ovrSession session, ovrGraphicsLuid luid)
OculusDevice::~OculusDevice() {}
void OculusDevice::RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
@@ -130,6 +129,7 @@ void OculusDevice::ExitPresent() {
render_loop_->task_runner()->PostTask(
FROM_HERE, base::BindOnce(&OculusRenderLoop::ExitPresent,
render_loop_->GetWeakPtr()));
+ OnExitPresent();
}
void OculusDevice::OnMagicWindowPoseRequest(
diff --git a/chromium/device/vr/oculus/oculus_device.h b/chromium/device/vr/oculus/oculus_device.h
index 061f7362aaa..414d83b1899 100644
--- a/chromium/device/vr/oculus/oculus_device.h
+++ b/chromium/device/vr/oculus/oculus_device.h
@@ -25,7 +25,6 @@ class OculusDevice : public VRDeviceBase {
// VRDeviceBase
void RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
diff --git a/chromium/device/vr/oculus/oculus_render_loop.cc b/chromium/device/vr/oculus/oculus_render_loop.cc
index 598f9f8c85e..24c3a8269a2 100644
--- a/chromium/device/vr/oculus/oculus_render_loop.cc
+++ b/chromium/device/vr/oculus/oculus_render_loop.cc
@@ -92,7 +92,7 @@ void OculusRenderLoop::SubmitFrameWithTextureHandle(
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(platform_handle);
MojoResult result = MojoUnwrapPlatformHandle(texture_handle.release().value(),
- &platform_handle);
+ nullptr, &platform_handle);
if (result != MOJO_RESULT_OK)
return;
@@ -228,6 +228,8 @@ void OculusRenderLoop::RequestPresent(
void OculusRenderLoop::ExitPresent() {
is_presenting_ = false;
+ binding_.Close();
+ submit_client_ = nullptr;
}
void OculusRenderLoop::Init() {}
diff --git a/chromium/device/vr/openvr/openvr_device.cc b/chromium/device/vr/openvr/openvr_device.cc
index 09f5a3041a4..8aee0efd125 100644
--- a/chromium/device/vr/openvr/openvr_device.cc
+++ b/chromium/device/vr/openvr/openvr_device.cc
@@ -169,7 +169,6 @@ void OpenVRDevice::Shutdown() {
}
void OpenVRDevice::RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
@@ -224,6 +223,7 @@ void OpenVRDevice::ExitPresent() {
FROM_HERE,
base::Bind(&OpenVRRenderLoop::ExitPresent, render_loop_->GetWeakPtr()));
render_loop_->Stop();
+ OnExitPresent();
}
void OpenVRDevice::OnMagicWindowPoseRequest(
diff --git a/chromium/device/vr/openvr/openvr_device.h b/chromium/device/vr/openvr/openvr_device.h
index d30505fff14..3a19299352b 100644
--- a/chromium/device/vr/openvr/openvr_device.h
+++ b/chromium/device/vr/openvr/openvr_device.h
@@ -30,7 +30,6 @@ class OpenVRDevice : public VRDeviceBase {
// VRDeviceBase
void RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
diff --git a/chromium/device/vr/openvr/openvr_render_loop.cc b/chromium/device/vr/openvr/openvr_render_loop.cc
index 97ec1f2d461..3cd7c8b4958 100644
--- a/chromium/device/vr/openvr/openvr_render_loop.cc
+++ b/chromium/device/vr/openvr/openvr_render_loop.cc
@@ -85,7 +85,7 @@ void OpenVRRenderLoop::SubmitFrameWithTextureHandle(
MojoPlatformHandle platform_handle;
platform_handle.struct_size = sizeof(platform_handle);
MojoResult result = MojoUnwrapPlatformHandle(texture_handle.release().value(),
- &platform_handle);
+ nullptr, &platform_handle);
if (result != MOJO_RESULT_OK)
return;
@@ -195,6 +195,8 @@ void OpenVRRenderLoop::RequestPresent(
void OpenVRRenderLoop::ExitPresent() {
is_presenting_ = false;
report_webxr_input_ = false;
+ binding_.Close();
+ submit_client_ = nullptr;
vr_compositor_->SuspendRendering(true);
}
diff --git a/chromium/device/vr/orientation/orientation_device.cc b/chromium/device/vr/orientation/orientation_device.cc
index 5c826c2e7ec..730814b5315 100644
--- a/chromium/device/vr/orientation/orientation_device.cc
+++ b/chromium/device/vr/orientation/orientation_device.cc
@@ -17,7 +17,6 @@
namespace device {
-using mojom::SensorType;
using gfx::Quaternion;
using gfx::Vector3dF;
@@ -54,11 +53,8 @@ VROrientationDevice::VROrientationDevice(
mojom::SensorProviderPtr* sensor_provider,
base::OnceClosure ready_callback)
: ready_callback_(std::move(ready_callback)), binding_(this) {
- // Use RELATIVE_ORIENTATION_QUATERNION rather than
- // ABSOLUTE_ORIENTATION_QUATERNION because compass readings can be innacurate
- // when used indoors.
(*sensor_provider)
- ->GetSensor(SensorType::RELATIVE_ORIENTATION_QUATERNION,
+ ->GetSensor(kOrientationSensorType,
base::BindOnce(&VROrientationDevice::SensorReady,
base::Unretained(this)));
diff --git a/chromium/device/vr/orientation/orientation_device.h b/chromium/device/vr/orientation/orientation_device.h
index f82c6569aec..dde90f77cbc 100644
--- a/chromium/device/vr/orientation/orientation_device.h
+++ b/chromium/device/vr/orientation/orientation_device.h
@@ -10,6 +10,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/threading/simple_thread.h"
+#include "build/build_config.h"
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device_base.h"
#include "mojo/public/cpp/bindings/binding.h"
@@ -20,6 +21,19 @@ namespace device {
class SensorReadingSharedBufferReader;
+// Use RELATIVE_ORIENTATION_QUATERNION rather than
+// ABSOLUTE_ORIENTATION_QUATERNION because compass readings can be inacurate
+// when used indoors, unless we're on Windows which doesn't support
+// RELATIVE_ORIENTATION_QUATERNION.
+// TODO(crbug.com/730440) If RELATIVE_ORIENTATION_QUATERNION is ever
+// implemented on Windows, use that instead.
+static constexpr mojom::SensorType kOrientationSensorType =
+#if defined(OS_WIN)
+ mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION;
+#else
+ mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION;
+#endif
+
// This class connects the orientation sensor events to the Web VR apis.
class DEVICE_VR_EXPORT VROrientationDevice : public VRDeviceBase,
public mojom::SensorClient {
diff --git a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
index 14757b50ab8..3af37569e8f 100644
--- a/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -70,16 +70,15 @@ class VROrientationDeviceProviderTest : public testing::Test {
auto init_params = mojom::SensorInitParams::New();
init_params->sensor = std::move(sensor_ptr_);
init_params->default_configuration = PlatformSensorConfiguration(
- SensorTraits<mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION>::
- kDefaultFrequency);
+ SensorTraits<kOrientationSensorType>::kDefaultFrequency);
init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_);
init_params->memory = shared_buffer_handle_->Clone(
mojo::SharedBufferHandle::AccessMode::READ_ONLY);
- init_params->buffer_offset = SensorReadingSharedBuffer::GetOffset(
- mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION);
+ init_params->buffer_offset =
+ SensorReadingSharedBuffer::GetOffset(kOrientationSensorType);
return init_params;
}
diff --git a/chromium/device/vr/orientation/orientation_device_unittest.cc b/chromium/device/vr/orientation/orientation_device_unittest.cc
index 4bbde60ddb6..db07c16bcfa 100644
--- a/chromium/device/vr/orientation/orientation_device_unittest.cc
+++ b/chromium/device/vr/orientation/orientation_device_unittest.cc
@@ -100,8 +100,7 @@ class VROrientationDeviceTest : public testing::Test {
void TearDown() override { shared_buffer_handle_.reset(); }
double GetBufferOffset() {
- return SensorReadingSharedBuffer::GetOffset(
- mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION);
+ return SensorReadingSharedBuffer::GetOffset(kOrientationSensorType);
}
void InitializeDevice(mojom::SensorInitParamsPtr params) {
@@ -154,8 +153,7 @@ class VROrientationDeviceTest : public testing::Test {
auto init_params = mojom::SensorInitParams::New();
init_params->sensor = std::move(sensor_ptr_);
init_params->default_configuration = PlatformSensorConfiguration(
- SensorTraits<mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION>::
- kDefaultFrequency);
+ SensorTraits<kOrientationSensorType>::kDefaultFrequency);
init_params->client_request = mojo::MakeRequest(&sensor_client_ptr_);
diff --git a/chromium/device/vr/public/mojom/BUILD.gn b/chromium/device/vr/public/mojom/BUILD.gn
index 0239637721e..c9befd61ef3 100644
--- a/chromium/device/vr/public/mojom/BUILD.gn
+++ b/chromium/device/vr/public/mojom/BUILD.gn
@@ -15,6 +15,7 @@ mojom_component("mojom") {
public_deps = [
"//gpu/ipc/common:interfaces",
"//mojo/public/mojom/base",
+ "//ui/display/mojo:interfaces",
"//ui/gfx/geometry/mojo",
"//ui/gfx/mojo:mojo",
]
diff --git a/chromium/device/vr/public/mojom/vr_service.mojom b/chromium/device/vr/public/mojom/vr_service.mojom
index e1b8281b228..1b5e4e5dd92 100644
--- a/chromium/device/vr/public/mojom/vr_service.mojom
+++ b/chromium/device/vr/public/mojom/vr_service.mojom
@@ -7,6 +7,7 @@ module device.mojom;
import "mojo/public/mojom/base/time.mojom";
import "gpu/ipc/common/mailbox_holder.mojom";
import "gpu/ipc/common/sync_token.mojom";
+import "ui/display/mojo/display.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/gpu_fence_handle.mojom";
import "ui/gfx/mojo/transform.mojom";
@@ -81,13 +82,25 @@ struct VRPose {
// For WebXR sessions only, reports the state of all active input devices
// synced with the head pose.
array<XRInputSourceState>? input_state;
+
+ // Indicates that a reset pose event was triggered, either by device specific
+ // UI or by some other method, and handled on the browser side, and the
+ // renderer should now bubble up an event to the WebXRDevice API.
+ bool pose_reset;
};
struct VRDisplayCapabilities {
bool hasPosition;
bool hasExternalDisplay;
+
// 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;
};
// Information about the optical properties for an eye in a VRDisplay.
@@ -159,6 +172,22 @@ struct VRDisplayFrameTransportOptions {
bool wait_for_gpu_fence;
};
+// The data needed for each frame for a magic window experience
+// that uses a background image / projection matrix instead of
+// just a VRPose - ex: non-exclusive AR needs a camera image and
+// to get a projection matrix directly from the backend rather than
+// FOV values to support features like focus.
+struct VRMagicWindowFrameData {
+ VRPose pose;
+ gpu.mojom.MailboxHolder buffer_holder;
+ gfx.mojom.Size buffer_size;
+ // TODO(https://crbug.com/838515): Is this delta since the last
+ // frame? OR an unspecified origin? Something else?
+ mojo_base.mojom.TimeDelta time_delta;
+ array<float, 16> projection_matrix;
+
+};
+
enum VRDisplayEventReason {
NONE = 0,
NAVIGATION = 1,
@@ -232,10 +261,24 @@ interface VRDisplayHost {
ExitPresent();
};
-// Provides the necessary functionality for a non-presenting WebVR page to draw
-// magic window content.
+// Provides the necessary functionality for a non-presenting WebXR session to
+// draw magic window content.
+// This interface is hosted in the Browser process, but will move to a sandboxed
+// utility process on Windows. The render process communicates with it.
+// For AR displays (VRDisplayCapabilities.can_provide_pass_through_images
+// is true), clients can use GetFrameData to get images.
+// TODO(836478): rename VRMagicWindowProvider to NonExclusiveWindowProvider or
+// similar.
interface VRMagicWindowProvider {
GetPose() => (VRPose? pose);
+
+ // Different devices can have different native orientations - 0
+ // is the native orientation, and then increments of 90 degrees
+ // from there.
+ // TODO(https://crbug.com/837944): frame_data should not be optional.
+ GetFrameData(gfx.mojom.Size frame_size,
+ display.mojom.Rotation display_rotation) =>
+ (VRMagicWindowFrameData? frame_data);
};
// Provides the necessary functionality for a presenting WebVR page to draw
diff --git a/chromium/device/vr/vr_device.h b/chromium/device/vr/vr_device.h
index 13fe9cc038e..792e923759a 100644
--- a/chromium/device/vr/vr_device.h
+++ b/chromium/device/vr/vr_device.h
@@ -36,6 +36,17 @@ enum class XrRuntimeAvailable {
const unsigned int VR_DEVICE_LAST_ID = 0xFFFFFFFF;
+class VRDeviceEventListener {
+ public:
+ virtual ~VRDeviceEventListener() {}
+
+ virtual void OnChanged(mojom::VRDisplayInfoPtr vr_device_info) = 0;
+ virtual void OnExitPresent() = 0;
+ virtual void OnActivate(mojom::VRDisplayEventReason reason,
+ base::OnceCallback<void(bool)> on_handled) = 0;
+ virtual void OnDeactivate(mojom::VRDisplayEventReason reason) = 0;
+};
+
// Represents one of the platform's VR devices. Owned by the respective
// VRDeviceProvider.
// TODO(mthiesse, crbug.com/769373): Remove DEVICE_VR_EXPORT.
@@ -46,10 +57,15 @@ class DEVICE_VR_EXPORT VRDevice {
virtual unsigned int GetId() const = 0;
virtual void PauseTracking() = 0;
virtual void ResumeTracking() = 0;
- virtual void Blur() = 0;
- virtual void Focus() = 0;
virtual mojom::VRDisplayInfoPtr GetVRDisplayInfo() = 0;
virtual void SetMagicWindowEnabled(bool enabled) = 0;
+ virtual void ExitPresent() = 0;
+ virtual void RequestPresent(
+ mojom::VRSubmitFrameClientPtr submit_client,
+ mojom::VRPresentationProviderRequest request,
+ mojom::VRRequestPresentOptionsPtr present_options,
+ mojom::VRDisplayHost::RequestPresentCallback callback) = 0;
+ virtual void SetListeningForActivate(bool is_listening) = 0;
// The fallback device should only be provided in lieu of other devices.
virtual bool IsFallbackDevice() = 0;
@@ -60,6 +76,8 @@ class DEVICE_VR_EXPORT VRDevice {
// exiting of presentation before notifying displays. This is currently messy
// because browser-side notions of presentation are mostly Android-specific.
virtual void OnExitPresent() = 0;
+
+ virtual void SetVRDeviceEventListener(VRDeviceEventListener* listener) = 0;
};
} // namespace device
diff --git a/chromium/device/vr/vr_device_base.cc b/chromium/device/vr/vr_device_base.cc
index 725634bc06a..9cf6c9b733a 100644
--- a/chromium/device/vr/vr_device_base.cc
+++ b/chromium/device/vr/vr_device_base.cc
@@ -27,23 +27,14 @@ void VRDeviceBase::PauseTracking() {}
void VRDeviceBase::ResumeTracking() {}
-void VRDeviceBase::Blur() {
- for (VRDisplayImpl* display : displays_)
- display->OnBlur();
+void VRDeviceBase::OnExitPresent() {
+ if (listener_)
+ listener_->OnExitPresent();
+ presenting_ = false;
}
-void VRDeviceBase::Focus() {
- for (VRDisplayImpl* display : displays_)
- display->OnFocus();
-}
-
-void VRDeviceBase::OnExitPresent() {
- if (!presenting_display_)
- return;
- auto it = displays_.find(presenting_display_);
- CHECK(it != displays_.end());
- (*it)->OnExitPresent();
- SetPresentingDisplay(nullptr);
+void VRDeviceBase::SetIsPresenting() {
+ presenting_ = true;
}
bool VRDeviceBase::IsFallbackDevice() {
@@ -56,7 +47,6 @@ mojom::VRDisplayInfoPtr VRDeviceBase::GetVRDisplayInfo() {
}
void VRDeviceBase::RequestPresent(
- VRDisplayImpl* display,
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
@@ -72,6 +62,10 @@ void VRDeviceBase::SetMagicWindowEnabled(bool enabled) {
magic_window_enabled_ = enabled;
}
+void VRDeviceBase::SetVRDeviceEventListener(VRDeviceEventListener* listener) {
+ listener_ = listener;
+}
+
void VRDeviceBase::GetMagicWindowPose(
mojom::VRMagicWindowProvider::GetPoseCallback callback) {
if (!magic_window_enabled_) {
@@ -82,26 +76,22 @@ void VRDeviceBase::GetMagicWindowPose(
OnMagicWindowPoseRequest(std::move(callback));
}
-void VRDeviceBase::AddDisplay(VRDisplayImpl* display) {
- displays_.insert(display);
-}
-
-void VRDeviceBase::RemoveDisplay(VRDisplayImpl* display) {
- if (CheckPresentingDisplay(display))
- ExitPresent();
- displays_.erase(display);
- if (listening_for_activate_diplay_ == display) {
- listening_for_activate_diplay_ = nullptr;
- OnListeningForActivate(false);
+void VRDeviceBase::GetMagicWindowFrameData(
+ const gfx::Size& frame_size,
+ display::Display::Rotation display_rotation,
+ mojom::VRMagicWindowProvider::GetFrameDataCallback callback) {
+ // TODO(https://crbug.com/836565): rename this boolean.
+ if (!magic_window_enabled_) {
+ std::move(callback).Run(nullptr);
+ return;
}
-}
-bool VRDeviceBase::IsAccessAllowed(VRDisplayImpl* display) {
- return (!presenting_display_ || presenting_display_ == display);
+ OnMagicWindowFrameDataRequest(frame_size, display_rotation,
+ std::move(callback));
}
-bool VRDeviceBase::CheckPresentingDisplay(VRDisplayImpl* display) {
- return (presenting_display_ && presenting_display_ == display);
+bool VRDeviceBase::IsAccessAllowed(VRDisplayImpl* display) {
+ return !presenting_;
}
void VRDeviceBase::OnListeningForActivateChanged(VRDisplayImpl* display) {
@@ -112,10 +102,6 @@ void VRDeviceBase::OnFrameFocusChanged(VRDisplayImpl* display) {
UpdateListeningForActivate(display);
}
-void VRDeviceBase::SetPresentingDisplay(VRDisplayImpl* display) {
- presenting_display_ = display;
-}
-
void VRDeviceBase::SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info) {
DCHECK(display_info);
DCHECK(display_info->index == id_);
@@ -125,17 +111,15 @@ void VRDeviceBase::SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info) {
// Don't notify when the VRDisplayInfo is initially set.
if (!initialized)
return;
- for (VRDisplayImpl* display : displays_)
- display->OnChanged(display_info_.Clone());
+
+ if (listener_)
+ listener_->OnChanged(display_info_.Clone());
}
void VRDeviceBase::OnActivate(mojom::VRDisplayEventReason reason,
base::Callback<void(bool)> on_handled) {
- if (listening_for_activate_diplay_) {
- listening_for_activate_diplay_->OnActivate(reason, std::move(on_handled));
- } else {
- std::move(on_handled).Run(true /* will_not_present */);
- }
+ if (listener_)
+ listener_->OnActivate(reason, std::move(on_handled));
}
void VRDeviceBase::OnListeningForActivate(bool listening) {}
@@ -145,6 +129,17 @@ void VRDeviceBase::OnMagicWindowPoseRequest(
std::move(callback).Run(nullptr);
}
+void VRDeviceBase::OnMagicWindowFrameDataRequest(
+ const gfx::Size& frame_size,
+ display::Display::Rotation display_rotation,
+ mojom::VRMagicWindowProvider::GetFrameDataCallback callback) {
+ std::move(callback).Run(nullptr);
+}
+
+void VRDeviceBase::SetListeningForActivate(bool is_listening) {
+ OnListeningForActivate(is_listening);
+}
+
void VRDeviceBase::UpdateListeningForActivate(VRDisplayImpl* display) {
if (display->ListeningForActivate() && display->InFocusedFrame()) {
bool was_listening = !!listening_for_activate_diplay_;
diff --git a/chromium/device/vr/vr_device_base.h b/chromium/device/vr/vr_device_base.h
index e4a520e8673..e6aa60a6a2e 100644
--- a/chromium/device/vr/vr_device_base.h
+++ b/chromium/device/vr/vr_device_base.h
@@ -10,6 +10,7 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_device.h"
#include "device/vr/vr_export.h"
+#include "ui/display/display.h"
namespace device {
@@ -27,51 +28,57 @@ class DEVICE_VR_EXPORT VRDeviceBase : public VRDevice {
unsigned int GetId() const override;
void PauseTracking() override;
void ResumeTracking() override;
- void Blur() override;
- void Focus() override;
void OnExitPresent() override;
mojom::VRDisplayInfoPtr GetVRDisplayInfo() final;
void SetMagicWindowEnabled(bool enabled) final;
+ void SetVRDeviceEventListener(VRDeviceEventListener* listener) final;
- virtual void RequestPresent(
- VRDisplayImpl* display,
+ void RequestPresent(
mojom::VRSubmitFrameClientPtr submit_client,
mojom::VRPresentationProviderRequest request,
mojom::VRRequestPresentOptionsPtr present_options,
- mojom::VRDisplayHost::RequestPresentCallback callback);
- virtual void ExitPresent();
+ mojom::VRDisplayHost::RequestPresentCallback callback) override;
+ void ExitPresent() override;
bool IsFallbackDevice() override;
- void AddDisplay(VRDisplayImpl* display);
- void RemoveDisplay(VRDisplayImpl* display);
bool IsAccessAllowed(VRDisplayImpl* display);
- bool CheckPresentingDisplay(VRDisplayImpl* display);
+ void SetListeningForActivate(bool is_listening) override;
void OnListeningForActivateChanged(VRDisplayImpl* display);
void OnFrameFocusChanged(VRDisplayImpl* display);
void GetMagicWindowPose(
mojom::VRMagicWindowProvider::GetPoseCallback callback);
-
- VRDisplayImpl* GetPresentingDisplay() { return presenting_display_; }
+ // TODO(https://crbug.com/836478): Rename this, and probably
+ // GetMagicWindowPose to GetNonExclusiveFrameData.
+ void GetMagicWindowFrameData(
+ const gfx::Size& frame_size,
+ display::Display::Rotation display_rotation,
+ mojom::VRMagicWindowProvider::GetFrameDataCallback callback);
protected:
- void SetPresentingDisplay(VRDisplayImpl* display);
+ void SetIsPresenting();
+ bool IsPresenting() { return presenting_; } // Exposed for test.
void SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info);
void OnActivate(mojom::VRDisplayEventReason reason,
base::Callback<void(bool)> on_handled);
private:
- void UpdateListeningForActivate(VRDisplayImpl* display);
+ virtual void UpdateListeningForActivate(VRDisplayImpl* display);
virtual void OnListeningForActivate(bool listening);
virtual void OnMagicWindowPoseRequest(
mojom::VRMagicWindowProvider::GetPoseCallback callback);
+ virtual void OnMagicWindowFrameDataRequest(
+ const gfx::Size& frame_size,
+ display::Display::Rotation display_rotation,
+ mojom::VRMagicWindowProvider::GetFrameDataCallback callback);
- std::set<VRDisplayImpl*> displays_;
+ VRDeviceEventListener* listener_ = nullptr;
- VRDisplayImpl* presenting_display_ = nullptr;
VRDisplayImpl* listening_for_activate_diplay_ = nullptr;
mojom::VRDisplayInfoPtr display_info_;
+ bool presenting_ = false;
+
unsigned int id_;
static unsigned int next_id_;
bool magic_window_enabled_ = true;
diff --git a/chromium/device/vr/vr_device_base_unittest.cc b/chromium/device/vr/vr_device_base_unittest.cc
index 37c9e8c5c8b..29118faa614 100644
--- a/chromium/device/vr/vr_device_base_unittest.cc
+++ b/chromium/device/vr/vr_device_base_unittest.cc
@@ -44,6 +44,25 @@ class VRDeviceBaseForTesting : public VRDeviceBase {
DISALLOW_COPY_AND_ASSIGN(VRDeviceBaseForTesting);
};
+class StubVRDeviceEventListener : public VRDeviceEventListener {
+ public:
+ ~StubVRDeviceEventListener() override {}
+
+ MOCK_METHOD1(DoOnChanged, void(mojom::VRDisplayInfo* vr_device_info));
+ void OnChanged(mojom::VRDisplayInfoPtr vr_device_info) override {
+ DoOnChanged(vr_device_info.get());
+ }
+
+ MOCK_METHOD2(OnActivate,
+ void(mojom::VRDisplayEventReason,
+ base::OnceCallback<void(bool)>));
+
+ MOCK_METHOD0(OnExitPresent, void());
+ MOCK_METHOD0(OnBlur, void());
+ MOCK_METHOD0(OnFocus, void());
+ MOCK_METHOD1(OnDeactivate, void(mojom::VRDisplayEventReason));
+};
+
} // namespace
class VRDeviceTest : public testing::Test {
@@ -58,8 +77,10 @@ class VRDeviceTest : public testing::Test {
}
std::unique_ptr<MockVRDisplayImpl> MakeMockDisplay(VRDeviceBase* device) {
+ mojom::VRDisplayClientPtr display_client;
return std::make_unique<testing::NiceMock<MockVRDisplayImpl>>(
- device, client(), nullptr, nullptr, false);
+ device, client(), nullptr, nullptr, mojo::MakeRequest(&display_client),
+ false);
}
std::unique_ptr<VRDeviceBaseForTesting> MakeVRDevice() {
@@ -88,8 +109,9 @@ class VRDeviceTest : public testing::Test {
// will receive the "vrdevicechanged" event.
TEST_F(VRDeviceTest, DeviceChangedDispatched) {
auto device = MakeVRDevice();
- auto display = MakeMockDisplay(device.get());
- EXPECT_CALL(*display, DoOnChanged(testing::_)).Times(1);
+ StubVRDeviceEventListener listener;
+ device->SetVRDeviceEventListener(&listener);
+ EXPECT_CALL(listener, DoOnChanged(testing::_)).Times(1);
device->SetVRDisplayInfoForTest(MakeVRDisplayInfo(device->GetId()));
}
@@ -97,57 +119,14 @@ TEST_F(VRDeviceTest, DisplayActivateRegsitered) {
device::mojom::VRDisplayEventReason mounted =
device::mojom::VRDisplayEventReason::MOUNTED;
auto device = MakeVRDevice();
- auto display1 = MakeMockDisplay(device.get());
- auto display2 = MakeMockDisplay(device.get());
-
- EXPECT_CALL(*display1, ListeningForActivate())
- .WillRepeatedly(testing::Return(true));
- EXPECT_CALL(*display1, InFocusedFrame())
- .WillRepeatedly(testing::Return(false));
- device->OnListeningForActivateChanged(display1.get());
- EXPECT_FALSE(device->ListeningForActivate());
-
- EXPECT_CALL(*display1, OnActivate(mounted, testing::_)).Times(0);
- EXPECT_CALL(*display2, OnActivate(mounted, testing::_)).Times(0);
- device->FireDisplayActivate();
-
- EXPECT_CALL(*display1, InFocusedFrame())
- .WillRepeatedly(testing::Return(true));
- device->OnFrameFocusChanged(display1.get());
- EXPECT_TRUE(device->ListeningForActivate());
-
- EXPECT_CALL(*display1, OnActivate(mounted, testing::_)).Times(1);
- device->FireDisplayActivate();
-
- EXPECT_CALL(*display2, ListeningForActivate())
- .WillRepeatedly(testing::Return(true));
- EXPECT_CALL(*display2, InFocusedFrame())
- .WillRepeatedly(testing::Return(true));
- device->OnListeningForActivateChanged(display2.get());
- EXPECT_TRUE(device->ListeningForActivate());
-
- EXPECT_CALL(*display2, OnActivate(mounted, testing::_)).Times(2);
- device->FireDisplayActivate();
-
- EXPECT_CALL(*display1, ListeningForActivate())
- .WillRepeatedly(testing::Return(false));
- device->OnListeningForActivateChanged(display1.get());
- EXPECT_TRUE(device->ListeningForActivate());
+ StubVRDeviceEventListener listener;
+ device->SetVRDeviceEventListener(&listener);
- device->FireDisplayActivate();
-
- EXPECT_CALL(*display2, ListeningForActivate())
- .WillRepeatedly(testing::Return(false));
- device->OnListeningForActivateChanged(display2.get());
EXPECT_FALSE(device->ListeningForActivate());
+ device->SetListeningForActivate(true);
+ EXPECT_TRUE(device->ListeningForActivate());
- // Make sure we don't send the DisplayActivate event.
- device->FireDisplayActivate();
-
- EXPECT_CALL(*display2, InFocusedFrame())
- .WillRepeatedly(testing::Return(false));
- device->OnFrameFocusChanged(display2.get());
-
+ EXPECT_CALL(listener, OnActivate(mounted, testing::_)).Times(1);
device->FireDisplayActivate();
}
diff --git a/chromium/device/vr/vr_display_impl.cc b/chromium/device/vr/vr_display_impl.cc
index e47cce8dd53..aba13dbb42b 100644
--- a/chromium/device/vr/vr_display_impl.cc
+++ b/chromium/device/vr/vr_display_impl.cc
@@ -9,79 +9,60 @@
#include "base/bind.h"
#include "device/vr/vr_device_base.h"
+namespace {
+constexpr int kMaxImageHeightOrWidth = 8000;
+} // namespace
+
namespace device {
VRDisplayImpl::VRDisplayImpl(VRDevice* device,
mojom::VRServiceClient* service_client,
mojom::VRDisplayInfoPtr display_info,
mojom::VRDisplayHostPtr display_host,
+ mojom::VRDisplayClientRequest client_request,
bool in_focused_frame)
: binding_(this),
device_(static_cast<VRDeviceBase*>(device)),
in_focused_frame_(in_focused_frame) {
- device_->AddDisplay(this);
mojom::VRMagicWindowProviderPtr magic_window_provider;
binding_.Bind(mojo::MakeRequest(&magic_window_provider));
service_client->OnDisplayConnected(
std::move(magic_window_provider), std::move(display_host),
- mojo::MakeRequest(&client_), std::move(display_info));
-}
-
-VRDisplayImpl::~VRDisplayImpl() {
- device_->RemoveDisplay(this);
-}
-
-void VRDisplayImpl::OnChanged(mojom::VRDisplayInfoPtr vr_device_info) {
- client_->OnChanged(std::move(vr_device_info));
-}
-
-void VRDisplayImpl::OnExitPresent() {
- client_->OnExitPresent();
+ std::move(client_request), std::move(display_info));
}
-void VRDisplayImpl::OnBlur() {
- client_->OnBlur();
-}
+VRDisplayImpl::~VRDisplayImpl() = default;
-void VRDisplayImpl::OnFocus() {
- client_->OnFocus();
-}
-
-void VRDisplayImpl::OnActivate(mojom::VRDisplayEventReason reason,
- base::Callback<void(bool)> on_handled) {
- client_->OnActivate(reason, std::move(on_handled));
-}
-
-void VRDisplayImpl::OnDeactivate(mojom::VRDisplayEventReason reason) {
- client_->OnDeactivate(reason);
-}
-
-void VRDisplayImpl::RequestPresent(
- mojom::VRSubmitFrameClientPtr submit_client,
- mojom::VRPresentationProviderRequest request,
- mojom::VRRequestPresentOptionsPtr present_options,
- mojom::VRDisplayHost::RequestPresentCallback callback) {
- if (!device_->IsAccessAllowed(this) || !InFocusedFrame()) {
- std::move(callback).Run(false, nullptr);
+// Gets a pose for magic window sessions.
+void VRDisplayImpl::GetPose(GetPoseCallback callback) {
+ if (!device_->IsAccessAllowed(this)) {
+ std::move(callback).Run(nullptr);
return;
}
-
- device_->RequestPresent(this, std::move(submit_client), std::move(request),
- std::move(present_options), std::move(callback));
-}
-
-void VRDisplayImpl::ExitPresent() {
- if (device_->CheckPresentingDisplay(this))
- device_->ExitPresent();
+ device_->GetMagicWindowPose(std::move(callback));
}
-// Gets a pose for magic window sessions.
-void VRDisplayImpl::GetPose(GetPoseCallback callback) {
+// Gets frame image data for AR magic window sessions.
+void VRDisplayImpl::GetFrameData(const gfx::Size& frame_size,
+ display::Display::Rotation rotation,
+ GetFrameDataCallback callback) {
if (!device_->IsAccessAllowed(this)) {
std::move(callback).Run(nullptr);
return;
}
- device_->GetMagicWindowPose(std::move(callback));
+
+ // Check for a valid frame size.
+ // While Mojo should handle negative values, we also do not want to allow 0.
+ // TODO(https://crbug.com/841062): Reconsider how we check the sizes.
+ if (frame_size.width() <= 0 || frame_size.height() <= 0 ||
+ frame_size.width() > kMaxImageHeightOrWidth ||
+ frame_size.height() > kMaxImageHeightOrWidth) {
+ DLOG(ERROR) << "Invalid frame size passed to GetFrameData().";
+ std::move(callback).Run(nullptr);
+ return;
+ }
+
+ device_->GetMagicWindowFrameData(frame_size, rotation, std::move(callback));
}
void VRDisplayImpl::SetListeningForActivate(bool listening) {
diff --git a/chromium/device/vr/vr_display_impl.h b/chromium/device/vr/vr_display_impl.h
index df334c3a0b7..1474337810f 100644
--- a/chromium/device/vr/vr_display_impl.h
+++ b/chromium/device/vr/vr_display_impl.h
@@ -12,6 +12,7 @@
#include "device/vr/public/mojom/vr_service.mojom.h"
#include "device/vr/vr_export.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/display/display.h"
namespace device {
@@ -30,34 +31,23 @@ class DEVICE_VR_EXPORT VRDisplayImpl : public mojom::VRMagicWindowProvider {
mojom::VRServiceClient* service_client,
mojom::VRDisplayInfoPtr display_info,
mojom::VRDisplayHostPtr display_host,
+ mojom::VRDisplayClientRequest client_request,
bool in_frame_focused);
~VRDisplayImpl() override;
- virtual void OnChanged(mojom::VRDisplayInfoPtr vr_device_info);
- virtual void OnExitPresent();
- virtual void OnBlur();
- virtual void OnFocus();
- virtual void OnActivate(mojom::VRDisplayEventReason reason,
- base::Callback<void(bool)> on_handled);
- virtual void OnDeactivate(mojom::VRDisplayEventReason reason);
-
void SetListeningForActivate(bool listening);
void SetInFocusedFrame(bool in_focused_frame);
virtual bool ListeningForActivate();
virtual bool InFocusedFrame();
- void RequestPresent(mojom::VRSubmitFrameClientPtr submit_client,
- mojom::VRPresentationProviderRequest request,
- mojom::VRRequestPresentOptionsPtr options,
- mojom::VRDisplayHost::RequestPresentCallback callback);
- void ExitPresent();
-
private:
// mojom::VRMagicWindowProvider
void GetPose(GetPoseCallback callback) override;
+ void GetFrameData(const gfx::Size& frame_size,
+ display::Display::Rotation rotation,
+ GetFrameDataCallback callback) override;
mojo::Binding<mojom::VRMagicWindowProvider> binding_;
- mojom::VRDisplayClientPtr client_;
device::VRDeviceBase* device_;
bool listening_for_activate_ = false;
bool in_focused_frame_ = false;
diff --git a/chromium/device/vr/vr_display_impl_unittest.cc b/chromium/device/vr/vr_display_impl_unittest.cc
index 42fb49f6269..0d90fb8e269 100644
--- a/chromium/device/vr/vr_display_impl_unittest.cc
+++ b/chromium/device/vr/vr_display_impl_unittest.cc
@@ -35,8 +35,10 @@ class VRDisplayImplTest : public testing::Test {
}
std::unique_ptr<VRDisplayImpl> MakeDisplay() {
+ mojom::VRDisplayClientPtr display_client;
return std::make_unique<VRDisplayImpl>(
- device(), client(), device()->GetVRDisplayInfo(), nullptr, false);
+ device(), client(), device()->GetVRDisplayInfo(), nullptr,
+ mojo::MakeRequest(&display_client), false);
}
void RequestPresent(VRDisplayImpl* display_impl) {
@@ -45,15 +47,15 @@ class VRDisplayImplTest : public testing::Test {
// is ok.
device::mojom::VRSubmitFrameClientPtr submit_client = nullptr;
device::mojom::VRPresentationProviderRequest request = nullptr;
- display_impl->RequestPresent(
+ device_->RequestPresent(
std::move(submit_client), std::move(request), nullptr,
- base::Bind(&VRDisplayImplTest::onPresentComplete,
- base::Unretained(this)));
+ base::BindOnce(&VRDisplayImplTest::onPresentComplete,
+ base::Unretained(this)));
}
- void ExitPresent(VRDisplayImpl* display_impl) { display_impl->ExitPresent(); }
+ void ExitPresent() { device_->ExitPresent(); }
- bool presenting() { return !!device_->GetPresentingDisplay(); }
+ bool presenting() { return device_->IsPresenting(); }
VRDeviceBase* device() { return device_.get(); }
FakeVRServiceClient* client() { return client_.get(); }
@@ -73,33 +75,17 @@ TEST_F(VRDisplayImplTest, DevicePresentationIsolation) {
EXPECT_TRUE(device()->IsAccessAllowed(display_1.get()));
EXPECT_TRUE(device()->IsAccessAllowed(display_2.get()));
- // Attempt to present without focus.
- RequestPresent(display_1.get());
- EXPECT_FALSE(is_request_presenting_success_);
- EXPECT_FALSE(presenting());
-
- // Begin presenting to the fake device with service 1.
- display_1->SetInFocusedFrame(true);
+ // Attempt to present.
RequestPresent(display_1.get());
EXPECT_TRUE(is_request_presenting_success_);
EXPECT_TRUE(presenting());
- // Service 2 should not be able to present to the device while service 1
- // is still presenting.
- RequestPresent(display_2.get());
- EXPECT_FALSE(is_request_presenting_success_);
- display_2->SetInFocusedFrame(true);
- RequestPresent(display_2.get());
- EXPECT_FALSE(is_request_presenting_success_);
- EXPECT_TRUE(device()->IsAccessAllowed(display_1.get()));
+ // While a device is presenting, noone should have access to magic window.
+ EXPECT_FALSE(device()->IsAccessAllowed(display_1.get()));
EXPECT_FALSE(device()->IsAccessAllowed(display_2.get()));
- // Service 2 should not be able to exit presentation to the device.
- ExitPresent(display_2.get());
- EXPECT_TRUE(presenting());
-
// Service 1 should be able to exit the presentation it initiated.
- ExitPresent(display_1.get());
+ ExitPresent();
EXPECT_FALSE(presenting());
// Once presentation had ended both services should be able to access the
@@ -108,14 +94,4 @@ TEST_F(VRDisplayImplTest, DevicePresentationIsolation) {
EXPECT_TRUE(device()->IsAccessAllowed(display_2.get()));
}
-// This test case tests that VRDisplayImpl dispatches a "vrdevicechanged" event
-// to its client when it's been told the device has changed.
-TEST_F(VRDisplayImplTest, DeviceChangedDispatched) {
- auto display = MakeDisplay();
- display->OnChanged(device()->GetVRDisplayInfo());
-
- base::RunLoop().RunUntilIdle();
-
- EXPECT_TRUE(client()->CheckDeviceId(device()->GetId()));
-}
}