gnome-keyring deals poorly with 'verify-required' ssh "SK" keys
Since a little while, SSH has support for offloading encryption to your FIDO U2F token. This works more or less OK with gnome-keyring until you get the "verify-required" option involved. This option means that the U2F token PIN will be required on each signing operation.
Given a capable token (like Yubikey 5 with newish firmware), you can create such a key like this:
$ ssh-keygen -t ed25519-sk -O verify-required -O resident
In this case, you end up with a key that can't be added to the agent, because the current version of the agent (openssh-8.7p1-3.fc35.x86_64, but also upstream git) doesn't support the agent asking for the PIN each time. You get this message:
$ ssh-add .ssh/id_ed25519_sk
FIDO verify-required key .ssh/id_ed25519_sk is not currently supported by ssh-agent
which is caused by this piece of code in ssh-add.c (from git):
if ((private->sk_flags & SSH_SK_USER_VERIFICATION_REQD) != 0) {
fprintf(stderr, "FIDO verify-required key %s is not "
"currently supported by ssh-agent\n", filename);
goto out;
}
(ie: the check is done in ssh-add
itself).
This situation normally doesn't create any problems: since the key can never be added to the agent, ssh
has to deal with it for itself, and it's perfectly capable of doing so.
The starts of the problem comes because gnome-keyring advertises any *.pub
files it finds in ~/.ssh
as if they were already added to the agent. That's pretty much the entire purpose of the code in daemon/ssh-agent/gkd-ssh-agent-preload.c
, as called from op_request_identities()
. Indeed, you can see the key in the output of ssh-add -l
, even though it would never actually be possible for this key to be added to the current (or any existing) version of ssh-agent
:
$ ssh-add -l
256 SHA256:fAxxFFykCijTdrVUUjbbi2TWfCWtOiafhuBhgG7siGg ssh: (ED25519-SK)
This trips up ssh
. It sees that the agent claims to support this identity, and when the server also allows that identity, it asks the agent to take care of it. That's where the real troubles come: normally from op_sign_request()
we deal with this by calling ensure_key()
which loads the key into the agent "just in time", before passing the sign request through via relay_request()
. Of course, ensure_key()
fails, and we end up with this in the journal:
Dec 22 22:20:04 fedora gnome-keyring-daemon[1598]: the /usr/bin/ssh-add command failed: Child process exited with code 1
Dec 22 22:20:04 fedora gnome-keyring-daemon[1598]: FIDO verify-required key /var/home/lis/.ssh/id_ed25519_sk is not currently supported by ssh-agent
So basically, gnome-keyring has advertised a key as being available, even though it has no hope of ever being able to actually add that key.
Fortunately, there's a relatively simple workaround for the time being: ssh
itself will look for the private half of the key (~/.ssh/id_ed25519_sk
) whereas the "preload" functionality in gnome-keyring is based on finding the public key files. Removing the public key file, or renaming it to have an extension other than .pub
will solve the issue.
A real solution is tricky. We could open the private component of the key file and look for the SSH_SK_USER_VERIFICATION_REQD
flag (as ssh-add
does) and exclude the key from the listing in that case. It seems that if the key has a passphrase then you need to decrypt it first (which isn't something we'd generally be able to do in the preload code).
It's also tricky because some day, ssh-agent
will probably grow proper support for this, and then any check we've added will need to be removed or disabled. It's not clear if there is or will be a feature negotiation that we could query for that change: the check in ssh-add
is pretty much hardcoded (presumably under the assumption that it lives in the same package as ssh-agent
and can be updated when the appropriate time comes).
So basically: here's a well-understood problem, but one with no clear solution. Sorry. :/