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
Carlos Cabanero
2022-Sep-19 22:42 UTC
Webauthn signatures working in the wild, and client-agent support
Thanks a lot for the prompt reply! It definitely does not sound like there is an easy way out of this one. I want to put on the table one more possibility though. On Mon, Sep 19, 2022 at 6:15 PM Damien Miller <djm at mindrot.org> wrote:> 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. >Between sshconnect2.c:sign_and_send_pubkey() and identity_sign(), there is a call to key_sig_algorithm and its output is used for SSH2_MSG_USERAUTH, and so on... key_sig_algorithm makes use of sshkey:sshkey_ssh_name_from_type_nid. The issue there is that webauthn and sk both are declared as the same type: KEY_ECDSA_SK. At the moment webauthn-sk is considered just a signature only type, per sshkey:keytypes, and per your "experiment", the pubkey type is made sk-ecdsa. But, trying to force things, if you create the pubkey as webauthn-sk-ecdsa, sshd will log you in if you add webkey-sk-ecdsa as an Allowed Pubkey Method. As you said, it is a violation that the key and signature are different, but could a case be made to grant webauthn-sk-ecdsa the full "key type" status? At the end of the day, it is not fully true that KEY_ECDSA_SK and Webauthn represent the same type of key, even if until now things have been "forced" to fit that way. I may be missing something or not have the full scope of a change like that, but just want to run it through you to see if it may be a viable possibility. Thanks again!