Commit abd93b98 authored by Martin Kreichgauer's avatar Martin Kreichgauer Committed by Commit Bot

fido: split up FidoReturnCode

FidoReturnCode is a unified namespace for any higher-level status of a
FidoRequestHandler. This was somewhat convient because security key
operations share certain failure modes (e.g. kSuccess,
kInvalidAuthenticatorResponse or kSoftPINBlock). On the other hand, it
meant that users of each FidoRequestHandler needed to implicitly know
which subset of FidoReturnCode was applicable to the particular
subclass.

This change replaces FidoReturnCode with separate status enums for each
request handler. This gets us better type safety and smaller
"switch(status) { ... }" blocks at the expense of having to duplicate
the few common status values across request handlers.

Bug: 876109

Change-Id: Ic0f5bfc08d6c2d4186bf4e2ca9bf99edf0bf6c87
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1774825
Commit-Queue: Martin Kreichgauer <martinkr@chromium.org>
Reviewed-by: default avatarDan Beam <dbeam@chromium.org>
Reviewed-by: default avatarAdam Langley <agl@chromium.org>
Cr-Commit-Position: refs/heads/master@{#692170}
parent 086ec374
...@@ -411,7 +411,8 @@ void SecurityKeysCredentialHandler::OnHaveCredentials( ...@@ -411,7 +411,8 @@ void SecurityKeysCredentialHandler::OnHaveCredentials(
DCHECK(!callback_id_.empty()); DCHECK(!callback_id_.empty());
if (status != device::CtapDeviceResponseCode::kSuccess) { if (status != device::CtapDeviceResponseCode::kSuccess) {
OnFinished(device::FidoReturnCode::kAuthenticatorResponseInvalid); OnFinished(
device::CredentialManagementStatus::kAuthenticatorResponseInvalid);
return; return;
} }
DCHECK(responses); DCHECK(responses);
...@@ -484,34 +485,32 @@ void SecurityKeysCredentialHandler::OnCredentialsDeleted( ...@@ -484,34 +485,32 @@ void SecurityKeysCredentialHandler::OnCredentialsDeleted(
: IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_FAILED))); : IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_FAILED)));
} }
void SecurityKeysCredentialHandler::OnFinished(device::FidoReturnCode status) { void SecurityKeysCredentialHandler::OnFinished(
device::CredentialManagementStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
int error; int error;
switch (status) { switch (status) {
case device::FidoReturnCode::kSoftPINBlock: case device::CredentialManagementStatus::kSoftPINBlock:
error = IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK; error = IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK;
break; break;
case device::FidoReturnCode::kHardPINBlock: case device::CredentialManagementStatus::kHardPINBlock:
error = IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK; error = IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK;
break; break;
case device::FidoReturnCode::kAuthenticatorMissingCredentialManagement: case device::CredentialManagementStatus::
kAuthenticatorMissingCredentialManagement:
error = IDS_SETTINGS_SECURITY_KEYS_NO_CREDENTIAL_MANAGEMENT; error = IDS_SETTINGS_SECURITY_KEYS_NO_CREDENTIAL_MANAGEMENT;
break; break;
case device::FidoReturnCode::kAuthenticatorMissingUserVerification: case device::CredentialManagementStatus::kNoPINSet:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_NO_PIN; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_NO_PIN;
break; break;
case device::FidoReturnCode::kAuthenticatorResponseInvalid: case device::CredentialManagementStatus::kAuthenticatorResponseInvalid:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR;
break; break;
case device::FidoReturnCode::kSuccess: case device::CredentialManagementStatus::kSuccess:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_REMOVED; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_REMOVED;
break; break;
default:
NOTREACHED();
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR;
break;
} }
FireWebUIListener("security-keys-credential-management-finished", FireWebUIListener("security-keys-credential-management-finished",
...@@ -594,34 +593,31 @@ void SecurityKeysBioEnrollmentHandler::OnReady() { ...@@ -594,34 +593,31 @@ void SecurityKeysBioEnrollmentHandler::OnReady() {
base::Value()); base::Value());
} }
void SecurityKeysBioEnrollmentHandler::OnError(device::FidoReturnCode code) { void SecurityKeysBioEnrollmentHandler::OnError(
device::BioEnrollmentStatus status) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
state_ = State::kNone; state_ = State::kNone;
int error; int error;
switch (code) { switch (status) {
case device::FidoReturnCode::kSoftPINBlock: case device::BioEnrollmentStatus::kSoftPINBlock:
error = IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK; error = IDS_SETTINGS_SECURITY_KEYS_PIN_SOFT_LOCK;
break; break;
case device::FidoReturnCode::kHardPINBlock: case device::BioEnrollmentStatus::kHardPINBlock:
error = IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK; error = IDS_SETTINGS_SECURITY_KEYS_PIN_HARD_LOCK;
break; break;
case device::FidoReturnCode::kAuthenticatorMissingBioEnrollment: case device::BioEnrollmentStatus::kAuthenticatorMissingBioEnrollment:
error = IDS_SETTINGS_SECURITY_KEYS_NO_BIOMETRIC_ENROLLMENT; error = IDS_SETTINGS_SECURITY_KEYS_NO_BIOMETRIC_ENROLLMENT;
break; break;
case device::FidoReturnCode::kAuthenticatorMissingUserVerification: case device::BioEnrollmentStatus::kNoPINSet:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_NO_PIN; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_NO_PIN;
break; break;
case device::FidoReturnCode::kAuthenticatorResponseInvalid: case device::BioEnrollmentStatus::kAuthenticatorResponseInvalid:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR;
break; break;
case device::FidoReturnCode::kSuccess: case device::BioEnrollmentStatus::kSuccess:
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_REMOVED; error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_REMOVED;
break; break;
default:
NOTREACHED();
error = IDS_SETTINGS_SECURITY_KEYS_CREDENTIAL_MANAGEMENT_ERROR;
break;
} }
FireWebUIListener("security-keys-bio-enroll-error", FireWebUIListener("security-keys-bio-enroll-error",
......
...@@ -24,9 +24,11 @@ namespace device { ...@@ -24,9 +24,11 @@ namespace device {
struct AggregatedEnumerateCredentialsResponse; struct AggregatedEnumerateCredentialsResponse;
class FidoDiscoveryFactory; class FidoDiscoveryFactory;
class CredentialManagementHandler; class CredentialManagementHandler;
enum class CredentialManagementStatus;
class SetPINRequestHandler; class SetPINRequestHandler;
class ResetRequestHandler; class ResetRequestHandler;
class BioEnrollmentHandler; class BioEnrollmentHandler;
enum class BioEnrollmentStatus;
} // namespace device } // namespace device
namespace settings { namespace settings {
...@@ -152,7 +154,7 @@ class SecurityKeysCredentialHandler : public SecurityKeysHandlerBase { ...@@ -152,7 +154,7 @@ class SecurityKeysCredentialHandler : public SecurityKeysHandlerBase {
base::Optional<size_t> remaining_credentials); base::Optional<size_t> remaining_credentials);
void OnGatherPIN(int64_t num_retries, base::OnceCallback<void(std::string)>); void OnGatherPIN(int64_t num_retries, base::OnceCallback<void(std::string)>);
void OnCredentialsDeleted(device::CtapDeviceResponseCode status); void OnCredentialsDeleted(device::CtapDeviceResponseCode status);
void OnFinished(device::FidoReturnCode status); void OnFinished(device::CredentialManagementStatus status);
State state_ = State::kNone; State state_ = State::kNone;
base::OnceCallback<void(std::string)> credential_management_provide_pin_cb_; base::OnceCallback<void(std::string)> credential_management_provide_pin_cb_;
...@@ -185,7 +187,7 @@ class SecurityKeysBioEnrollmentHandler : public SecurityKeysHandlerBase { ...@@ -185,7 +187,7 @@ class SecurityKeysBioEnrollmentHandler : public SecurityKeysHandlerBase {
void HandleStart(const base::ListValue* args); void HandleStart(const base::ListValue* args);
void OnReady(); void OnReady();
void OnError(device::FidoReturnCode code); void OnError(device::BioEnrollmentStatus status);
void OnGatherPIN(int64_t retries, base::OnceCallback<void(std::string)>); void OnGatherPIN(int64_t retries, base::OnceCallback<void(std::string)>);
void HandleProvidePIN(const base::ListValue* args); void HandleProvidePIN(const base::ListValue* args);
......
...@@ -39,6 +39,9 @@ class FidoRequestHandlerBase; ...@@ -39,6 +39,9 @@ class FidoRequestHandlerBase;
enum class FidoReturnCode : uint8_t; enum class FidoReturnCode : uint8_t;
enum class GetAssertionStatus;
enum class MakeCredentialStatus;
} // namespace device } // namespace device
namespace service_manager { namespace service_manager {
...@@ -137,7 +140,7 @@ class CONTENT_EXPORT AuthenticatorCommon { ...@@ -137,7 +140,7 @@ class CONTENT_EXPORT AuthenticatorCommon {
// Callback to handle the async response from a U2fDevice. // Callback to handle the async response from a U2fDevice.
void OnRegisterResponse( void OnRegisterResponse(
device::FidoReturnCode status_code, device::MakeCredentialStatus status_code,
base::Optional<device::AuthenticatorMakeCredentialResponse> response_data, base::Optional<device::AuthenticatorMakeCredentialResponse> response_data,
const device::FidoAuthenticator* authenticator); const device::FidoAuthenticator* authenticator);
...@@ -150,7 +153,7 @@ class CONTENT_EXPORT AuthenticatorCommon { ...@@ -150,7 +153,7 @@ class CONTENT_EXPORT AuthenticatorCommon {
// Callback to handle the async response from a U2fDevice. // Callback to handle the async response from a U2fDevice.
void OnSignResponse( void OnSignResponse(
device::FidoReturnCode status_code, device::GetAssertionStatus status_code,
base::Optional<std::vector<device::AuthenticatorGetAssertionResponse>> base::Optional<std::vector<device::AuthenticatorGetAssertionResponse>>
response_data, response_data,
const device::FidoAuthenticator* authenticator); const device::FidoAuthenticator* authenticator);
......
...@@ -108,7 +108,7 @@ void BioEnrollmentHandler::AuthenticatorRemoved( ...@@ -108,7 +108,7 @@ void BioEnrollmentHandler::AuthenticatorRemoved(
} }
authenticator_ = nullptr; authenticator_ = nullptr;
std::move(error_callback_).Run(FidoReturnCode::kSuccess); std::move(error_callback_).Run(BioEnrollmentStatus::kSuccess);
} }
void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) { void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) {
...@@ -122,15 +122,14 @@ void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) { ...@@ -122,15 +122,14 @@ void BioEnrollmentHandler::OnTouch(FidoAuthenticator* authenticator) {
AuthenticatorSupportedOptions::BioEnrollmentAvailability:: AuthenticatorSupportedOptions::BioEnrollmentAvailability::
kNotSupported)) { kNotSupported)) {
std::move(error_callback_) std::move(error_callback_)
.Run(FidoReturnCode::kAuthenticatorMissingBioEnrollment); .Run(BioEnrollmentStatus::kAuthenticatorMissingBioEnrollment);
return; return;
} }
if (authenticator->Options()->client_pin_availability != if (authenticator->Options()->client_pin_availability !=
AuthenticatorSupportedOptions::ClientPinAvailability:: AuthenticatorSupportedOptions::ClientPinAvailability::
kSupportedAndPinSet) { kSupportedAndPinSet) {
std::move(error_callback_) std::move(error_callback_).Run(BioEnrollmentStatus::kNoPINSet);
.Run(FidoReturnCode::kAuthenticatorMissingUserVerification);
return; return;
} }
...@@ -147,12 +146,12 @@ void BioEnrollmentHandler::OnRetriesResponse( ...@@ -147,12 +146,12 @@ void BioEnrollmentHandler::OnRetriesResponse(
FIDO_LOG(DEBUG) << "OnRetriesResponse failed with response code " FIDO_LOG(DEBUG) << "OnRetriesResponse failed with response code "
<< static_cast<int>(code); << static_cast<int>(code);
std::move(error_callback_) std::move(error_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid); .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return; return;
} }
if (response->retries == 0) { if (response->retries == 0) {
std::move(error_callback_).Run(FidoReturnCode::kHardPINBlock); std::move(error_callback_).Run(BioEnrollmentStatus::kHardPINBlock);
return; return;
} }
...@@ -176,7 +175,7 @@ void BioEnrollmentHandler::OnHaveEphemeralKey( ...@@ -176,7 +175,7 @@ void BioEnrollmentHandler::OnHaveEphemeralKey(
FIDO_LOG(DEBUG) << "OnHaveEphemeralKey failed with response code " FIDO_LOG(DEBUG) << "OnHaveEphemeralKey failed with response code "
<< static_cast<int>(code); << static_cast<int>(code);
std::move(error_callback_) std::move(error_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid); .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return; return;
} }
...@@ -196,14 +195,14 @@ void BioEnrollmentHandler::OnHavePINToken( ...@@ -196,14 +195,14 @@ void BioEnrollmentHandler::OnHavePINToken(
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
return; return;
case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked: case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
std::move(error_callback_).Run(FidoReturnCode::kSoftPINBlock); std::move(error_callback_).Run(BioEnrollmentStatus::kSoftPINBlock);
return; return;
case CtapDeviceResponseCode::kCtap2ErrPinBlocked: case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
std::move(error_callback_).Run(FidoReturnCode::kHardPINBlock); std::move(error_callback_).Run(BioEnrollmentStatus::kHardPINBlock);
return; return;
default: default:
std::move(error_callback_) std::move(error_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid); .Run(BioEnrollmentStatus::kAuthenticatorResponseInvalid);
return; return;
case CtapDeviceResponseCode::kSuccess: case CtapDeviceResponseCode::kSuccess:
// fall through on success // fall through on success
......
...@@ -19,10 +19,19 @@ class Connector; ...@@ -19,10 +19,19 @@ class Connector;
namespace device { namespace device {
enum class BioEnrollmentStatus {
kSuccess,
kAuthenticatorResponseInvalid,
kSoftPINBlock,
kHardPINBlock,
kNoPINSet,
kAuthenticatorMissingBioEnrollment,
};
class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler class COMPONENT_EXPORT(DEVICE_FIDO) BioEnrollmentHandler
: public FidoRequestHandlerBase { : public FidoRequestHandlerBase {
public: public:
using ErrorCallback = base::OnceCallback<void(FidoReturnCode)>; using ErrorCallback = base::OnceCallback<void(BioEnrollmentStatus)>;
using GetPINCallback = using GetPINCallback =
base::RepeatingCallback<void(int64_t retries, base::RepeatingCallback<void(int64_t retries,
base::OnceCallback<void(std::string)>)>; base::OnceCallback<void(std::string)>)>;
......
...@@ -71,7 +71,7 @@ class BioEnrollmentHandlerTest : public ::testing::Test { ...@@ -71,7 +71,7 @@ class BioEnrollmentHandlerTest : public ::testing::Test {
bool sampling_; bool sampling_;
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
test::TestCallbackReceiver<> ready_callback_; test::TestCallbackReceiver<> ready_callback_;
test::ValueCallbackReceiver<FidoReturnCode> error_callback_; test::ValueCallbackReceiver<BioEnrollmentStatus> error_callback_;
test::VirtualFidoDeviceFactory virtual_device_factory_; test::VirtualFidoDeviceFactory virtual_device_factory_;
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -91,8 +91,7 @@ TEST_F(BioEnrollmentHandlerTest, NoPINSupport) { ...@@ -91,8 +91,7 @@ TEST_F(BioEnrollmentHandlerTest, NoPINSupport) {
auto handler = MakeHandler(); auto handler = MakeHandler();
error_callback_.WaitForCallback(); error_callback_.WaitForCallback();
EXPECT_EQ(error_callback_.value(), EXPECT_EQ(error_callback_.value(), BioEnrollmentStatus::kNoPINSet);
FidoReturnCode::kAuthenticatorMissingUserVerification);
} }
// Tests getting authenticator modality without pin auth. // Tests getting authenticator modality without pin auth.
...@@ -159,7 +158,7 @@ TEST_F(BioEnrollmentHandlerTest, SoftPINBlock) { ...@@ -159,7 +158,7 @@ TEST_F(BioEnrollmentHandlerTest, SoftPINBlock) {
auto handler = MakeHandler(); auto handler = MakeHandler();
error_callback_.WaitForCallback(); error_callback_.WaitForCallback();
EXPECT_EQ(error_callback_.value(), FidoReturnCode::kSoftPINBlock); EXPECT_EQ(error_callback_.value(), BioEnrollmentStatus::kSoftPINBlock);
} }
// Tests bio enrollment commands against an authenticator lacking support. // Tests bio enrollment commands against an authenticator lacking support.
...@@ -172,7 +171,7 @@ TEST_F(BioEnrollmentHandlerTest, NoBioEnrollmentSupport) { ...@@ -172,7 +171,7 @@ TEST_F(BioEnrollmentHandlerTest, NoBioEnrollmentSupport) {
auto handler = MakeHandler(); auto handler = MakeHandler();
error_callback_.WaitForCallback(); error_callback_.WaitForCallback();
EXPECT_EQ(error_callback_.value(), EXPECT_EQ(error_callback_.value(),
FidoReturnCode::kAuthenticatorMissingBioEnrollment); BioEnrollmentStatus::kAuthenticatorMissingBioEnrollment);
} }
// Tests fingerprint enrollment lifecycle. // Tests fingerprint enrollment lifecycle.
......
...@@ -63,7 +63,8 @@ void CredentialManagementHandler::OnTouch(FidoAuthenticator* authenticator) { ...@@ -63,7 +63,8 @@ void CredentialManagementHandler::OnTouch(FidoAuthenticator* authenticator) {
authenticator->Options()->supports_credential_management_preview)) { authenticator->Options()->supports_credential_management_preview)) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_) std::move(finished_callback_)
.Run(FidoReturnCode::kAuthenticatorMissingCredentialManagement); .Run(CredentialManagementStatus::
kAuthenticatorMissingCredentialManagement);
return; return;
} }
...@@ -74,8 +75,7 @@ void CredentialManagementHandler::OnTouch(FidoAuthenticator* authenticator) { ...@@ -74,8 +75,7 @@ void CredentialManagementHandler::OnTouch(FidoAuthenticator* authenticator) {
// We should implement in-flow PIN setting, but for now just tell the user // We should implement in-flow PIN setting, but for now just tell the user
// to set a PIN themselves. // to set a PIN themselves.
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_) std::move(finished_callback_).Run(CredentialManagementStatus::kNoPINSet);
.Run(FidoReturnCode::kAuthenticatorMissingUserVerification);
return; return;
} }
...@@ -93,12 +93,13 @@ void CredentialManagementHandler::OnRetriesResponse( ...@@ -93,12 +93,13 @@ void CredentialManagementHandler::OnRetriesResponse(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_) std::move(finished_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid); .Run(CredentialManagementStatus::kAuthenticatorResponseInvalid);
return; return;
} }
if (response->retries == 0) { if (response->retries == 0) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_).Run(FidoReturnCode::kHardPINBlock); std::move(finished_callback_)
.Run(CredentialManagementStatus::kHardPINBlock);
return; return;
} }
state_ = State::kWaitingForPIN; state_ = State::kWaitingForPIN;
...@@ -133,7 +134,7 @@ void CredentialManagementHandler::OnHaveEphemeralKey( ...@@ -133,7 +134,7 @@ void CredentialManagementHandler::OnHaveEphemeralKey(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_) std::move(finished_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid); .Run(CredentialManagementStatus::kAuthenticatorResponseInvalid);
return; return;
} }
...@@ -159,16 +160,16 @@ void CredentialManagementHandler::OnHavePINToken( ...@@ -159,16 +160,16 @@ void CredentialManagementHandler::OnHavePINToken(
} }
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
FidoReturnCode error; CredentialManagementStatus error;
switch (status) { switch (status) {
case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked: case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
error = FidoReturnCode::kSoftPINBlock; error = CredentialManagementStatus::kSoftPINBlock;
break; break;
case CtapDeviceResponseCode::kCtap2ErrPinBlocked: case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
error = FidoReturnCode::kHardPINBlock; error = CredentialManagementStatus::kHardPINBlock;
break; break;
default: default:
error = FidoReturnCode::kAuthenticatorResponseInvalid; error = CredentialManagementStatus::kAuthenticatorResponseInvalid;
break; break;
} }
state_ = State::kFinished; state_ = State::kFinished;
...@@ -337,7 +338,7 @@ void CredentialManagementHandler::AuthenticatorRemoved( ...@@ -337,7 +338,7 @@ void CredentialManagementHandler::AuthenticatorRemoved(
authenticator_ = nullptr; authenticator_ = nullptr;
state_ = State::kFinished; state_ = State::kFinished;
std::move(finished_callback_).Run(FidoReturnCode::kSuccess); std::move(finished_callback_).Run(CredentialManagementStatus::kSuccess);
} }
} // namespace device } // namespace device
...@@ -29,6 +29,15 @@ namespace device { ...@@ -29,6 +29,15 @@ namespace device {
class FidoAuthenticator; class FidoAuthenticator;
class FidoDiscoveryFactory; class FidoDiscoveryFactory;
enum class CredentialManagementStatus {
kSuccess,
kAuthenticatorResponseInvalid,
kSoftPINBlock,
kHardPINBlock,
kAuthenticatorMissingCredentialManagement,
kNoPINSet,
};
// CredentialManagementHandler implements the authenticatorCredentialManagement // CredentialManagementHandler implements the authenticatorCredentialManagement
// protocol. // protocol.
// //
...@@ -39,7 +48,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CredentialManagementHandler ...@@ -39,7 +48,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) CredentialManagementHandler
public: public:
using DeleteCredentialCallback = using DeleteCredentialCallback =
base::OnceCallback<void(CtapDeviceResponseCode)>; base::OnceCallback<void(CtapDeviceResponseCode)>;
using FinishedCallback = base::OnceCallback<void(FidoReturnCode)>; using FinishedCallback = base::OnceCallback<void(CredentialManagementStatus)>;
using GetCredentialsCallback = base::OnceCallback<void( using GetCredentialsCallback = base::OnceCallback<void(
CtapDeviceResponseCode, CtapDeviceResponseCode,
base::Optional<std::vector<AggregatedEnumerateCredentialsResponse>>, base::Optional<std::vector<AggregatedEnumerateCredentialsResponse>>,
......
...@@ -64,7 +64,7 @@ class CredentialManagementHandlerTest : public ::testing::Test { ...@@ -64,7 +64,7 @@ class CredentialManagementHandlerTest : public ::testing::Test {
base::Optional<size_t>> base::Optional<size_t>>
get_credentials_callback_; get_credentials_callback_;
test::ValueCallbackReceiver<CtapDeviceResponseCode> delete_callback_; test::ValueCallbackReceiver<CtapDeviceResponseCode> delete_callback_;
test::ValueCallbackReceiver<FidoReturnCode> finished_callback_; test::ValueCallbackReceiver<CredentialManagementStatus> finished_callback_;
test::VirtualFidoDeviceFactory virtual_device_factory_; test::VirtualFidoDeviceFactory virtual_device_factory_;
#if defined(OS_WIN) #if defined(OS_WIN)
......
...@@ -16,39 +16,6 @@ ...@@ -16,39 +16,6 @@
namespace device { namespace device {
enum class FidoReturnCode : uint8_t {
kSuccess,
// Response received but didn't parse/serialize properly.
kAuthenticatorResponseInvalid,
// The user consented to the registration operation (e.g. by touching the
// authenticator), but the authenticator recognized one of the credentials
// that were already registered at the relying party.
kUserConsentButCredentialExcluded,
// The user consented to the assertion operation (e.g. by touching the
// authenticator), but none of the provided credentials were recognized by
// the authenticator.
kUserConsentButCredentialNotRecognized,
// The user explicitly refused to provide consent.
kUserConsentDenied,
kAuthenticatorRemovedDuringPINEntry,
kSoftPINBlock,
kHardPINBlock,
kAuthenticatorMissingResidentKeys,
kAuthenticatorMissingCredentialManagement,
// TODO(agl): kAuthenticatorMissingUserVerification can also be returned when
// the authenticator supports UV, but there's no UI support for collecting
// a PIN. This could be clearer.
kAuthenticatorMissingUserVerification,
// kStorageFull indicates that a resident credential could not be created
// because the authenticator has insufficient storage.
kStorageFull,
kAuthenticatorMissingBioEnrollment,
// The following correspond to errors returned by the Windows WebAuthn API.
kWinInvalidStateError,
kWinNotAllowedError,
};
// Length of the U2F challenge parameter: // Length of the U2F challenge parameter:
// https://goo.gl/y75WrX#registration-request-message---u2f_register // https://goo.gl/y75WrX#registration-request-message---u2f_register
constexpr size_t kU2fChallengeParamLength = 32; constexpr size_t kU2fChallengeParamLength = 32;
......
...@@ -26,11 +26,11 @@ class FidoDiscoveryFactory; ...@@ -26,11 +26,11 @@ class FidoDiscoveryFactory;
// and relaying response to the relying party. // and relaying response to the relying party.
// //
// TODO: this class should be dropped; it's not pulling its weight. // TODO: this class should be dropped; it's not pulling its weight.
template <class Response> template <typename Status, typename Response>
class FidoRequestHandler : public FidoRequestHandlerBase { class FidoRequestHandler : public FidoRequestHandlerBase {
public: public:
using CompletionCallback = using CompletionCallback =
base::OnceCallback<void(FidoReturnCode status_code, base::OnceCallback<void(Status status,
base::Optional<Response> response_data, base::Optional<Response> response_data,
const FidoAuthenticator* authenticator)>; const FidoAuthenticator* authenticator)>;
...@@ -54,7 +54,7 @@ class FidoRequestHandler : public FidoRequestHandlerBase { ...@@ -54,7 +54,7 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
// Converts authenticator response code received from CTAP1/CTAP2 device into // Converts authenticator response code received from CTAP1/CTAP2 device into
// FidoReturnCode and passes response data to webauth::mojom::Authenticator. // FidoReturnCode and passes response data to webauth::mojom::Authenticator.
void OnAuthenticatorResponse(FidoAuthenticator* authenticator, void OnAuthenticatorResponse(FidoAuthenticator* authenticator,
FidoReturnCode result, Status status,
base::Optional<Response> response_data) { base::Optional<Response> response_data) {
if (is_complete()) { if (is_complete()) {
// TODO: this should be handled at a higher level and so there should be // TODO: this should be handled at a higher level and so there should be
...@@ -63,58 +63,11 @@ class FidoRequestHandler : public FidoRequestHandlerBase { ...@@ -63,58 +63,11 @@ class FidoRequestHandler : public FidoRequestHandlerBase {
} }
std::move(completion_callback_) std::move(completion_callback_)
.Run(result, std::move(response_data), authenticator); .Run(status, std::move(response_data), authenticator);
} }
CompletionCallback completion_callback_; CompletionCallback completion_callback_;
static base::Optional<FidoReturnCode>
ConvertDeviceResponseCodeToFidoReturnCode(
CtapDeviceResponseCode device_response_code) {
switch (device_response_code) {
case CtapDeviceResponseCode::kSuccess:
return FidoReturnCode::kSuccess;
// These errors are only returned after the user interacted with the
// authenticator.
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
return FidoReturnCode::kUserConsentButCredentialExcluded;
case CtapDeviceResponseCode::kCtap2ErrNoCredentials:
return FidoReturnCode::kUserConsentButCredentialNotRecognized;
// 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:
return FidoReturnCode::kUserConsentDenied;
// External authenticators may return this error if internal user
// verification fails for a make credential request or if the pin token is
// not valid.
case CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid:
return FidoReturnCode::kUserConsentDenied;
case CtapDeviceResponseCode::kCtap2ErrKeyStoreFull:
return FidoReturnCode::kStorageFull;
// This error is returned by some authenticators (e.g. the "Yubico FIDO
// 2" CTAP2 USB keys) during GetAssertion **before the user interacted
// with the device**. The authenticator does this to avoid blinking (and
// possibly asking the user for their PIN) for requests it knows
// beforehand it cannot handle.
//
// Ignore this error to avoid canceling the request without user
// interaction.
case CtapDeviceResponseCode::kCtap2ErrInvalidCredential:
return base::nullopt;
// For all other errors, the authenticator will be dropped, and other
// authenticators may continue.
default:
return base::nullopt;
}
}
private: private:
DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler); DISALLOW_COPY_AND_ASSIGN(FidoRequestHandler);
}; };
......
...@@ -41,7 +41,7 @@ using FakeTaskCallback = ...@@ -41,7 +41,7 @@ using FakeTaskCallback =
base::OnceCallback<void(CtapDeviceResponseCode status_code, base::OnceCallback<void(CtapDeviceResponseCode status_code,
base::Optional<std::vector<uint8_t>>)>; base::Optional<std::vector<uint8_t>>)>;
using FakeHandlerCallbackReceiver = using FakeHandlerCallbackReceiver =
test::StatusAndValuesCallbackReceiver<FidoReturnCode, test::StatusAndValuesCallbackReceiver<bool,
base::Optional<std::vector<uint8_t>>, base::Optional<std::vector<uint8_t>>,
const FidoAuthenticator*>; const FidoAuthenticator*>;
...@@ -54,7 +54,8 @@ enum class FakeTaskResponse : uint8_t { ...@@ -54,7 +54,8 @@ enum class FakeTaskResponse : uint8_t {
// FidoRequestHandler that automatically starts discovery but does nothing on // FidoRequestHandler that automatically starts discovery but does nothing on
// DispatchRequest(). // DispatchRequest().
class EmptyRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> { class EmptyRequestHandler
: public FidoRequestHandler<bool, std::vector<uint8_t>> {
public: public:
EmptyRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols, EmptyRequestHandler(const base::flat_set<FidoTransportProtocol>& protocols,
test::FakeFidoDiscoveryFactory* fake_discovery_factory) test::FakeFidoDiscoveryFactory* fake_discovery_factory)
...@@ -228,7 +229,8 @@ class FakeFidoTask : public FidoTask { ...@@ -228,7 +229,8 @@ class FakeFidoTask : public FidoTask {
base::WeakPtrFactory<FakeFidoTask> weak_factory_{this}; base::WeakPtrFactory<FakeFidoTask> weak_factory_{this};
}; };
class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> { class FakeFidoRequestHandler
: public FidoRequestHandler<bool, std::vector<uint8_t>> {
public: public:
FakeFidoRequestHandler(service_manager::Connector* connector, FakeFidoRequestHandler(service_manager::Connector* connector,
test::FakeFidoDiscoveryFactory* fake_discovery_factory, test::FakeFidoDiscoveryFactory* fake_discovery_factory,
...@@ -272,19 +274,19 @@ class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> { ...@@ -272,19 +274,19 @@ class FakeFidoRequestHandler : public FidoRequestHandler<std::vector<uint8_t>> {
static_cast<FidoDeviceAuthenticator*>(authenticator); static_cast<FidoDeviceAuthenticator*>(authenticator);
device_authenticator->SetTaskForTesting(nullptr); device_authenticator->SetTaskForTesting(nullptr);
const base::Optional<FidoReturnCode> maybe_result = if (status == CtapDeviceResponseCode::kCtap2ErrOther) {
ConvertDeviceResponseCodeToFidoReturnCode(status); // Simulates an error that is sent without the user touching the
if (!maybe_result) { // authenticator (FakeTaskResponse::kProcessingError). Don't resolve
FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) // the request for this response.
<< " from " << authenticator->GetDisplayName();
active_authenticators().erase(authenticator->GetId());
return; return;
} }
if (!is_complete()) { if (!is_complete()) {
CancelActiveAuthenticators(authenticator->GetId()); CancelActiveAuthenticators(authenticator->GetId());
} }
OnAuthenticatorResponse(authenticator, *maybe_result, std::move(response)); OnAuthenticatorResponse(authenticator,
status == CtapDeviceResponseCode::kSuccess,
std::move(response));
} }
base::WeakPtrFactory<FakeFidoRequestHandler> weak_factory_{this}; base::WeakPtrFactory<FakeFidoRequestHandler> weak_factory_{this};
...@@ -383,7 +385,7 @@ TEST_F(FidoRequestHandlerTest, TestSingleDeviceSuccess) { ...@@ -383,7 +385,7 @@ TEST_F(FidoRequestHandlerTest, TestSingleDeviceSuccess) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_TRUE(callback().status());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
} }
...@@ -446,7 +448,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleDevices) { ...@@ -446,7 +448,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleDevices) {
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_TRUE(callback().status());
} }
// Test a scenario where 2 devices respond successfully with small time // Test a scenario where 2 devices respond successfully with small time
...@@ -486,7 +488,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleSuccessResponses) { ...@@ -486,7 +488,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleSuccessResponses) {
task_environment_.FastForwardUntilNoTasksRemain(); 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_TRUE(callback().status());
} }
// Test a scenario where 3 devices respond with a processing error, an UP(user // Test a scenario where 3 devices respond with a processing error, an UP(user
...@@ -545,8 +547,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleFailureResponses) { ...@@ -545,8 +547,7 @@ TEST_F(FidoRequestHandlerTest, TestRequestWithMultipleFailureResponses) {
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kUserConsentButCredentialNotRecognized, EXPECT_FALSE(callback().status());
callback().status());
} }
// If a device with transport type kInternal returns a // If a device with transport type kInternal returns a
...@@ -585,7 +586,7 @@ TEST_F(FidoRequestHandlerTest, ...@@ -585,7 +586,7 @@ TEST_F(FidoRequestHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_FALSE(callback().status());
} }
// Like |TestRequestWithOperationDeniedErrorInternalTransport|, but with a // Like |TestRequestWithOperationDeniedErrorInternalTransport|, but with a
...@@ -611,7 +612,7 @@ TEST_F(FidoRequestHandlerTest, ...@@ -611,7 +612,7 @@ TEST_F(FidoRequestHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_FALSE(callback().status());
} }
// Requests should be dispatched to the platform authenticator. // Requests should be dispatched to the platform authenticator.
...@@ -644,7 +645,7 @@ TEST_F(FidoRequestHandlerTest, TestWithPlatformAuthenticator) { ...@@ -644,7 +645,7 @@ TEST_F(FidoRequestHandlerTest, TestWithPlatformAuthenticator) {
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_TRUE(callback().status());
} }
TEST_F(FidoRequestHandlerTest, InternalTransportDisallowedIfMarkedUnavailable) { TEST_F(FidoRequestHandlerTest, InternalTransportDisallowedIfMarkedUnavailable) {
......
...@@ -43,7 +43,7 @@ namespace { ...@@ -43,7 +43,7 @@ namespace {
constexpr uint8_t kBogusCredentialId[] = {0x01, 0x02, 0x03, 0x04}; constexpr uint8_t kBogusCredentialId[] = {0x01, 0x02, 0x03, 0x04};
using TestGetAssertionRequestCallback = test::StatusAndValuesCallbackReceiver< using TestGetAssertionRequestCallback = test::StatusAndValuesCallbackReceiver<
FidoReturnCode, GetAssertionStatus,
base::Optional<std::vector<AuthenticatorGetAssertionResponse>>, base::Optional<std::vector<AuthenticatorGetAssertionResponse>>,
const FidoAuthenticator*>; const FidoAuthenticator*>;
...@@ -204,7 +204,7 @@ TEST_F(FidoGetAssertionHandlerTest, CtapRequestOnSingleDevice) { ...@@ -204,7 +204,7 @@ TEST_F(FidoGetAssertionHandlerTest, CtapRequestOnSingleDevice) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
} }
...@@ -221,7 +221,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestU2fSign) { ...@@ -221,7 +221,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestU2fSign) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
} }
...@@ -244,7 +244,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) { ...@@ -244,7 +244,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestIncompatibleUserVerificationSetting) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kUserConsentButCredentialNotRecognized, EXPECT_EQ(GetAssertionStatus::kUserConsentButCredentialNotRecognized,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -267,7 +267,7 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -267,7 +267,7 @@ TEST_F(FidoGetAssertionHandlerTest,
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kUserConsentButCredentialNotRecognized, EXPECT_EQ(GetAssertionStatus::kUserConsentButCredentialNotRecognized,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -284,7 +284,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) { ...@@ -284,7 +284,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectRpIdHash) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, EXPECT_EQ(GetAssertionStatus::kAuthenticatorResponseInvalid,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -309,7 +309,7 @@ TEST_F(FidoGetAssertionHandlerTest, InvalidCredential) { ...@@ -309,7 +309,7 @@ TEST_F(FidoGetAssertionHandlerTest, InvalidCredential) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, EXPECT_EQ(GetAssertionStatus::kAuthenticatorResponseInvalid,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -331,7 +331,7 @@ TEST_F(FidoGetAssertionHandlerTest, ValidEmptyCredential) { ...@@ -331,7 +331,7 @@ TEST_F(FidoGetAssertionHandlerTest, ValidEmptyCredential) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
const auto& response = get_assertion_callback().value<0>(); const auto& response = get_assertion_callback().value<0>();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
ASSERT_TRUE(response); ASSERT_TRUE(response);
ASSERT_EQ(1u, response->size()); ASSERT_EQ(1u, response->size());
EXPECT_TRUE(response.value()[0].credential()); EXPECT_TRUE(response.value()[0].credential());
...@@ -359,7 +359,7 @@ TEST_F(FidoGetAssertionHandlerTest, TruncatedUTF8) { ...@@ -359,7 +359,7 @@ TEST_F(FidoGetAssertionHandlerTest, TruncatedUTF8) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
const auto& response = get_assertion_callback().value<0>(); const auto& response = get_assertion_callback().value<0>();
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
ASSERT_TRUE(response); ASSERT_TRUE(response);
ASSERT_EQ(1u, response->size()); ASSERT_EQ(1u, response->size());
ASSERT_TRUE(response.value()[0].user_entity()); ASSERT_TRUE(response.value()[0].user_entity());
...@@ -399,7 +399,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectUserEntity) { ...@@ -399,7 +399,7 @@ TEST_F(FidoGetAssertionHandlerTest, IncorrectUserEntity) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kAuthenticatorResponseInvalid, EXPECT_EQ(GetAssertionStatus::kAuthenticatorResponseInvalid,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -518,7 +518,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyUsbTransportAllowed) { ...@@ -518,7 +518,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyUsbTransportAllowed) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_THAT( EXPECT_THAT(
...@@ -552,7 +552,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyBleTransportAllowed) { ...@@ -552,7 +552,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyBleTransportAllowed) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_THAT( EXPECT_THAT(
...@@ -586,7 +586,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyNfcTransportAllowed) { ...@@ -586,7 +586,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyNfcTransportAllowed) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_THAT( EXPECT_THAT(
...@@ -625,7 +625,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) { ...@@ -625,7 +625,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) {
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
EXPECT_TRUE(get_assertion_callback().value<0>()); EXPECT_TRUE(get_assertion_callback().value<0>());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
EXPECT_THAT( EXPECT_THAT(
...@@ -635,7 +635,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) { ...@@ -635,7 +635,7 @@ TEST_F(FidoGetAssertionHandlerTest, SuccessWithOnlyInternalTransportAllowed) {
// If a device with transport type kInternal returns a // If a device with transport type kInternal returns a
// CTAP2_ERR_OPERATION_DENIED error, the request should complete with // CTAP2_ERR_OPERATION_DENIED error, the request should complete with
// FidoReturnCode::kUserConsentDenied. Pending authenticators should be // GetAssertionStatus::kUserConsentDenied. Pending authenticators should be
// cancelled. // cancelled.
TEST_F(FidoGetAssertionHandlerTest, TEST_F(FidoGetAssertionHandlerTest,
TestRequestWithOperationDeniedErrorPlatform) { TestRequestWithOperationDeniedErrorPlatform) {
...@@ -661,7 +661,7 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -661,7 +661,7 @@ TEST_F(FidoGetAssertionHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called()); EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -680,12 +680,12 @@ TEST_F(FidoGetAssertionHandlerTest, ...@@ -680,12 +680,12 @@ TEST_F(FidoGetAssertionHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called()); EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status()); get_assertion_callback().status());
} }
// If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete // If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete
// with FidoReturnCode::kUserConsentDenied. // with GetAssertionStatus::kUserConsentDenied.
TEST_F(FidoGetAssertionHandlerTest, TestRequestWithPinAuthInvalid) { TEST_F(FidoGetAssertionHandlerTest, TestRequestWithPinAuthInvalid) {
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
device->ExpectCtap2CommandAndRespondWithError( device->ExpectCtap2CommandAndRespondWithError(
...@@ -698,7 +698,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestRequestWithPinAuthInvalid) { ...@@ -698,7 +698,7 @@ TEST_F(FidoGetAssertionHandlerTest, TestRequestWithPinAuthInvalid) {
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(get_assertion_callback().was_called()); EXPECT_TRUE(get_assertion_callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, EXPECT_EQ(GetAssertionStatus::kUserConsentDenied,
get_assertion_callback().status()); get_assertion_callback().status());
} }
...@@ -738,7 +738,7 @@ TEST_F(FidoGetAssertionHandlerTest, DeviceFailsImmediately) { ...@@ -738,7 +738,7 @@ TEST_F(FidoGetAssertionHandlerTest, DeviceFailsImmediately) {
discovery()->AddDevice(std::move(broken_device)); discovery()->AddDevice(std::move(broken_device));
get_assertion_callback().WaitForCallback(); get_assertion_callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); EXPECT_EQ(GetAssertionStatus::kSuccess, get_assertion_callback().status());
} }
// Tests a scenario where authenticator of incorrect transport type was used to // Tests a scenario where authenticator of incorrect transport type was used to
......
...@@ -36,6 +36,47 @@ namespace device { ...@@ -36,6 +36,47 @@ namespace device {
namespace { namespace {
base::Optional<GetAssertionStatus> ConvertDeviceResponseCode(
CtapDeviceResponseCode device_response_code) {
switch (device_response_code) {
case CtapDeviceResponseCode::kSuccess:
return GetAssertionStatus::kSuccess;
// Only returned after the user interacted with the
// authenticator.
case CtapDeviceResponseCode::kCtap2ErrNoCredentials:
return GetAssertionStatus::kUserConsentButCredentialNotRecognized;
// 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:
return GetAssertionStatus::kUserConsentDenied;
// External authenticators may return this error if internal user
// verification fails for a make credential request or if the pin token is
// not valid.
case CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid:
return GetAssertionStatus::kUserConsentDenied;
// This error is returned by some authenticators (e.g. the "Yubico FIDO
// 2" CTAP2 USB keys) during GetAssertion **before the user interacted
// with the device**. The authenticator does this to avoid blinking (and
// possibly asking the user for their PIN) for requests it knows
// beforehand it cannot handle.
//
// Ignore this error to avoid canceling the request without user
// interaction.
case CtapDeviceResponseCode::kCtap2ErrInvalidCredential:
return base::nullopt;
// For all other errors, the authenticator will be dropped, and other
// authenticators may continue.
default:
return base::nullopt;
}
}
bool ResponseValid(const FidoAuthenticator& authenticator, bool ResponseValid(const FidoAuthenticator& authenticator,
const CtapGetAssertionRequest& request, const CtapGetAssertionRequest& request,
const AuthenticatorGetAssertionResponse& response) { const AuthenticatorGetAssertionResponse& response) {
...@@ -286,7 +327,7 @@ void GetAssertionRequestHandler::AuthenticatorRemoved( ...@@ -286,7 +327,7 @@ void GetAssertionRequestHandler::AuthenticatorRemoved(
state_ == State::kWaitingForSecondTouch) { state_ == State::kWaitingForSecondTouch) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorRemovedDuringPINEntry, .Run(GetAssertionStatus::kAuthenticatorRemovedDuringPINEntry,
base::nullopt, nullptr); base::nullopt, nullptr);
} }
} }
...@@ -311,16 +352,16 @@ void GetAssertionRequestHandler::HandleResponse( ...@@ -311,16 +352,16 @@ void GetAssertionRequestHandler::HandleResponse(
state_ = State::kFinished; state_ = State::kFinished;
CancelActiveAuthenticators(authenticator->GetId()); CancelActiveAuthenticators(authenticator->GetId());
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(
WinCtapDeviceResponseCodeToFidoReturnCode(status), authenticator, WinCtapDeviceResponseCodeToGetAssertionStatus(status),
base::nullopt); base::nullopt);
return; return;
} }
DCHECK(responses_.empty()); DCHECK(responses_.empty());
responses_.emplace_back(std::move(*response)); responses_.emplace_back(std::move(*response));
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(
WinCtapDeviceResponseCodeToFidoReturnCode(status), authenticator, WinCtapDeviceResponseCodeToGetAssertionStatus(status),
std::move(responses_)); std::move(responses_));
return; return;
} }
#endif #endif
...@@ -330,12 +371,12 @@ void GetAssertionRequestHandler::HandleResponse( ...@@ -330,12 +371,12 @@ void GetAssertionRequestHandler::HandleResponse(
authenticator->WillNeedPINToGetAssertion(request_, observer()) == authenticator->WillNeedPINToGetAssertion(request_, observer()) ==
FidoAuthenticator::GetAssertionPINDisposition::kNoPIN); FidoAuthenticator::GetAssertionPINDisposition::kNoPIN);
const base::Optional<FidoReturnCode> maybe_result = const base::Optional<GetAssertionStatus> maybe_result =
ConvertDeviceResponseCodeToFidoReturnCode(status); ConvertDeviceResponseCode(status);
if (!maybe_result) { if (!maybe_result) {
if (state_ == State::kWaitingForSecondTouch) { if (state_ == State::kWaitingForSecondTouch) {
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, GetAssertionStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
} else { } else {
FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status)
...@@ -359,7 +400,7 @@ void GetAssertionRequestHandler::HandleResponse( ...@@ -359,7 +400,7 @@ void GetAssertionRequestHandler::HandleResponse(
FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " FIDO_LOG(ERROR) << "Failing assertion request due to bad response from "
<< authenticator->GetDisplayName(); << authenticator->GetDisplayName();
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, GetAssertionStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
return; return;
} }
...@@ -369,7 +410,7 @@ void GetAssertionRequestHandler::HandleResponse( ...@@ -369,7 +410,7 @@ void GetAssertionRequestHandler::HandleResponse(
if (num_responses == 0 || if (num_responses == 0 ||
(num_responses > 1 && !request_.allow_list.empty())) { (num_responses > 1 && !request_.allow_list.empty())) {
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, GetAssertionStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
return; return;
} }
...@@ -388,7 +429,7 @@ void GetAssertionRequestHandler::HandleResponse( ...@@ -388,7 +429,7 @@ void GetAssertionRequestHandler::HandleResponse(
ReportGetAssertionResponseTransport(authenticator); ReportGetAssertionResponseTransport(authenticator);
OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, OnAuthenticatorResponse(authenticator, GetAssertionStatus::kSuccess,
std::move(responses_)); std::move(responses_));
} }
...@@ -406,7 +447,7 @@ void GetAssertionRequestHandler::HandleNextResponse( ...@@ -406,7 +447,7 @@ void GetAssertionRequestHandler::HandleNextResponse(
<< static_cast<int>(status) << " from " << static_cast<int>(status) << " from "
<< authenticator->GetDisplayName(); << authenticator->GetDisplayName();
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, GetAssertionStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
return; return;
} }
...@@ -415,7 +456,7 @@ void GetAssertionRequestHandler::HandleNextResponse( ...@@ -415,7 +456,7 @@ void GetAssertionRequestHandler::HandleNextResponse(
FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " FIDO_LOG(ERROR) << "Failing assertion request due to bad response from "
<< authenticator->GetDisplayName(); << authenticator->GetDisplayName();
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, GetAssertionStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
return; return;
} }
...@@ -433,7 +474,7 @@ void GetAssertionRequestHandler::HandleNextResponse( ...@@ -433,7 +474,7 @@ void GetAssertionRequestHandler::HandleNextResponse(
ReportGetAssertionResponseTransport(authenticator); ReportGetAssertionResponseTransport(authenticator);
OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, OnAuthenticatorResponse(authenticator, GetAssertionStatus::kSuccess,
std::move(responses_)); std::move(responses_));
} }
...@@ -460,7 +501,7 @@ void GetAssertionRequestHandler::HandleInapplicableAuthenticator( ...@@ -460,7 +501,7 @@ void GetAssertionRequestHandler::HandleInapplicableAuthenticator(
state_ = State::kFinished; state_ = State::kFinished;
CancelActiveAuthenticators(authenticator->GetId()); CancelActiveAuthenticators(authenticator->GetId());
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kUserConsentButCredentialNotRecognized, .Run(GetAssertionStatus::kUserConsentButCredentialNotRecognized,
base::nullopt, nullptr); base::nullopt, nullptr);
} }
...@@ -472,14 +513,14 @@ void GetAssertionRequestHandler::OnRetriesResponse( ...@@ -472,14 +513,14 @@ void GetAssertionRequestHandler::OnRetriesResponse(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt, .Run(GetAssertionStatus::kAuthenticatorResponseInvalid, base::nullopt,
nullptr); nullptr);
return; return;
} }
if (response->retries == 0) { if (response->retries == 0) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kHardPINBlock, base::nullopt, nullptr); .Run(GetAssertionStatus::kHardPINBlock, base::nullopt, nullptr);
return; return;
} }
state_ = State::kWaitingForPIN; state_ = State::kWaitingForPIN;
...@@ -516,7 +557,7 @@ void GetAssertionRequestHandler::OnHaveEphemeralKey( ...@@ -516,7 +557,7 @@ void GetAssertionRequestHandler::OnHaveEphemeralKey(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt, .Run(GetAssertionStatus::kAuthenticatorResponseInvalid, base::nullopt,
nullptr); nullptr);
return; return;
} }
...@@ -544,16 +585,16 @@ void GetAssertionRequestHandler::OnHavePINToken( ...@@ -544,16 +585,16 @@ void GetAssertionRequestHandler::OnHavePINToken(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
FidoReturnCode ret; GetAssertionStatus ret;
switch (status) { switch (status) {
case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked: case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
ret = FidoReturnCode::kSoftPINBlock; ret = GetAssertionStatus::kSoftPINBlock;
break; break;
case CtapDeviceResponseCode::kCtap2ErrPinBlocked: case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
ret = FidoReturnCode::kHardPINBlock; ret = GetAssertionStatus::kHardPINBlock;
break; break;
default: default:
ret = FidoReturnCode::kAuthenticatorResponseInvalid; ret = GetAssertionStatus::kAuthenticatorResponseInvalid;
break; break;
} }
std::move(completion_callback_).Run(ret, base::nullopt, nullptr); std::move(completion_callback_).Run(ret, base::nullopt, nullptr);
......
...@@ -28,8 +28,26 @@ class FidoAuthenticator; ...@@ -28,8 +28,26 @@ class FidoAuthenticator;
class FidoDiscoveryFactory; class FidoDiscoveryFactory;
class AuthenticatorGetAssertionResponse; class AuthenticatorGetAssertionResponse;
enum class GetAssertionStatus {
kSuccess,
kAuthenticatorResponseInvalid,
kUserConsentButCredentialNotRecognized,
kUserConsentDenied,
kAuthenticatorRemovedDuringPINEntry,
kSoftPINBlock,
kHardPINBlock,
kAuthenticatorMissingResidentKeys,
// TODO(agl): kAuthenticatorMissingUserVerification can
// also be returned when the authenticator supports UV, but
// there's no UI support for collecting a PIN. This could
// be clearer.
kAuthenticatorMissingUserVerification,
kWinNotAllowedError,
};
class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler class COMPONENT_EXPORT(DEVICE_FIDO) GetAssertionRequestHandler
: public FidoRequestHandler< : public FidoRequestHandler<
GetAssertionStatus,
std::vector<AuthenticatorGetAssertionResponse>> { std::vector<AuthenticatorGetAssertionResponse>> {
public: public:
GetAssertionRequestHandler( GetAssertionRequestHandler(
......
...@@ -48,7 +48,7 @@ namespace device { ...@@ -48,7 +48,7 @@ namespace device {
namespace { namespace {
using TestMakeCredentialRequestCallback = test::StatusAndValuesCallbackReceiver< using TestMakeCredentialRequestCallback = test::StatusAndValuesCallbackReceiver<
FidoReturnCode, MakeCredentialStatus,
base::Optional<AuthenticatorMakeCredentialResponse>, base::Optional<AuthenticatorMakeCredentialResponse>,
const FidoAuthenticator*>; const FidoAuthenticator*>;
...@@ -176,7 +176,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestCtap2MakeCredential) { ...@@ -176,7 +176,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestCtap2MakeCredential) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
} }
...@@ -192,7 +192,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestU2fRegister) { ...@@ -192,7 +192,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestU2fRegister) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_TRUE(request_handler->is_complete()); EXPECT_TRUE(request_handler->is_complete());
} }
...@@ -211,7 +211,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) { ...@@ -211,7 +211,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithUserVerificationRequired) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingUserVerification, EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingUserVerification,
callback().status()); callback().status());
} }
...@@ -230,7 +230,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) { ...@@ -230,7 +230,7 @@ TEST_F(FidoMakeCredentialHandlerTest, U2fRegisterWithResidentKeyRequirement) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status()); callback().status());
} }
...@@ -251,7 +251,7 @@ TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) { ...@@ -251,7 +251,7 @@ TEST_F(FidoMakeCredentialHandlerTest, UserVerificationRequirementNotMet) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingUserVerification, EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingUserVerification,
callback().status()); callback().status());
} }
...@@ -311,7 +311,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyRequirementNotMet) { ...@@ -311,7 +311,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyRequirementNotMet) {
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status()); callback().status());
} }
...@@ -391,7 +391,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancelOtherAuthenticator) { ...@@ -391,7 +391,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancelOtherAuthenticator) {
discovery()->AddDevice(std::move(device2)); discovery()->AddDevice(std::move(device2));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
} }
TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancel) { TEST_F(FidoMakeCredentialHandlerTest, ResidentKeyCancel) {
...@@ -446,7 +446,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -446,7 +446,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_THAT( EXPECT_THAT(
request_handler->transport_availability_info().available_transports, request_handler->transport_availability_info().available_transports,
...@@ -478,7 +478,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -478,7 +478,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
UserVerificationRequirement::kRequired)); UserVerificationRequirement::kRequired));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
EXPECT_THAT( EXPECT_THAT(
request_handler->transport_availability_info().available_transports, request_handler->transport_availability_info().available_transports,
...@@ -589,7 +589,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -589,7 +589,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
} }
// Tests that MakeCredential request fails when asking to use resident keys with // Tests that MakeCredential request fails when asking to use resident keys with
...@@ -607,13 +607,13 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -607,13 +607,13 @@ TEST_F(FidoMakeCredentialHandlerTest,
discovery()->AddDevice(std::move(device)); discovery()->AddDevice(std::move(device));
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_EQ(FidoReturnCode::kAuthenticatorMissingResidentKeys, EXPECT_EQ(MakeCredentialStatus::kAuthenticatorMissingResidentKeys,
callback().status()); callback().status());
} }
// If a device with transport type kInternal returns a // If a device with transport type kInternal returns a
// CTAP2_ERR_OPERATION_DENIED error, the request should complete with // CTAP2_ERR_OPERATION_DENIED error, the request should complete with
// FidoReturnCode::kUserConsentDenied. // MakeCredentialStatus::kUserConsentDenied.
TEST_F(FidoMakeCredentialHandlerTest, TEST_F(FidoMakeCredentialHandlerTest,
TestRequestWithOperationDeniedErrorPlatform) { TestRequestWithOperationDeniedErrorPlatform) {
auto platform_device = MockFidoDevice::MakeCtapWithGetInfoExpectation( auto platform_device = MockFidoDevice::MakeCtapWithGetInfoExpectation(
...@@ -633,7 +633,7 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -633,7 +633,7 @@ TEST_F(FidoMakeCredentialHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called()); EXPECT_TRUE(callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
} }
// Like |TestRequestWithOperationDeniedErrorPlatform|, but with a // Like |TestRequestWithOperationDeniedErrorPlatform|, but with a
...@@ -656,11 +656,11 @@ TEST_F(FidoMakeCredentialHandlerTest, ...@@ -656,11 +656,11 @@ TEST_F(FidoMakeCredentialHandlerTest,
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called()); EXPECT_TRUE(callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
} }
// If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete // If a device returns CTAP2_ERR_PIN_AUTH_INVALID, the request should complete
// with FidoReturnCode::kUserConsentDenied. // with MakeCredentialStatus::kUserConsentDenied.
TEST_F(FidoMakeCredentialHandlerTest, TestRequestWithPinAuthInvalid) { TEST_F(FidoMakeCredentialHandlerTest, TestRequestWithPinAuthInvalid) {
auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); auto device = MockFidoDevice::MakeCtapWithGetInfoExpectation();
device->ExpectCtap2CommandAndRespondWithError( device->ExpectCtap2CommandAndRespondWithError(
...@@ -678,7 +678,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestRequestWithPinAuthInvalid) { ...@@ -678,7 +678,7 @@ TEST_F(FidoMakeCredentialHandlerTest, TestRequestWithPinAuthInvalid) {
task_environment_.FastForwardUntilNoTasksRemain(); task_environment_.FastForwardUntilNoTasksRemain();
EXPECT_TRUE(callback().was_called()); EXPECT_TRUE(callback().was_called());
EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); EXPECT_EQ(MakeCredentialStatus::kUserConsentDenied, callback().status());
} }
MATCHER_P(IsCtap2Command, expected_command, "") { MATCHER_P(IsCtap2Command, expected_command, "") {
...@@ -717,7 +717,7 @@ TEST_F(FidoMakeCredentialHandlerTest, DeviceFailsImmediately) { ...@@ -717,7 +717,7 @@ TEST_F(FidoMakeCredentialHandlerTest, DeviceFailsImmediately) {
discovery()->AddDevice(std::move(broken_device)); discovery()->AddDevice(std::move(broken_device));
callback().WaitForCallback(); callback().WaitForCallback();
EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); EXPECT_EQ(MakeCredentialStatus::kSuccess, callback().status());
} }
} // namespace device } // namespace device
...@@ -36,6 +36,38 @@ using MakeCredentialPINDisposition = ...@@ -36,6 +36,38 @@ using MakeCredentialPINDisposition =
namespace { namespace {
base::Optional<MakeCredentialStatus> ConvertDeviceResponseCode(
CtapDeviceResponseCode device_response_code) {
switch (device_response_code) {
case CtapDeviceResponseCode::kSuccess:
return MakeCredentialStatus::kSuccess;
// Only returned after the user interacted with the authenticator.
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
return MakeCredentialStatus::kUserConsentButCredentialExcluded;
// 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:
return MakeCredentialStatus::kUserConsentDenied;
// External authenticators may return this error if internal user
// verification fails for a make credential request or if the pin token is
// not valid.
case CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid:
return MakeCredentialStatus::kUserConsentDenied;
case CtapDeviceResponseCode::kCtap2ErrKeyStoreFull:
return MakeCredentialStatus::kStorageFull;
// For all other errors, the authenticator will be dropped, and other
// authenticators may continue.
default:
return base::nullopt;
}
}
// IsCandidateAuthenticatorPreTouch returns true if the given authenticator // IsCandidateAuthenticatorPreTouch returns true if the given authenticator
// should even blink for a request. // should even blink for a request.
bool IsCandidateAuthenticatorPreTouch( bool IsCandidateAuthenticatorPreTouch(
...@@ -63,7 +95,7 @@ bool IsCandidateAuthenticatorPreTouch( ...@@ -63,7 +95,7 @@ bool IsCandidateAuthenticatorPreTouch(
// IsCandidateAuthenticatorPostTouch returns a value other than |kSuccess| if // IsCandidateAuthenticatorPostTouch returns a value other than |kSuccess| if
// the given authenticator cannot handle a request. // the given authenticator cannot handle a request.
FidoReturnCode IsCandidateAuthenticatorPostTouch( MakeCredentialStatus IsCandidateAuthenticatorPostTouch(
const CtapMakeCredentialRequest& request, const CtapMakeCredentialRequest& request,
FidoAuthenticator* authenticator, FidoAuthenticator* authenticator,
const AuthenticatorSelectionCriteria& authenticator_selection_criteria, const AuthenticatorSelectionCriteria& authenticator_selection_criteria,
...@@ -79,10 +111,10 @@ FidoReturnCode IsCandidateAuthenticatorPostTouch( ...@@ -79,10 +111,10 @@ FidoReturnCode IsCandidateAuthenticatorPostTouch(
if (request.cred_protect && request.cred_protect->second && if (request.cred_protect && request.cred_protect->second &&
!static_cast<WinWebAuthnApiAuthenticator*>(authenticator) !static_cast<WinWebAuthnApiAuthenticator*>(authenticator)
->SupportsCredProtectExtension()) { ->SupportsCredProtectExtension()) {
return FidoReturnCode::kAuthenticatorMissingResidentKeys; return MakeCredentialStatus::kAuthenticatorMissingResidentKeys;
} }
return FidoReturnCode::kSuccess; return MakeCredentialStatus::kSuccess;
} }
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
...@@ -90,20 +122,20 @@ FidoReturnCode IsCandidateAuthenticatorPostTouch( ...@@ -90,20 +122,20 @@ FidoReturnCode IsCandidateAuthenticatorPostTouch(
if (authenticator_selection_criteria.require_resident_key() && if (authenticator_selection_criteria.require_resident_key() &&
!opt_options->supports_resident_key) { !opt_options->supports_resident_key) {
return FidoReturnCode::kAuthenticatorMissingResidentKeys; return MakeCredentialStatus::kAuthenticatorMissingResidentKeys;
} }
if (request.cred_protect && request.cred_protect->second && if (request.cred_protect && request.cred_protect->second &&
!authenticator->Options()->supports_cred_protect) { !authenticator->Options()->supports_cred_protect) {
return FidoReturnCode::kAuthenticatorMissingResidentKeys; return MakeCredentialStatus::kAuthenticatorMissingResidentKeys;
} }
if (authenticator->WillNeedPINToMakeCredential(request, observer) == if (authenticator->WillNeedPINToMakeCredential(request, observer) ==
MakeCredentialPINDisposition::kUnsatisfiable) { MakeCredentialPINDisposition::kUnsatisfiable) {
return FidoReturnCode::kAuthenticatorMissingUserVerification; return MakeCredentialStatus::kAuthenticatorMissingUserVerification;
} }
return FidoReturnCode::kSuccess; return MakeCredentialStatus::kSuccess;
} }
base::flat_set<FidoTransportProtocol> GetTransportsAllowedByRP( base::flat_set<FidoTransportProtocol> GetTransportsAllowedByRP(
...@@ -192,7 +224,7 @@ void MakeCredentialRequestHandler::DispatchRequest( ...@@ -192,7 +224,7 @@ void MakeCredentialRequestHandler::DispatchRequest(
if (IsCandidateAuthenticatorPostTouch( if (IsCandidateAuthenticatorPostTouch(
request_, authenticator, authenticator_selection_criteria_, request_, authenticator, authenticator_selection_criteria_,
observer()) != FidoReturnCode::kSuccess) { observer()) != MakeCredentialStatus::kSuccess) {
#if defined(OS_WIN) #if defined(OS_WIN)
// If the Windows API cannot handle a request, just reject the request // If the Windows API cannot handle a request, just reject the request
// outright. There are no other authenticators to attempt, so calling // outright. There are no other authenticators to attempt, so calling
...@@ -280,7 +312,7 @@ void MakeCredentialRequestHandler::AuthenticatorRemoved( ...@@ -280,7 +312,7 @@ void MakeCredentialRequestHandler::AuthenticatorRemoved(
state_ == State::kWaitingForSecondTouch) { state_ == State::kWaitingForSecondTouch) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorRemovedDuringPINEntry, .Run(MakeCredentialStatus::kAuthenticatorRemovedDuringPINEntry,
base::nullopt, nullptr); base::nullopt, nullptr);
} }
} }
...@@ -301,9 +333,9 @@ void MakeCredentialRequestHandler::HandleResponse( ...@@ -301,9 +333,9 @@ void MakeCredentialRequestHandler::HandleResponse(
if (authenticator->IsWinNativeApiAuthenticator()) { if (authenticator->IsWinNativeApiAuthenticator()) {
state_ = State::kFinished; state_ = State::kFinished;
CancelActiveAuthenticators(authenticator->GetId()); CancelActiveAuthenticators(authenticator->GetId());
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(
WinCtapDeviceResponseCodeToFidoReturnCode(status), authenticator, WinCtapDeviceResponseCodeToMakeCredentialStatus(status),
std::move(response)); std::move(response));
return; return;
} }
#endif #endif
...@@ -313,13 +345,13 @@ void MakeCredentialRequestHandler::HandleResponse( ...@@ -313,13 +345,13 @@ void MakeCredentialRequestHandler::HandleResponse(
authenticator->WillNeedPINToMakeCredential(request_, observer()) == authenticator->WillNeedPINToMakeCredential(request_, observer()) ==
MakeCredentialPINDisposition::kNoPIN); MakeCredentialPINDisposition::kNoPIN);
const base::Optional<FidoReturnCode> maybe_result = const base::Optional<MakeCredentialStatus> maybe_result =
ConvertDeviceResponseCodeToFidoReturnCode(status); ConvertDeviceResponseCode(status);
if (!maybe_result) { if (!maybe_result) {
if (state_ == State::kWaitingForSecondTouch) { if (state_ == State::kWaitingForSecondTouch) {
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(
FidoReturnCode::kAuthenticatorResponseInvalid, authenticator, MakeCredentialStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
} else { } else {
FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status) FIDO_LOG(ERROR) << "Ignoring status " << static_cast<int>(status)
<< " from " << authenticator->GetDisplayName(); << " from " << authenticator->GetDisplayName();
...@@ -344,7 +376,7 @@ void MakeCredentialRequestHandler::HandleResponse( ...@@ -344,7 +376,7 @@ void MakeCredentialRequestHandler::HandleResponse(
FIDO_LOG(ERROR) << "Failing assertion request due to bad response from " FIDO_LOG(ERROR) << "Failing assertion request due to bad response from "
<< authenticator->GetDisplayName(); << authenticator->GetDisplayName();
OnAuthenticatorResponse(authenticator, OnAuthenticatorResponse(authenticator,
FidoReturnCode::kAuthenticatorResponseInvalid, MakeCredentialStatus::kAuthenticatorResponseInvalid,
base::nullopt); base::nullopt);
return; return;
} }
...@@ -355,7 +387,7 @@ void MakeCredentialRequestHandler::HandleResponse( ...@@ -355,7 +387,7 @@ void MakeCredentialRequestHandler::HandleResponse(
*authenticator->AuthenticatorTransport()); *authenticator->AuthenticatorTransport());
} }
OnAuthenticatorResponse(authenticator, FidoReturnCode::kSuccess, OnAuthenticatorResponse(authenticator, MakeCredentialStatus::kSuccess,
std::move(response)); std::move(response));
} }
...@@ -402,9 +434,11 @@ void MakeCredentialRequestHandler::HandleInapplicableAuthenticator( ...@@ -402,9 +434,11 @@ void MakeCredentialRequestHandler::HandleInapplicableAuthenticator(
// User touched an authenticator that cannot handle this request. // User touched an authenticator that cannot handle this request.
state_ = State::kFinished; state_ = State::kFinished;
CancelActiveAuthenticators(authenticator->GetId()); CancelActiveAuthenticators(authenticator->GetId());
const FidoReturnCode capability_error = IsCandidateAuthenticatorPostTouch( const MakeCredentialStatus capability_error =
request_, authenticator, authenticator_selection_criteria_, observer()); IsCandidateAuthenticatorPostTouch(request_, authenticator,
DCHECK_NE(capability_error, FidoReturnCode::kSuccess); authenticator_selection_criteria_,
observer());
DCHECK_NE(capability_error, MakeCredentialStatus::kSuccess);
std::move(completion_callback_).Run(capability_error, base::nullopt, nullptr); std::move(completion_callback_).Run(capability_error, base::nullopt, nullptr);
} }
...@@ -440,14 +474,14 @@ void MakeCredentialRequestHandler::OnRetriesResponse( ...@@ -440,14 +474,14 @@ void MakeCredentialRequestHandler::OnRetriesResponse(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt, .Run(MakeCredentialStatus::kAuthenticatorResponseInvalid, base::nullopt,
nullptr); nullptr);
return; return;
} }
if (response->retries == 0) { if (response->retries == 0) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kHardPINBlock, base::nullopt, nullptr); .Run(MakeCredentialStatus::kHardPINBlock, base::nullopt, nullptr);
return; return;
} }
state_ = State::kWaitingForPIN; state_ = State::kWaitingForPIN;
...@@ -468,7 +502,7 @@ void MakeCredentialRequestHandler::OnHaveEphemeralKey( ...@@ -468,7 +502,7 @@ void MakeCredentialRequestHandler::OnHaveEphemeralKey(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt, .Run(MakeCredentialStatus::kAuthenticatorResponseInvalid, base::nullopt,
nullptr); nullptr);
return; return;
} }
...@@ -499,7 +533,7 @@ void MakeCredentialRequestHandler::OnHaveSetPIN( ...@@ -499,7 +533,7 @@ void MakeCredentialRequestHandler::OnHaveSetPIN(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
std::move(completion_callback_) std::move(completion_callback_)
.Run(FidoReturnCode::kAuthenticatorResponseInvalid, base::nullopt, .Run(MakeCredentialStatus::kAuthenticatorResponseInvalid, base::nullopt,
nullptr); nullptr);
return; return;
} }
...@@ -529,16 +563,16 @@ void MakeCredentialRequestHandler::OnHavePINToken( ...@@ -529,16 +563,16 @@ void MakeCredentialRequestHandler::OnHavePINToken(
if (status != CtapDeviceResponseCode::kSuccess) { if (status != CtapDeviceResponseCode::kSuccess) {
state_ = State::kFinished; state_ = State::kFinished;
FidoReturnCode ret; MakeCredentialStatus ret;
switch (status) { switch (status) {
case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked: case CtapDeviceResponseCode::kCtap2ErrPinAuthBlocked:
ret = FidoReturnCode::kSoftPINBlock; ret = MakeCredentialStatus::kSoftPINBlock;
break; break;
case CtapDeviceResponseCode::kCtap2ErrPinBlocked: case CtapDeviceResponseCode::kCtap2ErrPinBlocked:
ret = FidoReturnCode::kHardPINBlock; ret = MakeCredentialStatus::kHardPINBlock;
break; break;
default: default:
ret = FidoReturnCode::kAuthenticatorResponseInvalid; ret = MakeCredentialStatus::kAuthenticatorResponseInvalid;
break; break;
} }
std::move(completion_callback_).Run(ret, base::nullopt, nullptr); std::move(completion_callback_).Run(ret, base::nullopt, nullptr);
......
...@@ -30,8 +30,28 @@ class FidoAuthenticator; ...@@ -30,8 +30,28 @@ class FidoAuthenticator;
class FidoDiscoveryFactory; class FidoDiscoveryFactory;
class AuthenticatorMakeCredentialResponse; class AuthenticatorMakeCredentialResponse;
enum class MakeCredentialStatus {
kSuccess,
kAuthenticatorResponseInvalid,
kUserConsentButCredentialExcluded,
kUserConsentDenied,
kAuthenticatorRemovedDuringPINEntry,
kSoftPINBlock,
kHardPINBlock,
kAuthenticatorMissingResidentKeys,
// TODO(agl): kAuthenticatorMissingUserVerification can
// also be returned when the authenticator supports UV, but
// there's no UI support for collecting a PIN. This could
// be clearer.
kAuthenticatorMissingUserVerification,
kStorageFull,
kWinInvalidStateError,
kWinNotAllowedError,
};
class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler class COMPONENT_EXPORT(DEVICE_FIDO) MakeCredentialRequestHandler
: public FidoRequestHandler<AuthenticatorMakeCredentialResponse> { : public FidoRequestHandler<MakeCredentialStatus,
AuthenticatorMakeCredentialResponse> {
public: public:
MakeCredentialRequestHandler( MakeCredentialRequestHandler(
service_manager::Connector* connector, service_manager::Connector* connector,
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "device/fido/authenticator_get_assertion_response.h" #include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h" #include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/fido_transport_protocol.h" #include "device/fido/fido_transport_protocol.h"
#include "device/fido/get_assertion_request_handler.h"
#include "device/fido/make_credential_request_handler.h"
#include "device/fido/opaque_attestation_statement.h" #include "device/fido/opaque_attestation_statement.h"
namespace device { namespace device {
...@@ -223,21 +225,43 @@ CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode( ...@@ -223,21 +225,43 @@ CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode(
} }
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
FidoReturnCode WinCtapDeviceResponseCodeToFidoReturnCode( MakeCredentialStatus WinCtapDeviceResponseCodeToMakeCredentialStatus(
CtapDeviceResponseCode status) { CtapDeviceResponseCode status) {
switch (status) { switch (status) {
case CtapDeviceResponseCode::kSuccess: case CtapDeviceResponseCode::kSuccess:
return FidoReturnCode::kSuccess; return MakeCredentialStatus::kSuccess;
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded: case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
return FidoReturnCode::kWinInvalidStateError; return MakeCredentialStatus::kWinInvalidStateError;
case CtapDeviceResponseCode::kCtap2ErrOperationDenied: case CtapDeviceResponseCode::kCtap2ErrOperationDenied:
return FidoReturnCode::kWinNotAllowedError; return MakeCredentialStatus::kWinNotAllowedError;
default: default:
NOTREACHED() << "Must only be called with a status returned from " NOTREACHED() << "Must only be called with a status returned from "
"WinErrorNameToCtapDeviceResponseCode()."; "WinErrorNameToCtapDeviceResponseCode().";
FIDO_LOG(ERROR) << "Unexpected FidoReturnCode: " FIDO_LOG(ERROR) << "Unexpected CtapDeviceResponseCode: "
<< static_cast<int>(status); << static_cast<int>(status);
return FidoReturnCode::kWinNotAllowedError; return MakeCredentialStatus::kWinNotAllowedError;
}
}
COMPONENT_EXPORT(DEVICE_FIDO)
GetAssertionStatus WinCtapDeviceResponseCodeToGetAssertionStatus(
CtapDeviceResponseCode status) {
switch (status) {
case CtapDeviceResponseCode::kSuccess:
return GetAssertionStatus::kSuccess;
case CtapDeviceResponseCode::kCtap2ErrOperationDenied:
return GetAssertionStatus::kWinNotAllowedError;
case CtapDeviceResponseCode::kCtap2ErrCredentialExcluded:
// The API should never return InvalidStateError for GetAssertion.
FIDO_LOG(ERROR) << "Unexpected CtapDeviceResponseCode: "
<< static_cast<int>(status);
return GetAssertionStatus::kWinNotAllowedError;
default:
NOTREACHED() << "Must only be called with a status returned from "
"WinErrorNameToCtapDeviceResponseCode().";
FIDO_LOG(ERROR) << "Unexpected CtapDeviceResponseCode: "
<< static_cast<int>(status);
return GetAssertionStatus::kWinNotAllowedError;
} }
} }
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
namespace device { namespace device {
enum class GetAssertionStatus;
enum class MakeCredentialStatus;
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
base::Optional<AuthenticatorMakeCredentialResponse> base::Optional<AuthenticatorMakeCredentialResponse>
ToAuthenticatorMakeCredentialResponse( ToAuthenticatorMakeCredentialResponse(
...@@ -50,17 +53,26 @@ std::vector<WEBAUTHN_CREDENTIAL_EX> ToWinCredentialExVector( ...@@ -50,17 +53,26 @@ std::vector<WEBAUTHN_CREDENTIAL_EX> ToWinCredentialExVector(
// whereas FidoAuthenticator callbacks generally resolve with a // whereas FidoAuthenticator callbacks generally resolve with a
// CtapDeviceResponseCode. This method hence yields a "synthetic" // CtapDeviceResponseCode. This method hence yields a "synthetic"
// CtapDeviceResponseCode that can then be mapped to the corresponding // CtapDeviceResponseCode that can then be mapped to the corresponding
// FidoReturnCode by calling WinCtapDeviceResponseCodeToFidoReturnCode(). // {MakeCredential,GetAssertion}Status by calling
// WinCtapDeviceResponseCodeTo{MakeCredential,GetAssertion}Status().
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode( CtapDeviceResponseCode WinErrorNameToCtapDeviceResponseCode(
const base::string16& error_name); const base::string16& error_name);
// WinCtapDeviceResponseCodeToFidoReturnCode returns the FidoReturnCode that // WinCtapDeviceResponseCodeToMakeCredentialStatus returns the
// corresponds to a synthetic CtapDeviceResponseCode obtained from // MakeCredentialStatus that corresponds to a synthetic CtapDeviceResponseCode
// WinErrorNameToCtapDeviceResponseCode(). Return values are one of // obtained from WinErrorNameToCtapDeviceResponseCode(). Return values are one
// {kSuccess, kWinInvalidStateError, kWinNotAllowedError}. // of {kSuccess, kWinInvalidStateError, kWinNotAllowedError}.
COMPONENT_EXPORT(DEVICE_FIDO)
MakeCredentialStatus WinCtapDeviceResponseCodeToMakeCredentialStatus(
CtapDeviceResponseCode status);
// WinCtapDeviceResponseCodeToGetAssertionStatus returns the GetAssertionStatus
// that corresponds to a synthetic CtapDeviceResponseCode obtained from
// WinErrorNameToCtapDeviceResponseCode(). Return values are one of {kSuccess,
// kWinNotAllowedError}.
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
FidoReturnCode WinCtapDeviceResponseCodeToFidoReturnCode( GetAssertionStatus WinCtapDeviceResponseCodeToGetAssertionStatus(
CtapDeviceResponseCode status); CtapDeviceResponseCode status);
COMPONENT_EXPORT(DEVICE_FIDO) COMPONENT_EXPORT(DEVICE_FIDO)
......
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