f-23/react-native-passkey

Android incorrect b-64 credentialId

Closed this issue · 4 comments

Function PasskeyAndroid.register transforms the returned credentialId from base64url to base64:

  /**
   * Transform the attestation or assertion result
   */
  private static handleNativeResponse(
    response: PasskeyRegistrationResult & PasskeyAuthenticationResult
  ): PasskeyRegistrationResult & PasskeyAuthenticationResult {
    // Transform Base64URL Response to Base64
    let id = response.id;
    if (id.length % 4 !== 0) {
      id += '==='.slice(0, 4 - (id.length % 4));
    }
    id = id.replace(/-/g, '+').replace(/_/g, '/');

    return {
      ...response,
      id,
      rawId: id,
    };
  }
}

When this credentialId is used later in authenticate, it's still transformed to base64 format while android expects base64url. Android fails to decode the credentialId if it ends with ==:

11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: ebyf: java.lang.IllegalArgumentException: bad base-64
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at baoi.apply(:com.google.android.gms@234313039@23.43.13 (190408-577232161):43)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ebua.d(:com.google.android.gms@234313039@23.43.13 (190408-577232161):3)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ebub.run(:com.google.android.gms@234313039@23.43.13 (190408-577232161):139)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ajlc.c(:com.google.android.gms@234313039@23.43.13 (190408-577232161):50)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ajlc.run(:com.google.android.gms@234313039@23.43.13 (190408-577232161):76)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ajqf.run(:com.google.android.gms@234313039@23.43.13 (190408-577232161):8)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at java.lang.Thread.run(Thread.java:1012)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: Caused by: java.lang.IllegalArgumentException: bad base-64
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at android.util.Base64.decode(Base64.java:163)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at android.util.Base64.decode(Base64.java:138)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at android.util.Base64.decode(Base64.java:120)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialDescriptor.b(:com.google.android.gms@234313039@23.43.13 (190408-577232161):15)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at com.google.android.gms.fido.fido2.api.common.PublicKeyCredentialRequestOptions.a(:com.google.android.gms@234313039@23.43.13 (190408-577232161):94)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at udq.a(:com.google.android.gms@234313039@23.43.13 (190408-577232161):14)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at baog.a(:com.google.android.gms@234313039@23.43.13 (190408-577232161):7)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ebug.d(:com.google.android.gms@234313039@23.43.13 (190408-577232161):3)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	at ebui.run(:com.google.android.gms@234313039@23.43.13 (190408-577232161):42)
11-06 11:48:26.170 12673 13701 W Auth.Api.Credentials: 	... 6 more

And returns error:

11-06 11:48:26.187 13250 13388 I ReactNativeJS: [login error]: Error: [checkSignatureIsValid]: Error: [Passkey authentication error]: {"error":"NoCredentials","message":"No viable credential is available for the user."}

Possible fixes: Return rawId with value returned by platform to use it in authenticate. Add base64 to base64url credentialId transformation based on current platform in authenticate

f-23 commented

Hi @asimaranov

thank you for bringing this up!
I'll have a look at it.

Hi team,

Just want to add my investigation onto the pile here - I printed out the output of NativePasskey.register() which was relevantly:

{
  "response": {
    "clientDataJSON": "xxx",
    "attestationObject": "xxx",
    "transports": [
      "internal",
      "hybrid"
    ]
  },
  "authenticatorAttachment": "platform",
  "clientExtensionResults": {
    "credProps": {
      "rk": false
    }
  },
  "id": "AbUZWsr6+b94Aea2iNfDO+/wNAmkHKTA/SzjxmkiWi1Ph6LKzLFoQoY4gdyuZnlFJ4pjtWjz8lxtHIt9kL8Sl9c=",
  "rawId": "AbUZWsr6+b94Aea2iNfDO+/wNAmkHKTA/SzjxmkiWi1Ph6LKzLFoQoY4gdyuZnlFJ4pjtWjz8lxtHIt9kL8Sl9c=",
  "type": "public-key"
}

Note that I believe the above "proves" the assetlinks.json configuration is valid as the passkey would not be created unless it can link it to a valid origin (which I have redacted here).

I then attempt to (using the exact same configuration) call Passkey.authenticate(requestJSON) where requestJSON is:

{
        challenge: 'abc123',
        allowCredentials: [
          {
            id: 'AbUZWsr6-b94Aea2iNfDO-_wNAmkHKTA_SzjxmkiWi1Ph6LKzLFoQoY4gdyuZnlFJ4pjtWjz8lxtHIt9kL8Sl9c',
            type: "public-key",
            transports: ["internal", "hybrid"],
          }
        ],
        "timeout": 1800000,
        "userVerification": "required",
        rpId: 'xxx',
      }

But I also receive:

{"error": "NoCredentials", "message": "No viable credential is available for the user."}

I have also tried using a base64 formatted id (as opposed to the above base64url formatted id). Am I correct in thinking this is related to this thread; or do I have a device-specific issue, or am I missing something else here...? I hope this helps nonetheless!

P.s. @asimaranov, how are you obtaining the stack trace - does it print out of React Native or are you doing something else in Android Studio?

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

This issue was closed because it has been stalled for 5 days with no activity.