Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managing FIDO keys #1612

Closed
cyberphone opened this issue May 14, 2021 · 30 comments
Closed

Managing FIDO keys #1612

cyberphone opened this issue May 14, 2021 · 30 comments

Comments

@cyberphone
Copy link

Pardon a question/comment from a person who has just started to work with FIDO/WebAuthn...

I have tested several WebAuthn demos (Duo Security, Yubico, StrongKey) and they all seem to pass on deletion of keys which leaves you with lots of "zombie" keys which then makes the selection process unmanageable. The tests were mainly performed on W10 using resident keys (Windows Hello).

How is this supposed to work? For traditional security tokens (X.509) there always was a built-in manager but not so for FIDO.

Is discovery and deletion supported at the CTAP2 level?

@Firstyear
Copy link
Contributor

Pardon a question/comment from a person who has just started to work with FIDO/WebAuthn...

I have tested several WebAuthn demos (Duo Security, Yubico, StrongKey) and they all seem to pass on deletion of keys which leaves you with lots of "zombie" keys which then makes the selection process unmanageable. The tests were mainly performed on W10 using resident keys (Windows Hello).

This is most likely a fault of those demos - when you delete a key, it should no longer be offered by the relying party which means it should not appear in the selection process.

How is this supposed to work? For traditional security tokens (X.509) there always was a built-in manager but not so for FIDO.

Is discovery and deletion supported at the CTAP2 level?

https://www.w3.org/TR/webauthn-2/#client-side-discoverable-public-key-credential-source

There is a lot of text here in this section, and a lot of language about "resident/non-resident keys" and "discoverable/non-discoverable" credentials. This relates to your question, but I believe that the spec does not communicate clearly with it's language what is really going on.

There are two types of keys available to a CTAP2 device. "discoverable" aka "resident", but better this is a "Persistent Private Key". This is a private key that is stored (resident) in a ring buffer on the authenticator, and the client can "discover" if no other credential ID's are requested.

The second type is "non-discoverable" aka "non-resident" keys, which would be better known as "Ephemeral Key-Wrapped Key". In this mode, the authenticator has a single "primary secret". When you perform an authentication, the credentialid presented to the device is actually an encrypted blob, encrypted by the primary secret. Succesful decryption allows the private key to exist in memory of the authenticator for that operation (ephemeral) and the signing proceeds. After the operation, it is removed from ram.

This is how the devices "appear" to have unlimited storage - when you "delete" the credential from the RP (server, demo site), because you are destroying the "credential id" this means that it is "lost" as it was never stored in the device at all!

I hope that helps explain it.

@cyberphone
Copy link
Author

cyberphone commented May 14, 2021

Thanx @Firstyear for your prompt response!
However, I'm still (very) confused 😵
There is a CM get() which seems (?) to permit enumeration but then when you are about to delete, don't you get into alternative 3 here?
https://www.w3.org/TR/webauthn-2/#sctn-sample-decommissioning

The use-case is very simple. I have an already enrolled credential and I want to remove it. Not only from the server, but from the device.

@Firstyear
Copy link
Contributor

Possibility three only applies to resident keys, which in order for the RP to request, you send an empty array of credential ID's anyway. So this would effectively just mean the server has some "defunct" keys in it's DB, but they are not offered in an authentication ceremony :)

If the user wants to remove a non resident (key wrapped key), they would need to remove this from the RP's specific interface, which would then remove it from their DB, and remove it from subsequent authentications.

So really, the fact you are seeing "zombie" credentials here is because those demo sites probably aren't handling those deletes properly.

@cyberphone
Copy link
Author

I'm not sure I'm following here...

Sticking to resident keys here:
Is there a standardized Web API for deleting a known key from the device?

@Firstyear
Copy link
Contributor

No. The RP would just stop accepting the key in this case.

@Kieun
Copy link
Member

Kieun commented May 14, 2021

There is no Web API for deleting keys from the security keys. But, you can manage your keys through platform provided settings like Windows Hello or you can delete the keys through Chrome settings.
chrome://settings/securityKeys

@cyberphone
Copy link
Author

Thanx @Kieun !
This though makes testing and development considerably more challenging.

In my own application, I would like to clear any possible earlier key (for the domain of course) for each enrollment as the key may have been deleted at the RP. This seems like a possible real-world scenario as well. In an enroll-disenroll-enroll scenario you don't want the confuse the user and you also want to get a freshly attested key. Keeping a registry of disenrolled keys is usually not an option. Requiring users to go to platform specific "settings" does (IMO) only work for experts which defeats the purpose of FIDO.

Maybe I'm just missing something? Reading the WebAuthn specs is not for everybody...

@cyberphone
Copy link
Author

cyberphone commented May 14, 2021

Continuing...
Assume an RP wants to perform an update like replacing an RSA key with an Ed25519 key. Effectively the current credential management scheme seems to presume that you just add keys.

For the FIDO "wallet" I'm working with, this could becomes a major hurdle.
https://fido-web-pay.github.io/

@haxelion
Copy link

haxelion commented May 14, 2021

@cyberphone In that case the RP/FIDO server can communicate a list of "allowed credentials". This permits, in effect, to prevent the client from using "zombie" credentials like you said.

@cyberphone
Copy link
Author

@haxelion You are right. Unfortunately this does not address the testing/development scenario where users are supposed to enroll and disenroll for the same kind of key, and potentially more than once (like I did).

I may (also) be biased because I've been working with a more RP-oriented KM scheme.

Anyway, apparently you cannot delete a key (in a reasonable manner), which was my original concern, so I'm into "workaround hell" 🥵

@Firstyear
Copy link
Contributor

There are many such "work around hells" and traps in webauthn.

@haxelion
Copy link

@cyberphone For our FIDO development and testing needs, our FIDO server has a specific API used to delete a credential from its DB and we have a management interface in our test/demo applications. Since our FIDO server always set the allowCredentials array according to its DB content, the behavior is exactly the same as if we had deleted the credential from the authenticator.

I believe the reason why the client doesn't expose a delete credential API is for privacy reasons: this prevent the RP from discovering all the credentials (from potentially other accounts) managed by the authenticators. This could be used by a malicious RP as a way to break the "private navigation" model or simply a user attempting to maintain separate accounts on the same authenticator.

@cyberphone
Copy link
Author

cyberphone commented May 14, 2021

@haxelion Possibly I am stupid (or simply doesn't know enough about WebAuthn yet), but I don't understand how you can filter away zombie credentials (created when deleting a registration from the DB), for a not yet authenticated user, here referring to authentication rather than registration.

@cyberphone
Copy link
Author

@haxelion It is when I authenticate without user-name I get the zombies. With user-name I understand that there are no issues.

@haxelion
Copy link

@cyberphone Ah yes I was referring to the case where a user ID is used.

@MasterKale
Copy link
Contributor

MasterKale commented May 14, 2021

Assume an RP wants to perform an update like replacing an RSA key with an Ed25519 key. Effectively the current credential management scheme seems to presume that you just add keys.

@cyberphone I think the way to accomplish this is to require the use of resident keys during attestation. Since resident keys are stored internally in the authenticator keyed to rpID + userHandle, replacing a key should be as simple as:

  1. Don't specify the ID of the credential being replaced in excludeCredentials, and require resident keys, in attestation options
  2. Make sure user.id in attestation options is the same as was used last time performing attestation
  3. Upon successful completion, register the new credential in the DB and delete the "old" one

Internally the authenticator will drop the old resident key and replace it with the new one. The RP just has to make sure to clean up afterwards or else it'll have a bunch of zombie credentials. Is this what you were looking for?

I have tested several WebAuthn demos (Duo Security, Yubico, StrongKey) and they all seem to pass on deletion of keys which leaves you with lots of "zombie" keys which then makes the selection process unmanageable. The tests were mainly performed on W10 using resident keys (Windows Hello).

When I read this I instantly flashed on the fact that many demos generate random user IDs every time you perform attestation. If resident keys are being required, or if the authenticator chooses to store a resident key on its own (Touch ID on macOS does this...), you can easily end up with a ton of junk credentials 🙃

Screen Shot 2021-05-14 at 11 50 31 AM

I agree it's frustrating that there's no way to delete these until A) Chrome decides it's important enough to make it into their growing selection of security key tools, and B) platform vendors see fit to add in OS-level UI to manage resident keys.

@cyberphone
Copy link
Author

It is obvious that this is a mess with respect to [some] platform implementations as well:
https://superuser.com/questions/1527685/how-to-remove-webauthn-credentials-from-onboard-tpm-on-win10-device

C:\>certutil -csp NGC -key

Doesn't seem to be exactly what a normal user would go for 🤣

@emlun
Copy link
Member

emlun commented May 16, 2021

There is a cross-platform protocol for this standardized by FIDO, but it's not exposed through WebAuthn to the RP due to the privacy concerns mentioned above. But recent versions of Chrome do already ship a credential management GUI (I believe Windows does too, but I don't have a machine on hand to check) in the browser settings: chrome://settings/securityKeys . At least Chrome 89 has a "sign-in data" section there which allows you to manage resident credentials. Though I will concede that it's a bit buried and not easily discoverable unless you already know to look for it.

@cyberphone
Copy link
Author

Thanx @emlun! Unfortunately it seems that this feature is missing in Windows or is in such an obscure place that mere mortals like me will never find it. chrome://settings/securityKeys doesn't appear to be available either. Fortunately the solution mentioned by @MasterKale reduces the number of "zombie" keys and the user won't see them at all. Aided by a persistent cookie I was able to filter away the zombies.

I may be off track here, but it seems that some kind of scoping feature could improve the multi-key scenario.

@emlun
Copy link
Member

emlun commented May 17, 2021

I'm not sure what you mean by "scoping feature", care to elaborate?

Thinking about what a "delete credential" command in WebAuthn would look like and whether it would be useful if we were to add it... and I think that it would in fact not be all that useful, for a combination of reasons. First off: in terms of security, there's no strict need to delete credentials from the authenticator since the RP can simply stop accepting signatures from them, so the reasons to delete credentials all come from user experience concerns. And I don't think we expect end-users to be fully aware of the difference between resident and non-resident credentials, so a delete command might just add confusion since it is only relevant for resident credentials.

Also, @MasterKale's advice above already solves most of the things a delete command would: you avoid the user being confused by an account picker showing more "accounts" than the user has, and you avoid inadvertently exhausting a user's authenticator storage with replacement credentials. By consistently setting the same user handle for all credential registrations for a given account, you ensure that the user will only see one option (per account) in username-less account pickers. Beyond that, the only real reason to delete credentials from the authenticator is to reclaim that one slot of storage capacity.

But then, that means that deleting credentials only really becomes relevant when authenticator storage is full. This would most likely become an issue when the user is trying to register to a new RP, which of course wouldn't be allowed to delete credentials for other RPs even if WebAuthn did offer a "delete" API. So it might be more user-friendly in that case to just have the client inform the user that storage is full, and (if the authenticator supports it) offer to open credential management where they can delete credentials they no longer need.

@emlun
Copy link
Member

emlun commented Sep 22, 2021

Closing due to inactivity; you're welcome to re-open the issue if there's more to discuss here.

@emlun emlun closed this as completed Sep 22, 2021
@erionpc
Copy link

erionpc commented Nov 30, 2022

Hi. I’ve recently been working on a project involving FIDO2.
While working on this project, I generated several FIDO2 keys on Windows Hello in my laptop using a non-admin account. I now have about 40. I’ve been looking for a way to delete them. The only way is apparently running this command from an elevated powershell:

certutil -csp NGC -key
certutil -csp NGC -delkey

The problem with this is that the archive that contains the keys is user-specific, so when I use an elevated Powershell, I don’t see the keys for my non-admin account. I only see them using my non-admin account (from a non-elevated Powershell), but I can’t delete them from that account.

I’m not sure how to get around this problem.
Any ideas would be appreciated.

@FlxMgdnz
Copy link

We all hope that Windows will soon have a passkey management UI :)

@agl
Copy link
Contributor

agl commented Nov 30, 2022

If you install Chrome Canary you can open chrome://settings/passkeys which should allow you to manage credentials in Windows Hello, assuming that you're using Windows 11 22H2.

@erionpc
Copy link

erionpc commented Nov 30, 2022

I'm using Windows 10 Pro 22H2 on this machine. Chrome tells me:
"To manage passkeys, use a newer version of Windows"
:(

@FlxMgdnz
Copy link

If you install Chrome Canary you can open chrome://settings/passkeys which should allow you to manage credentials in Windows Hello, assuming that you're using Windows 11 22H2.

Thanks @agl, I did not know that and it's very helpful. Will this work on Windows 10 as well at some point? Or are passkeys only happening on Windows 11?

@agl
Copy link
Contributor

agl commented Nov 30, 2022

Will this work on Windows 10 as well at some point? Or are passkeys only happening on Windows 11?

The needed APIs are currently only available on Windows 11. If Windows 10 gets an update that includes them, I believe Chrome will immediately be able to use them, but I've no knowledge about whether that's planned.

@ndpar
Copy link

ndpar commented Dec 1, 2022

If you install Chrome Canary you can open chrome://settings/passkeys which should allow you to manage credentials in Windows Hello, assuming that you're using Windows 11 22H2.

@agl That page seems to be available on macOS as well. What does it show there?

@agl
Copy link
Contributor

agl commented Dec 1, 2022

@agl That page seems to be available on macOS as well. What does it show there?

It shows passkeys from Chrome's Touch ID-based platform authenticator. This predates macOS's native support for passkeys and stores credentials, wrapped by the system's enclave, in a Chrome profile.

@erionpc
Copy link

erionpc commented Dec 5, 2022

The solution I found was to ask for my non-admin account to be added to the Administrators group temporarily, just so I could run

certutil -csp NGC -delkey

from my account with admin privileges. This allowed me to delete the Fido2 keys. I hope the Fido key management API is made available for Windows 10 too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

11 participants