Open mathewparet opened 1 week ago
It's seems that the data sent to the library is not good. The javascript must not give the payload given by passkey, but only the json in the passkey var :
{
"id":"qIzoqgJ8ZO3qrn6LQ9UttXGTAUvbWcsFM-gAhEedatY",
"rawId":"qIzoqgJ8ZO3qrn6LQ9UttXGTAUvbWcsFM-gAhEedatY",
"response":{
"attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVikrfib3PjzQH9ab0yDXhjFR6LN1Un-cXd32vJpl6_yc5tNAAAAAPOAlUB_FEnBqLOPgTsiVUEAIKiM6KoCfGTt6q5-i0PVLbVxkwFL21nLBTPoAIRHnWrWpQECAyYgASFYIARlkW_nc2GzO_S5C5Z5Bkh4CjugYg1dtmLhuNrybkmWIlggSjx51ABpkesJlQnGKM-qDodSrqrHziA5DO7l2Kt82Zg",
"clientDataJSON":"eyJ0eXBlIjogIndlYmF1dGhuLmNyZWF0ZSIsICJjaGFsbGVuZ2UiOiAiNXQ5RTlJRFlOa1hrR0RfTExMdkJ3TXZ4Vk85V19PRjh5UkVKSEdyajdsZHJTRVVuZG5vc1JVaWFzYl80bHpiaV93Z3RpcmJySEJRMWthUkpKN29rWFEiLCAib3JpZ2luIjogImh0dHBzOi8vdGVzbGEtc3RhdHMucGlvbmVlcmR5bmFtaWNzLmNvbS5hdSJ9",
"transports":[
"internal",
"hybrid"
]
},
"type":"public-key",
"clientExtensionResults":[
],
"authenticatorAttachment":"cross-platform"
}
You can look at this doc to see what it must be sent to the lib.
But, in the json data, I don't see publicKeyAlgorithm and publicKey. It's a problem. Without the alg and the publickey, it's not possible to verify the signature for authentication.
Well only the contents of the passkey
json property is passed to the library, so that is fine.
For the rest I think I'll have to raise a bug report to https://github.com/MasterKale/SimpleWebAuthn - the JS library I use & possibly with Enpass too (since other password managers work). So looks like one of them have a bug.
Thanks anyways @svgta1
I use SimpleWebAuthn too. I've never had problem with it. But, I don't know Enpass. It's seems that they add the feature this year only. The publicKeyAlgorithm and the publicKey have to been given from Enpass. If you don't have them in the json, it's not normal.
Which pubKeyCredParams are you sending when you create the params to send to endpass ? Maybe some alg are not compatible with Enpass and then the datas are note given (but it's should send an error). For my personnal use, I use theses, in order of my preference :
You can find the list of alg compatible with the library there : https://svgtas-organization.gitbook.io/php-webauthn/registration/create-params#pubkeycredparams
I reopen the issue. I'm interested to know if you find a solution with the pubKeyCredParams.
I use the below algorithms.
Also I checked the response generated by Enpass on other websites - like GitHub. Interestingly it has the public key and algorithm in the response. But when used on my website it doesn't seem to do that.
This is how the registration options are generated
public function generateOptions(?PasskeyUser $passkeyUser = null)
{
$this->setUser($passkeyUser); // PasskeyUser is just an interface attached to User. So technically its same as the user.
$this->webauthn->userVerification->preferred();
$this->webauthn->residentKey->preferred();
$this->webauthn->authenticatorAttachment->all();
$this->webauthn->attestation->none();
$this->setSupportedPublicKeyParameters();
return json_decode($this->webauthn->register()->toJson(), true);
}
public function setUser(?PasskeyUser $passkeyUser = null)
{
if($passkeyUser)
{
$this->webauthn->user->set(
name: $passkeyUser->getDisplayName(),
id: $passkeyUser->getUserId(),
icon: $passkeyUser->getUserIcon()
);
$passkeyUser->passkeys->each(fn($passkey) => $this->webauthn->excludeCredentials->add($passkey->credential_id));
}
return $this;
}
And this is how I process it in JS using SimpleWebAuthn:
const register = () => {
registrationInProgress.value = true
form.post(route('passkeys.registration-options'), { // fetch the registration options from server
preserveScroll: true,
preserveState: true,
onSuccess: () => {
console.log('from server', usePage().props.jetstream.flash.options); // the response is received in `usePage().props.jetstream.flash.options`
startRegistration(JSON.parse(JSON.stringify(usePage().props.jetstream.flash.options))) // because of all the inertiajs proxying, I have to do JSON.parse and JSON.stringify to remove the proxies and get the actual values.
.then((res) =>{
form.passkey = res;
console.log(res); // res is the response sent by Enpass and that's what I send to the server to store. This has missing public key and the algorithm.
form.post(route('passkeys.store'), {
preserveScroll: true
})
})
.catch((err) => console.log(err))
.finally(() => closeModal());
}
})
}
Sample output generated by server for registration options, i.e. contents of usePage().props.jetstream.flash
:
"options": {
"rp": {
"name": "Tesla Stats",
"icon": "data:image\/svg+xml;utf8,<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"100\" height=\"100\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"#4F46E5\"\/><rect x=\"8\" y=\"6\" width=\"8\" height=\"4\" fill=\"#FFFFFF\"\/><rect x=\"9\" y=\"10\" width=\"6\" height=\"5\" fill=\"#FFFFFF\"\/><path d=\"M8 15h8v2H8z\" fill=\"#FFFFFF\"\/><\/svg>",
"id": "tesla-stats.pioneerdynamics.com.au"
},
"user": {
"name": "mathewparet@gmail.com",
"id": "MQ",
"displayName": "Matt"
},
"challenge": "9NEj_B9IVtTc2Jw_C24s3ojQRcqhouKyhZg5JMZ4YUYSkECpSmCRW7l0eR-h_HA20-65YsQGk5OMzhohBgJw2Q",
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -37
},
{
"type": "public-key",
"alg": -38
},
{
"type": "public-key",
"alg": -39
},
{
"type": "public-key",
"alg": -257
},
{
"type": "public-key",
"alg": -258
},
{
"type": "public-key",
"alg": -259
},
{
"type": "public-key",
"alg": -7
},
{
"type": "public-key",
"alg": -35
},
{
"type": "public-key",
"alg": -36
},
{
"type": "public-key",
"alg": -260
},
{
"type": "public-key",
"alg": -261
},
{
"type": "public-key",
"alg": -46
}
],
"timeout": 600000,
"excludeCredentials": [
{
"type": "public-key",
"id": "vzYkTJ_bt1UOcqXB9LFBDSgEc3p3C6Qk_x0mQDTfPxY"
},
{
"type": "public-key",
"id": "JmTmsvJBBGymvt-ahkmTRw"
},
{
"type": "public-key",
"id": "IdxtPi2HcfiPHIDuGu3dI2C1sWQ_bjeNRzRJkUz7Kmc"
}
],
"authenticatorSelection": {
"requireResidentKey": false,
"userVerification": "preferred",
"residentKey": "preferred"
},
"attestation": "none"
}
Strange... Normally, webauthn RP must choose the first alg it's can handle with. But, maybe Enpass doesn't do that. Try to change the order of the Alg. Put -257 (RS256) in first and -7 (ES256) in second. If it doesn't work, try -7 in first and -257 in second.
Tried the below orders:
-257 -7
and:
-7 -257
The issue persists
Strange, strange, strange... And if you try only one alg each time ? Then test every alg, one by one.
This library seems to work fine with all password managers, browsers and, and operating systems I've tried except for Enpass.
While attempting to register the passkey sent by Enpass an exception is thrown at
vendor/svgta/webauthn/lib/register.php:118
Exception:
Undefined property: stdClass::$publicKeyAlgorithm
The payload received from Enpass looks like this:
Initially I thought it was an issue with Enpass, but they claim most websites are able to handle Enpass generated Passkeys.