[CTAP2] Implement authenticator selection
msirringhaus opened this issue · 1 comments
This bugreport only applies to the ctap2-branch.
When multiple tokens are plugged in, there is currently no good way to select which to use.
Chromium does it, by forcing a touch from the user first, but only if multiple devices are found. Otherwise it skips this step.
With CTAP2.1 there is authenticatorSelection (0x0B), which is basically a "please touch me"-request. The one that is touched and returns, can thus be identified by the platform as the one to be used.
But any device with an older CTAP version does not support this.
Chromium solved this by checking the supported version first and if it is too old, by sending a dummy MakeCredential request instead:
// We want to flash and wait for a touch. Newer versions of the CTAP2 spec
// include a provision for blocking for a touch when an empty pinAuth is
// specified, but devices exist that predate this part of the spec and also
// the spec says that devices need only do that if they implement PIN support.
// Therefore, in order to portably wait for a touch, a dummy credential is
// created. This does assume that the device supports ECDSA P-256, however.
PublicKeyCredentialUserEntity user({1} /* user ID */);
// The user name is incorrectly marked as optional in the CTAP2 spec.
user.name = "dummy";
CtapMakeCredentialRequest req(
"" /* client_data_json */, PublicKeyCredentialRpEntity(kDummyRpID),
std::move(user),
PublicKeyCredentialParams(
{{CredentialType::kPublicKey,
base::strict_cast<int>(CoseAlgorithmIdentifier::kEs256)}}));
// If a device supports CTAP2 and has PIN support then setting an empty
// pinAuth should trigger just a touch[1]. Our U2F code also understands
// this convention.
// [1]
// https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#using-pinToken-in-authenticatorGetAssertion
if (device->supported_protocol() == ProtocolVersion::kU2f ||
(device->device_info() &&
device->device_info()->options.client_pin_availability !=
AuthenticatorSupportedOptions::ClientPinAvailability::
kNotSupported)) {
req.pin_auth.emplace();
req.pin_protocol = PINUVAuthProtocol::kV1;
}
The device that is touched by the user is then selected for usage on that webpage (prompting more touch-requests for the actual usage later on).
The current setup is such that the actual request is sent to all found devices, leading to some returning immediately with "PIN required", which turns messy.
Using Chromiums approach, there is no need to expose any of this outside of this crate, as the additional selection process is happening internally.
However, there is the possibility to return a list of found devices instead, then let the user of this crate select which should be used, and handing that in again. Firefox, for example, could then show a list of available devices to the user (using manufacturer and other info we get from GetInfo), who selects it with the mouse instead of touching it.
Fixed (in the ctap2-branch) with #163