Commit adad15cc authored by Nina Satragno's avatar Nina Satragno Committed by Commit Bot

[fido] Use authenticatorSelection when available

CTAP 2.1 devices support the authenticatorSelection command to get a
touch. Use authenticatorSelection instead of creating a dummy credential
on those devices.

Fixed: 1039426
Change-Id: I89420f1a181470fbbcce59a6ca0cdf3a44bd2ec0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2535874
Commit-Queue: Nina Satragno <nsatragno@chromium.org>
Reviewed-by: default avatarMartin Kreichgauer <martinkr@google.com>
Cr-Commit-Position: refs/heads/master@{#827991}
parent 6a60fb44
...@@ -129,6 +129,8 @@ component("fido") { ...@@ -129,6 +129,8 @@ component("fido") {
"credential_management_handler.cc", "credential_management_handler.cc",
"credential_management_handler.h", "credential_management_handler.h",
"ctap2_device_operation.h", "ctap2_device_operation.h",
"ctap_authenticator_selection_request.cc",
"ctap_authenticator_selection_request.h",
"ctap_get_assertion_request.cc", "ctap_get_assertion_request.cc",
"ctap_get_assertion_request.h", "ctap_get_assertion_request.h",
"ctap_make_credential_request.cc", "ctap_make_credential_request.cc",
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "base/ranges/algorithm.h"
#include "components/cbor/values.h" #include "components/cbor/values.h"
#include "components/cbor/writer.h" #include "components/cbor/writer.h"
#include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_parsing_utils.h"
...@@ -137,4 +138,12 @@ std::vector<uint8_t> AuthenticatorGetInfoResponse::EncodeToCBOR( ...@@ -137,4 +138,12 @@ std::vector<uint8_t> AuthenticatorGetInfoResponse::EncodeToCBOR(
return *encoded_bytes; return *encoded_bytes;
} }
bool AuthenticatorGetInfoResponse::SupportsAtLeast(
Ctap2Version ctap2_version) const {
return base::ranges::any_of(ctap2_versions,
[ctap2_version](const Ctap2Version& version) {
return version >= ctap2_version;
});
}
} // namespace device } // namespace device
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "device/fido/authenticator_supported_options.h" #include "device/fido/authenticator_supported_options.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/fido_types.h"
namespace device { namespace device {
...@@ -35,6 +36,10 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorGetInfoResponse { ...@@ -35,6 +36,10 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorGetInfoResponse {
static std::vector<uint8_t> EncodeToCBOR( static std::vector<uint8_t> EncodeToCBOR(
const AuthenticatorGetInfoResponse& response); const AuthenticatorGetInfoResponse& response);
// Returns true if there is a Ctap2Version in |ctap2_versions| greater or
// equal to |ctap2_version|.
bool SupportsAtLeast(Ctap2Version ctap2_version) const;
base::flat_set<ProtocolVersion> versions; base::flat_set<ProtocolVersion> versions;
base::flat_set<Ctap2Version> ctap2_versions; base::flat_set<Ctap2Version> ctap2_versions;
std::array<uint8_t, kAaguidLength> aaguid; std::array<uint8_t, kAaguidLength> aaguid;
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/fido/ctap_authenticator_selection_request.h"
namespace device {
std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
AsCTAPRequestValuePair(const CtapAuthenticatorSelectionRequest&) {
return std::make_pair(CtapRequestCommand::kAuthenticatorSelection,
base::nullopt);
}
} // namespace device
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_FIDO_CTAP_AUTHENTICATOR_SELECTION_REQUEST_H_
#define DEVICE_FIDO_CTAP_AUTHENTICATOR_SELECTION_REQUEST_H_
#include <utility>
#include "base/optional.h"
#include "components/cbor/values.h"
#include "device/fido/fido_constants.h"
namespace device {
struct CtapAuthenticatorSelectionRequest {};
std::pair<CtapRequestCommand, base::Optional<cbor::Value>>
AsCTAPRequestValuePair(const CtapAuthenticatorSelectionRequest&);
} // namespace device
#endif // DEVICE_FIDO_CTAP_AUTHENTICATOR_SELECTION_REQUEST_H_
...@@ -238,6 +238,7 @@ enum class CtapRequestCommand : uint8_t { ...@@ -238,6 +238,7 @@ enum class CtapRequestCommand : uint8_t {
kAuthenticatorClientPin = 0x06, kAuthenticatorClientPin = 0x06,
kAuthenticatorReset = 0x07, kAuthenticatorReset = 0x07,
kAuthenticatorBioEnrollment = 0x09, kAuthenticatorBioEnrollment = 0x09,
kAuthenticatorSelection = 0x0B,
kAuthenticatorLargeBlobs = 0x0C, kAuthenticatorLargeBlobs = 0x0C,
kAuthenticatorBioEnrollmentPreview = 0x40, kAuthenticatorBioEnrollmentPreview = 0x40,
kAuthenticatorCredentialManagement = 0x0a, kAuthenticatorCredentialManagement = 0x0a,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
#include "device/fido/authenticator_supported_options.h" #include "device/fido/authenticator_supported_options.h"
#include "device/fido/credential_management.h" #include "device/fido/credential_management.h"
#include "device/fido/ctap_authenticator_selection_request.h"
#include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h" #include "device/fido/ctap_make_credential_request.h"
#include "device/fido/features.h" #include "device/fido/features.h"
...@@ -175,7 +176,26 @@ void FidoDeviceAuthenticator::GetNextAssertion(GetAssertionCallback callback) { ...@@ -175,7 +176,26 @@ void FidoDeviceAuthenticator::GetNextAssertion(GetAssertionCallback callback) {
GetAssertionTask::StringFixupPredicate); GetAssertionTask::StringFixupPredicate);
} }
void FidoDeviceAuthenticator::GetTouch(base::OnceCallback<void()> callback) { void FidoDeviceAuthenticator::GetTouch(base::OnceClosure callback) {
if (device()->device_info() &&
device()->device_info()->SupportsAtLeast(Ctap2Version::kCtap2_1)) {
RunOperation<CtapAuthenticatorSelectionRequest, pin::EmptyResponse>(
CtapAuthenticatorSelectionRequest(),
base::BindOnce(
[](std::string authenticator_id, base::OnceClosure callback,
CtapDeviceResponseCode status,
base::Optional<pin::EmptyResponse> _) {
if (status == CtapDeviceResponseCode::kSuccess) {
std::move(callback).Run();
return;
}
FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
<< " from " << authenticator_id;
},
GetId(), std::move(callback)),
base::BindOnce(&pin::EmptyResponse::Parse));
return;
}
MakeCredential( MakeCredential(
MakeCredentialTask::GetTouchRequest(device()), MakeCredentialTask::GetTouchRequest(device()),
base::BindOnce( base::BindOnce(
......
...@@ -49,7 +49,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator ...@@ -49,7 +49,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
CtapGetAssertionOptions options, CtapGetAssertionOptions options,
GetAssertionCallback callback) override; GetAssertionCallback callback) override;
void GetNextAssertion(GetAssertionCallback callback) override; void GetNextAssertion(GetAssertionCallback callback) override;
void GetTouch(base::OnceCallback<void()> callback) override; void GetTouch(base::OnceClosure callback) override;
void GetPinRetries(GetRetriesCallback callback) override; void GetPinRetries(GetRetriesCallback callback) override;
void GetPINToken(std::string pin, void GetPINToken(std::string pin,
std::vector<pin::Permissions> permissions, std::vector<pin::Permissions> permissions,
......
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h" #include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_types.h"
#include "device/fido/large_blob.h" #include "device/fido/large_blob.h"
#include "device/fido/pin.h" #include "device/fido/pin.h"
#include "device/fido/test_callback_receiver.h" #include "device/fido/test_callback_receiver.h"
...@@ -31,6 +33,7 @@ using ReadCallback = device::test::StatusAndValueCallbackReceiver< ...@@ -31,6 +33,7 @@ using ReadCallback = device::test::StatusAndValueCallbackReceiver<
using PinCallback = device::test::StatusAndValueCallbackReceiver< using PinCallback = device::test::StatusAndValueCallbackReceiver<
CtapDeviceResponseCode, CtapDeviceResponseCode,
base::Optional<pin::TokenResponse>>; base::Optional<pin::TokenResponse>>;
using TouchCallback = device::test::TestCallbackReceiver<>;
constexpr LargeBlobKey kDummyKey1 = {{0x01}}; constexpr LargeBlobKey kDummyKey1 = {{0x01}};
constexpr LargeBlobKey kDummyKey2 = {{0x02}}; constexpr LargeBlobKey kDummyKey2 = {{0x02}};
...@@ -41,7 +44,7 @@ constexpr size_t kMaxStorageSize = 4096; ...@@ -41,7 +44,7 @@ constexpr size_t kMaxStorageSize = 4096;
constexpr char kPin[] = "1234"; constexpr char kPin[] = "1234";
class FidoDeviceAuthenticatorTest : public testing::Test { class FidoDeviceAuthenticatorTest : public testing::Test {
public: protected:
void SetUp() override { void SetUp() override {
VirtualCtap2Device::Config config; VirtualCtap2Device::Config config;
config.pin_support = true; config.pin_support = true;
...@@ -50,7 +53,11 @@ class FidoDeviceAuthenticatorTest : public testing::Test { ...@@ -50,7 +53,11 @@ class FidoDeviceAuthenticatorTest : public testing::Test {
config.available_large_blob_storage = kMaxStorageSize; config.available_large_blob_storage = kMaxStorageSize;
config.pin_uv_auth_token_support = true; config.pin_uv_auth_token_support = true;
config.ctap2_versions = {Ctap2Version::kCtap2_1}; config.ctap2_versions = {Ctap2Version::kCtap2_1};
SetUpAuthenticator(std::move(config));
}
protected:
void SetUpAuthenticator(VirtualCtap2Device::Config config) {
authenticator_state_ = base::MakeRefCounted<VirtualFidoDevice::State>(); authenticator_state_ = base::MakeRefCounted<VirtualFidoDevice::State>();
auto virtual_device = auto virtual_device =
std::make_unique<VirtualCtap2Device>(authenticator_state_, config); std::make_unique<VirtualCtap2Device>(authenticator_state_, config);
...@@ -63,7 +70,6 @@ class FidoDeviceAuthenticatorTest : public testing::Test { ...@@ -63,7 +70,6 @@ class FidoDeviceAuthenticatorTest : public testing::Test {
callback.WaitForCallback(); callback.WaitForCallback();
} }
protected:
scoped_refptr<VirtualFidoDevice::State> authenticator_state_; scoped_refptr<VirtualFidoDevice::State> authenticator_state_;
std::unique_ptr<FidoDeviceAuthenticator> authenticator_; std::unique_ptr<FidoDeviceAuthenticator> authenticator_;
VirtualCtap2Device* virtual_device_; VirtualCtap2Device* virtual_device_;
...@@ -213,6 +219,29 @@ TEST_F(FidoDeviceAuthenticatorTest, TestUpdateLargeBlob) { ...@@ -213,6 +219,29 @@ TEST_F(FidoDeviceAuthenticatorTest, TestUpdateLargeBlob) {
std::make_pair(kDummyKey2, small_blob2))); std::make_pair(kDummyKey2, small_blob2)));
} }
// Tests getting a touch.
TEST_F(FidoDeviceAuthenticatorTest, TestGetTouch) {
for (Ctap2Version version :
{Ctap2Version::kCtap2_0, Ctap2Version::kCtap2_1}) {
SCOPED_TRACE(std::string("CTAP ") +
(version == Ctap2Version::kCtap2_0 ? "2.0" : "2.1"));
VirtualCtap2Device::Config config;
config.ctap2_versions = {version};
SetUpAuthenticator(std::move(config));
TouchCallback callback;
bool touch_pressed = false;
authenticator_state_->simulate_press_callback =
base::BindLambdaForTesting([&](VirtualFidoDevice* device) {
touch_pressed = true;
return true;
});
authenticator_->GetTouch(callback.callback());
callback.WaitForCallback();
EXPECT_TRUE(touch_pressed);
}
}
} // namespace } // namespace
} // namespace device } // namespace device
...@@ -517,7 +517,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state, ...@@ -517,7 +517,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
options.supports_pin_uv_auth_token = config.pin_uv_auth_token_support; options.supports_pin_uv_auth_token = config.pin_uv_auth_token_support;
DCHECK(!options.supports_pin_uv_auth_token || DCHECK(!options.supports_pin_uv_auth_token ||
base::Contains(config.ctap2_versions, Ctap2Version::kCtap2_1)); SupportsAtLeast(Ctap2Version::kCtap2_1));
if (config.resident_key_support) { if (config.resident_key_support) {
options_updated = true; options_updated = true;
...@@ -576,7 +576,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state, ...@@ -576,7 +576,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
if (config.large_blob_support) { if (config.large_blob_support) {
DCHECK(config.resident_key_support); DCHECK(config.resident_key_support);
DCHECK(base::Contains(config.ctap2_versions, Ctap2Version::kCtap2_1)); DCHECK(SupportsAtLeast(Ctap2Version::kCtap2_1));
DCHECK((!config.pin_support && !config.internal_uv_support) || DCHECK((!config.pin_support && !config.internal_uv_support) ||
config.pin_uv_auth_token_support) config.pin_uv_auth_token_support)
<< "PinUvAuthToken support is required to write large blobs for " << "PinUvAuthToken support is required to write large blobs for "
...@@ -636,8 +636,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state, ...@@ -636,8 +636,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
base::flat_set<PINUVAuthProtocol>{config.pin_protocol}; base::flat_set<PINUVAuthProtocol>{config.pin_protocol};
} }
if (config.resident_key_support && if (config.resident_key_support && SupportsAtLeast(Ctap2Version::kCtap2_1)) {
base::Contains(config.ctap2_versions, Ctap2Version::kCtap2_1)) {
device_info_->remaining_discoverable_credentials = device_info_->remaining_discoverable_credentials =
remaining_resident_credentials(); remaining_resident_credentials();
} }
...@@ -696,7 +695,8 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact( ...@@ -696,7 +695,8 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact(
} }
const auto request_bytes = base::make_span(command).subspan(1); const auto request_bytes = base::make_span(command).subspan(1);
CtapDeviceResponseCode response_code = CtapDeviceResponseCode::kCtap2ErrOther; CtapDeviceResponseCode response_code =
CtapDeviceResponseCode::kCtap1ErrInvalidCommand;
std::vector<uint8_t> response_data; std::vector<uint8_t> response_data;
switch (static_cast<CtapRequestCommand>(cmd_type)) { switch (static_cast<CtapRequestCommand>(cmd_type)) {
...@@ -747,6 +747,14 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact( ...@@ -747,6 +747,14 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact(
case CtapRequestCommand::kAuthenticatorBioEnrollmentPreview: case CtapRequestCommand::kAuthenticatorBioEnrollmentPreview:
response_code = OnBioEnrollment(request_bytes, &response_data); response_code = OnBioEnrollment(request_bytes, &response_data);
break; break;
case CtapRequestCommand::kAuthenticatorSelection:
DCHECK(SupportsAtLeast(Ctap2Version::kCtap2_1));
if (!SimulatePress()) {
// Simulate timeout due to unresponded User Presence check.
return 0;
}
response_code = CtapDeviceResponseCode::kSuccess;
break;
case CtapRequestCommand::kAuthenticatorLargeBlobs: case CtapRequestCommand::kAuthenticatorLargeBlobs:
response_code = OnLargeBlobs(request_bytes, &response_data); response_code = OnLargeBlobs(request_bytes, &response_data);
break; break;
...@@ -2580,7 +2588,7 @@ AttestedCredentialData VirtualCtap2Device::ConstructAttestedCredentialData( ...@@ -2580,7 +2588,7 @@ AttestedCredentialData VirtualCtap2Device::ConstructAttestedCredentialData(
std::move(public_key)); std::move(public_key));
} }
size_t VirtualCtap2Device::remaining_resident_credentials() { size_t VirtualCtap2Device::remaining_resident_credentials() const {
size_t num_resident_keys = 0; size_t num_resident_keys = 0;
for (const auto& registration : mutable_state()->registrations) { for (const auto& registration : mutable_state()->registrations) {
if (registration.second.is_resident) { if (registration.second.is_resident) {
...@@ -2592,4 +2600,11 @@ size_t VirtualCtap2Device::remaining_resident_credentials() { ...@@ -2592,4 +2600,11 @@ size_t VirtualCtap2Device::remaining_resident_credentials() {
return config_.resident_credential_storage - num_resident_keys; return config_.resident_credential_storage - num_resident_keys;
} }
bool VirtualCtap2Device::SupportsAtLeast(Ctap2Version ctap2_version) const {
return base::ranges::any_of(config_.ctap2_versions,
[ctap2_version](const Ctap2Version& version) {
return version >= ctap2_version;
});
}
} // namespace device } // namespace device
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "device/fido/ctap_get_assertion_request.h" #include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h" #include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h" #include "device/fido/fido_constants.h"
#include "device/fido/fido_types.h"
#include "device/fido/virtual_fido_device.h" #include "device/fido/virtual_fido_device.h"
namespace device { namespace device {
...@@ -257,7 +258,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device ...@@ -257,7 +258,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
base::span<const uint8_t> key_handle, base::span<const uint8_t> key_handle,
std::unique_ptr<PublicKey> public_key); std::unique_ptr<PublicKey> public_key);
size_t remaining_resident_credentials(); size_t remaining_resident_credentials() const;
bool SupportsAtLeast(Ctap2Version ctap2_version) const;
std::unique_ptr<VirtualU2fDevice> u2f_device_; std::unique_ptr<VirtualU2fDevice> u2f_device_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment