w3c / webauthn

Web Authentication: An API for accessing Public Key Credentials
https://w3c.github.io/webauthn/
Other
1.17k stars 170 forks source link

Which "pubKeyCredParams" to use? #1757

Closed dagnelies closed 1 year ago

dagnelies commented 2 years ago

Hi,

I noticed that during credentials.create(...), if the list does not contain what the authenticator can provide, the authenticator will not be included in the list of authenticators to choose from. For example, if you don't include "alg":-257, Windows Hello won't work.

Now, as a relying party this all sounds a bit like unknown mysteries.

In practice, using this list restricts your choice to a subset of authenticators available... if you manage to find out which algo is needed. Also, most RPs are not deeply knowledgeable about which crypto algorithms is better suited or not.

So ...are all common authenticators covered by RS256 and ES256? Or should you as an RP add some more to cover most authenticators? Which ones?

MasterKale commented 2 years ago

It's true that you need to explicitly set -257 to get Hello to work. At Cisco we've managed to support all known authenticators with just -7 and -257 in pubKeyCredParams. Anecdotal, yes, and unfortunately I don't know if the spec can be so prescriptive...

MasterKale commented 2 years ago

And for anyone interested: based on some extensive testing I did a few months back of in-the-wild authenticators, most everything I tested only supported -7 ("ES256"), with the exception of Windows Hello which was only -257 ("RS256"). Only the YubiKey 5C, 5Ci, and Bio also supported Ed25519 (-8, "EdDSA").

emlun commented 2 years ago

The short answer is that you should set pubKeyCredParams to include all algorithms whose verification procedure you support. But that of course leaves the question of what's the minimal set of algorithms you should support.

As @MasterKale points out, ES256 and RS256 is a good start. This is what pubKeyCredParams defaults to if you don't specify it. CTAP1 (U2F) authenticators are hard-coded to only support ES256, and most CTAP2 devices support it too.

So I'd recommend at least ES256 and RS256 as a baseline. Beyond that it's up to the RP how much effort to spend on supporting additional algorithms. If you use a library for signature verification, you should probably support everything supported by the library.

timcappalli commented 2 years ago

Please use fido-dev@fidoalliance.org (register here: https://groups.google.com/a/fidoalliance.org/g/fido-dev) for implementation discussions. This repo is for the WebAuthn specification itself.

dagnelies commented 2 years ago

Well, I asked since it's not written in the specs which algorithms you should support as an RP. Currently the specs says "the signing algo could be anything, good luck!" Which is IMHO not ideal.

And for anyone interested: based on some extensive testing I did a few months back of in-the-wild authenticators, most everything I tested only supported -7 ("ES256"), with the exception of Windows Hello which was only -257 ("RS256"). Only the YubiKey 5C, 5Ci, and Bio also supported Ed25519 (-8, "EdDSA").

Since apparently all authenticators use either of those three algorithms, it would at least make sense to hint it in the specs.

One could question even further if the specs should constrain the usable signature algorithms to those three. In that case, the pubKeyCredParams could even be dropped/deprecated since it becomes useless. Just specifying that authenticators and RPs agree on a subset of crypto algorithms is enough to ensure compatibility.

cyberphone commented 2 years ago

The idea is to let algorithms evolve including support for quantum safe ditto.

It would though be useful creating a separate "living" algorithm document so that RPs can see what the current options are and which are deprecated.

Having a default doesn't work because then a RP may be get a registration for a "new" algorithm which it isn't yet prepared for. Therefore specifying the algorithms that the RP understands and accepts remains a viable solution.

dagnelies commented 2 years ago

Well, the question is what is better...

  1. If the authenticator uses another algorithm than in the pubKeyCredParams list, it will simply not appear in the list in the browser pop up. For a user, it is basically like it does not exist and the RP does not know about it.
  2. In the other case, if the RP receives an unknown algo, it can simply reply "Sorry, your device is not yet supported" and both the User and the RP know what's going on.

I personnally prefer to be informed and receive explicit errors rather than having the device simply not listed.

Moreover if the empty list is used with pubKeyCredParams it will be filled with defaults. Therefore, you might receive new unknown algos anyway. ...and this has already changed in the past rather discretely.

Lastly, I don't think signing algos evolve that quickly and this sounds like YAGNI. For instance, the JWT spec from 2015 still uses the same list of signing algos as today.

If the "supported signing algos" are specified, you know which set you need to support instead of guessing wildly. Moreover, if the specification updates this list in the future, you also know which one you have to add support for ....instead of having to guess wildly again and be taken by surprise.

From a dev POV, it would also make sense if the JWT signing algos could be used, since broad support is already available in all programming languages. It's just nice to have RFCs share a same set of algos (ideally using the same names) instead of different subsets.

MasterKale commented 2 years ago

I'm going to turn this into an editorial PR that suggests RP's can benefit from wide authenticator support if they support -7 -257. By having it laid out so explicitly I think it'll help RP's understand and move on to more important questions about WebAuthn use.

Firstyear commented 2 years ago

I noticed that during credentials.create(...), if the list does not contain what the authenticator can provide, the authenticator will not be included in the list of authenticators to choose from. For example, if you don't include "alg":-257, Windows Hello won't work.

Worth pointing out that in the windows Hello attestation, there is SHA1 used over the signatures which can be potentially a secuirity risk, so you need to check for the use of RS1 in some internal code paths and reject if found.

So ...are all common authenticators covered by RS256 and ES256? Or should you as an RP add some more to cover most authenticators? Which ones?

And ED25519 (EDDSA) is the other one. We have been running a compatibility tester as part of webauthn-rs and "in the wild" we have only seen RS256, ES256 and EDDSA ( '-8' ) .

It's also worth noting that there are some authenticators that will ignore the list you send of pubkey params and well send whatever they feel like to you (looking at you Android ...). Part of our test is "what happens if you remove the primary cred type that the authenticator likes to provide". Many fail (correct), many provide a fallback alg (also correct), and some ignore you and yeet whatever they like (not correct)

nuno0529 commented 2 years ago

For the RP which want to pass FIDO2 server certification, the 3 algos mentioned above are marked as required, https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#other I can't say for FIDO if this is an out-of-date document or any strong opinion here, but for sure it's a little useful to your question about compatibility. Besides, I can't see any other spec or document says for that, except https://github.com/w3c/webauthn/blob/main/index.bs#L2772 for user agent's compatibility.

And for what algos authenticators can support what, a good approach is to check the FIDO MDS and there is a copy of the latest data under https://github.com/opotonniee/fido-mds-explorer/blob/main/mds.js and that is monthly updated from FIDO MDS3. You can search for the public information about how many other authenticators can support "alg": -8 or other algos. But obviously, MDS3 is optional and it's only for some authenticator vendors which want to have relative certifications and agree to publish the metadata information.

MasterKale commented 2 years ago

I'm trying to figure out the best place to put such an editorial blurb. There are currently maybe three places that I see as candidates:

  1. Sample code in the registration examples: https://www.w3.org/TR/webauthn-2/#sctn-sample-registration
  2. Step 10 in createCredential() steps: https://www.w3.org/TR/webauthn-2/#sctn-createCredential
  3. This section on Easily Accessing Credential Data: https://www.w3.org/TR/webauthn-2/#sctn-public-key-easy
  4. The section in PublicKeyCredentialCreationOptions about pubKeyCredParams: https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-pubkeycredparams

I'd like to put this addition in #4 as it feels like it has the best chance of an RP dev seeing it as they're trying to understand all the options. That said, it'd mean creating a fourth place to need to keep up-to-date as future algorithms get introduced. If putting an editorial suggestion to use -256 and -257 (and maybe -8 now) here has the greatest chance of being the most clear recommendation on which algorithms an RP should put into pubKeyCredParams (or suggesting not specifying a value for pubKeyCredParams so the defaults in #2 are used), then maybe I include further changes to these other sections to reference #4. Thoughts?

BTW #2 is missing a reference to -8 that exists in #3, is that something we should reconcile? And perhaps we should consider updating #2 (in a separate issue) to prioritize Ed25519 keypairs (by putting -8 first) now that it's in the wild 🤔

Firstyear commented 2 years ago

@MasterKale Or you add a new section and link to it from those locations so that it's only one place? Saying that it's a bit of a weird situation because the webauthn spec is the "only dev guide" today, when really this is an implementation detail and requires more than just "use these algos" because there is a lot going on.

MasterKale commented 2 years ago

...this is an implementation detail and requires more than just "use these algos" because there is a lot going on.

It doesn't help that the spec is prescriptive about specific algorithms (-256, -257, and -8), but leaves the door open for support of other algorithms (that RP's would have to somehow track independent of the spec.)

emlun commented 2 years ago

@MasterKale by -256, did you mean -7 (P-256)?

I think (4) pubKeyCredParams is the most appropriate place to put this guidance. I agree that's where an RP dev is most likely to see it. (1) should ideally agree with whatever we put in (4), but shouldn't be the primary authoritative source. I don't think this is necessarily related to the algs list in (3). (2) and (4) should probably be the same, but I'm not sure if it's appropriate to have them reference each other. But if so, (2) should probably reference (4) rather than vice versa.

It would be nice to recommend [] to fall back to the default, but it's not backward-compatible with browser implementations still on L1, so I'm not sure it's a good idea. (...although I suppose you could feature-detect on e.g. window.AuthenticatorAttestationResponse.prototype.getPublicKey === undefined to distinguish L1 clients. But that gets pretty involved - and in the end you'd still need to choose a pubKeyCredParams value for L1, so you might as well always use it.)

WordlessEcho commented 1 year ago

For developer: tldr use -7 (ES256) -8 (EdDSA, for Yubikey), -7 (ES256), -257 (RS256)

I do some research of Windows Hello (22H2), Apple Passkey (iOS 16.2 (20B82)), and Android Passkey (Chrome Canary 110.0.5428.0, Android 11 RSR1.201211.001, GMS 22.44.17 (150800-488410709)). Windows (authenticatorAttachment: 'platform'): -257 (RS256) and -7 (ES256) is supported. If you specify unsupported algorithm, you will get DOMException: The operation either timed out or was not allowed. See: https://www.w3.org/TR/webauthn-2/#sctn-privacy-considerations-client. on Chrome and DOMException: The operation failed for an unknown transient reason on Firefox. iOS: -7 (ES256) is supported. Passkey will prompt "can not finish this operation" after you finish biometrics verification. Android: -7 (ES256) is supported. DOMException: None of the algorithms specified in `pubKeyCredParams` are supported by this device.

For hardware key (tested by Yubikey 5C, FIDO 2 PIN is set, firmware 5.4.3): Windows: If you leave authenticatorAttachment default with unsupported algorithm, Windows Hello will directly ask for hardware key. If unsupported algorithm for key is specified, an error message will be flashed once quickly then return to ask PIN for key (loop). iOS (via NFC): If unsupported algorithm for key is specified, you will stuck in "insert your key". No indicates or prompt. Android: You won't see any interface if you specify unsupported algorithm for Android. Even if authenticatorAttachment is set to cross-platform. So I can't continue to test because I don't have hardware key that doesn't support -7 (ES256).

Without PIN: Windows: Prompt "Cannot read your security key. Please retry." iOS and Android: Same as PIN set.

MasterKale commented 1 year ago

For developer: tldr use -7 (ES256)

The three algorithms I've thought lately we can safely suggest within the spec are, in this order:

I'd put -8 at the top of the list to encourage adoption of Ed25519, since authenticators that can support it will choose to use it if it's first on the list (in my experience this is basically YubiKey 5's, but I think SoloKeys support it too). After that -7 and -257 are the two that practically cover almost 100% of existing authenticators.

I wouldn't drop -257 just yet, even if signs are that platform authenticators used via Windows Hello will start using ES256, because of how long older versions of Windows can stick around.

Thanks for bumping this up, it reminded me that I need to get started on this 😅

Firstyear commented 1 year ago

We have issues with ed25519 in webauthn-rs just because it's not properly supported in the ecosystem cryptographically, but that's "our problem".

RS256 is okay, but the risk is sometimes they'll be signed with RS1 (yes, sha 1) so implementors need to be careful of that.

dagnelies commented 1 year ago

For developer: tldr use -7 (ES256)

Well, depending on your Windows version, you might fall on your face. Until recently only RS256 was supported for Windows Hello. Dunno when exactly this changed.

There is also quite some discrepancy between the "real world" and the implementations of the "big three" and the specs here, and both evolve at different paces. It's already good that the spec trimmed down the recommended algos to three.

WordlessEcho commented 1 year ago

For developer: tldr use -7 (ES256)

Well, depending on your Windows version, you might fall on your face. Until recently only RS256 was supported for Windows Hello. Dunno when exactly this changed.

There is also quite some discrepancy between the "real world" and the implementations of the "big three" and the specs here, and both evolve at different paces. It's already good that the spec trimmed down the recommended algos to three.

Okay. I made some change for my comment. But I wish EdDSA will be supported by Microsoft, Google and Apple. )

petrdvorak commented 1 year ago

... I retroactively wonder what is the benefit of recommending multiple algorithms... More work, less compatibility, slower adoption... Can you see any hard benefits over just recommending: "Use ES256 at a minimum" (which is universally supported in all new systems)? Mixing RSA with EC in one codebase on a server just adds complexity, while almost nobody ends up using RSA these days so the complexity (as I see it) does not bring much value.

petrdvorak commented 1 year ago

To better explain my perspective... We are finalizing a new FIDO2 product and we will need to end up building abstraction for legacy RS256 and still a bit "exotic" Ed25519 just so nobody ends up using it when we are done. The recommendation just puts additional dead weight in our software.

MasterKale commented 1 year ago

Windows Hello still uses RS256, and of course it won't be an overnight transition to anything else even if Microsoft's passkeys support flips Windows over to using ES256 exclusively. RP's have to build to what's in the market, and so I think it's still important to help RP's support use of RSA with WebAuthn even if it's seen as "legacy support".

petrdvorak commented 1 year ago

@MasterKale Understood, and thank you for the prompt response. 👍 I am thinking the recommendation could maybe be worded as:

    [=[RPS]=] MUST support the following {{COSEAlgorithmIdentifier}} value:

    * -7 (ES256)

   [=[RPS]=] that wish to support a wide range of [=authenticators=], including some legacy ones,
   SHOULD also include at least the following {{COSEAlgorithmIdentifier}} values:

    * -8 (Ed25519)
    * -257 (RS256)

    Additional signature algorithms can be included as needed.

This approach will both:

ES256 is already widely adopted, not only in WebAuthn but also when working with JWTs. I think making this the default could speed up WebAuthn adoption (as even small website makers will be able to provide minimalistic implementations). I will first sleep on it to see if this sounds like a good idea in the morning 🙂 and if it does, I will try to draft a PR - in the worst case, it gets rejected with some comments, which is fine.

emlun commented 1 year ago

I think that in practice, the majority of RPs will most likely use an external library to implement WebAuthn signature verification. In that case they usually shouldn't have to do anything extra to support the additional algorithms, all of that work is on the library developer.

The main exception I can see is platforms like Java where you need to provide JCA providers for each algorithm, but even there the common ones are built in on recent JRE versions.

petrdvorak commented 1 year ago

@emlun Agreed. We are makers of such a back-end system for banks, considering adding WebAuthn support and seeing close to zero benefits in implementing RS256 and Ed25519 because these will be rarely used. Plus, we have an idea on how to build WebAuthn back-end in a more creative way to simplify enrollment to service providers, and we are reluctant to support RS256 there because of the "old Windows problem."

Still need more sleep actually to make any move there. Maybe we are too "pragmatic" and I sure understand the "broader industry view" to formally support more algorithms despite not being really used.

MasterKale commented 1 year ago

We are makers of such a back-end system for banks, considering adding WebAuthn support and seeing close to zero benefits in implementing RS256 and Ed25519 because these will be rarely used. Plus, we have an idea on how to build WebAuthn back-end in a more creative way to simplify enrollment to service providers, and we are reluctant to support RS256 there because of the "old Windows problem."

This is starting to get into "product requirement" territory. If you decide you don't want to support RS256 or Ed25519 then that's your decision as the product owner. Your customers will ultimately decide whether that's viable long-term.

However "supporting as many versions of Windows as possible" is likely to be a requirement for the majority of other projects. Therefore I'd suggest we keep the current guidance as-is because the spec should aim for maximum support of the API.

petrdvorak commented 1 year ago

@MasterKale Yes, I get that... But then why not support all other algorithms on the same level? This would broaden the range of supported authenticators, right? I think this is one of the situations of "if we do not specify default choice, people will just make choices and use everything" (which - again - might be right). I don't want to push this too hard - you are doing an excellent job with the activity and we are excited about WebAuthn. But looking at legacy Windows authenticators (people with old Windows can still use Passkeys or USB authenticators) is exactly the type of anchor that will eventually hold the activity back.

dagnelies commented 1 year ago

@petrdvorak we're not looking at "old Windows legacy systems", it's about the "latest Windows 11" 😉

petrdvorak commented 1 year ago

@dagnelies I will do some testing (... Mac user here 🐑 ) but Hello should support ES256 too.

MasterKale commented 1 year ago

I think I remember being surprised by an ES256 response from Windows 11 at some point, but with Windows 10 and slower-updating (enterprise) installs of Windows 11 still out in the wild, I don't think RS256 is going away any time soon.

I think this is one of the situations of "if we do not specify default choice, people will just make choices and use everything"

But the L3 spec now does suggest a default choice:

https://w3c.github.io/webauthn/#dom-publickeycredentialcreationoptions-pubkeycredparams

This is, admittedly, based on observation of actual algorithms being returned out in the real world (-7 and -257), with a sprinkling of "this is great to use if it's available" (-8.) If at some point an algorithm stops being used, or a newer, better algorithm gains traction in the authenticator space, then we should absolutely update this list.

petrdvorak commented 1 year ago

@MasterKale Agreed. Chrome actually complains when JavaScript does not request both -7 and -257, so as far as Google is concerned, these two are the minimum.

Screenshot 2023-05-03 at 18 31 40

The choice of -8 is pleasing to the "cryptographer me" (the algorithm is indeed "interesting"), but I am a bit puzzled about why this is the first choice on the list as this is not really reflected by any dominating position of the algorithm on the market...

petrdvorak commented 1 year ago

But anyway, I think this discussion was helpful for me, and thank you for the patient responses. I think no change is needed, we will start with just supporting -7 and if we see our customers scream, we will revisit our options. 🙂

antonymott commented 6 months ago

@MasterKale, petrdvorak and other contributors: thanks for this discussion which I find very useful, and even though closed now, perhaps useful to add April 2024 update on my experience with algorithm order.

I'm doing webauthn from scratch with a library mentality, and expect most of my customers to be early-adopters or mobile users with standard platform biometrics (touch or faceid). I thought about not supporting ancient windows Hello users, but I also had those chrome warnings when I left out the legacy -257.

I followed Matthew's suggestion and reorganized my algs to put -8 first, to encourage the more current algorithms to bubble up...sure enough latest Chrome used -8, and ignored -7 which was second in my alg list. I did keep last the -257 alg.

If it helps anyone else, the publicKeyBytes (CBOR) contain the algorithm as a signed int in the '3' field, however to avoid extracting and decoding the CBOR to get it every time, I created another int column in my webauthn table just for the algorithm. Now it'll be easy over the next year or so to measure what percentage if any of my customers created keys with the old -257 alg. If anyone is interested in the metrics as they evolve, shout out, and I'll post the metrics here or somewhere more useful as soon as I've gathered a statistically useful volume of 'in the wild' info.

Exciting technology: the way forward!

coolaj86 commented 1 month ago

I'd put -8 at the top of the list to encourage adoption of Ed25519, since authenticators that can support it will choose to use it if it's first on the list.

Can someone perhaps get a message over to the WebCrypto people to make a stronger recommendation for Ed25519 support in the browser itself?

I'm looking at 1mb of libsodium in this demo, and that's a big deterrent to adoption for me. Demo: https://mylofi.github.io/webauthn-local-client/

Verifying the the signatures and whatever else without the native browser support makes for a lot of bloat.

Also, I see a references to regResult.response.attestationObject being CBOR, so that would need to be made browser-native as well for adoption to really kick off (at least for devs that are conscientious about load times)?

antonymott commented 1 month ago

@MasterKale and to anyone else interested, here's an in-the-wild stats update to my April 2 comment that indicates more adoption of EdDSA. Thanks partly to MasterKale's useful youTube vids and various github comments, my authenticator listed 3 algs in the order [-8,-7,-257]. After 5 months of in-the-wild usage with approx 900 users, roughly half authenticated with ES256 (-7), roughly half with EdDSA (-8) and less than 1% used legacy -257.

MasterKale commented 1 month ago

@antonymott Thanks for reporting back! That's very encouraging to see how commonly Ed25519 is being supported! Have you tried to understand how many of those are security keys vs platform authenticators? If I had to guess all the -8 are security keys 🤔