0

WebAuthn: Use TestFuture in tests pt. 2

Getting rid of the TestCallbackReceiver duplication

Bug: 347047628, 40275628
Change-Id: Ia638ece50aa2a0ed2b9ce9316e38d802daf74aa4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5644906
Reviewed-by: Adam Langley <agl@chromium.org>
Commit-Queue: Adem Derinel <derinel@google.com>
Cr-Commit-Position: refs/heads/main@{#1319576}
This commit is contained in:
Adem Derinel
2024-06-26 06:11:28 +00:00
committed by Chromium LUCI CQ
parent 685c84eef1
commit 7f954eebef
13 changed files with 550 additions and 446 deletions

@ -4,18 +4,32 @@
#include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
@ -25,6 +39,7 @@
#include "base/types/strong_alias.h"
#include "build/build_config.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate.h"
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate_factory.h"
#include "chrome/browser/webauthn/authenticator_reference.h"
#include "chrome/browser/webauthn/authenticator_transport.h"
@ -37,7 +52,9 @@
#include "components/sync/base/features.h"
#include "components/vector_icons/vector_icons.h"
#include "components/webauthn/core/browser/passkey_model.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/cable/v2_constants.h"
#include "device/fido/discoverable_credential_metadata.h"
#include "device/fido/features.h"
#include "device/fido/fido_constants.h"
@ -45,14 +62,12 @@
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/fido_types.h"
#include "device/fido/platform_user_verification_policy.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/vector_icon_types.h"
#include "url/gurl.h"
#if BUILDFLAG(IS_WIN)
#include "device/fido/win/fake_webauthn_api.h"

@ -5,12 +5,23 @@
#include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
#include <algorithm>
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/password_manager/chrome_webauthn_credentials_delegate_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h"
@ -21,15 +32,14 @@
#include "chrome/browser/webauthn/webauthn_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/sync/base/features.h"
#include "components/sync/base/user_selectable_type.h"
#include "components/sync/test/test_sync_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/webauthn/core/browser/passkey_model.h"
#include "components/webauthn/core/browser/test_passkey_model.h"
#include "content/public/browser/authenticator_request_client_delegate.h"
@ -37,14 +47,13 @@
#include "content/public/test/web_contents_tester.h"
#include "crypto/scoped_mock_unexportable_key_provider.h"
#include "device/fido/cable/cable_discovery_data.h"
#include "device/fido/cable/v2_constants.h"
#include "device/fido/discoverable_credential_metadata.h"
#include "device/fido/features.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_discovery_factory.h"
#include "device/fido/fido_request_handler_base.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/fido_types.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/virtual_ctap2_device.h"
#include "device/fido/virtual_fido_device_authenticator.h"
#include "extensions/browser/extension_registry.h"
@ -63,6 +72,7 @@
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_MAC)
#include "chrome/test/base/testing_profile.h"
#include "device/fido/mac/authenticator_config.h"
#endif // BUILDFLAG(IS_MAC)
@ -712,11 +722,11 @@ TEST_F(ChromeAuthenticatorRequestDelegateTest, VirtualEnvironmentAttestation) {
delegate.SetVirtualEnvironment(true);
device::VirtualFidoDeviceAuthenticator authenticator(
std::make_unique<device::VirtualCtap2Device>());
device::test::ValueCallbackReceiver<bool> cb;
base::test::TestFuture<bool> future;
delegate.ShouldReturnAttestation(kRelyingPartyID, &authenticator,
/*is_enterprise_attestation=*/false,
cb.callback());
EXPECT_TRUE(cb.value());
future.GetCallback());
EXPECT_TRUE(future.Get());
}
// Tests that synced GPM passkeys are injected in the transport availability
@ -1063,10 +1073,11 @@ TEST_F(EnclaveAuthenticatorRequestDelegateTest,
.emplace<crypto::ScopedMockUnexportableKeyProvider>();
}
device::test::ValueCallbackReceiver<bool> cb;
delegate.BrowserProvidedPasskeysAvailable(browser_context(), cb.callback());
cb.WaitForCallback();
EXPECT_EQ(cb.value(), test.expected_passkeys_available);
base::test::TestFuture<bool> future;
delegate.BrowserProvidedPasskeysAvailable(browser_context(),
future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), test.expected_passkeys_available);
signin::ClearPrimaryAccount(identity_manager);
}
}
@ -1128,13 +1139,13 @@ TEST_F(ChromeAuthenticatorRequestDelegateTest, ShouldPromptForAttestationWin) {
::device::WinWebAuthnApiAuthenticator authenticator(
/*current_window=*/nullptr, &win_webauthn_api);
::device::test::ValueCallbackReceiver<bool> cb;
base::test::TestFuture<bool> future;
ChromeAuthenticatorRequestDelegate delegate(main_rfh());
delegate.ShouldReturnAttestation(kRelyingPartyID, &authenticator,
/*is_enterprise_attestation=*/false,
cb.callback());
cb.WaitForCallback();
EXPECT_EQ(cb.value(), true);
future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), true);
}
#endif // BUILDFLAG(IS_WIN)

@ -2,17 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <tuple>
#include "chrome/browser/webauthn/local_credential_management_win.h"
#include "base/run_loop.h"
#include <cstdint>
#include <optional>
#include <vector>
#include "base/test/test_future.h"
#include "build/build_config.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/discoverable_credential_metadata.h"
#include "device/fido/win/fake_webauthn_api.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -30,22 +31,22 @@ class LocalCredentialManagementTest : public testing::Test {
void SetUp() override { api_.set_supports_silent_discovery(true); }
bool HasCredentials() {
device::test::TestCallbackReceiver<bool> callback;
local_cred_man_.HasCredentials(callback.callback());
base::test::TestFuture<bool> future;
local_cred_man_.HasCredentials(future.GetCallback());
callback.WaitForCallback();
return std::get<0>(callback.TakeResult());
EXPECT_TRUE(future.Wait());
return future.Get();
}
std::optional<std::vector<device::DiscoverableCredentialMetadata>>
Enumerate() {
device::test::TestCallbackReceiver<
base::test::TestFuture<
std::optional<std::vector<device::DiscoverableCredentialMetadata>>>
callback;
local_cred_man_.Enumerate(callback.callback());
future;
local_cred_man_.Enumerate(future.GetCallback());
callback.WaitForCallback();
return std::get<0>(callback.TakeResult());
EXPECT_TRUE(future.Wait());
return future.Get();
}
// A `BrowserTaskEnvironment` needs to be in-scope in order to create a

@ -4,26 +4,31 @@
#include <stdint.h>
#include <cstring>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include "base/base64.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/cbor/reader.h"
#include "content/browser/payments/stub_payment_credential.h"
#include "content/browser/renderer_host/back_forward_cache_disable.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
@ -50,23 +55,22 @@
#include "content/shell/browser/shell.h"
#include "content/test/did_commit_navigation_interceptor.h"
#include "content/test/fake_network_url_loader_factory.h"
#include "crypto/sha2.h"
#include "crypto/signature_verifier.h"
#include "device/base/features.h"
#include "device/fido/fake_fido_discovery.h"
#include "device/fido/features.h"
#include "device/fido/fido_discovery_factory.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/fido_types.h"
#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/p256_public_key.h"
#include "device/fido/public_key.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/public_key_credential_params.h"
#include "device/fido/virtual_fido_device.h"
#include "device/fido/virtual_fido_device_factory.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/webauthn/authenticator.mojom.h"
@ -87,16 +91,15 @@ using blink::mojom::GetAssertionAuthenticatorResponsePtr;
using blink::mojom::MakeCredentialAuthenticatorResponsePtr;
using blink::mojom::WebAuthnDOMExceptionDetailsPtr;
using TestCreateCallbackReceiver =
device::test::StatusAndValuesCallbackReceiver<
AuthenticatorStatus,
MakeCredentialAuthenticatorResponsePtr,
WebAuthnDOMExceptionDetailsPtr>;
using TestCreateFuture =
base::test::TestFuture<AuthenticatorStatus,
MakeCredentialAuthenticatorResponsePtr,
WebAuthnDOMExceptionDetailsPtr>;
using TestGetCallbackReceiver = device::test::StatusAndValuesCallbackReceiver<
AuthenticatorStatus,
GetAssertionAuthenticatorResponsePtr,
WebAuthnDOMExceptionDetailsPtr>;
using TestGetFuture =
base::test::TestFuture<AuthenticatorStatus,
GetAssertionAuthenticatorResponsePtr,
WebAuthnDOMExceptionDetailsPtr>;
constexpr char kOkMessage[] = "OK";
@ -767,10 +770,10 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
base::BindLambdaForTesting(
[&](device::VirtualFidoDevice* device) { return false; });
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
create_callback_receiver.callback());
ASSERT_FALSE(create_callback_receiver.was_called());
create_future.GetCallback());
ASSERT_FALSE(create_future.IsReady());
EXPECT_TRUE(
NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
WaitForConnectionError();
@ -779,11 +782,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
// navigator.credentials.create({publicKey: ...}) again.
ConnectToAuthenticator();
InjectVirtualFidoDeviceFactory();
TestCreateCallbackReceiver create_callback_receiver2;
TestCreateFuture create_future2;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
create_callback_receiver2.callback());
create_callback_receiver2.WaitForCallback();
EXPECT_EQ(create_callback_receiver2.status(), AuthenticatorStatus::SUCCESS);
create_future2.GetCallback());
EXPECT_TRUE(create_future2.Wait());
EXPECT_EQ(std::get<0>(create_future2.Get()), AuthenticatorStatus::SUCCESS);
}
// Tests that no crash occurs when the implementation is destroyed with a
@ -796,10 +799,10 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
base::BindLambdaForTesting(
[&](device::VirtualFidoDevice* device) { return false; });
TestGetCallbackReceiver get_callback_receiver;
TestGetFuture get_future;
authenticator()->GetAssertion(BuildBasicGetOptions(),
get_callback_receiver.callback());
ASSERT_FALSE(get_callback_receiver.was_called());
get_future.GetCallback());
ASSERT_FALSE(get_future.IsReady());
EXPECT_TRUE(
NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
WaitForConnectionError();
@ -808,11 +811,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
// navigator.credentials.get({publicKey: ...}) again.
ConnectToAuthenticator();
InjectVirtualFidoDeviceFactory();
TestGetCallbackReceiver get_callback_receiver2;
TestGetFuture get_future2;
authenticator()->GetAssertion(BuildBasicGetOptions(),
get_callback_receiver2.callback());
get_callback_receiver2.WaitForCallback();
EXPECT_EQ(get_callback_receiver2.status(),
get_future2.GetCallback());
EXPECT_TRUE(get_future2.Wait());
EXPECT_EQ(std::get<0>(get_future2.Get()),
AuthenticatorStatus::NOT_ALLOWED_ERROR);
}
@ -847,11 +850,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
SCOPED_TRACE(AttestationCallbackBehaviorToString(behavior));
InjectVirtualFidoDeviceFactory();
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
auto options = BuildBasicCreateOptions();
options->attestation = device::AttestationConveyancePreference::kDirect;
authenticator()->MakeCredential(std::move(options),
create_callback_receiver.callback());
create_future.GetCallback());
bool attestation_callback_was_invoked = false;
test_state()->attestation_prompt_callback_ = base::BindLambdaForTesting(
[&](base::OnceCallback<void(bool)> callback) {
@ -887,11 +890,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
NavigateToURL(shell(), GetHttpsURL("www.acme.com", "/title2.html")));
InjectVirtualFidoDeviceFactory();
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
create_callback_receiver.callback());
create_callback_receiver.WaitForCallback();
EXPECT_EQ(create_callback_receiver.status(), AuthenticatorStatus::SUCCESS);
create_future.GetCallback());
EXPECT_TRUE(create_future.Wait());
EXPECT_EQ(std::get<0>(create_future.Get()), AuthenticatorStatus::SUCCESS);
}
// Tests that a navigator.credentials.create({publicKey: ...}) issued at the
@ -900,13 +903,13 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
CreatePublicKeyCredentialRacingWithNavigation) {
InjectVirtualFidoDeviceFactory();
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
auto request_options = BuildBasicCreateOptions();
ClosureExecutorBeforeNavigationCommit executor(
shell()->web_contents(), base::BindLambdaForTesting([&]() {
authenticator()->MakeCredential(std::move(request_options),
create_callback_receiver.callback());
create_future.GetCallback());
}));
EXPECT_TRUE(
@ -916,11 +919,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
// The next active document should be able to successfully call
// navigator.credentials.create({publicKey: ...}) again.
ConnectToAuthenticator();
TestCreateCallbackReceiver create_callback_receiver2;
TestCreateFuture create_future2;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
create_callback_receiver2.callback());
create_callback_receiver2.WaitForCallback();
EXPECT_EQ(AuthenticatorStatus::SUCCESS, create_callback_receiver2.status());
create_future2.GetCallback());
EXPECT_TRUE(create_future2.Wait());
EXPECT_EQ(AuthenticatorStatus::SUCCESS, std::get<0>(create_future2.Get()));
}
// Regression test for https://crbug.com/818219.
@ -932,16 +935,16 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
base::BindLambdaForTesting(
[&](device::VirtualFidoDevice* device) { return false; });
TestCreateCallbackReceiver callback_receiver_1;
TestCreateCallbackReceiver callback_receiver_2;
TestCreateFuture future_1;
TestCreateFuture future_2;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
callback_receiver_1.callback());
future_1.GetCallback());
authenticator()->MakeCredential(BuildBasicCreateOptions(),
callback_receiver_2.callback());
callback_receiver_2.WaitForCallback();
future_2.GetCallback());
EXPECT_TRUE(future_2.Wait());
EXPECT_EQ(AuthenticatorStatus::PENDING_REQUEST, callback_receiver_2.status());
EXPECT_FALSE(callback_receiver_1.was_called());
EXPECT_EQ(AuthenticatorStatus::PENDING_REQUEST, std::get<0>(future_2.Get()));
EXPECT_FALSE(future_1.IsReady());
}
// Regression test for https://crbug.com/818219.
@ -953,16 +956,14 @@ IN_PROC_BROWSER_TEST_F(WebAuthLocalClientBrowserTest,
base::BindLambdaForTesting(
[&](device::VirtualFidoDevice* device) { return false; });
TestGetCallbackReceiver callback_receiver_1;
TestGetCallbackReceiver callback_receiver_2;
authenticator()->GetAssertion(BuildBasicGetOptions(),
callback_receiver_1.callback());
authenticator()->GetAssertion(BuildBasicGetOptions(),
callback_receiver_2.callback());
callback_receiver_2.WaitForCallback();
TestGetFuture future_1;
TestGetFuture future_2;
authenticator()->GetAssertion(BuildBasicGetOptions(), future_1.GetCallback());
authenticator()->GetAssertion(BuildBasicGetOptions(), future_2.GetCallback());
EXPECT_TRUE(future_2.Wait());
EXPECT_EQ(AuthenticatorStatus::PENDING_REQUEST, callback_receiver_2.status());
EXPECT_FALSE(callback_receiver_1.was_called());
EXPECT_EQ(AuthenticatorStatus::PENDING_REQUEST, std::get<0>(future_2.Get()));
EXPECT_FALSE(future_1.IsReady());
}
// WebAuthJavascriptClientBrowserTest -----------------------------------------
@ -1954,12 +1955,12 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest, TestMakeCredential) {
auto* virtual_device_factory = InjectVirtualFidoDeviceFactory();
virtual_device_factory->SetSupportedProtocol(protocol);
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
authenticator()->MakeCredential(BuildBasicCreateOptions(),
create_callback_receiver.callback());
create_future.GetCallback());
create_callback_receiver.WaitForCallback();
EXPECT_EQ(AuthenticatorStatus::SUCCESS, create_callback_receiver.status());
EXPECT_TRUE(create_future.Wait());
EXPECT_EQ(AuthenticatorStatus::SUCCESS, std::get<0>(create_future.Get()));
}
}
@ -1982,13 +1983,13 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest,
device::test_data::kCtap2MakeCredentialCredentialId),
make_credential_request->relying_party.id));
TestCreateCallbackReceiver create_callback_receiver;
TestCreateFuture create_future;
authenticator()->MakeCredential(std::move(make_credential_request),
create_callback_receiver.callback());
create_future.GetCallback());
create_callback_receiver.WaitForCallback();
EXPECT_TRUE(create_future.Wait());
EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_EXCLUDED,
create_callback_receiver.status());
std::get<0>(create_future.Get()));
}
}
@ -2002,11 +2003,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest, TestGetAssertion) {
device::test_data::kTestGetAssertionCredentialId),
get_assertion_request_params->relying_party_id));
TestGetCallbackReceiver get_callback_receiver;
TestGetFuture get_future;
authenticator()->GetAssertion(std::move(get_assertion_request_params),
get_callback_receiver.callback());
get_callback_receiver.WaitForCallback();
EXPECT_EQ(AuthenticatorStatus::SUCCESS, get_callback_receiver.status());
get_future.GetCallback());
EXPECT_TRUE(get_future.Wait());
EXPECT_EQ(AuthenticatorStatus::SUCCESS, std::get<0>(get_future.Get()));
}
}
@ -2017,12 +2018,12 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest,
virtual_device_factory->SetSupportedProtocol(protocol);
auto get_assertion_request_params = BuildBasicGetOptions();
TestGetCallbackReceiver get_callback_receiver;
TestGetFuture get_future;
authenticator()->GetAssertion(std::move(get_assertion_request_params),
get_callback_receiver.callback());
get_callback_receiver.WaitForCallback();
get_future.GetCallback());
EXPECT_TRUE(get_future.Wait());
EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
get_callback_receiver.status());
std::get<0>(get_future.Get()));
}
}
@ -2073,11 +2074,11 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest,
device::test_data::kTestGetAssertionCredentialId),
get_assertion_request_params->relying_party_id));
TestGetCallbackReceiver get_callback_receiver;
TestGetFuture get_future;
authenticator()->GetAssertion(std::move(get_assertion_request_params),
get_callback_receiver.callback());
get_callback_receiver.WaitForCallback();
EXPECT_EQ(AuthenticatorStatus::SUCCESS, get_callback_receiver.status());
get_future.GetCallback());
EXPECT_TRUE(get_future.Wait());
EXPECT_EQ(AuthenticatorStatus::SUCCESS, std::get<0>(get_future.Get()));
EXPECT_THAT(logger->log(), testing::ElementsAre("www.acme.com"));
}
@ -2093,12 +2094,12 @@ IN_PROC_BROWSER_TEST_F(WebAuthBrowserCtapTest,
blink::mojom::PublicKeyCredentialRequestOptionsPtr
get_assertion_request_params = BuildBasicGetOptions();
TestGetCallbackReceiver get_callback_receiver;
TestGetFuture get_future;
authenticator()->GetAssertion(std::move(get_assertion_request_params),
get_callback_receiver.callback());
get_callback_receiver.WaitForCallback();
get_future.GetCallback());
EXPECT_TRUE(get_future.Wait());
EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR,
get_callback_receiver.status());
std::get<0>(get_future.Get()));
EXPECT_TRUE(logger->log().empty());
}

@ -4,15 +4,17 @@
#include "device/fido/ble_adapter_manager.h"
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include "base/functional/callback_helpers.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
@ -21,7 +23,6 @@
#include "device/fido/fido_authenticator.h"
#include "device/fido/fido_request_handler_base.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -238,10 +239,10 @@ TEST_F(FidoBleAdapterManagerTest, RequestBluetoothPermissionAllowed) {
SetAdapterPermissions(BluetoothAdapter::PermissionStatus::kAllowed);
EXPECT_CALL(*adapter(), IsPowered).WillOnce(::testing::Return(true));
test::ValueCallbackReceiver<BleStatus> callback;
fake_request_handler_->RequestBluetoothPermission(callback.callback());
callback.WaitForCallback();
EXPECT_EQ(callback.value(), BleStatus::kOn);
base::test::TestFuture<BleStatus> future;
fake_request_handler_->RequestBluetoothPermission(future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), BleStatus::kOn);
}
TEST_F(FidoBleAdapterManagerTest, RequestBluetoothPermissionDenied) {
@ -249,10 +250,10 @@ TEST_F(FidoBleAdapterManagerTest, RequestBluetoothPermissionDenied) {
SetAdapterPermissions(BluetoothAdapter::PermissionStatus::kDenied);
EXPECT_CALL(*adapter(), IsPowered).Times(0);
test::ValueCallbackReceiver<BleStatus> callback;
fake_request_handler_->RequestBluetoothPermission(callback.callback());
callback.WaitForCallback();
EXPECT_EQ(callback.value(), BleStatus::kPermissionDenied);
base::test::TestFuture<BleStatus> future;
fake_request_handler_->RequestBluetoothPermission(future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), BleStatus::kPermissionDenied);
}
// Tests that if the Bluetooth API happens to report the OS permission status as
@ -264,10 +265,10 @@ TEST_F(FidoBleAdapterManagerTest,
SetAdapterPermissions(BluetoothAdapter::PermissionStatus::kUndetermined);
EXPECT_CALL(*adapter(), IsPowered).WillOnce(::testing::Return(true));
test::ValueCallbackReceiver<BleStatus> callback;
fake_request_handler_->RequestBluetoothPermission(callback.callback());
callback.WaitForCallback();
EXPECT_EQ(callback.value(), BleStatus::kOn);
base::test::TestFuture<BleStatus> future;
fake_request_handler_->RequestBluetoothPermission(future.GetCallback());
EXPECT_TRUE(future.Wait());
EXPECT_EQ(future.Get(), BleStatus::kOn);
}
} // namespace device

@ -5,23 +5,28 @@
#include "device/fido/cable/fido_cable_device.h"
#include <array>
#include <cstdint>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/check.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "crypto/aead.h"
#include "device/bluetooth/test/bluetooth_test.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/cable/mock_fido_ble_connection.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/test_callback_receiver.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -32,8 +37,8 @@ namespace {
using ::testing::_;
using ::testing::Invoke;
using ::testing::Test;
using TestDeviceCallbackReceiver =
test::ValueCallbackReceiver<std::optional<std::vector<uint8_t>>>;
using TestDeviceFuture =
base::test::TestFuture<std::optional<std::vector<uint8_t>>>;
using NiceMockBluetoothAdapter = ::testing::NiceMock<MockBluetoothAdapter>;
// Sufficiently large test control point length as we are not interested
@ -192,13 +197,13 @@ TEST_F(FidoCableDeviceTest, GetIdTest) {
TEST_F(FidoCableDeviceTest, Timeout) {
EXPECT_CALL(*connection(), ConnectPtr);
TestDeviceCallbackReceiver callback_receiver;
device()->SendPing(std::vector<uint8_t>(), callback_receiver.callback());
TestDeviceFuture future;
device()->SendPing(std::vector<uint8_t>(), future.GetCallback());
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoDevice::State::kDeviceError, device()->state_for_testing());
EXPECT_TRUE(callback_receiver.was_called());
EXPECT_FALSE(callback_receiver.value());
EXPECT_TRUE(future.IsReady());
EXPECT_FALSE(future.Get());
}
TEST_F(FidoCableDeviceTest, TestCaBleDeviceSendData) {
@ -220,12 +225,12 @@ TEST_F(FidoCableDeviceTest, TestCaBleDeviceSendData) {
for (size_t i = 0; i < 3; i++) {
SCOPED_TRACE(i);
TestDeviceCallbackReceiver callback_receiver;
TestDeviceFuture future;
device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
callback_receiver.callback());
future.GetCallback());
callback_receiver.WaitForCallback();
const auto& value = callback_receiver.value();
EXPECT_TRUE(future.Wait());
const auto& value = future.Get();
ASSERT_TRUE(value);
EXPECT_THAT(*value, ::testing::ElementsAreArray(kTestData));
}
@ -251,12 +256,12 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnIncorrectSessionKey) {
authenticator_reply)));
}));
TestDeviceCallbackReceiver callback_receiver;
TestDeviceFuture future;
device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
callback_receiver.callback());
future.GetCallback());
callback_receiver.WaitForCallback();
const auto& value = callback_receiver.value();
EXPECT_TRUE(future.Wait());
const auto& value = future.Get();
EXPECT_FALSE(value);
}
@ -280,12 +285,12 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceFailOnUnexpectedCounter) {
authenticator_reply)));
}));
TestDeviceCallbackReceiver callback_receiver;
TestDeviceFuture future;
device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
callback_receiver.callback());
future.GetCallback());
callback_receiver.WaitForCallback();
const auto& value = callback_receiver.value();
EXPECT_TRUE(future.Wait());
const auto& value = future.Get();
EXPECT_FALSE(value);
}
@ -312,13 +317,13 @@ TEST_F(FidoCableDeviceTest, TestCableDeviceErrorOnMaxCounter) {
authenticator_reply)));
}));
TestDeviceCallbackReceiver callback_receiver;
TestDeviceFuture future;
device()->SetSequenceNumbersForTesting(kInvalidCounter, 0);
device()->DeviceTransact(fido_parsing_utils::Materialize(kTestData),
callback_receiver.callback());
future.GetCallback());
callback_receiver.WaitForCallback();
const auto& value = callback_receiver.value();
EXPECT_TRUE(future.Wait());
const auto& value = future.Get();
EXPECT_FALSE(value);
}

@ -4,20 +4,35 @@
#include "device/fido/credential_management_handler.h"
#include <algorithm>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/check_op.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "device/fido/credential_management.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/fido_types.h"
#include "device/fido/large_blob.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/virtual_ctap2_device.h"
#include "device/fido/virtual_fido_device.h"
#include "device/fido/virtual_fido_device_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -44,7 +59,7 @@ class CredentialManagementHandlerTest : public ::testing::Test {
&virtual_device_factory_,
base::flat_set<FidoTransportProtocol>{
FidoTransportProtocol::kUsbHumanInterfaceDevice},
ready_callback_.callback(),
ready_future_.GetCallback(),
base::BindRepeating(&CredentialManagementHandlerTest::GetPIN,
base::Unretained(this)),
finished_callback_.callback());
@ -59,7 +74,7 @@ class CredentialManagementHandlerTest : public ::testing::Test {
base::test::TaskEnvironment task_environment_;
test::TestCallbackReceiver<> ready_callback_;
base::test::TestFuture<void> ready_future_;
test::StatusAndValuesCallbackReceiver<
CtapDeviceResponseCode,
std::optional<std::vector<AggregatedEnumerateCredentialsResponse>>,
@ -91,7 +106,7 @@ TEST_F(CredentialManagementHandlerTest, TestDeleteCredentials) {
kCredentialID, rp, user));
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
ASSERT_TRUE(ready_future_.Wait());
handler->GetCredentials(get_credentials_callback_.callback());
get_credentials_callback_.WaitForCallback();
@ -155,7 +170,7 @@ TEST_F(CredentialManagementHandlerTest, TestGarbageCollectLargeBlob_Startup) {
virtual_device_factory_.mutable_state()->registrations.clear();
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
EXPECT_EQ(virtual_device_factory_.mutable_state()->large_blob,
empty_large_blob);
}
@ -178,7 +193,7 @@ TEST_F(CredentialManagementHandlerTest, TestGarbageCollectLargeBlob_Delete) {
virtual_device_factory_.mutable_state()->large_blob;
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
PublicKeyCredentialRpEntity rp(kRPID, kRPName);
PublicKeyCredentialUserEntity user(fido_parsing_utils::Materialize(kUserID),
@ -224,7 +239,7 @@ TEST_F(CredentialManagementHandlerTest,
virtual_device_factory_.mutable_state()->large_blob;
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
PublicKeyCredentialRpEntity rp(kRPID, kRPName);
PublicKeyCredentialUserEntity user(fido_parsing_utils::Materialize(kUserID),
@ -277,7 +292,7 @@ TEST_F(CredentialManagementHandlerTest, TestUpdateUserInformation) {
kCredentialID, rp, user));
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
PublicKeyCredentialUserEntity updated_user(
fido_parsing_utils::Materialize(kUserID), "bobbyr@example.com",
@ -358,7 +373,7 @@ TEST_F(CredentialManagementHandlerTest,
base::StrCat({display_name, kTruncatedUTF8}))));
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
handler->GetCredentials(get_credentials_callback_.callback());
get_credentials_callback_.WaitForCallback();
@ -407,7 +422,7 @@ TEST_F(CredentialManagementHandlerTest, EnumerateCredentialsMultipleRPs) {
}
auto handler = MakeHandler();
ready_callback_.WaitForCallback();
EXPECT_TRUE(ready_future_.Wait());
handler->GetCredentials(get_credentials_callback_.callback());
get_credentials_callback_.WaitForCallback();

@ -2,42 +2,54 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstdint>
#include <memory>
#include <optional>
#include <tuple>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/device_response_converter.h"
#include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device_authenticator.h"
#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_request_handler_base.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/fido_transport_protocol.h"
#include "device/fido/fido_types.h"
#include "device/fido/get_assertion_request_handler.h"
#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/make_credential_task.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/u2f_command_constructor.h"
#include "device/fido/virtual_ctap2_device.h"
#include "device/fido/virtual_fido_device.h"
#include "device/fido/virtual_fido_device_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_WIN)
#include "device/fido/hid/fake_hid_impl_for_testing.h"
#include "device/fido/win/fake_webauthn_api.h"
#endif // BUILDFLAG(IS_WIN)
@ -55,7 +67,7 @@ constexpr char kRequestTransportHistogram[] =
constexpr char kResponseTransportHistogram[] =
"WebAuthentication.GetAssertionResponseTransport";
using TestGetAssertionRequestCallback = test::StatusAndValuesCallbackReceiver<
using TestGetAssertionRequestFuture = base::test::TestFuture<
GetAssertionStatus,
std::optional<std::vector<AuthenticatorGetAssertionResponse>>,
FidoAuthenticator*>;
@ -125,7 +137,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
fake_discovery_factory_.get(),
std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
supported_transports_, std::move(request), CtapGetAssertionOptions(),
/*allow_skipping_pin_touch=*/true, get_assertion_cb_.callback());
/*allow_skipping_pin_touch=*/true, get_assertion_future_.GetCallback());
return handler;
}
@ -156,7 +168,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
platform_discovery()->WaitForCallToStartAndSimulateSuccess();
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(get_assertion_callback().was_called());
EXPECT_FALSE(get_assertion_future().IsReady());
if (!base::Contains(transports, Transport::kUsbHumanInterfaceDevice))
EXPECT_FALSE(discovery()->is_start_requested());
@ -187,8 +199,8 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* platform_discovery() const {
return platform_discovery_;
}
TestGetAssertionRequestCallback& get_assertion_callback() {
return get_assertion_cb_;
TestGetAssertionRequestFuture& get_assertion_future() {
return get_assertion_future_;
}
void set_supported_transports(
@ -207,7 +219,7 @@ class FidoGetAssertionHandlerTest : public ::testing::Test {
raw_ptr<test::FakeFidoDiscovery, DanglingUntriaged> platform_discovery_;
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_ =
base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
TestGetAssertionRequestCallback get_assertion_cb_;
TestGetAssertionRequestFuture get_assertion_future_;
base::flat_set<FidoTransportProtocol> supported_transports_ = {
FidoTransportProtocol::kUsbHumanInterfaceDevice,
FidoTransportProtocol::kInternal,
@ -348,10 +360,11 @@ TEST_F(FidoGetAssertionHandlerTest, CtapRequestOnSingleDevice) {
test_data::kTestGetAssertionResponse);
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()));
}
// Test a scenario where the connected authenticator is a U2F device.
@ -366,8 +379,9 @@ TEST_F(FidoGetAssertionHandlerTest, TestU2fSign) {
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) {
@ -389,7 +403,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(GetAssertionStatus::kAuthenticatorMissingUserVerification,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionHandlerTest,
@ -412,7 +426,7 @@ TEST_F(FidoGetAssertionHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(GetAssertionStatus::kAuthenticatorMissingUserVerification,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
@ -427,9 +441,9 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kAuthenticatorResponseInvalid,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
// Tests a scenario where the authenticator responds with credential ID that
@ -455,7 +469,7 @@ TEST_F(FidoGetAssertionHandlerTest, InvalidCredential) {
// The response with the invalid credential ID is considered to be an error at
// the task level and the request handler will drop the authenticator.
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(get_assertion_callback().was_called());
EXPECT_FALSE(get_assertion_future().IsReady());
}
// Tests a scenario where the authenticator responds with an empty credential.
@ -473,9 +487,10 @@ TEST_F(FidoGetAssertionHandlerTest, ValidEmptyCredential) {
test_data::kTestGetAssertionResponseWithEmptyCredential);
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
const auto& response = get_assertion_callback().value<0>();
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_future().Wait());
const auto& response = std::get<1>(get_assertion_future().Get());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
ASSERT_TRUE(response);
ASSERT_EQ(1u, response->size());
EXPECT_TRUE(response.value()[0].credential);
@ -500,9 +515,10 @@ TEST_F(FidoGetAssertionHandlerTest, TruncatedUTF8) {
test_data::kTestGetAssertionResponseWithTruncatedUTF8);
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
const auto& response = get_assertion_callback().value<0>();
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_future().Wait());
const auto& response = std::get<1>(get_assertion_future().Get());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
ASSERT_TRUE(response);
ASSERT_EQ(1u, response->size());
ASSERT_TRUE(response.value()[0].user_entity);
@ -523,7 +539,7 @@ TEST_F(FidoGetAssertionHandlerTest, TruncatedAndInvalidUTF8) {
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(get_assertion_callback().was_called());
EXPECT_FALSE(get_assertion_future().IsReady());
}
// Tests a scenario where authenticator responds without user entity in its
@ -541,9 +557,9 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectUserEntity) {
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kAuthenticatorResponseInvalid,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionHandlerTest,
@ -656,10 +672,11 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyUsbTransportAllowed) {
discovery()->WaitForCallToStartAndSimulateSuccess();
discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()));
EXPECT_THAT(
request_handler->transport_availability_info().available_transports,
::testing::UnorderedElementsAre(
@ -689,10 +706,11 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyNfcTransportAllowed) {
nfc_discovery()->WaitForCallToStartAndSimulateSuccess();
nfc_discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()));
EXPECT_THAT(
request_handler->transport_availability_info().available_transports,
::testing::UnorderedElementsAre(
@ -727,10 +745,11 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) {
platform_discovery()->WaitForCallToStartAndSimulateSuccess();
platform_discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()));
EXPECT_THAT(
request_handler->transport_availability_info().available_transports,
::testing::UnorderedElementsAre(FidoTransportProtocol::kInternal));
@ -762,9 +781,9 @@ TEST_F(FidoGetAssertionHandlerTest,
discovery()->AddDevice(std::move(other_device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_TRUE(get_assertion_future().IsReady());
EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
// Like |TestRequestWithOperationDeniedErrorPlatform|, but with a
@ -781,9 +800,9 @@ TEST_F(FidoGetAssertionHandlerTest,
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_TRUE(get_assertion_future().IsReady());
EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
// If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete
@ -799,9 +818,9 @@ TEST_F(FidoGetAssertionHandlerTest, TestRequestWithPinAuthInvalid) {
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_TRUE(get_assertion_future().IsReady());
EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status());
std::get<0>(get_assertion_future().Get()));
}
MATCHER_P(IsCtap2Command, expected_command, "") {
@ -839,8 +858,9 @@ TEST_F(FidoGetAssertionHandlerTest, DeviceFailsImmediately) {
discovery()->WaitForCallToStartAndSimulateSuccess();
discovery()->AddDevice(std::move(broken_device));
get_assertion_callback().WaitForCallback();
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionHandlerTest, PinUvAuthTokenPreTouchFailure) {
@ -867,7 +887,7 @@ TEST_F(FidoGetAssertionHandlerTest, PinUvAuthTokenPreTouchFailure) {
std::move(state), std::move(config)));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(get_assertion_callback().was_called());
EXPECT_FALSE(get_assertion_future().IsReady());
}
// Tests a scenario where authenticator of incorrect transport type was used to
@ -897,17 +917,17 @@ TEST(GetAssertionRequestHandlerTest, IncorrectTransportType) {
{FidoTransportProtocol::kBluetoothLowEnergy}),
};
TestGetAssertionRequestCallback cb;
TestGetAssertionRequestFuture future;
auto request_handler = std::make_unique<GetAssertionRequestHandler>(
&virtual_device_factory,
std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
std::move(request), CtapGetAssertionOptions(),
/*allow_skipping_pin_touch=*/true, cb.callback());
/*allow_skipping_pin_touch=*/true, future.GetCallback());
task_environment.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(cb.was_called());
EXPECT_FALSE(future.IsReady());
}
TEST_F(FidoGetAssertionHandlerTest, ReportTransportMetric) {
@ -930,9 +950,10 @@ TEST_F(FidoGetAssertionHandlerTest, ReportTransportMetric) {
nfc_discovery()->WaitForCallToStartAndSimulateSuccess();
discovery()->WaitForCallToStartAndSimulateSuccess();
get_assertion_callback().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_EQ(GetAssertionStatus::kSuccess,
std::get<0>(get_assertion_future().Get()));
histograms.ExpectBucketCount(kRequestTransportHistogram,
FidoTransportProtocol::kUsbHumanInterfaceDevice,
1);
@ -963,7 +984,7 @@ TEST(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
ScopedFakeFidoHidManager fake_hid_manager;
fake_hid_manager.AddFidoHidDevice("guid");
TestGetAssertionRequestCallback cb;
TestGetAssertionRequestFuture future;
FidoDiscoveryFactory fido_discovery_factory;
CtapGetAssertionRequest request(test_data::kRelyingPartyId,
test_data::kClientDataJson);
@ -977,7 +998,7 @@ TEST(GetAssertionRequestHandlerWinTest, TestWinUsbDiscovery) {
base::flat_set<FidoTransportProtocol>(
{FidoTransportProtocol::kUsbHumanInterfaceDevice}),
std::move(request), CtapGetAssertionOptions(),
/*allow_skipping_pin_touch=*/true, cb.callback());
/*allow_skipping_pin_touch=*/true, future.GetCallback());
task_environment.RunUntilIdle();
EXPECT_EQ(handler->AuthenticatorsForTesting().size(), 1u);

@ -4,24 +4,28 @@
#include "device/fido/get_assertion_task.h"
#include <iterator>
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/containers/span.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/task_environment.h"
#include "crypto/ec_private_key.h"
#include "device/base/features.h"
#include "base/test/test_future.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/device_response_converter.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_types.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/virtual_ctap2_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -31,22 +35,19 @@ using ::testing::_;
namespace device {
namespace {
using TestGetAssertionTaskCallbackReceiver =
::device::test::StatusAndValueCallbackReceiver<
CtapDeviceResponseCode,
std::vector<AuthenticatorGetAssertionResponse>>;
using TestGetAssertionTaskFuture =
base::test::TestFuture<CtapDeviceResponseCode,
std::vector<AuthenticatorGetAssertionResponse>>;
class FidoGetAssertionTaskTest : public testing::Test {
public:
FidoGetAssertionTaskTest() = default;
TestGetAssertionTaskCallbackReceiver& get_assertion_callback_receiver() {
return cb_;
}
TestGetAssertionTaskFuture& get_assertion_future() { return future_; }
private:
base::test::TaskEnvironment task_environment_;
TestGetAssertionTaskCallbackReceiver cb_;
TestGetAssertionTaskFuture future_;
};
TEST_F(FidoGetAssertionTaskTest, TestGetAssertionSuccess) {
@ -57,19 +58,19 @@ TEST_F(FidoGetAssertionTaskTest, TestGetAssertionSuccess) {
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
test_data::kClientDataJson);
request_param.allow_list.emplace_back(PublicKeyCredentialDescriptor(
request_param.allow_list.emplace_back(
CredentialType::kPublicKey,
fido_parsing_utils::Materialize(
test_data::kTestGetAssertionCredentialId)));
test_data::kTestGetAssertionCredentialId));
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request_param), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
get_assertion_callback_receiver().status());
EXPECT_EQ(get_assertion_callback_receiver().value().size(), 1u);
std::get<0>(get_assertion_future().Get()));
EXPECT_EQ(std::get<1>(get_assertion_future().Get()).size(), 1u);
}
TEST_F(FidoGetAssertionTaskTest, TestU2fSignSuccess) {
@ -81,18 +82,18 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignSuccess) {
CtapGetAssertionRequest request_param(test_data::kRelyingPartyId,
test_data::kClientDataJson);
request_param.allow_list.emplace_back(PublicKeyCredentialDescriptor(
request_param.allow_list.emplace_back(
CredentialType::kPublicKey,
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle)));
fido_parsing_utils::Materialize(test_data::kU2fSignKeyHandle));
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request_param), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
get_assertion_callback_receiver().status());
EXPECT_EQ(get_assertion_callback_receiver().value().size(), 1u);
std::get<0>(get_assertion_future().Get()));
EXPECT_EQ(std::get<1>(get_assertion_future().Get()).size(), 1u);
}
TEST_F(FidoGetAssertionTaskTest, TestSignSuccessWithFake) {
@ -106,33 +107,30 @@ TEST_F(FidoGetAssertionTaskTest, TestSignSuccessWithFake) {
auto device = std::make_unique<VirtualCtap2Device>();
ASSERT_TRUE(device->mutable_state()->InjectRegistration(
kCredentialId, test_data::kRelyingPartyId));
test::TestCallbackReceiver<> done;
device->DiscoverSupportedProtocolAndDeviceInfo(done.callback());
done.WaitForCallback();
base::test::TestFuture<void> done;
device->DiscoverSupportedProtocolAndDeviceInfo(done.GetCallback());
EXPECT_TRUE(done.Wait());
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request_param), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
get_assertion_callback_receiver().status());
std::get<0>(get_assertion_future().Get()));
// Just a sanity check, we don't verify the actual signature.
ASSERT_GE(32u + 1u + 4u + 8u, // Minimal ECDSA signature is 8 bytes
get_assertion_callback_receiver()
.value()
std::get<1>(get_assertion_future().Get())
.at(0)
.authenticator_data.SerializeToByteArray()
.size());
EXPECT_EQ(0x01,
get_assertion_callback_receiver()
.value()
std::get<1>(get_assertion_future().Get())
.at(0)
.authenticator_data.SerializeToByteArray()[32]); // UP flag
// Counter starts at zero and is incremented for every sign request.
EXPECT_EQ(1, get_assertion_callback_receiver()
.value()
EXPECT_EQ(1, std::get<1>(get_assertion_future().Get())
.at(0)
.authenticator_data.SerializeToByteArray()[36]); // counter
}
@ -146,12 +144,12 @@ TEST_F(FidoGetAssertionTaskTest, TestIncorrectGetAssertionResponse) {
device.get(),
CtapGetAssertionRequest(test_data::kRelyingPartyId,
test_data::kClientDataJson),
CtapGetAssertionOptions(), get_assertion_callback_receiver().callback());
CtapGetAssertionOptions(), get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther,
get_assertion_callback_receiver().status());
EXPECT_TRUE(get_assertion_callback_receiver().value().empty());
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()).empty());
}
TEST_F(FidoGetAssertionTaskTest, TestU2fSignRequestWithEmptyAllowedList) {
@ -166,12 +164,12 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fSignRequestWithEmptyAllowedList) {
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrNoCredentials,
get_assertion_callback_receiver().status());
EXPECT_TRUE(get_assertion_callback_receiver().value().empty());
std::get<0>(get_assertion_future().Get()));
EXPECT_TRUE(std::get<1>(get_assertion_future().Get()).empty());
}
// Checks that when device supports both CTAP2 and U2F protocol and when
@ -199,11 +197,11 @@ TEST_F(FidoGetAssertionTaskTest, TestSilentSignInWhenAppIdExtensionPresent) {
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_future().GetCallback());
get_assertion_callback_receiver().WaitForCallback();
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
get_assertion_callback_receiver().status());
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionTaskTest, TestU2fFallbackForAppIdExtension) {
@ -243,10 +241,10 @@ TEST_F(FidoGetAssertionTaskTest, TestU2fFallbackForAppIdExtension) {
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
get_assertion_future().GetCallback());
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
get_assertion_callback_receiver().status());
std::get<0>(get_assertion_future().Get()));
}
TEST_F(FidoGetAssertionTaskTest, TestAvoidSilentSignInForCtapOnlyDevice) {
@ -273,10 +271,10 @@ TEST_F(FidoGetAssertionTaskTest, TestAvoidSilentSignInForCtapOnlyDevice) {
auto task = std::make_unique<GetAssertionTask>(
device.get(), std::move(request), CtapGetAssertionOptions(),
get_assertion_callback_receiver().callback());
get_assertion_callback_receiver().WaitForCallback();
get_assertion_future().GetCallback());
EXPECT_TRUE(get_assertion_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther,
get_assertion_callback_receiver().status());
std::get<0>(get_assertion_future().Get()));
}
} // namespace

@ -2,16 +2,29 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <cstdint>
#include <memory>
#include <optional>
#include <tuple>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/cbor/reader.h"
@ -21,12 +34,14 @@
#include "device/fido/authenticator_get_info_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/authenticator_selection_criteria.h"
#include "device/fido/authenticator_supported_options.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/device_response_converter.h"
#include "device/fido/fake_fido_discovery.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_device.h"
#include "device/fido/fido_device_authenticator.h"
#include "device/fido/fido_discovery_base.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_test_data.h"
#include "device/fido/fido_transport_protocol.h"
@ -34,8 +49,11 @@
#include "device/fido/make_credential_request_handler.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/public_key_credential_params.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/virtual_ctap2_device.h"
#include "device/fido/virtual_fido_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -53,10 +71,10 @@ namespace device {
namespace {
using TestMakeCredentialRequestCallback = test::StatusAndValuesCallbackReceiver<
MakeCredentialStatus,
std::optional<AuthenticatorMakeCredentialResponse>,
const FidoAuthenticator*>;
using TestMakeCredentialRequestFuture =
base::test::TestFuture<MakeCredentialStatus,
std::optional<AuthenticatorMakeCredentialResponse>,
const FidoAuthenticator*>;
} // namespace
@ -98,7 +116,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
fake_discovery_factory_.get(),
std::vector<std::unique_ptr<FidoDiscoveryBase>>(),
supported_transports_, std::move(request_parameter), std::move(options),
cb_.callback());
future_.GetCallback());
if (pending_mock_platform_device_) {
platform_discovery_->AddDevice(std::move(pending_mock_platform_device_));
platform_discovery_->WaitForCallToStartAndSimulateSuccess();
@ -116,7 +134,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
nfc_discovery()->WaitForCallToStartAndSimulateSuccess();
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(callback().was_called());
EXPECT_FALSE(future().IsReady());
if (!base::Contains(transports, Transport::kUsbHumanInterfaceDevice))
EXPECT_FALSE(discovery()->is_start_requested());
@ -130,7 +148,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
test::FakeFidoDiscovery* discovery() const { return discovery_; }
test::FakeFidoDiscovery* nfc_discovery() const { return nfc_discovery_; }
TestMakeCredentialRequestCallback& callback() { return cb_; }
TestMakeCredentialRequestFuture& future() { return future_; }
void set_mock_platform_device(std::unique_ptr<MockFidoDevice> device) {
pending_mock_platform_device_ = std::move(device);
@ -152,7 +170,7 @@ class FidoMakeCredentialHandlerTest : public ::testing::Test {
platform_discovery_;
scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_;
std::unique_ptr<MockFidoDevice> pending_mock_platform_device_;
TestMakeCredentialRequestCallback cb_;
TestMakeCredentialRequestFuture future_;
base::flat_set<FidoTransportProtocol> supported_transports_ = {
FidoTransportProtocol::kUsbHumanInterfaceDevice,
FidoTransportProtocol::kHybrid,
@ -221,8 +239,8 @@ TEST_F(FidoMakeCredentialHandlerTest, TestCtap2MakeCredential) {
test_data::kTestMakeCredentialResponse);
discovery()->AddDevice(std::move(device));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
// Test a scenario where the connected authenticator is a U2F device.
@ -236,8 +254,8 @@ TEST_F(FidoMakeCredentialHandlerTest, TestU2fRegister) {
test_data::kApduEncodedNoErrorRegisterResponse);
discovery()->AddDevice(std::move(device));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) {
@ -255,7 +273,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingUserVerification,
callback().status());
std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) {
@ -273,7 +291,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status());
std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) {
@ -293,7 +311,7 @@ TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingUserVerification,
callback().status());
std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, CrossPlatformAttachment) {
@ -353,7 +371,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyRequirementNotMet) {
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status());
std::get<0>(future().Get()));
}
MATCHER(IsResidentKeyRequest, "") {
@ -474,8 +492,8 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancelOtherAuthenticator) {
discovery()->AddDevice(std::move(device1));
discovery()->AddDevice(std::move(device2));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancel) {
@ -526,8 +544,8 @@ TEST_F(FidoMakeCredentialHandlerTest,
test_data::kTestMakeCredentialResponse);
discovery()->AddDevice(std::move(device));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
EXPECT_THAT(
request_handler->transport_availability_info().available_transports,
@ -556,8 +574,8 @@ TEST_F(FidoMakeCredentialHandlerTest,
AuthenticatorAttachment::kPlatform, ResidentKeyRequirement::kRequired,
UserVerificationRequirement::kRequired));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
EXPECT_THAT(
request_handler->transport_availability_info().available_transports,
@ -586,9 +604,9 @@ TEST_F(FidoMakeCredentialHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain();
#if BUILDFLAG(IS_CHROMEOS)
EXPECT_TRUE(callback().was_called());
EXPECT_TRUE(future().IsReady());
#else
EXPECT_FALSE(callback().was_called());
EXPECT_FALSE(future().IsReady());
#endif
}
@ -612,7 +630,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
UserVerificationRequirement::kRequired));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(callback().was_called());
EXPECT_FALSE(future().IsReady());
}
TEST_F(FidoMakeCredentialHandlerTest, SupportedTransportsAreOnlyNfc) {
@ -643,7 +661,7 @@ TEST_F(FidoMakeCredentialHandlerTest, IncorrectRpIdHash) {
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(callback().was_called());
EXPECT_FALSE(future().IsReady());
}
// Tests that only authenticators with resident key support will successfully
@ -667,8 +685,8 @@ TEST_F(FidoMakeCredentialHandlerTest,
std::move(state), std::move(config)));
task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
// Tests that MakeCredential request fails when asking to use resident keys with
@ -686,7 +704,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status());
std::get<0>(future().Get()));
}
// If a device with transport type kInternal returns a
@ -708,8 +726,9 @@ TEST_F(FidoMakeCredentialHandlerTest,
UserVerificationRequirement::kPreferred));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
EXPECT_TRUE(future().IsReady());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied,
std::get<0>(future().Get()));
}
// Like |TestRequestWithOperationDeniedErrorPlatform|, but with a
@ -730,8 +749,9 @@ TEST_F(FidoMakeCredentialHandlerTest,
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
EXPECT_TRUE(future().IsReady());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied,
std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest,
@ -757,8 +777,8 @@ TEST_F(FidoMakeCredentialHandlerTest,
discovery()->AddDevice(std::move(device));
discovery()->WaitForCallToStartAndSimulateSuccess();
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
// If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete
@ -778,8 +798,9 @@ TEST_F(FidoMakeCredentialHandlerTest, TestRequestWithPinAuthInvalid) {
discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
EXPECT_TRUE(future().IsReady());
EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied,
std::get<0>(future().Get()));
}
MATCHER_P(IsCtap2Command, expected_command, "") {
@ -817,8 +838,8 @@ TEST_F(FidoMakeCredentialHandlerTest, DeviceFailsImmediately) {
discovery()->WaitForCallToStartAndSimulateSuccess();
discovery()->AddDevice(std::move(broken_device));
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
}
TEST_F(FidoMakeCredentialHandlerTest, PinUvAuthTokenPreTouchFailure) {
@ -837,7 +858,7 @@ TEST_F(FidoMakeCredentialHandlerTest, PinUvAuthTokenPreTouchFailure) {
std::move(state), std::move(config)));
task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(callback().was_called());
EXPECT_FALSE(future().IsReady());
}
TEST_F(FidoMakeCredentialHandlerTest, ReportTransportMetric) {
@ -859,8 +880,8 @@ TEST_F(FidoMakeCredentialHandlerTest, ReportTransportMetric) {
nfc_discovery()->AddDevice(std::move(nfc_device));
nfc_discovery()->WaitForCallToStartAndSimulateSuccess();
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
histograms.ExpectUniqueSample(kResponseTransportHistogram,
FidoTransportProtocol::kUsbHumanInterfaceDevice,
1);
@ -875,8 +896,8 @@ TEST_F(FidoMakeCredentialHandlerTest, ReportTransportMetricWin) {
base::HistogramTester histograms;
fake_discovery_factory_->set_discover_win_webauthn_api_authenticator(true);
auto request_handler = CreateMakeCredentialHandler();
callback().WaitForCallback();
EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(future().Wait());
EXPECT_EQ(MakeCredentialStatus::kSuccess, std::get<0>(future().Get()));
histograms.ExpectUniqueSample(kResponseTransportHistogram,
FidoTransportProtocol::kBluetoothLowEnergy, 1);
}

@ -2,24 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <utility>
#include "device/fido/make_credential_task.h"
#include <array>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/numerics/safe_conversions.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "device/base/features.h"
#include "base/test/test_future.h"
#include "device/fido/authenticator_get_info_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/authenticator_supported_options.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/device_response_converter.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/make_credential_task.h"
#include "device/fido/fido_types.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/public_key_credential_params.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/virtual_ctap2_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -34,10 +42,9 @@ constexpr std::array<uint8_t, kAaguidLength> kTestDeviceAaguid = {
{0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17, 0x11,
0x1F, 0x9E, 0xDC, 0x7D}};
using TestMakeCredentialTaskCallback =
::device::test::StatusAndValueCallbackReceiver<
CtapDeviceResponseCode,
std::optional<AuthenticatorMakeCredentialResponse>>;
using TestMakeCredentialTaskFuture = ::base::test::TestFuture<
CtapDeviceResponseCode,
std::optional<AuthenticatorMakeCredentialResponse>>;
class FidoMakeCredentialTaskTest : public testing::Test {
public:
@ -54,16 +61,14 @@ class FidoMakeCredentialTaskTest : public testing::Test {
test_data::kClientDataJson, std::move(rp), std::move(user),
PublicKeyCredentialParams(
std::vector<PublicKeyCredentialParams::CredentialInfo>(1))),
MakeCredentialOptions(), callback_receiver_.callback());
MakeCredentialOptions(), future_.GetCallback());
}
TestMakeCredentialTaskCallback& make_credential_callback_receiver() {
return callback_receiver_;
}
TestMakeCredentialTaskFuture& make_credential_future() { return future_; }
protected:
base::test::TaskEnvironment task_environment_;
TestMakeCredentialTaskCallback callback_receiver_;
TestMakeCredentialTaskFuture future_;
};
TEST_F(FidoMakeCredentialTaskTest, MakeCredentialSuccess) {
@ -73,30 +78,29 @@ TEST_F(FidoMakeCredentialTaskTest, MakeCredentialSuccess) {
test_data::kTestMakeCredentialResponse);
const auto task = CreateMakeCredentialTask(device.get());
make_credential_callback_receiver().WaitForCallback();
EXPECT_TRUE(make_credential_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
make_credential_callback_receiver().status());
EXPECT_TRUE(make_credential_callback_receiver().value());
std::get<0>(make_credential_future().Get()));
EXPECT_TRUE(std::get<1>(make_credential_future().Get()));
EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kCtap2);
EXPECT_TRUE(device->device_info());
}
TEST_F(FidoMakeCredentialTaskTest, TestRegisterSuccessWithFake) {
auto device = std::make_unique<VirtualCtap2Device>();
test::TestCallbackReceiver<> done_init;
device->DiscoverSupportedProtocolAndDeviceInfo(done_init.callback());
done_init.WaitForCallback();
base::test::TestFuture<void> done_init;
device->DiscoverSupportedProtocolAndDeviceInfo(done_init.GetCallback());
EXPECT_TRUE(done_init.Wait());
const auto task = CreateMakeCredentialTask(device.get());
make_credential_callback_receiver().WaitForCallback();
EXPECT_TRUE(make_credential_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
make_credential_callback_receiver().status());
std::get<0>(make_credential_future().Get()));
// We don't verify the response from the fake, but do a quick sanity check.
ASSERT_TRUE(make_credential_callback_receiver().value());
EXPECT_EQ(32u, make_credential_callback_receiver()
.value()
ASSERT_TRUE(std::get<1>(make_credential_future().Get()));
EXPECT_EQ(32u, std::get<1>(make_credential_future().Get())
->attestation_object.GetCredentialId()
.size());
}
@ -109,11 +113,11 @@ TEST_F(FidoMakeCredentialTaskTest, FallbackToU2fRegisterSuccess) {
test_data::kApduEncodedNoErrorRegisterResponse);
const auto task = CreateMakeCredentialTask(device.get());
make_credential_callback_receiver().WaitForCallback();
EXPECT_TRUE(make_credential_future().Wait());
EXPECT_EQ(ProtocolVersion::kU2f, device->supported_protocol());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
make_credential_callback_receiver().status());
std::get<0>(make_credential_future().Get()));
}
TEST_F(FidoMakeCredentialTaskTest, DefaultToU2fWhenClientPinSet) {
@ -132,10 +136,10 @@ TEST_F(FidoMakeCredentialTaskTest, DefaultToU2fWhenClientPinSet) {
test_data::kApduEncodedNoErrorRegisterResponse);
const auto task = CreateMakeCredentialTask(device.get());
make_credential_callback_receiver().WaitForCallback();
EXPECT_TRUE(make_credential_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
make_credential_callback_receiver().status());
EXPECT_TRUE(make_credential_callback_receiver().value());
std::get<0>(make_credential_future().Get()));
EXPECT_TRUE(std::get<1>(make_credential_future().Get()));
}
TEST_F(FidoMakeCredentialTaskTest, EnforceClientPinWhenUserVerificationSet) {
@ -161,12 +165,12 @@ TEST_F(FidoMakeCredentialTaskTest, EnforceClientPinWhenUserVerificationSet) {
request.user_verification = UserVerificationRequirement::kRequired;
const auto task = std::make_unique<MakeCredentialTask>(
device.get(), std::move(request), MakeCredentialOptions(),
callback_receiver_.callback());
make_credential_future().GetCallback());
make_credential_callback_receiver().WaitForCallback();
EXPECT_TRUE(make_credential_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther,
make_credential_callback_receiver().status());
EXPECT_FALSE(make_credential_callback_receiver().value());
std::get<0>(make_credential_future().Get()));
EXPECT_FALSE(std::get<1>(make_credential_future().Get()));
}
} // namespace

@ -5,16 +5,23 @@
#include "device/fido/u2f_register_operation.h"
#include <memory>
#include <optional>
#include <tuple>
#include <utility>
#include <vector>
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#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/fido_types.h"
#include "device/fido/mock_fido_device.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/public_key_credential_params.h"
#include "device/fido/public_key_credential_rp_entity.h"
#include "device/fido/public_key_credential_user_entity.h"
#include "device/fido/virtual_u2f_device.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -54,21 +61,19 @@ CtapMakeCredentialRequest CreateRegisterRequest(
std::vector<PublicKeyCredentialDescriptor>(), is_individual_attestation);
}
using TestRegisterCallback = ::device::test::StatusAndValueCallbackReceiver<
CtapDeviceResponseCode,
std::optional<AuthenticatorMakeCredentialResponse>>;
using TestRegisterFuture =
base::test::TestFuture<CtapDeviceResponseCode,
std::optional<AuthenticatorMakeCredentialResponse>>;
} // namespace
class U2fRegisterOperationTest : public ::testing::Test {
public:
TestRegisterCallback& register_callback_receiver() {
return register_callback_receiver_;
}
TestRegisterFuture& register_future() { return register_future_; }
private:
base::test::TaskEnvironment task_environment_;
TestRegisterCallback register_callback_receiver_;
TestRegisterFuture register_future_;
};
TEST_F(U2fRegisterOperationTest, TestRegisterSuccess) {
@ -81,16 +86,14 @@ TEST_F(U2fRegisterOperationTest, TestRegisterSuccess) {
test_data::kApduEncodedNoErrorRegisterResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request),
register_callback_receiver().callback());
device.get(), std::move(request), register_future().GetCallback());
u2f_register->Start();
register_callback_receiver().WaitForCallback();
EXPECT_TRUE(register_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
EXPECT_THAT(register_callback_receiver()
.value()
std::get<0>(register_future().Get()));
ASSERT_TRUE(std::get<1>(register_future().Get()));
EXPECT_THAT(std::get<1>(register_future().Get())
->attestation_object.GetCredentialId(),
::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
@ -100,17 +103,15 @@ TEST_F(U2fRegisterOperationTest, TestRegisterSuccessWithFake) {
auto device = std::make_unique<VirtualU2fDevice>();
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request),
register_callback_receiver().callback());
device.get(), std::move(request), register_future().GetCallback());
u2f_register->Start();
register_callback_receiver().WaitForCallback();
EXPECT_TRUE(register_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
register_callback_receiver().status());
std::get<0>(register_future().Get()));
// We don't verify the response from the fake, but do a quick sanity check.
ASSERT_TRUE(register_callback_receiver().value());
EXPECT_EQ(32ul, register_callback_receiver()
.value()
ASSERT_TRUE(std::get<1>(register_future().Get()));
EXPECT_EQ(32ul, std::get<1>(register_future().Get())
->attestation_object.GetCredentialId()
.size());
}
@ -133,16 +134,14 @@ TEST_F(U2fRegisterOperationTest, TestDelayedSuccess) {
test_data::kApduEncodedNoErrorRegisterResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request),
register_callback_receiver().callback());
device.get(), std::move(request), register_future().GetCallback());
u2f_register->Start();
register_callback_receiver().WaitForCallback();
EXPECT_TRUE(register_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
register_callback_receiver().status());
ASSERT_TRUE(register_callback_receiver().value());
EXPECT_THAT(register_callback_receiver()
.value()
std::get<0>(register_future().Get()));
ASSERT_TRUE(std::get<1>(register_future().Get()));
EXPECT_THAT(std::get<1>(register_future().Get())
->attestation_object.GetCredentialId(),
::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
@ -180,16 +179,14 @@ TEST_F(U2fRegisterOperationTest, TestRegistrationWithExclusionList) {
test_data::kApduEncodedNoErrorRegisterResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request),
register_callback_receiver().callback());
device.get(), std::move(request), register_future().GetCallback());
u2f_register->Start();
register_callback_receiver().WaitForCallback();
EXPECT_TRUE(register_future().Wait());
ASSERT_TRUE(register_callback_receiver().value());
ASSERT_TRUE(std::get<1>(register_future().Get()));
EXPECT_EQ(CtapDeviceResponseCode::kSuccess,
register_callback_receiver().status());
EXPECT_THAT(register_callback_receiver()
.value()
std::get<0>(register_future().Get()));
EXPECT_THAT(std::get<1>(register_future().Get())
->attestation_object.GetCredentialId(),
::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
@ -233,14 +230,13 @@ TEST_F(U2fRegisterOperationTest, TestRegistrationWithDuplicateHandle) {
test_data::kApduEncodedNoErrorSignResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request),
register_callback_receiver().callback());
device.get(), std::move(request), register_future().GetCallback());
u2f_register->Start();
register_callback_receiver().WaitForCallback();
EXPECT_TRUE(register_future().Wait());
EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrCredentialExcluded,
register_callback_receiver().status());
EXPECT_FALSE(register_callback_receiver().value());
std::get<0>(register_future().Get()));
EXPECT_FALSE(std::get<1>(register_future().Get()));
}
MATCHER_P(IndicatesIndividualAttestation, expected, "") {
@ -252,7 +248,7 @@ TEST_F(U2fRegisterOperationTest, TestIndividualAttestation) {
// resulting registration APDU.
for (const auto& individual_attestation : {false, true}) {
SCOPED_TRACE(individual_attestation);
TestRegisterCallback cb;
TestRegisterFuture future;
auto request = CreateRegisterRequest(individual_attestation);
auto device = std::make_unique<MockFidoDevice>();
@ -266,13 +262,13 @@ TEST_F(U2fRegisterOperationTest, TestIndividualAttestation) {
test_data::kApduEncodedNoErrorRegisterResponse);
auto u2f_register = std::make_unique<U2fRegisterOperation>(
device.get(), std::move(request), cb.callback());
device.get(), std::move(request), future.GetCallback());
u2f_register->Start();
cb.WaitForCallback();
EXPECT_TRUE(future.Wait());
EXPECT_EQ(CtapDeviceResponseCode::kSuccess, cb.status());
ASSERT_TRUE(cb.value());
EXPECT_THAT(cb.value()->attestation_object.GetCredentialId(),
EXPECT_EQ(CtapDeviceResponseCode::kSuccess, std::get<0>(future.Get()));
ASSERT_TRUE(std::get<1>(future.Get()));
EXPECT_THAT(std::get<1>(future.Get())->attestation_object.GetCredentialId(),
::testing::ElementsAreArray(test_data::kU2fSignKeyHandle));
}
}

@ -4,24 +4,40 @@
#include "device/fido/virtual_ctap2_device.h"
#include <cstdint>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/check.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "components/cbor/reader.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "device/fido/attestation_statement.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/device_response_converter.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/fido_types.h"
#include "device/fido/large_blob.h"
#include "device/fido/test_callback_receiver.h"
#include "device/fido/public_key_credential_descriptor.h"
#include "device/fido/virtual_fido_device.h"
#include "net/cert/asn1_util.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
@ -32,8 +48,7 @@ namespace device {
namespace {
using TestCallbackReceiver =
test::ValueCallbackReceiver<std::optional<std::vector<uint8_t>>>;
using TestFuture = base::test::TestFuture<std::optional<std::vector<uint8_t>>>;
void SendCommand(VirtualCtap2Device* device,
base::span<const uint8_t> command,
@ -175,12 +190,12 @@ TEST_F(VirtualCtap2DeviceTest, DestroyInsideSimulatePressCallback) {
// https://w3c.github.io/webauthn/#sctn-packed-attestation-cert-requirements
TEST_F(VirtualCtap2DeviceTest, AttestationCertificateIsValid) {
MakeDevice();
TestCallbackReceiver callback_receiver;
TestFuture future;
SendCommand(device_.get(), test_data::kCtapSimpleMakeCredentialRequest,
callback_receiver.callback());
callback_receiver.WaitForCallback();
future.GetCallback());
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorMakeCredentialResponse> response =
ReadCTAPMakeCredentialResponse(
@ -253,12 +268,12 @@ TEST_F(VirtualCtap2DeviceTest, RejectsCredentialsWithExtraKeys) {
static_cast<uint8_t>(CtapRequestCommand::kAuthenticatorGetAssertion));
MakeDevice();
TestCallbackReceiver callback_receiver;
SendCommand(device_.get(), *bytes, callback_receiver.callback());
callback_receiver.WaitForCallback();
TestFuture future;
SendCommand(device_.get(), *bytes, future.GetCallback());
EXPECT_TRUE(future.Wait());
ASSERT_TRUE(callback_receiver.value().has_value());
base::span<const uint8_t> result = *callback_receiver.value();
ASSERT_TRUE(future.Get().has_value());
base::span<const uint8_t> result = future.Get().value();
ASSERT_EQ(result.size(), 1u);
EXPECT_EQ(result[0],
static_cast<uint8_t>(
@ -277,7 +292,7 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionBogusSignature) {
device_->mutable_state()->InjectRegistration(kCredentialId,
test_data::kRelyingPartyId);
TestCallbackReceiver callback_receiver;
TestFuture future;
device::CtapGetAssertionRequest request = CtapGetAssertionRequest(
test_data::kRelyingPartyId, test_data::kClientDataJson);
std::vector<uint8_t> credential_id =
@ -289,10 +304,10 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionBogusSignature) {
request.allow_list.push_back(std::move(descriptor));
device_->DeviceTransact(
ToCTAP2Command(AsCTAPRequestValuePair(std::move(request))),
base::BindOnce(callback_receiver.callback()));
callback_receiver.WaitForCallback();
base::BindOnce(future.GetCallback()));
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorGetAssertionResponse> response =
@ -307,11 +322,11 @@ TEST_F(VirtualCtap2DeviceTest, OnMakeCredentialBogusSignature) {
device_->mutable_state()->ctap2_invalid_signature = true;
constexpr uint8_t bogus_sig[] = {0x00};
TestCallbackReceiver callback_receiver;
TestFuture future;
SendCommand(device_.get(), test_data::kCtapSimpleMakeCredentialRequest,
callback_receiver.callback());
callback_receiver.WaitForCallback();
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
future.GetCallback());
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorMakeCredentialResponse> response =
ReadCTAPMakeCredentialResponse(
@ -333,7 +348,7 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionUnsetUPBit) {
device_->mutable_state()->InjectRegistration(kCredentialId,
test_data::kRelyingPartyId);
TestCallbackReceiver callback_receiver;
TestFuture future;
device::CtapGetAssertionRequest request = CtapGetAssertionRequest(
test_data::kRelyingPartyId, test_data::kClientDataJson);
std::vector<uint8_t> credential_id =
@ -345,10 +360,10 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionUnsetUPBit) {
request.allow_list.push_back(std::move(descriptor));
device_->DeviceTransact(
ToCTAP2Command(AsCTAPRequestValuePair(std::move(request))),
base::BindOnce(callback_receiver.callback()));
callback_receiver.WaitForCallback();
base::BindOnce(future.GetCallback()));
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorGetAssertionResponse> response =
@ -370,7 +385,7 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionUnsetUVBit) {
state->InjectRegistration(kCredentialId, test_data::kRelyingPartyId);
MakeDevice(state, config);
TestCallbackReceiver callback_receiver;
TestFuture future;
device::CtapGetAssertionRequest request = CtapGetAssertionRequest(
test_data::kRelyingPartyId, test_data::kClientDataJson);
std::vector<uint8_t> credential_id =
@ -383,10 +398,10 @@ TEST_F(VirtualCtap2DeviceTest, OnGetAssertionUnsetUVBit) {
request.user_verification = UserVerificationRequirement::kRequired;
device_->DeviceTransact(
ToCTAP2Command(AsCTAPRequestValuePair(std::move(request))),
base::BindOnce(callback_receiver.callback()));
callback_receiver.WaitForCallback();
base::BindOnce(future.GetCallback()));
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorGetAssertionResponse> response =
@ -400,11 +415,11 @@ TEST_F(VirtualCtap2DeviceTest, OnMakeCredentialUnsetUPBit) {
MakeDevice();
device_->mutable_state()->unset_up_bit = true;
TestCallbackReceiver callback_receiver;
TestFuture future;
SendCommand(device_.get(), test_data::kCtapSimpleMakeCredentialRequest,
callback_receiver.callback());
callback_receiver.WaitForCallback();
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
future.GetCallback());
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorMakeCredentialResponse> response =
ReadCTAPMakeCredentialResponse(
@ -424,12 +439,12 @@ TEST_F(VirtualCtap2DeviceTest, OnMakeCredentialUnsetUVBit) {
state->unset_uv_bit = true;
MakeDevice(state, config);
TestCallbackReceiver callback_receiver;
TestFuture future;
SendCommand(device_.get(), test_data::kCtapMakeCredentialRequest,
callback_receiver.callback());
callback_receiver.WaitForCallback();
future.GetCallback());
EXPECT_TRUE(future.Wait());
std::optional<cbor::Value> cbor = DecodeCBOR(*callback_receiver.value());
std::optional<cbor::Value> cbor = DecodeCBOR(future.Take().value());
ASSERT_TRUE(cbor);
std::optional<AuthenticatorMakeCredentialResponse> response =
ReadCTAPMakeCredentialResponse(