Home > other >  PublicKeyCredentials Webauthn "internal" authentication missing userHandle on Android (And
PublicKeyCredentials Webauthn "internal" authentication missing userHandle on Android (And

Time:01-20

I'm currently able to create publicKeyCredentials using:

navigator.credentials.create({
      challenge: Uint8Array.from('CCCCCCCCCCCCCCCCCCCCCC', c => c.charCodeAt(0)),
      rp: {
        id,
        name: 'rpName'
      },
      user: {
        id: Uint8Array.from('userHandleId', c => c.charCodeAt(0)),
        name: 'userName',
        displayName: 'DisplayName'
      },
      pubKeyCredParams: [{alg: -7, type: 'public-key'}],
      authenticatorSelection: {
        userVerification: 'discouraged',
        authenticatorAttachment: 'platform',
        requireResidentKey: true, // don't seem to do anything with android-saftynet
        residentKey: 'required' // don't seem to do anything with android-saftynet
      },
      timeout: 60000,
      attestation: 'direct'
    })

Then retrieve the credential using:

navigator.credentials.get({
        publicKey: {
          challenge: generateChallenge(),
          allowCredentials: [{
            id: decodeArray(id),
            type: 'public-key'
          }],
          timeout: 60000,
          transport: ['internal'],
          userVerification: 'discouraged'
        },
      })

This flow works on all of my apple devices, however, on Android the 'fmt' of the credentials is 'android-saftynet' which doesn't seem to support userHandles.

Are there any formats I can force on Android that I can save userHandles with? Or another way to store information with the publicKeyCredential to allow me to support the usernameless webauthn flow?

EDIT: Looks like android-saftynet doesn't support userHandle. Does anyone know if there is an Android authenticator flow that supports userHandle? (aside from the USB auth flow)

CodePudding user response:

Attestation (with various formats such as android-safetynet) and usernameless flows are two completely separate concepts. You can have usernameless flows without attestation (format none).

Attestation allows you to verify the authenticator itself - whether the authenticator actually is an iPhone, Yubikey or (non-rooted) Android device, and properties like how key material is stored or what the false positive rate of the fingerprint scanner is. For more details see https://fidoalliance.org/fido-technotes-the-truth-about-attestation/ and https://medium.com/webauthnworks/webauthn-fido2-demystifying-attestation-and-mds-efc3b3cb3651

In WebAuthn level 1 usernameless registration (with requireResidentKey: true) was allowed to continue even if the user agent doesn't support this (see authenticatorMakeCredential operation step 20). In level 2 a few things changed:

  • resident keys are now referred to as client-side discoverable credentials,
  • requireResidentKey boolean was changed to the residentKey enum, but stiull supported for backwards compatibility,
  • the authenticatorMakeCredential operation was changed to return an error in step 4 if client-side discoverable credentials are not supported,
  • the credProps extension was added to determine if a client-side discoverable credential was created, either at the request of the RP or because the authenticator chose to (step 7.4).

Usernameless authentication (with an empty allowCredentials array) at the time of writing is not supported on Android using Chrome 97. This has been a known issue for a while.

CodePudding user response:

This flow works on all of my apple devices, however, on Android the 'fmt' of the credentials is 'android-saftynet' which doesn't seem to support userHandles.

Just to clarify, the format of the attestation statement has no bearing on an authenticator's ability to return a userHandle from navigator.credentials.get(). According to the spec it's basically up to the authenticator whether it wants to return userHandle or not.

Are there any formats I can force on Android that I can save userHandles with?

WebAuthn doesn't offer any way for an RP (Relying Party, i.e. your server) to require a specific attestation station format, so you either have to support them all (for which I'd highly encourage you use an existing library) or pick and choose and reject registration of credentials with statements you don't want to support.

Or another way to store information with the publicKeyCredential to allow me to support the usernameless webauthn flow?

I'll correct this if I'm wrong but I don't think you need userHandle to accomplish usernameless. You should be able to take the credential ID you get back from navigator.credentials.get() and match it first to your list of registered credentials, and then pull the corresponding user ID from your own internal record of which credentials belong to which user.

All that to say that FIDO2 support on Android is a little spotty. Last I checked discoverable credentials are basically unsupported on the platform which means usernameless support on Android devices is pretty much out of the question for now.

  •  Tags:  
  • Related