U2F Support in OpenSSH Head
marc.infoThis is awesome, I can now have hardware backed SSH keys without any PKCS#11 or gpg-agent in the mix. A blue security key is enough.
You can use U2F with SSH today by making U2F a pam authentication requirement... though this normally requires some copy and paste of the u2f challenge and response since your terminal doesn't know to do that and the ssh client software itself doesn't recognize the U2F challenge.
Making it easier would be really nice.
The linked post really unclear to me about the security properties provided. This document ( https://github.com/openssh/openssh-portable/commit/57ecc1062... ) is a least a little more clear about what its doing, though it doesn't make an explicit statement about the intended security properties. (So I can't tell if what I'm about to describe is a security break or just simply an attack outside of the security model.)
The language of the post implies, or at least is likely to be read as claiming, that an attacker has to possess the id_ecdsa_sk private key and that a compromised token wouldn't be enough to break your security. This is not the case.
Lets imagine that your U2F device maker is totally malicious or at least the manufacture of your device compromised (e.g. by substituting it in the post)-- under this assumption they know all the secrets in the device and have tampered with its signing procedure.
Given my understanding of the protocol, under that threat model this form of ssh auth is totally insecure: the device can exfiltrate the key-handle (or just the derived private key itself) via the ECDSA nonce.
For example, the token knows some attacker pubkey Q, It takes its current secret x and does ECDH with that and Q, hashes the result with the message being signed and uses that as k. The attacker can observe a single signature, compute the same k then just calculate the user's x which is enough for them to authenticate as the user using ecdsa-sa.
A simple variation of this allows the device to leak 32-bits of data per signature: use the shared secret to index into an error correcting code over the data-to-be-leaked, and grab 32-bits and add it to k. The leak would allow the attacker to get the key-handle of a third party site without ever having to observe an authenticating signature to that site. N bits of additional secret can be learned by the attacker after observing N/32 signatures.
I'm a little unclear about how the enrollment procedure works, but I think nothing about it actually certifies that the public key returned by the device was generated based on the transmitted key handle... If, as I suspect, it doesn't a malicious device doesn't need to bother with any of the above nonce sidechannel stuff, it can simply return a static pubkey regardless of the key handle and simplify the process and the attacker can simply guess your usename and then look up the key in their database to login as you.
As such, I don't believe users should consider use of "ecdsa-sk" to be two-factor... and for ones where their threat model includes attackers that could tamper with the hardware manufacture or shipment (e.g. certainly any major state attackers), they should probably not use this authentication mechanism without an additional effort to use strong two factor auth of some kind. (and it would be kind of unfortunate if it reduced their security to just a crappy user-provided password...)
I think this is really unfortunate missed opportunity, and potentially an unprecedented increase in exposure of boring ssh installs to state attackers. Use of a HW token is a massive security increase against less cosmic attackers, but users shouldn't have to choose between security against weak attackers and powerful ones.
The authentication procedure could have simply included a second ec point in the pubkey (or made the "pubkey" a hash for two ec points which are provided in the signature) and the authentication could have included an additional signature made with an ordinary private key stored in the key file and never presented to the U2F device. This way a malicious U2F device alone wouldn't be enough to compromise the user security, an attacker would also need to steal the key file. This security improvement wouldn't hurt the usability of the system at all, because honest use also still requires the key file. [Super-extra-paranoids-bonus: the second key could be a better trusted curve, or even a PQ safe cryptosystem like SPHINCS]
If the goal wasn't to require the key file-- why store the key handle there at all and not just derive it from data sent by the server as in a more typical U2F application? The only other advantage I see is potentially limiting some cros-domain attacks (e.g. where server A provides server B's key handle).
> If the goal wasn't to require the key file-- why store the key handle there at all and not just derive it from data sent by the server as in a more typical U2F application? The only other advantage I see is potentially limiting some cros-domain attacks (e.g. where server A provides server B's key handle).
I was also a little surprised this isn't used as a second factor, like Universal 2nd Factor is meant to be used. But maybe it's not so surprising given there are at this moment probably more U2F keys than FIDO2 keys in users' hands and the author chose to went with the option that has a bigger installed base.
FIDO2 offers resident keys[0] where a unique key is generated and stored on the authenticator. The server does not need to present the key handle to the authenticator so it can decrypt it and initialize its internal state. The server gets back the userHandle[1] that was set during registration as well.
Protecting the resident credential(s) can be done via a PIN or fingerprint scan, depending on the capabilities of the authenticator and user preference.
[0]: a. https://auth0.com/blog/a-look-at-webauthn-resident-credentia... b. https://www.w3.org/TR/2019/REC-webauthn-1-20190304/#resident...
[1]: https://www.w3.org/TR/2019/REC-webauthn-1-20190304/#user-han...
You can use it as a second factor by configuring the server to require both password & key with the "AuthenticationMethods" directive
You can also configure it to require public key + U2F by specifying pubkey auth twice which will require two different pub keys but I suppose that would depend on the user having only 1 regular pubkey and one U2F pubkey in their authorized_keys file
> I was also a little surprised this isn't used as a second factor, like Universal 2nd Factor is meant to be used. But maybe it's not so surprising given there are at this moment probably more U2F keys
Even with just U2F, the public key you install on the server could include both the "key handle" and the derived public key... then the ssh client doesn't need to know anything (except perhaps that its should prompt you to use the device).
The author says: "I'm pretty excited about this feature so please give it a try and let me know your feedback."
Have you considered replying to the thread with your feedback? It's not released yet, so there's likely plenty of scope to adjust the implementation.
I emailed the author concurrently with this post. :)
Neat, Can you update us with their reply? :)
I absolutely will. I offered that they could reply directly and I'd update-- or that they could come school me in public if they disagree with me and preferred to reply in public. :)
Yes, please update this thread!
It's not clear now how "then just calculate the user's x" works?
With standard (non-pairing) ECC signatures every signature uses a secret nonce.
These discrete-log signatures can be understood as a linear equation with one known, the signature itself, and two unknowns, the nonce and private key. You can verify the signature without the secrets because linear systems also hold when projected into an elliptic curve group. The verifier knows the EC image of the private key-- that's the public key--, and the signature includes the EC image of the nonce, so they can check the system by projecting the signature into the EC group and checking that the equation holds there.
However, if an attacker knows the nonce they can simply calculate the private key because they will have an equal number of knows and unknowns, like any other exactly determined linear system. (Similarly, if you have multiple signatures with a known linear relation between the nonces and between the secret keys-- again, you can solve for the key.)
To make this concrete, here is a r,s schnorr signature:
[Notation: lower case variables are elements of finite field, upper case are elements of a cyclic group where the DL problem is presumed hard (elliptic curve points), the group operation is notated as addition, G is any generator of that group, and hash() is some cryptographic hash that produces values in the finite field.]
The verification equation is simply the signing equation re-orderd to put k on the left and multiplied by G, because the verifier only knows xG (the pubkey) not x-- and they can't 'divide out' G to check the signature because they can't solve the discrete log problem... but they can multiply G by a field element where its missing.secret-key: x // Hopefully random public-key: P = xG signer's nonce: k // Hopefully random signature: {R,s} where R = kG, s = k + x*hash(R||message) Verifier checks: R == sG - P*hash(R||message)Now imagine you don't know x but you have a valid signature {R,s,message} where you happen to know the k being used. You can derive x:
This is literally just rearranging the signing equation to get the x alone on the left hand side. The case for related nonces (e.g. nonce reuse) is hardly any more complicated.x = (s - k) / hash(R||message)ECDSA is equivalent but the formulas are just a little messier.
Now, how does the attacker go about knowing k? If they control the signing software, it's easy. The attacker picks a secret x_2 and computes a pubkey Q = x_2 G and embeds his pubkey in the malicious signer. Instead of making k random, set k = hash(xQ || message), x being the user's secret key. The attacker computes k = (x_2 P || message). Both k's are the same value because both xQ and x_2P are equivalent to x * x_2 * G-- this is just ECDH. So the attacker, and _only_ the attacker, knows your k... yet k is different and random looking for each message. If the attacker wants to be extra lazy, they can skip the ECDH but then someone who reverse engineers a compromised signer will also know all the Ks.
This attack is slightly aided by the existence of the de-randomized nonce procedure of RFC6979 or EdDSA, because in those k is supposed to equal effectively hash(x || message), instead of being actually random-- which looks a lot like our tampered equation and to someone who doesn't know x they're indistinguishable-- if you sign the same message multiple times you'll get the same signature. It's not at all surprising for a signer to behave 'non-randomly' in this manner.
The attacker can also leak out some additional data-- say up to 32-bits per signature-- by making the signer's k not be identical to their computed k but merely close to it. Then they can subtract off their computed kG from R and look up the discrete log in a precomputed table (and with a meet in the middle the table can be made small, for fun).
Because k is necessarily private its very hard to determine if k was set faithfully or instead was the product of some malicious process. There are ways to guard against a malicious hardware token by using a marginally trusted host to help randomize the nonce, but no one implements them.
Anything that makes SSH authentication secure and easy to use is a win for me and many others!
Just wondering, is there an NFC-based U2F key out there? Would really like being able to use that with my phone as well if an app can support it.
The Yubikey 5 NFC [0] has NFC and works in Android.
Theoretically you could probably hack the U2F device protocol to _be_ your ssh key.
I've switched to using GPG and GPG-Agent as my SSH identity however. I keep my PGP key on a Nitrokey and keep it with me.
> Theoretically you could probably hack the U2F device protocol to _be_ your ssh key.
That's exactly what this is.
I see this now. When I first glanced at it, I thought it was another PAM module
Is the Nitrokey supported? I didn't see it.
I understand OpenSSH is going to support the FIDO U2F standard in which case all standard-conform implementations would work, including Nitrokey FIDO U2F devices.
Nitrokey start works with openssh and the pkcs11 lib from (IIRC) opensc.
Yes, this works since ages. Here are details: https://www.nitrokey.com/solutions/sichere-administration-vo...