Skip to content

Commit 155ae8c

Browse files
authored
fix: fix authenticatorData format (#402)
1 parent 296a804 commit 155ae8c

File tree

5 files changed

+50
-10
lines changed

5 files changed

+50
-10
lines changed

src/Services/Webauthn.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Contracts\Auth\Authenticatable as User;
66
use Illuminate\Database\Eloquent\Model;
7+
use Illuminate\Support\Arr;
78
use LaravelWebauthn\Events\WebauthnLogin;
89
use LaravelWebauthn\Events\WebauthnLoginData;
910
use LaravelWebauthn\Events\WebauthnRegister;
@@ -12,8 +13,10 @@
1213
use LaravelWebauthn\Services\Webauthn\CredentialAssertionValidator;
1314
use LaravelWebauthn\Services\Webauthn\CredentialAttestationValidator;
1415
use LaravelWebauthn\Services\Webauthn\RequestOptionsFactory;
16+
use ParagonIE\ConstantTime\Base64UrlSafe;
1517
use Webauthn\PublicKeyCredentialCreationOptions;
1618
use Webauthn\PublicKeyCredentialRequestOptions;
19+
use Webauthn\Util\Base64;
1720

1821
class Webauthn extends WebauthnRepository
1922
{
@@ -132,6 +135,10 @@ public static function prepareAssertion(User $user): PublicKeyCredentialRequestO
132135
*/
133136
public static function validateAssertion(User $user, array $credentials): bool
134137
{
138+
if (($authenticatorData = Arr::get($credentials, 'response.authenticatorData')) !== null) {
139+
Arr::set($credentials, 'response.authenticatorData', Base64UrlSafe::encodeUnpadded(Base64::decode($authenticatorData)));
140+
}
141+
135142
return app(CredentialAssertionValidator::class)($user, $credentials);
136143
}
137144

src/Services/Webauthn/CredentialAttestationValidator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ protected function pullPublicKey(User $user): PublicKeyCredentialCreationOptions
7373
try {
7474
return PublicKeyCredentialCreationOptions::createFromArray($this->cache->pull($this->cacheKey($user)));
7575
} catch (\Exception $e) {
76-
Log::debug('Webauthn publickKey deserialize error', ['exception' => $e]);
76+
Log::debug('Webauthn publicKey deserialize error', ['exception' => $e]);
7777
abort(404);
7878
}
7979
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace LaravelWebauthn\Tests\Unit\Models;
4+
5+
use LaravelWebauthn\Models\Casts\Base64;
6+
use LaravelWebauthn\Models\WebauthnKey;
7+
use LaravelWebauthn\Tests\FeatureTestCase;
8+
9+
class Base64Test extends FeatureTestCase
10+
{
11+
/**
12+
* @test
13+
* @dataProvider dataProvider
14+
*/
15+
public function it_deserialize_credentialId($credentialId, $expected)
16+
{
17+
$webauthnKey = new WebauthnKey();
18+
19+
$bin = (new Base64)->get($webauthnKey, 'credentialId', $credentialId, []);
20+
21+
$this->assertEquals($expected, (new Base64)->set($webauthnKey, 'credentialId', $bin, []));
22+
}
23+
24+
public function dataProvider()
25+
{
26+
return [
27+
[
28+
'xrXvxSyol4aHHmmYLBcJyln6pAHgjc/+6UnE2EX4ZGl5Vw82/AjX/5wryErEUfeIBU4djcj2HMXWv0e+Ck/GbA==',
29+
'xrXvxSyol4aHHmmYLBcJyln6pAHgjc_-6UnE2EX4ZGl5Vw82_AjX_5wryErEUfeIBU4djcj2HMXWv0e-Ck_GbA==',
30+
],
31+
];
32+
}
33+
}

tests/Unit/Services/WebauthnTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,20 +117,20 @@ public function test_do_authenticate()
117117
$this->assertInstanceOf(\Webauthn\PublicKeyCredentialRequestOptions::class, $publicKey);
118118

119119
$data = [
120-
'id' => Base64UrlSafe::encode($webauthnKey->credentialId),
120+
'id' => Base64UrlSafe::encodeUnpadded($webauthnKey->credentialId),
121121
'rawId' => Base64UrlSafe::encode($webauthnKey->credentialId),
122122
'type' => 'public-key',
123123
'response' => [
124-
'clientDataJSON' => Base64UrlSafe::encode(json_encode([
124+
'clientDataJSON' => Base64UrlSafe::encodeUnpadded(json_encode([
125125
'type' => 'webauthn.get',
126-
'challenge' => Base64UrlSafe::encode($publicKey->getChallenge()),
126+
'challenge' => Base64UrlSafe::encodeUnpadded($publicKey->getChallenge()),
127127
'origin' => 'https://localhost',
128128
'tokenBinding' => [
129129
'status' => 'supported',
130130
'id' => 'id',
131131
],
132132
])),
133-
'authenticatorData' => Base64UrlSafe::encode(
133+
'authenticatorData' => Base64UrlSafe::encodeUnpadded(
134134
hash('sha256', 'localhost', true). // rp_id_hash
135135
pack('C', 65). // flags
136136
pack('N', 1). // signCount
@@ -176,20 +176,20 @@ public function test_wrong_do_authenticate()
176176
private function getAttestationData($publicKey)
177177
{
178178
return [
179-
'id' => Base64UrlSafe::encode('0'),
179+
'id' => Base64UrlSafe::encodeUnpadded('0'),
180180
'rawId' => Base64UrlSafe::encode('0'),
181181
'type' => 'public-key',
182182
'response' => [
183-
'clientDataJSON' => Base64UrlSafe::encode(json_encode([
183+
'clientDataJSON' => Base64UrlSafe::encodeUnpadded(json_encode([
184184
'type' => 'webauthn.create',
185-
'challenge' => Base64UrlSafe::encode($publicKey->getChallenge()),
185+
'challenge' => Base64UrlSafe::encodeUnpadded($publicKey->getChallenge()),
186186
'origin' => 'https://localhost',
187187
'tokenBinding' => [
188188
'status' => 'supported',
189189
'id' => 'id',
190190
],
191191
])),
192-
'attestationObject' => Base64UrlSafe::encode((string) (new MapObject([
192+
'attestationObject' => Base64UrlSafe::encodeUnpadded((string) (new MapObject([
193193
new MapItem(
194194
new TextStringObject('authData'),
195195
new TextStringObject(

tests/database/factories/WebauthnKeyFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
'name' => $faker->word,
1212
'counter' => 0,
1313
'credentialId' => function (array $data) {
14-
return Base64UrlSafe::encode($data['user_id']);
14+
return Base64UrlSafe::encodeUnpadded($data['user_id']);
1515
},
1616
'type' => 'public-key',
1717
'transports' => [],

0 commit comments

Comments
 (0)