Closed Bug 1915919 Opened 1 month ago Closed 6 days ago

WebAuthn public-key (SPKI) is not compatible with crypto-subtle importKey()

Categories

(Core :: DOM: Web Authentication, defect, P3)

Firefox 129
defect

Tracking

()

RESOLVED FIXED
132 Branch
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:

  1. Visit https://dev.getify.com/test-webauthn-publickey-firefox-bug.html on a WebAuthn enabled device (touch-ID, face-id, etc).

  2. Open the dev-tools console, click the "register passkey" button.

  3. 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.

For cross-reference, this bug is affecting my "WebAuthn-Local-Client" library, by failing auth-verification in FF (windows, linux, perhaps mac?).

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.

Component: Untriaged → DOM: Web Authentication
Product: Firefox → Core

This sounds more like an issue with the Web Crypto API.

Component: DOM: Web Authentication → DOM: Web Crypto

@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.

@Kyle, I don't have a token that generates RSA keys handy. Could you attach the SPKI that you get from getPublicKey() here?

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.

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.

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.

Component: DOM: Web Crypto → DOM: Web Authentication
Assignee: nobody → jschanck
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Severity: -- → S3
Priority: -- → P3

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?

Thanks for the reminder. The patch will be in Firefox 132.

Great, thank you!

Pushed by jschanck@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/8162a2ca1e12 vendor authenticator-rs v0.4.1. r=keeler,supply-chain-reviewers
Status: ASSIGNED → RESOLVED
Closed: 6 days ago
Resolution: --- → FIXED
Target Milestone: --- → 132 Branch
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: