Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CTAP2] Implement authenticator selection #155

Closed
msirringhaus opened this issue Oct 26, 2021 · 1 comment
Closed

[CTAP2] Implement authenticator selection #155

msirringhaus opened this issue Oct 26, 2021 · 1 comment

Comments

@msirringhaus
Copy link
Contributor

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;
  }

Source.

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.

@msirringhaus
Copy link
Contributor Author

Fixed (in the ctap2-branch) with #163

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant