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") {
"credential_management_handler.cc",
"credential_management_handler.h",
"ctap2_device_operation.h",
"ctap_authenticator_selection_request.cc",
"ctap_authenticator_selection_request.h",
"ctap_get_assertion_request.cc",
"ctap_get_assertion_request.h",
"ctap_make_credential_request.cc",
......
......@@ -6,6 +6,7 @@
#include <utility>
#include "base/ranges/algorithm.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "device/fido/fido_parsing_utils.h"
......@@ -137,4 +138,12 @@ std::vector<uint8_t> AuthenticatorGetInfoResponse::EncodeToCBOR(
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
......@@ -16,6 +16,7 @@
#include "base/optional.h"
#include "device/fido/authenticator_supported_options.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_types.h"
namespace device {
......@@ -35,6 +36,10 @@ struct COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorGetInfoResponse {
static std::vector<uint8_t> EncodeToCBOR(
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<Ctap2Version> ctap2_versions;
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 {
kAuthenticatorClientPin = 0x06,
kAuthenticatorReset = 0x07,
kAuthenticatorBioEnrollment = 0x09,
kAuthenticatorSelection = 0x0B,
kAuthenticatorLargeBlobs = 0x0C,
kAuthenticatorBioEnrollmentPreview = 0x40,
kAuthenticatorCredentialManagement = 0x0a,
......
......@@ -15,6 +15,7 @@
#include "build/chromeos_buildflags.h"
#include "device/fido/authenticator_supported_options.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_make_credential_request.h"
#include "device/fido/features.h"
......@@ -175,7 +176,26 @@ void FidoDeviceAuthenticator::GetNextAssertion(GetAssertionCallback callback) {
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(
MakeCredentialTask::GetTouchRequest(device()),
base::BindOnce(
......
......@@ -49,7 +49,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoDeviceAuthenticator
CtapGetAssertionOptions options,
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 GetPINToken(std::string pin,
std::vector<pin::Permissions> permissions,
......
......@@ -8,9 +8,11 @@
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_parsing_utils.h"
#include "device/fido/fido_types.h"
#include "device/fido/large_blob.h"
#include "device/fido/pin.h"
#include "device/fido/test_callback_receiver.h"
......@@ -31,6 +33,7 @@ using ReadCallback = device::test::StatusAndValueCallbackReceiver<
using PinCallback = device::test::StatusAndValueCallbackReceiver<
CtapDeviceResponseCode,
base::Optional<pin::TokenResponse>>;
using TouchCallback = device::test::TestCallbackReceiver<>;
constexpr LargeBlobKey kDummyKey1 = {{0x01}};
constexpr LargeBlobKey kDummyKey2 = {{0x02}};
......@@ -41,7 +44,7 @@ constexpr size_t kMaxStorageSize = 4096;
constexpr char kPin[] = "1234";
class FidoDeviceAuthenticatorTest : public testing::Test {
public:
protected:
void SetUp() override {
VirtualCtap2Device::Config config;
config.pin_support = true;
......@@ -50,7 +53,11 @@ class FidoDeviceAuthenticatorTest : public testing::Test {
config.available_large_blob_storage = kMaxStorageSize;
config.pin_uv_auth_token_support = true;
config.ctap2_versions = {Ctap2Version::kCtap2_1};
SetUpAuthenticator(std::move(config));
}
protected:
void SetUpAuthenticator(VirtualCtap2Device::Config config) {
authenticator_state_ = base::MakeRefCounted<VirtualFidoDevice::State>();
auto virtual_device =
std::make_unique<VirtualCtap2Device>(authenticator_state_, config);
......@@ -63,7 +70,6 @@ class FidoDeviceAuthenticatorTest : public testing::Test {
callback.WaitForCallback();
}
protected:
scoped_refptr<VirtualFidoDevice::State> authenticator_state_;
std::unique_ptr<FidoDeviceAuthenticator> authenticator_;
VirtualCtap2Device* virtual_device_;
......@@ -213,6 +219,29 @@ TEST_F(FidoDeviceAuthenticatorTest, TestUpdateLargeBlob) {
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 device
......@@ -517,7 +517,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
options.supports_pin_uv_auth_token = config.pin_uv_auth_token_support;
DCHECK(!options.supports_pin_uv_auth_token ||
base::Contains(config.ctap2_versions, Ctap2Version::kCtap2_1));
SupportsAtLeast(Ctap2Version::kCtap2_1));
if (config.resident_key_support) {
options_updated = true;
......@@ -576,7 +576,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
if (config.large_blob_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) ||
config.pin_uv_auth_token_support)
<< "PinUvAuthToken support is required to write large blobs for "
......@@ -636,8 +636,7 @@ VirtualCtap2Device::VirtualCtap2Device(scoped_refptr<State> state,
base::flat_set<PINUVAuthProtocol>{config.pin_protocol};
}
if (config.resident_key_support &&
base::Contains(config.ctap2_versions, Ctap2Version::kCtap2_1)) {
if (config.resident_key_support && SupportsAtLeast(Ctap2Version::kCtap2_1)) {
device_info_->remaining_discoverable_credentials =
remaining_resident_credentials();
}
......@@ -696,7 +695,8 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact(
}
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;
switch (static_cast<CtapRequestCommand>(cmd_type)) {
......@@ -747,6 +747,14 @@ FidoDevice::CancelToken VirtualCtap2Device::DeviceTransact(
case CtapRequestCommand::kAuthenticatorBioEnrollmentPreview:
response_code = OnBioEnrollment(request_bytes, &response_data);
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:
response_code = OnLargeBlobs(request_bytes, &response_data);
break;
......@@ -2580,7 +2588,7 @@ AttestedCredentialData VirtualCtap2Device::ConstructAttestedCredentialData(
std::move(public_key));
}
size_t VirtualCtap2Device::remaining_resident_credentials() {
size_t VirtualCtap2Device::remaining_resident_credentials() const {
size_t num_resident_keys = 0;
for (const auto& registration : mutable_state()->registrations) {
if (registration.second.is_resident) {
......@@ -2592,4 +2600,11 @@ size_t VirtualCtap2Device::remaining_resident_credentials() {
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
......@@ -22,6 +22,7 @@
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/fido_constants.h"
#include "device/fido/fido_types.h"
#include "device/fido/virtual_fido_device.h"
namespace device {
......@@ -257,7 +258,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualCtap2Device
base::span<const uint8_t> key_handle,
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_;
......
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