f-23 / react-native-passkey

Passkeys for React Native
MIT License
121 stars 25 forks source link

Android incorrect b-64 credentialId #24

Closed asimaranov closed 1 month ago

asimaranov commented 8 months ago

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 6 months ago

Hi @asimaranov

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

davidthornton commented 5 months ago

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?

github-actions[bot] commented 2 months ago

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.

github-actions[bot] commented 1 month ago

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