Webauthn verify signature using crypto.subtle

603 views
Skip to first unread message

Phil Holden

unread,
May 12, 2021, 6:59:32 AM5/12/21
to FIDO Dev (fido-dev)
Hi,

I am trying to do passwordless webauthn login in a Cloudflare Worker. This uses web crypto so full login and verify can be simulated in browser. When I try to verify the signature after login I get false. You can see full code and run in the console just copy this gist into browser console (must be on https site):

https://gist.github.com/philholden/50120652bfe0498958fd5926694ba354

Someone else is asking the same question on StackOverflow:

https://stackoverflow.com/questions/54631177/calculate-hash-for-signature-verification-in-webauthn

What do I need to change to get this to work?

Things to look at:

Am I creating the signed data correctly? authenticatorData + hash(clientDataJSON)
Is my public key import correct?
Why does verify fail? 

Help much appreciated (if I get solution I will create a tutorial)

Phil

Alex Seigler

unread,
May 12, 2021, 8:02:37 AM5/12/21
to Phil Holden, FIDO Dev (fido-dev)

The data you are looking for is hash(authenticatorData + clientDataJSON), so hash(signedData) from the gist.  You don’t need the clientDataHash at all.

 

Check out the verification procedure https://www.w3.org/TR/webauthn/#sctn-packed-attestation, particularly #3 with self attestation.

 

I also recommend checking out this project: https://github.com/MasterKale/SimpleWebAuthn

 

-aseigler

--
You received this message because you are subscribed to the Google Groups "FIDO Dev (fido-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fido-dev+u...@fidoalliance.org.
To view this discussion on the web visit https://groups.google.com/a/fidoalliance.org/d/msgid/fido-dev/e6cb814f-f150-4d1a-be50-f34ad344537en%40fidoalliance.org.

Alex Seigler

unread,
May 12, 2021, 8:07:42 AM5/12/21
to Alex Seigler, Phil Holden, FIDO Dev (fido-dev)

Sorry, wow, got that spectacularly wrong.  Way too little coffee.

 

You’re doing everything right up to the key handling.  Not following what is going on there.

Emil Lundberg

unread,
May 12, 2021, 9:50:26 AM5/12/21
to Alex Seigler, Phil Holden, FIDO Dev (fido-dev)
I replied in the GitHub Gist and on StackOverflow too, but I'll reply here too for completeness.

The signature returned from navigator.credentials.create() is not made with the credential private key, but with the attestation private key. So the public key you need to verify with is not cred.response.getPublicKey(), but the one in the attestation certificate contained in cred.response.attestationObject["attStmt"]. The exception would be if the authenticator is using self attestation, which I don't think I've seen used in practice.

For subsequent navigator.credentials.get() operations, however, you do need the public key returned as cred.response.getPublicKey() in the registration ceremony.

Hope that helps! And please remember that you will also need to validate the contents of clientDataJSON (for example, the challenge), and that you usually need to run all these validation steps in an environment outside the (possibly malicious) user's control, usually a server-side process.




--

Emil Lundberg

Software Developer | Yubico


Emil Lundberg

unread,
May 12, 2021, 10:04:28 AM5/12/21
to Alex Seigler, Phil Holden, FIDO Dev (fido-dev)
On second thought, the bigger problem is that what you're trying to do here is verify an assertion signature, but navigator.credentials.get() returns an attestation signature. The structure of, and verification procedure for, an attestation signature is determined by what attestation statement format it is. Verifying an attestation signature always requires parsing the CBOR in both the attestation statement (in order to verify the signature) and the authenticator data (because the credential public key in the authenticator data is covered by the signature, while cred.response.getPublicKey() is not). Only if the RP does not care about verifying the attestation, then it can use cred.response.getPublicKey() as a shortcut so it doesn't have to parse CBOR to get the credential public key or verify future assertions.

Jen Nicole

unread,
May 13, 2021, 3:52:07 AM5/13/21
to Emil Lundberg, Alex Seigler, Phil Holden, FIDO Dev (fido-dev)

Phil Holden

unread,
May 15, 2021, 5:38:03 PM5/15/21
to FIDO Dev (fido-dev), jennifer...@gmail.com, alexs...@hotmail.com, Phil Holden, FIDO Dev (fido-dev), Emil Lundberg
There are now more comments on the Gist. We have verified that all the data is correct. So it looks like the key import must be to blame. Probably this line:

{ name: "ECDSA", namedCurve: "P-256", hash: { name: "SHA-256" } } // key algorithm  is -7

Can anyone shed some more light on this webauthn and crypto.subtle are both web standards so the two must be able to play well together (some clear docs here would be really helpful). This is important for identity in decentralized apps using WebRTC and no server.

https://gist.github.com/philholden/50120652bfe0498958fd5926694ba354

Reply all
Reply to author
Forward
0 new messages