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
Add WinHello support #302
base: master
Are you sure you want to change the base?
Add WinHello support #302
Conversation
5221f2f
to
517dc9e
Compare
|
Just rebased to latest master |
|
Just rebased to latest master |
|
Rebased to latest master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I have left some comments. If you prefer to resume the conversation via e-mail, I am available at pedro@yubico.com. I would also be happy to arrange UV/non-UV keys for testing, if needed. Thank you.
|
Is there any more input on this? I think I explained every design decision, so it would be nice to know if this stuff has a chance to be merged in at all, and if there's still something to discuss or to change in the code or whatever... |
|
@djmdjm ping? |
|
I have merged most of this, but added a couple of comments to the remaining part |
d3fd687
to
0826ac8
Compare
Hi Damien @djmdjm, I changed the pending two patches per your and @martelletto's input, built and tested it under Cygwin. Pleae have a look. Thanks, |
0826ac8
to
4e90fd8
Compare
|
I just merged something equivalent to the |
|
I think that just leaves the |
a01dbfe
to
fb03b93
Compare
Hi Damien, thanks for merging this stuff. In terms of deferring the PIN prompt, after looking at my patch for Tested on Linux and Cygwin with "up"-only keys as well as "uv/up"-keys. Please note that the "You may need to touch your authenticator." message Please see the latest patch I just pushed into this MR. I'm pretty sure As an extension, we could replace the "You may need to touch your so I think that's not feasible. What do you think? Thanks, |
|
Hmm, what are those failures on Ubuntu 22.04? I can't see the error log, unfortunately. |
|
I've pushed a slightly-tweaked version of that last commit as f964809, so I think that is everything. Please take a look and close the PR if you're happy |
I replace the deprecated 18.04 builders with 22.04, but 22.04 made a change to the home directory permissions which tripped up the agent-getpeereid test when it tried to run ssh-add as "nobody". It was fixed by 5a5c580.
There's nothing sensitive in the logs, but I don't know if it's possible to make the logs world readable. I had a quick look at the settings and didn't see anything obvious. Possibly relevant to your interests: I got a Cygwin build working on the Github hosted runners: I'll be adding the "cygwin-release" config shortly, if there's anything else that should be added please let me know. |
If I'm reading https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/using-workflow-run-logs correctly you should be able to see the logs for the public repo as long as you're logged into github itself. "You must be logged in to a GitHub account to view workflow run information, including for public repositories." If that's not the case I'll see what we can do. |
Actually, I can see the logs. I'm just not used to working on github, so I expected an error output in the "Details" view of a CI check. However, this only shows a red line with the text "Error:" and nothing else. Your reply here got me thinking and I searched for other ways to see the logs and, lo and behold, I finally found the "View raw logs" menu entry in the cogwheel menu on the upper right. D'oh. Thanks for nudging me.
This is great news, thanks! I just noticed that the required devel packages are missing to build a full distro OpenSSH package. It needs all the Kerberos stuff, libedit-devel, libfido2-devel and all their dependencies. The config options used when building the Thanks, |
|
I forgot to add a sk_test_option function to the regress sk-dummy, sorry about that. |
|
Thank you, @github-cygwin. I hope to give the changes a look on Friday or over the weekend. Meanwhile:
That sounds a bit strange. Could you try to capture debug output from ssh on Linux? |
What kind of debug output? strace or running ssh with SK_DEBUG/DEBUG_SK flags? |
|
Apologies for being unclear. The output of |
I collected the debug logs. Two files attached, one of which is the log for For comparison I attached the debug log for a key enrolled under WinHello, but Edit: Please don't be confused by the usage of paths starting with /cygwin. HTH, |
|
I'm going to wait and not do anything until Pedro has had a chance to look at these changes - he's much better at this stuff then I am :) |
|
Thank you @github-cygwin and @djmdjm. I had a look at the patches and feedback. A problem we will have in accommodating Windows Hello is that, contrary to FIDO's CTAP protocol, Microsoft's webauthn.h does not provide a way for the application to observe the actual capabilities of the token. All we can do is to perform enrollment/authentication operations and deduce the token's capabilities based on the result. That, however, does not allow us to distinguish between PIN and UV, since they look the same (by design) as far as results are concerned. We have a good example of this difficulty here:
This is happening because of our decision to consider Windows Hello a UV-capable token. Thinking the underlying token capable of built-in UV, we drop Overall, I suggest we take a step back and reevaluate the bare minimum needed to support Windows Hello. Once the bits for Windows Hello are all in, we could close this PR and look at improvements to existing functionality in a separate PR. With that in mind, leaving the double "user presence" prompt aside for a second, is there anything else we need to do to support Windows Hello other than not dropping -p. |
|
Hi Pedro,
But that's missing out on the other problem: By leaving that out, you're giving up on interoperability. A user enrolling That's exactly the reason I reverted my patch so SSH_SK_USER_VERIFICATION_REQD The key itself is a "verify-user" key. The key should not enforce how
So you would like to move the sk_test_option stuff entirely into a new PR?
Yes, see above. The "don't drop SSH_SK_USER_VERIFICATION_REQD only if Thanks, |
|
Hi Corinna,
Do we know why that is failing? I suspect it is because of this snippet in sk_sign(): /*
* WinHello requests the PIN by default. Make "uv" request explicit
* to allow keys with and without -O verify-required to make sense.
*/
if (pin == NULL && fido_dev_is_winhello (sk->dev) &&
(r = fido_assert_set_uv(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
}which explains why you want/need My preference would be to drop this snippet, even if it causes unexpected PIN prompts from Windows Hello, and eventually retire Perhaps there is something we can do. If possible, can you try to patch libfido2's set_assert_uv() in winhello.c so that the function sets
Absolutely! My bad. I just wanted to get Windows Hello out of the picture and look at the functionality as a whole. In a nutshell, I agree with the intention, but believe the execution could be simpler. For example, it would be best if we could avoid having code outside sk-usbhid.c care about FIDO concepts such as PIN and UV and FIDO options in general. Something along the lines of: retry_sk:
sk_flags = SSH_SK_CHECK_TOKEN;
if ((r = sshkey_sign(sign_key, NULL, 0, NULL, 0, alg,
options.sk_provider, pin, compat, &sk_flags)) != 0) {
/* error */
}
if (sk_flags & SSH_SK_NO_TOKEN_FOUND) {
/* prompt user to insert token */
goto retry_sk;
}
if (pin == NULL && (sk_flags & SSH_SK_PIN_NEEDED)) {
/* read pin */
}
if (sk_flags & SSH_SK_USER_PRESENCE_NEEDED) {
/* prompt for user presence */
}
sk_flags &= ~SSH_SK_CHECK_TOKEN;
if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
alg, options.sk_provider, pin, compat)) != 0) {
/* error */
} Does that make sense? -p. |
|
Hi Pedro, [Editorial Note: See my followup to my own reply first, before answering here. I just kept this in for the sake of discussion] just the first point for now, I have to check into the other stuff later.
That's very certainly not the reason for this problem. I didn't test this yet, but it would be very strange. WinHello defaults to user verification. The result is that for OpenSSH keys created without "verify-required", WinHello still requests user verification. On other systems I can create OpenSSH keys which only ask for user presence, on WinHello this is impossible, because of this default. So this snippet just sets the default for user verification to FALSE. This allows keys created without "verify-required" to be checked for user presence only on WinHello just as well as on any other system. However, we're talking about "verify-required" keys here only. For these keys, the next code snippet will do the right thing, independent of the above code snippet: Just what we get, no PIN, but the SSH_SK_USER_VERIFICATION_REQD flag is set Nope, we actually have a device supporting "uv", so we don't return with SSH_SK_ERR_PIN_REQUIRED, but instead... ...we set the "uv" flag explicitely to TRUE. I don't see how setting the value to FALSE by default changes anything here, because the subsequent code will set the value for "verify-required" keys to TRUE anyway, isn't it? Thx, |
|
Oh, wait. I confused cause and effect! If we actually drop the SSH_SK_ERR_PIN_REQUIRED flag, the condition fails, and thus is never called. So if I change to it should work as desired. This would allow user presence keys to be used as actual user presence keys on WinHello, too, and user verification keys should work, even if we drop the SSH_SK_USER_VERIFICATION_REQD flag for keys enrolled on "uv" devices. But still, IMHO, the SSH_SK_USER_VERIFICATION_REQD flag is used wrongly. Its name is confusing, because it *seems to include keys enrolled on "uv"-capable devices, but in fact it appears to include only keys enrolled on "clientPin" devices. While the above might fix the problem, I really wonder if it's the right thing to do. IMHO, a "verify-required" key should not have different flags, just because the device it has been enrolled on has different capabilities. It's the wrong place to make such a decision. So, yes, it would be great to get rid of the SSH_SK_USER_VERIFICATION_REQD flag in the long run, but wouldn't it be just as well to clean up how it's used as long as we still have it? Thanks, |
|
Hi Corinna, Your analysis is correct, but do note that it is predicated on On a not completely unrelated note, have you had a chance to try -p. |
|
oops, we replied at the same time. Glad we are on the same page. Let me mull it a bit and get back to you; an adequate reply would take more time than I have at the moment. In the meantime, it would probably make sense to look into |
Yes, we need the flag for WinHello, but the problem is, we need it for keys enrolled on any system, not only for keys on WinHello. The current code breaks interoperability,
Yes, I did this right at the start. no-touch-required keys don't work on WinHello. Corinna |
On second thought, no, it wouldn't. If I enroll a "verify-required" key on a "uv" device, the SSH_SK_USER_VERIFICATION_REQD flag will be removed. Thus, there's no way anymore to distinguish plain keys which only require user presence from keys requiring user verification. Thus the idea to allow plain user presence keys will be broken for "uv" devices, if the "uv" device defaults to user verification. So, if I'm not again missing a crucial detail here, that would be another reason never to drop the SSH_SK_USER_VERIFICATION_REQD flag, as outlined in my previous monologue... Corinna |
It makes sense, and it would really be nice if we could encapsulate the FIDO concepts inside sk-usbhid.c. I just see a problem there as soon as user prompting is required. Right now, the UI is solely in the application layer. The above code is moving prompting into the middleware. That means, ssh-sk-helper would have to be able to call all the prompting calls like read_passphrase(), notify_start(), etc. I think that's not feasible, the helper is not UI-aware. My stance is this: The application layer is responsible for the UI. If the UI gets changed or improved, the middleware should be unaffected. To do the UI right in terms of hardware tokens, there's no easy way out. The application layer needs some information about the current scenario, and that includes to learn what way of user verification should be performed, because that's UI. Having said that, the way I solved it is not necessarily the best way. It requires actual knowledge of the FIDO2 protocol and the meaning of strings used therein ("uv", "clientPin"). Either way, the UI basically needs the information
Maybe for a start we should just dumb down the sk_test_option call I added in 99d7032, along the lines of The function names need some polishing, but you get my drift, I think. Thanks, |
|
Hi Corinna, Quickly chiming in here to keep the conversation going. Please excuse me for my brevity.
There is a way to differentiate between keys requiring only user presence from keys requiring user verification without However, as observed in this PR, that is not possible when using Windows Hello, because Windows Hello is not a FIDO2 token, and therefore does not conform to the FIDO2 client-to-authenticator (CTAP) spec. Instead of returning I am not fundamentally opposed to the reintroduction of Regarding changes to the notification/prompting process:
If that is how you understood it, then I wasn't clear. My apologies. I did not mean to suggest moving the prompting to the middleware. What I had in mind was having the middleware try to use the key and respond with a set of flags telling ssh/ssh-agent what to prompt for. The prompting would take place where it currently does, it would just be "instructed" by the middleware. -p. |
Ok, I think I got that now. Bummer that WinHello is not working conformant in this single area, it could have been so easy, oh well. Unless... there isn't a way in WinHello to enforce that the call returns immediately, by any chance? So, yeah, I accept that we need the SSH_SK_USER_VERIFICATION_REQD flag for WinHello only, but apparently we need it yet. How do we proceed? I guess in the light of the above, we can push the first two patches, baa2928 and 6b3c62d now? Also, 2f2b0b1 should be obvious, right? @djmdjm?
I'm pretty sure I don't understand exactly how to do that. Look at 7262b10, please. I rearranged prompting again, to be able to generate the correct user information in the UI before calling sshkey_sign. For instance if the device is a "uv" device, how would you be able to do this inside the sshkey_sign call itself? The first call might already succeed and you're too late to do any prompting. How you would do that without giving the UI at least some information prior to the sshkey_sign call, some kind of call allowing the UI to ask the middleware what is supposed to happen next. That's where my sshsk_test_option() call comes into play. Apart from stylistic changes, I'm really unsure how to do this differently, let alone, encapsulated inside sshkey_sign. BTW., I'm more or less offline the next 4 weeks, starting this weekend. Corinna |
33a1541
to
514103f
Compare
|
just rebased... |
|
|
||
| fido_init(SSH_FIDO_INIT_ARG); | ||
|
|
||
| sk = sk_probe(NULL, NULL, 0, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this will do the right thing when multiple devices are present, which is a case we've worked fairly hard to support. Given multiple devices IMO "device supports feature X" is only useful the presence of a key handle that refers to that device.
Maybe a better way of supporting this would be to add another per-key flag, say SSH_SK_UV_PROVIDED that is set when the token provides user verification internally. We could set this for biometric keys, etc and then use it to skip or proactively prompt for PINs.
Would this help?
I.e. putting something like this in sk_enroll()
if (check_sk_options(sk->dev, "uv", &internal_uv) == 0 && internal_uv != -1) {
/* user verification handled by token */
response->flags &= ~SSH_SK_UV_PROVIDED;
}
(yes, this looks a lot like the code that I just removed via Corinna's change)
The application level has no access to device info, especially if the device is "uv" capable or requires "clientPin" for user verification. The "verify-required" ssh keys are now always marked as SSH_SK_USER_PRESENCE_REQD keys given commit baa2928 ("sk_enroll: never drop SSH_SK_USER_VERIFICATION_REQD flag from response") Add a method sk_test_option to the middleware and add matching functions sshsk_test_option to request device options. Bump SSH_SK_HELPER_VERSION accordingly. Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
Create more correct notification based on the fact if user verification is via "uv" or "clientPin". Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
Create more correct notification based on the fact if user verification is via "uv" or "clientPin". Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
When using "uv", for instance a fingerprint reader or face recognition, there's a good chance that biometrics fail. For instance, if you use the wrong finger, or if your finger has a cut. In cases like this, WinHello automatically falls back to "clientPin" entry. This patch emulates that behaviour on all systems. If the first call to sshkey_sign fails with the error code SSH_ERR_INVALID_FORMAT, and if the device supports "uv" and "clientPin", fall back to "clientPin" entry. Signed-off-by: Corinna Vinschen <vinschen@redhat.com>
514103f
to
ae0d916
Compare
|
just rebased onto current master |
|
The Fuzzing check failed with a weird DWARF error, followed by I built and ran the testsuite successfully, so I'm puzzeled why this fails in the fuzzing test. What's missing? |

Adding WinHello support to OpenSSH-portable
Version2: