Commit 8e6f1b32 authored by Martin Kreichgauer's avatar Martin Kreichgauer Committed by Commit Bot

fido: make CTAP2_ERR_OPERATION_DENIED cancel the request

This is a follow-up to crrev.com/c/1181863, which added OPERATION_DENIED
handling for Touch ID. In this change that behavior is extended to all
transports.

Bug: 875982
Change-Id: If10000f8333dccd4c2e83becf51e36baedbc2655
Reviewed-on: https://chromium-review.googlesource.com/1187683
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585823}
parent d61dcd66
...@@ -58,9 +58,9 @@ class FidoRequestHandler : public FidoRequestHandlerBase { ...@@ -58,9 +58,9 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
return; return;
} }
const auto return_code = ConvertDeviceResponseCodeToFidoReturnCode( base::Optional<FidoReturnCode> return_code =
device_response_code, response_data.has_value(), ConvertDeviceResponseCodeToFidoReturnCode(device_response_code,
authenticator->AuthenticatorTransport()); response_data.has_value());
// Any authenticator response codes that do not result from user consent // Any authenticator response codes that do not result from user consent
// imply that the authenticator should be dropped and that other on-going // imply that the authenticator should be dropped and that other on-going
...@@ -82,8 +82,7 @@ class FidoRequestHandler : public FidoRequestHandlerBase { ...@@ -82,8 +82,7 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
static base::Optional<FidoReturnCode> static base::Optional<FidoReturnCode>
ConvertDeviceResponseCodeToFidoReturnCode( ConvertDeviceResponseCodeToFidoReturnCode(
CtapDeviceResponseCode device_response_code, CtapDeviceResponseCode device_response_code,
bool response_has_value, bool response_has_value) {
FidoTransportProtocol transport) {
switch (device_response_code) { switch (device_response_code) {
case CtapDeviceResponseCode::kSuccess: case CtapDeviceResponseCode::kSuccess:
return response_has_value return response_has_value
...@@ -97,21 +96,11 @@ class FidoRequestHandler : public FidoRequestHandlerBase { ...@@ -97,21 +96,11 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
case CtapDeviceResponseCode::kCtap2ErrNoCredentials: case CtapDeviceResponseCode::kCtap2ErrNoCredentials:
return FidoReturnCode::kUserConsentButCredentialNotRecognized; return FidoReturnCode::kUserConsentButCredentialNotRecognized;
// The user explicitly denied the operation. // The user explicitly denied the operation. Touch ID returns this error
// when the user cancels the macOS prompt. External authenticators may
// return it e.g. after the user fails fingerprint verification.
case CtapDeviceResponseCode::kCtap2ErrOperationDenied: case CtapDeviceResponseCode::kCtap2ErrOperationDenied:
// TODO(crbug/875982): Clarify if |CTAP2_ERR_OPERATION_DENIED| is "a return FidoReturnCode::kUserConsentDenied;
// status indicating that the user cancelled the operation" in the
// spirit of https://www.w3.org/TR/webauthn/, sections 5.1.3 and
// 5.1.4.. The CTAP2 spec also uses it for authenticator-chosen
// timeouts, so it is a little unclear.
//
// For Touch ID, we know it means that the operation failed during (or
// after) user verification, so we do the translation the internal
// transport only.
return transport == FidoTransportProtocol::kInternal
? base::make_optional<FidoReturnCode>(
FidoReturnCode::kUserConsentDenied)
: base::nullopt;
// This error is returned by some authenticators (e.g. the "Yubico FIDO // This error is returned by some authenticators (e.g. the "Yubico FIDO
// 2" CTAP2 USB keys) during GetAssertion **before the user interacted // 2" CTAP2 USB keys) during GetAssertion **before the user interacted
......
...@@ -431,10 +431,8 @@ TEST_F(FidoRequestHandlerTest, ...@@ -431,10 +431,8 @@ TEST_F(FidoRequestHandlerTest,
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status());
} }
// Like |TestRequestWithOperationDeniedErrorInternalTransport|, but the // Like |TestRequestWithOperationDeniedErrorInternalTransport|, but with a
// CTAP2_ERR_OPERATION_DENIED error is returned by a device with // cross-platform authenticator.
// cross-platform transport. The operation should not be cancelled (see
// https://crbug/875982).
TEST_F(FidoRequestHandlerTest, TEST_F(FidoRequestHandlerTest,
TestRequestWithOperationDeniedErrorCrossPlatform) { TestRequestWithOperationDeniedErrorCrossPlatform) {
auto request_handler = CreateFakeHandler(); auto request_handler = CreateFakeHandler();
...@@ -446,21 +444,17 @@ TEST_F(FidoRequestHandlerTest, ...@@ -446,21 +444,17 @@ TEST_F(FidoRequestHandlerTest,
device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(), device0->ExpectRequestAndRespondWith(std::vector<uint8_t>(),
CreateFakeOperationDeniedError()); CreateFakeOperationDeniedError());
// Pending device will *NOT* be cancelled and can send a success reply
// eventually.
auto device1 = MockFidoDevice::MakeCtapWithGetInfoExpectation(); auto device1 = MockFidoDevice::MakeCtapWithGetInfoExpectation();
device1->ExpectRequestAndRespondWith(std::vector<uint8_t>(), device1->ExpectRequestAndDoNotRespond(std::vector<uint8_t>());
CreateFakeSuccessDeviceResponse(), EXPECT_CALL(*device1, Cancel());
base::TimeDelta::FromMicroseconds(10));
discovery()->AddDevice(std::move(device0)); discovery()->AddDevice(std::move(device0));
discovery()->AddDevice(std::move(device1)); discovery()->AddDevice(std::move(device1));
// The request will stay pending, the reply has not triggered the callback.
scoped_task_environment_.FastForwardUntilNoTasksRemain(); scoped_task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status());
} }
// Requests should be dispatched to the authenticator passed to // Requests should be dispatched to the authenticator passed to
......
...@@ -620,8 +620,7 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -620,8 +620,7 @@ TEST_F(FidoGetAssertionHandlerTest,
} }
// Like |TestRequestWithOperationDeniedErrorPlatform|, but with a // Like |TestRequestWithOperationDeniedErrorPlatform|, but with a
// cross-platform device. The request should not complete after the // cross-platform device.
// CTAP2_ERR_OPERATION_DENIED error (see https://crbug/875982).
TEST_F(FidoGetAssertionHandlerTest, TEST_F(FidoGetAssertionHandlerTest,
TestRequestWithOperationDeniedErrorCrossPlatform) { TestRequestWithOperationDeniedErrorCrossPlatform) {
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
...@@ -634,7 +633,9 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -634,7 +633,9 @@ TEST_F(FidoGetAssertionHandlerTest,
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
scoped_task_environment_.FastForwardUntilNoTasksRemain(); scoped_task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(get_assertion_callback().was_called()); EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied,
get_assertion_callback().status());
} }
} // namespace device } // namespace device
...@@ -562,8 +562,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -562,8 +562,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
} }
// Like |TestRequestWithOperationDeniedErrorPlatform|, but with a // Like |TestRequestWithOperationDeniedErrorPlatform|, but with a
// cross-platform device. The request should not complete after the // cross-platform device.
// CTAP2_ERR_OPERATION_DENIED error (see https://crbug/875982).
TEST_F(FidoMakeCredentialHandlerTest, TEST_F(FidoMakeCredentialHandlerTest,
TestRequestWithOperationDeniedErrorCrossPlatform) { TestRequestWithOperationDeniedErrorCrossPlatform) {
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
...@@ -582,7 +581,8 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -582,7 +581,8 @@ TEST_F(FidoMakeCredentialHandlerTest,
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
scoped_task_environment_.FastForwardUntilNoTasksRemain(); scoped_task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_FALSE(callback().was_called()); EXPECT_TRUE(callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status());
} }
} // namespace device } // namespace 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