Laragear / WebAuthn

Authenticate users with Passkeys: fingerprints, patterns and biometric data.
MIT License
286 stars 37 forks source link

[3.x] iCloud (TouchID) userHandle is without dash #83

Closed stoutZero closed 3 weeks ago

stoutZero commented 3 months ago

PHP & Platform

8.3.6 - macOS 14.4.1 aarch64

Database

PostgreSQL 14.11

Laravel version

11.5.0

Have you done this?

Expectation

When I use 1Password / my macbook's TouchId, as long as I have registered it in the system, I should be able to login.

Description

When using 1Password as a Passkey, 1Password seems to be sending the userHandle in the format that this package expects, which is without dash, e.g.: 6943324022c046d395de29ceda194b63

Which will be validated in \Laragear\WebAuthn\Assertion\Validator\Pipes\CheckCredentialIsForUser@validateId like so:

hash_equals(Uuid::fromString($validation->credential->user_id)->getHex()->toString(), $handle);
// using the userHandle 1Password provided, the line above becomes:
'6943324022c046d395de29ceda194b63' === '6943324022c046d395de29ceda194b63';

But my MBP's TouchID seems to sent userHandle with dash, i.e.: 69433240-22c0-46d3-95de-29ceda194b63 the hash_equals above effectively becomes:

'6943324022c046d395de29ceda194b63' === '69433240-22c0-46d3-95de-29ceda194b63';

This makes logging-in using my TouchID to be impossible, I reckon other people also can not login.

Right now this issue is not a problem in my projects, as I am using this workaround in my WebAuthnLoginController.php:

    public function login(AssertedRequest $request)
        : \Symfony\Component\HttpFoundation\Response
    {
        // hacky workaround =>
        $userHandle = $request->json()->get('response.userHandle');

        $request->json()->set('response',
            [
                'userHandle' => Str::replace(
                    '-', '', $userHandle ?? ''
                )
            ]
            + $request->json('response')
        );

        $user = $request->login();

        // ...
    }

But someone might want to address this issue

Reproduction

// sorry, don't have the time to make a repro, feel free to just close this issue :)
// the issue itself is easily fixable on userland, with a little hack.

Stack trace & logs

// This is the TouchID
[2024-05-03 09:50:12] local.DEBUG: array (
  'request' => 
  array (
    'remember' => NULL,
    'id' => 'ZDariNmfR72XYzZEG-QMubXC9Mc',
    'rawId' => 'ZDariNmfR72XYzZEG-QMubXC9Mc',
    'response' => 
    array (
      'authenticatorData' => 'REDACTED',
      'clientDataJSON' => 'REDACTED',
      'signature' => 'REDACTED',
      'userHandle' => '69433240-22c0-46d3-95de-29ceda194b63',
    ),
    'type' => 'public-key',
    'clientExtensionResults' => 
    array (
    ),
    'authenticatorAttachment' => 'platform',
  ),
  'handle' => '69433240-22c0-46d3-95de-29ceda194b63',
  'Uuid::fromString()->getHex()->toString()' => '6943324022c046d395de29ceda194b63',
)  
[2024-05-03 09:50:12] local.DEBUG: Assertion Error: User ID is not owner of the stored credential.  

// This is 1Password
[2024-05-03 09:50:35] local.DEBUG: array (
  'request' => 
  array (
    'remember' => NULL,
    'id' => 'auDdo3Qn2MZ47Fp0bg0hIg',
    'rawId' => 'auDdo3Qn2MZ47Fp0bg0hIg',
    'response' => 
    array (
      'authenticatorData' => 'REDACTED',
      'clientDataJSON' => 'REDACTED',
      'signature' => 'REDACTED',
      'userHandle' => '6943324022c046d395de29ceda194b63',
    ),
    'type' => 'public-key',
    'clientExtensionResults' => 
    array (
    ),
    'authenticatorAttachment' => 'platform',
  ),
  'handle' => '6943324022c046d395de29ceda194b63',
  'Uuid::fromString()->getHex()->toString()' => '6943324022c046d395de29ceda194b63',
)
DarkGhostHunter commented 3 months ago

This should be fixed by simply checking if the user handle sent by the Authenticator is an UUID, and normalize it, on the pipe that checks that.