Carlos Cabanero
2022-Sep-19 20:33 UTC
Webauthn signatures working in the wild, and client-agent support
Hey everyone! We just added support (maybe a first?) for Webauthn keys in Blink. Everything seems to be working great except in one scenario, using them with our agent. You can see a quick demo here: https://twitter.com/BlinkShell/status/1570427813819486212?s=20&t=2GNv08ro2zyBcI14DK4tIA The implementation is making use of Passkeys and Secure Keys with Webauthn support. I think the interesting part is how easy creating and using keys like this is, and maybe future use cases would showcase more possibilities for Webauthn keys. This is all based on Damien Miller?s test projects (thanks a lot!) but as mentioned, the Client-Agent (at sshconnect2.c) will not accept webauthn-sk signatures at the moment. The setup is that we use our Agent to forward a key to the remote. Then when trying to sign with this key, the SSH Client is expecting a sk-ecdsa signature type, but our agent can only provide a webauthn-sk-ecdsa type. The issue seems to be that the sign_and_send_pubkey will expect a sk-ecdsa signature in all cases, and not a webauthn-sk-ecdsa. We have been reading the code to see if we could bend things somehow, but it looks like everywhere that a transform from key to signature-algorithm happens, will always result in the sk-ecdsa type. We also tried different flags for Accepted Pubkeys, disabling sk-ecdsa, trying to set webauthn-sk type at the top, all with no luck. On the SSHD side when logging in, this is not an issue as both are accommodated during validation. Are we missing something that could make things work? Is there anything from our side that we could do to try things out or to support this scenario? Tons of thanks for any guidance!!
Damien Miller
2022-Sep-19 22:15 UTC
Webauthn signatures working in the wild, and client-agent support
On Mon, 19 Sep 2022, Carlos Cabanero wrote:> Hey everyone! > > We just added support (maybe a first?) for Webauthn keys in Blink. > Everything seems to be working great except in one scenario, using > them with our agent. You can see a quick demo here: > https://twitter.com/BlinkShell/status/1570427813819486212?s=20&t=2GNv08ro2zyBcI14DK4tIA > > The implementation is making use of Passkeys and Secure Keys with > Webauthn support. I think the interesting part is how easy creating > and using keys like this is, and maybe future use cases would showcase > more possibilities for Webauthn keys. > > This is all based on Damien Miller?s test projects (thanks a lot!) but > as mentioned, the Client-Agent (at sshconnect2.c) will not accept > webauthn-sk signatures at the moment. The setup is that we use our > Agent to forward a key to the remote. Then when trying to sign with > this key, the SSH Client is expecting a sk-ecdsa signature type, but > our agent can only provide a webauthn-sk-ecdsa type.Oh wow, I have not heard of anyone else using this for real before. Nice work!> The issue seems to be that the sign_and_send_pubkey will expect a > sk-ecdsa signature in all cases, and not a webauthn-sk-ecdsa. We have > been reading the code to see if we could bend things somehow, but it > looks like everywhere that a transform from key to signature-algorithm > happens, will always result in the sk-ecdsa type. We also tried > different flags for Accepted Pubkeys, disabling sk-ecdsa, trying to > set webauthn-sk type at the top, all with no luck. On the SSHD side > when logging in, this is not an issue as both are accommodated during > validation. > > Are we missing something that could make things work? Is there > anything from our side that we could do to try things out or to > support this scenario?Unfortunately this webauthn keys via the agent isn't going to work ATM and I'm not immediately sure how to fix it. The problem is between sshconnect2.c:sign_and_send_pubkey() and identity_sign(). In sign_and_send_pubkey() we have to assembled the data to be signed (basically the SSH2_MSG_USERAUTH_REQUEST we're about to send), and that includes the signature algorithm:> if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || > (r = sshbuf_put_cstring(b, authctxt->server_user)) != 0 || > (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || > (r = sshbuf_put_cstring(b, method)) != 0 || > (r = sshbuf_put_u8(b, 1)) != 0 || > (r = sshbuf_put_cstring(b, alg)) != 0 || > (r = sshkey_puts(id->key, b)) != 0) { > fatal_fr(r, "assemble signed data");Unfortunately, we don't learn that the key is only capable of making webauthn signatures until we attempt signing via identity_sign() and observe (via sshkey_check_sigtype()) that we got a webauthn signature back. Perhaps there should be some way for ssh-agent to signal to the client that a particular key can only make webauthn signatures, but I'm not sure how best to do this. It would be best if the agent simply told the client about it but, at the moment, the SSH_AGENTC_REQUEST_IDENTITIES agent request used to obtain the list of keys from the agent has no extra data fields that could be used to signal this. Now, we could extend the agent protocol to add an extra field to carry stuff like this, but that has a number of costs including time-to-deploy (this is less of a problem if you control the agent and the ssh client). One uglier IMO option would be to use the key comment field returned by SSH_AGENTC_REQUEST_IDENTITIES to signal that a key is webauthn only. This is possible, but since comments are user-specified, a user could break their key if they put the magic signalling string in a key comment. Another possibility is abusing the key blob format returned by SSH_AGENTC_REQUEST_IDENTITIES and having the webauthn keys identify themselves as webauthn-sk-ecdsa-sha2-nistp256 at openssh.com rather than as sk-ecdsa-sha2-nistp256 at openssh.com, and add associated plumbing to carry the webauthn-only status of these keys through to sshconnect2.c. IDK how other tools will handle this, as it's strictly a spec violation to use a signature algorithm name in place of a key name (though OpenSSH has hardly been sinless in this regard historically...) Hope this clarifies the problem a little (it sure doesn't solve it though). -d