Open Bug 1854089 Opened 1 year ago Updated 8 months ago

WebAuthn credentials requires PIN even when user verification and discoverable credentials are "discouraged"

Categories

(Core :: DOM: Web Authentication, defect, P3)

Firefox 118
defect

Tracking

()

ASSIGNED

People

(Reporter: cleyfaye, Assigned: jschanck)

References

Details

Steps to reproduce:

UA of the browser displaying the issue: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/118.0

  • Go to webauthn.io
  • in advanced settings, set both user verification and discoverable credentials to "discouraged"
  • register with a FIDO2 token (YubiKey 5)

Actual results:

To register, a PIN is asked, and upon entering it a discoverable credential slot is used on the token.

Expected results:

With both "user verification" and "discoverable credentials" set to discouraged, a PIN should not have been asked, and no discoverable credentials should be stored on the token.
This expected result is supported by both the documentation and various other implementations.

Setting security.webauthn.ctap2 to false remove the PIN requirements, but does not seems like a future-proof solution. Disabling the FIDO2 interface on the token also seems to work as it fallback to FIDO2 U2F.

A similar issue was found in #1811866 but the current state of things does not match the resolution status.

Component: Untriaged → DOM: Web Authentication
Flags: needinfo?(jschanck)
Product: Firefox → Core
See Also: → 1811866

The Bugbug bot thinks this bug should belong to the 'Core::DOM: Web Authentication' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

I'm not able to reproduce this with a YubiKey 5 NFC running firmware version 5.4.3. Can you run ykman info and copy the "Device type" and "Firmware version" lines here?

Flags: needinfo?(jschanck)

Sure. It seems I have a different firmware version. I have a hard time finding details about different firmware versions, though.

Device type: YubiKey 5 NFC
Firmware version: 5.2.4
Form factor: Keychain (USB-A)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is disabled.

Applications    USB             NFC
FIDO2           Enabled         Disabled
OTP             Enabled         Disabled
FIDO U2F        Enabled         Disabled
OATH            Enabled         Disabled
YubiHSM Auth    Not available   Not available
OpenPGP         Enabled         Disabled
PIV             Enabled         Disabled

Will, any idea what might be going on here? Does YK5 firmware 5.2.4 imply a max supported version of FIDO_2_0 instead of FIDO_2_1_PRE?

Flags: needinfo?(will.smart)

Not sure making an un-requested discoverable credential is a new one for me.

That should be a FIDO_2_1_PRE device (it supports credprotect & credential management). I'll try and see if I can get ahold of a 5.2.4 device to test.

@clayfaye, can you test with this site and see how it behaves?
https://demo.yubico.com/webauthn-technical/registration
This site is hard-coded to make a non-discoverable, non-uv credential.

Flags: needinfo?(will.smart)

When registering, it did ask me for a PIN, then to touch the device (same behavior I see on webauthn.io), then succeeded.
However, it did not ask for a PIN to "authenticate", and listing the stored credentials on the key did not show a new one.
It seems I mixed up different tests (obviously I didn't initially come across this issue on webauthn.io, it was just a convenient way to reproduce the issue), and while a PIN is asked, it actually does not store a credentials on the key in that case. Sorry about that.

It does, however, always ask for a PIN when registering, which I feel is still not the expected behavior in this case. I may be biased because it does not ask for a PIN in other browsers, I only noticed this behavior afterward in Firefox. However this is based on my limited experience with these keys, and the issue may be with other's implementations.

If it is expected to ask a PIN at registration in this scenario, then I'm sorry for the noise.

I'm not sure dumping the data from the demo would still be relevant, but I'll just post everything here anyway in case the PIN situation is not as expected (I do know that there is nothing sensitive in there) :

navigator.credentials.create() argument:

{
  "publicKey": {
    "attestation": "direct",
    "authenticatorSelection": {
      "requireResidentKey": false,
      "residentKey": "discouraged",
      "userVerification": "discouraged"
    },
    "challenge": "6Toq+v9Zu1wYrkkTtfDgQXVmvhe2w48XgoVSX+jJwX0=",
    "excludeCredentials": [],
    "pubKeyCredParams": [
      {
        "alg": -7,
        "type": "public-key"
      },
      {
        "alg": -257,
        "type": "public-key"
      }
    ],
    "rp": {
      "id": "demo.yubico.com",
      "name": "Yubico Demo"
    },
    "timeout": 90000,
    "user": {
      "displayName": "Yubico demo user",
      "id": "m71W1UXHKeI3mveGf/MJjmMcVmQIG8RGvcEQUssaY/Q=",
      "name": "Yubico demo user"
    }
  }
}

navigator.credentials.create() response:

{
  "id": "4h5Ku-j22zKLrEPDCs2CmL5DQDHMAyr6dvUK55LoJEPvhBmRYdKge1jDNJ6IJRhYkXbo774-YCqqDmpQY7aMUg",
  "response": {
    "attestationObject": "o2NmbXRmcGFja2VkZ2F0dFN0bXSjY2FsZyZjc2lnWEcwRQIhAPAs+Vu4hkN13sC1T6HBDU4DAvDCqUBT9Qb8ABtle6XSAiBnaezaM9S8OTuaNK8llqD11iipTuO/ThOATAlm7TsYmGN4NWOBWQLCMIICvjCCAaagAwIBAgIEXdBO4TANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowbzELMAkGA1UEBhMCU0UxEjAQBgNVBAoMCVl1YmljbyBBQjEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEoMCYGA1UEAwwfWXViaWNvIFUyRiBFRSBTZXJpYWwgMTU3MzkzMjc2OTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCNp4As+URnWqbTRh760QYDNrHHqUpiB4+d9HPWBoTtnMSupMoY1ncNIDYET1l4UFOzm0Q67LR7I3Zo/Av1cgNSjbDBqMCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS43MBMGCysGAQQBguUcAgEBBAQDAgQwMCEGCysGAQQBguUcAQEEBBIEEC/AV5+BE0fqsRa7Wo25ICowDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAh8odJU4o9FIUYSm3h1UhrTGfnukczFJd3ojEJnxzZBnDBye7VfzVFJ05VQzu859HI3mRxK5FH4HLo6LnVrKrKh7cPEhECrQgEgbtjIwD+AAXQkAAZT1eyng572o82o/6Ua9e0/N+BktXV3TwzPGgMQaWGgql41gyiRc+8YBBbWF+ozozvRT2h+qexpd7YwPVk6FRiLhNyiqhl9qpnraHtrcQyEl++5PMnCUSygNyKTzS9DH7d8G+qTFZV23bdecAyjS2EcfztFLSs0Au6+jLLvt9R0pjGW28kObE8F9BBkJtLKZtPaw3W/LyZXOxs3PK+iENM5K3UtbbKPPi2a/AYWhhdXRoRGF0YVjExGzvgq0bVGR3WR0Aiwh1nsPm0uy085R0v+ppaZJdA7dFAAAAAS/AV5+BE0fqsRa7Wo25ICoAQOIeSrvo9tsyi6xDwwrNgpi+Q0AxzAMq+nb1CueS6CRD74QZkWHSoHtYwzSeiCUYWJF26O++PmAqqg5qUGO2jFKlAQIDJiABIVggSL4JXRZVWAMWQFS3yc5teAysEta8V79BGHQyEM8S3voiWCDK2SN9Us39eYWH+nXvyfrVAUaPejAc6A2o0RJsWAd0EQ==",
    "clientDataJSON": "eyJjaGFsbGVuZ2UiOiI2VG9xLXY5WnUxd1lya2tUdGZEZ1FYVm12aGUydzQ4WGdvVlNYLWpKd1gwIiwib3JpZ2luIjoiaHR0cHM6Ly9kZW1vLnl1Ymljby5jb20iLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0="
  },
  "clientExtensionResults": {}
}

parsed clientDataJSON response:

{
  "challenge": "6Toq-v9Zu1wYrkkTtfDgQXVmvhe2w48XgoVSX-jJwX0",
  "origin": "https://demo.yubico.com",
  "type": "webauthn.create"
}

Response from the Relying Party:

{
  "success": true,
  "attestationObject": {
    "attStmt": {
      "alg": -7,
      "sig": "MEUCIQDwLPlbuIZDdd7AtU+hwQ1OAwLwwqlAU/UG/AAbZXul0gIgZ2ns2jPUvDk7mjSvJZag9dYoqU7jv04TgEwJZu07GJg=",
      "x5c": [
        "MIICvjCCAaagAwIBAgIEXdBO4TANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowbzELMAkGA1UEBhMCU0UxEjAQBgNVBAoMCVl1YmljbyBBQjEiMCAGA1UECwwZQXV0aGVudGljYXRvciBBdHRlc3RhdGlvbjEoMCYGA1UEAwwfWXViaWNvIFUyRiBFRSBTZXJpYWwgMTU3MzkzMjc2OTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCNp4As+URnWqbTRh760QYDNrHHqUpiB4+d9HPWBoTtnMSupMoY1ncNIDYET1l4UFOzm0Q67LR7I3Zo/Av1cgNSjbDBqMCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS43MBMGCysGAQQBguUcAgEBBAQDAgQwMCEGCysGAQQBguUcAQEEBBIEEC/AV5+BE0fqsRa7Wo25ICowDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAh8odJU4o9FIUYSm3h1UhrTGfnukczFJd3ojEJnxzZBnDBye7VfzVFJ05VQzu859HI3mRxK5FH4HLo6LnVrKrKh7cPEhECrQgEgbtjIwD+AAXQkAAZT1eyng572o82o/6Ua9e0/N+BktXV3TwzPGgMQaWGgql41gyiRc+8YBBbWF+ozozvRT2h+qexpd7YwPVk6FRiLhNyiqhl9qpnraHtrcQyEl++5PMnCUSygNyKTzS9DH7d8G+qTFZV23bdecAyjS2EcfztFLSs0Au6+jLLvt9R0pjGW28kObE8F9BBkJtLKZtPaw3W/LyZXOxs3PK+iENM5K3UtbbKPPi2a/AYQ=="
      ]
    },
    "authData": {
      "credentialData": {
        "aaguid": "L8BXn4ETR+qxFrtajbkgKg==",
        "credentialId": "4h5Ku+j22zKLrEPDCs2CmL5DQDHMAyr6dvUK55LoJEPvhBmRYdKge1jDNJ6IJRhYkXbo774+YCqqDmpQY7aMUg==",
        "publicKey": {
          "1": 2,
          "3": -7,
          "-1": 1,
          "-2": "SL4JXRZVWAMWQFS3yc5teAysEta8V79BGHQyEM8S3vo=",
          "-3": "ytkjfVLN/XmFh/p178n61QFGj3owHOgNqNESbFgHdBE="
        }
      },
      "flags": {
        "AT": true,
        "ED": false,
        "UP": true,
        "UV": true,
        "value": 69
      },
      "rpIdHash": "xGzvgq0bVGR3WR0Aiwh1nsPm0uy085R0v+ppaZJdA7c=",
      "signatureCounter": 1
    },
    "fmt": "packed"
  },
  "clientData": "eyJjaGFsbGVuZ2UiOiI2VG9xLXY5WnUxd1lya2tUdGZEZ1FYVm12aGUydzQ4WGdvVlNYLWpKd1gwIiwib3JpZ2luIjoiaHR0cHM6Ly9kZW1vLnl1Ymljby5jb20iLCJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIn0=",
  "device": {
    "mds": {
      "certifications": [
        "FIDO_CERTIFIED_L1"
      ]
    },
    "names": [
      "YubiKey 5 NFC",
      "YubiKey 5C NFC"
    ],
    "type": "yk5nfc-cnfc"
  }
}

Followed by an X509 certificate matching my key's serial number.

Thanks @clayfaye - generally speaking the output from webauthn debugging is not terribly sensitive, especially when used with sites designed to test FIDO2 authenticators.
It's good that it's not making discoverable credentials, because that had me positively stumped.

I can confirm the bug behavior w/ a firmware 5.4.3 YubiKey on the FF118 beta.

I had a look at authenticator.rs, and I think this issue is with https://github.com/mozilla/authenticator-rs/blob/915bcbc289101a50beb093c6ac9d9dc3d6a15c12/src/ctap2/commands/make_credentials.rs#L385C71-L385C71

It should be possible to create a non-UV credential even if a PIN has been set on the authenticator:

Otherwise, implying the authenticator is not presently protected by some form of user verification, or the Relying Party wants to create a non-discoverable credential and not require user verification (e.g., by setting options.authenticatorSelection.userVerification to "discouraged" in the WebAuthn API), the platform invokes the authenticatorMakeCredential operation using the marshalled input parameters along with the "uv" option key set to false and terminate these steps.
https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#sctn-makeCred-platf-actions

!always_uv && (!device_protected || make_cred_uv_not_required) should probably just be !always_uv && make_cred_uv_not_required

Now I have to go back and figure out why my testing suite didn't detect this as an issue, because I didn't notice it as a problem while testing the initial CTAP2 support.

OK, we can change this, but the spec needs to be updated too.

"Otherwise" in the section Will quoted is the "else" branch for

If the authenticator is protected by some form of user verification, or the Relying Party prefers enforcing user verification (e.g., by setting options.authenticatorSelection.userVerification to "required", or "preferred" in the WebAuthn API):

The device is "protected by some form of user verification", so we followed the "if" side of the branch.

Assignee: nobody → jschanck
Severity: -- → S3
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Priority: -- → P3

Actually, I'm still confused. The makeCredUvNotRqd option says

present and set to false, or absent: the authenticator requires some form of user verification for creating non-discoverable credentials, regardless of the parameters the platform supplies for the authenticatorMakeCredential command.

My YK5 running the 5.4.3 firmware does not return the makeCredUvNotRqd option. So I think our behavior is correct.

I've requested some clarification from our spec folks, but I think you may be right.

I've discovered that the behavior on Chrome appears to be a result of Chrome pre-emptively falling back to U2F - if you disable U2F on the Yubikey, Firefox 118 and Chrome behave the same way.

@jschanck - You are technically correct. The CTAP2 spec does require UV for new registrations if a PIN is set on the authenticator - regardless of whether a credential is discoverable or not, or whether the RP sets UV=discouraged. I'm still trying to get some clarification on the spec wording.

In CTAP2.1-pre, makeCredUvNotRqd was added as a property that an authenticator could set to signal to platforms that it would allow new registrations without UV, if the RP set UV=discouraged, even if a PIN was already set on the authenticator. Neither the 5.2.4 keys nor the 5.4.3 support makeCredUvNotRqd.

I think the reason why @cleyfaye (and I) saw this as a bug is because other platforms (Chrome on Mac/Linux) will see this situation and silently downgrade the communication with the authenticator to CTAP1 (U2F) - so this behavior is unexpected, but not because the Firefox implementation of the CTAP2 spec is incorrect.

You can cause this behavior on Chrome by disabling the U2F Protocol on a YubiKey and then re-trying the test. You'll get the PIN prompt just like FireFox 118.

You need to log in before you can comment on or make changes to this bug.