WebAuthn public-key (SPKI) is not compatible with crypto-subtle importKey()
Categories
(Core :: DOM: Web Authentication, defect, P3)
Tracking
()
Tracking | Status | |
---|---|---|
firefox132 | --- | fixed |
People
(Reporter: getify, Assigned: jschanck)
References
(Blocks 1 open bug)
Details
Attachments
(3 files)
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0) Gecko/20100101 Firefox/129.0
Steps to reproduce:
-
Visit https://dev.getify.com/test-webauthn-publickey-firefox-bug.html on a WebAuthn enabled device (touch-ID, face-id, etc).
-
Open the dev-tools console, click the "register passkey" button.
-
Follow the system modal prompts to register a passkey.
Actual results:
Notice that after the passkey is created, its public-key fails to be be imported when passed to crypto.subtle.importKey()
. A DOMException is logged to the console:
"DOMException: Data provided to an operation does not meet requirements"
(see attached screenshot)
It's entirely unclear from that error message why the public-key (SPKI format) that comes from the AuthenticatorAttestationResponse.getPublicKey() call cannot be imported by crypto.subtle.importKey()
.
Also notice that the -257 algo COSE is returned from webauthn, which is indeed the RSASSA-PKCS1-v1_5 algorithm being used in the importKey()
call.
Expected results:
I expect that a public-key, in SPKI format, from firefox's navigator.credentials.create() call, is valid and compatible with the crypto.subtle.importKey()
when importing a key in SPKI format.
If I cannot import that public-key from webauthn into crypto.subtle, then I cannot verify the challenge-signature on subsequent webauthn authentication attempts.
Moreover, this exact same test works fine in Chrome 128.0.6613.114 (on this same windows 11 device). See attached success screenshot.
Reporter | ||
Comment 1•1 month ago
|
||
Reporter | ||
Comment 2•1 month ago
|
||
For cross-reference, this bug is affecting my "WebAuthn-Local-Client" library, by failing auth-verification in FF (windows, linux, perhaps mac?).
Comment 3•1 month ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::DOM: Web Authentication' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Comment 4•1 month ago
|
||
This sounds more like an issue with the Web Crypto API.
Reporter | ||
Comment 5•1 month ago
|
||
@Tom I kind of initially assumed that was the case as well, however I don't necessarily think that's true.
I took a public-key SPKI produced from Firefox's getPublicKey()
call (which its own importKey()
choked on) and tried to use importKey()
in Chrome instead, and Chrome also choked on it, even though Chrome works fine with any public-key it gets from its own getPublicKey()
call.
So that let me think that perhaps the public-key that FF's getPublicKey()
is spitting out is somehow garbled. That might explain why importKey()
in both FF and Chrome choke on it?
Since we're only talking about a public-key (of a credential), I can't think of any reason why the key would be incompatible between FF and Chrome, and expect such a cross-browser import to otherwise fail. So I think there's something unfit about that key itself, as FF is spitting out.
Assignee | ||
Comment 6•1 month ago
|
||
@Kyle, I don't have a token that generates RSA keys handy. Could you attach the SPKI that you get from getPublicKey()
here?
Reporter | ||
Comment 7•1 month ago
|
||
Here's one I had my FF just generate for me via getPublicKey()
:
Uint8Array([
48,130,1,34,48,13,6,9,42,134,72,134,247,
13,1,1,11,5,0,3,130,1,15,0,48,130,1,10,2,
130,1,1,0,209,0,59,142,239,142,11,212,7,
235,79,176,151,26,221,246,232,39,78,228,
20,138,22,24,106,100,162,133,252,233,170,
61,84,163,121,12,214,248,205,199,112,103,
139,131,163,57,215,232,101,179,81,240,186,
165,193,223,211,243,144,122,125,255,46,
181,141,109,63,69,207,108,181,157,24,89,
170,0,6,104,217,181,235,133,78,198,59,135,
134,71,59,180,67,92,149,145,190,214,80,231,
116,199,238,234,176,123,51,54,228,218,206,
90,57,36,50,104,15,24,116,144,105,42,214,
196,180,206,222,234,159,52,186,109,231,164,
241,186,90,121,196,79,101,225,6,80,16,43,
103,170,191,105,145,167,199,193,45,187,53,
98,46,24,100,245,126,98,129,248,111,169,51,
101,186,189,198,205,132,175,130,210,211,
189,125,3,184,203,59,235,225,223,83,56,233,
4,174,68,162,165,103,169,179,114,145,221,87,
42,223,196,210,16,130,38,15,142,147,103,198,
130,76,183,128,169,227,40,140,204,101,168,4,
1,99,161,131,85,108,111,15,131,159,243,180,
89,130,115,158,164,34,225,116,83,59,132,96,
123,200,99,109,133,173,191,2,3,1,0,1
])
Note: I wrapped it in a Uint8Array
, because it's easier to inspect/debug, but of course, getPublicKey()
returns a raw ArrayBuffer
of the same contents. And importKey()
docs indicate that it's OK to pass either the raw ArrayBuffer
or a typed-array.
Assignee | ||
Comment 8•1 month ago
|
||
OK, passing that through der2ascii I get:
SEQUENCE {
SEQUENCE {
# sha256WithRSAEncryption
OBJECT_IDENTIFIER { 1.2.840.113549.1.1.11 }
NULL {}
}
BIT_STRING {
`00`
SEQUENCE {
INTEGER { `00d1003b8eef8e0bd407eb4fb0971addf6e8274ee4148a16186a64a285fce9aa3d54a3790cd6f8cdc770678b83a339d7e865b351f0baa5c1dfd3f3907a7dff2eb58d6d3f45cf6cb59d1859aa000668d9b5eb854ec63b8786473bb4435c9591bed650e774c7eeeab07b3336e4dace5a392432680f187490692ad6c4b4cedeea9f34ba6de7a4f1ba5a79c44f65e10650102b67aabf6991a7c7c12dbb35622e1864f57e6281f86fa93365babdc6cd84af82d2d3bd7d03b8cb3bebe1df5338e904ae44a2a567a9b37291dd572adfc4d21082260f8e9367c6824cb780a9e3288ccc65a8040163a183556c6f0f839ff3b45982739ea422e174533b84607bc8636d85adbf` }
INTEGER { 65537 }
}
}
}
I believe the issue is that getPublicKey()
is returning an SPKI with the OID set to sha256WithRSAEncryption
rather than rsaEncryption
. The more specific OID was previously allowed by WebCrypto (see: Line 2.6 of Section 20.8.Import Key), but it was never supported by browsers and it was removed from the specification recently https://github.com/w3c/webcrypto/pull/325.
The getPublicKey()
definition doesn't give a reference for the expected OID. It just links to RFC 5280 which doesn't disambiguate this case. The baseline requirements for TLS certificates mandate the use of the more precise OID, so I would have expected any SPKI on the web to do the same.
Ultimately this looks like a specification gap between WebAuthn and WebCrypto. We could change the OID returned by our getPublicKey()
implementation to align our behavior with Chrome, but this is something for the relevant working groups to sort out.
Assignee | ||
Comment 9•1 month ago
|
||
Ah, no I had that wrong. The baseline requirements for TLS certificates require the use of rsaEncryption. So we should change the OID output by getPublicKey()
. I'll move this back to WebAuthn.
Assignee | ||
Updated•1 month ago
|
Assignee | ||
Updated•1 month ago
|
Reporter | ||
Comment 10•6 days ago
|
||
Could I please ask, since this was merged 3-4 weeks ago, what is the expected timeframe (or version number) where it might land in FF stable?
Assignee | ||
Comment 11•6 days ago
|
||
Assignee | ||
Comment 12•6 days ago
|
||
Thanks for the reminder. The patch will be in Firefox 132.
Reporter | ||
Comment 13•6 days ago
|
||
Great, thank you!
Comment 14•6 days ago
|
||
Comment 15•6 days ago
|
||
bugherder |
Description
•