Scdaemon needs to restart after wake up from sleep mode for YubiKey to work on Windows
Closed, ResolvedPublic

Description

Hi,
when I use my YubiKey, gpg-agent and scdaemon and I put my computer into sleep mode, after waking up the shared state among the smartcard and gpg is broken and scdaemon gives reset card (0x80100068) error. That is not handled gracefully and user is required to replug the smartcard or restart the scdaemon in order to use it.

Steps to reproduce:

  • plug in YubiKey, run gpg-agent and login with putty to ssh session using key on the smartcard
  • put computer to sleep and wake it up
  • try to login into another ssh session

Actual result:
Putty outputs "Pageant failed to answer challenge" error dialog.

Expected result:
Pinentry asks for smartcard PIN or uses cache.

Logs:

  • the actions taken around 2018-03-04 12:18 is normal successful ssh authentication
  • then computer was put in sleep mode until 2018-03-04 12:51 when the unsuccessful ssh auth attempt took place
  • I really hope the logs don't contain sensitive information, any reassurance is welcomed

Spec:

  • Windows 10 Pro x64
  • gnupg-w32-2.2.5_20180222.exe (GUI less)
  • YubiKey 4 Nano

This issue has been mentioned in T2167, so I CC this to @gniibe and @dhoffend.

vovcacik created this task.Mar 5 2018, 11:17 AM
vovcacik created this object in space S1 Public.
vovcacik created this object with visibility "All Users".
vovcacik updated the task description. (Show Details)Mar 5 2018, 11:22 AM
werner added a subscriber: werner.Mar 5 2018, 1:46 PM

This seems to be the relevant part of the log:

2017-11-18 07:45:15 scdaemon[8918] DBG: ccid-driver: CCID: card inactive/removed
2017-11-18 07:45:15 scdaemon[8918] ccid open error: skip
2017-11-18 07:45:15 scdaemon[8918] pcsc_establish_context failed: no service (0x8010001d)
2017-11-18 07:45:15 scdaemon[8918] DBG: ccid-driver: CCID: interrupt callback 0
2017-11-18 07:45:15 scdaemon[8918] DBG: ccid-driver: CCID: card removed

Note: AFAICS you are using gpg-agent 2.2.5 with the older scdaemon 2.2.2 - that is not a good idea.

@werner there had to be some mix up, as the log snippet is not mine.

It looks like SCardGetStatusChange doesn't return failure after wake up.
Here, what we need is catching the event of wake up, which requires reset of the card.
I think that we can check by the dwEventState field.
I'll try on GNU/Linux environment, then ask you to try.

gniibe added a comment.Mar 6 2018, 2:11 AM

I realized that suspend/resume is not supported yet on GNU/Linux: https://anonscm.debian.org/cgit/pcsclite/PCSC.git/tree/TODO#n7
So, I can't test myself.
Here is an attempt to improve:


The reference is: https://stackoverflow.com/questions/11294638/how-to-use-scardgetstatuschange-correctly-on-windows-8

aheinecke edited projects, added gpg4win; removed Windows 64.Mar 6 2018, 7:53 AM
gniibe triaged this task as Normal priority.EditedMar 6 2018, 8:25 AM

If possible, please try with this (patched version of scdaemon):

gniibe changed the visibility from "All Users" to "Public (No Login Required)".Mar 6 2018, 8:27 AM

@gniibe it seems the patched scdaemon.exe is 64 bit executable and it requires libassuan6-0.dll. However I got installed 32 bit version of gpg that only has incompatible libassuan-0.dll. I scanned whole computer for the missing lib, skimmed your ftp for 64 bit binaries and looked into gpg4win installer to find it, but no luck. There is also libassuan github repo, but I would like to avoid building the dll myself; there would probably be more than one dll to build anyway.

I can test it if you point me to 64 bit version of gpg or build me 32 bit scdaemon.

gniibe added a comment.Mar 8 2018, 6:07 AM

Sorry, my build was not good even if it's for x86_64 (I used development version of libassuan, etc.).

Here is 32-bit (i686) version:

You can see the path of scdaemon by invoking gpgconf command. Please move original scdaemon and put this scdaemon.
Run gpgconf --reload scdaemon before testing.

Thanks, this version of scdaemon executes.

However I can't get good ssh authentication with it as putty always give me "Disconnected No supported authentication methods available (server sent publickey)". This would normally indicate the yubikey is not plugin in, but it is. I've tried restarting gpg-agent+scdaemon, replugging the smartcard. After reverting to the unpatched scdaemon authentication was possible again.

Logs here:

I've diff'd it with previous successful auth and this part looked interesting:

2018-03-08 19:12:35 scdaemon[8860] DBG: leave: apdu_get_status => sw=0x0 status=0______________________<- this used to be "status=7"
2018-03-08 19:12:35 scdaemon[8860] triggering event 158 (0x00000158) for client -1
2018-03-08 19:12:35 scdaemon[8860] DBG: Removal of a card: 0
2018-03-08 19:12:35 scdaemon[8860] DBG: enter: apdu_close_reader: slot=0_________________________________<- none of it should be happening
2018-03-08 19:12:35 scdaemon[8860] DBG: enter: apdu_disconnect: slot=0
2018-03-08 19:12:35 scdaemon[8860] DBG: chan_0x0000016c -> OK
2018-03-08 19:12:35 scdaemon[8860] DBG: chan_0x0000016c <- GETINFO card_list
2018-03-08 19:12:35 scdaemon[8860] DBG: leave: apdu_disconnect => sw=0x0
2018-03-08 19:12:35 scdaemon[8860] DBG: leave: apdu_close_reader => 0x0 (close_reader)

gniibe added a comment.Mar 9 2018, 2:02 AM

Thanks a lot for your testing. So, apparently, the PC/SC behavior is different between GNU/Linux and Windows.
Thus, I pushed another change: rG1e27c0e04cd3: scd: More fix with PC/SC for Windows.. Please test this. (Both of previous version and this version work well on GNU/Linux for operations not including suspend/resume with Yubikey and Gnuk Token, while my Yubikey with PC/SC doesn't work well for suspend/resume.)

Yeah, this is better, we got apdu_get_status => sw=0x0 status=7 and I can auth with this version as usual. After sleep-wake cycle it would however fail with pcsc_transmit failed: reset card (0x80100068). Logs attached.

I've noticed new line 2018-03-09 18:48:35 scdaemon[14940] DBG: pcsc_get_status_change: changed present excl unuse.

Again, thanks a lot for your testing. The log said: The code I added cannot detect the event of suspend/resume.
It seems that there is no way to recover from suspend/resume for Yubikey.

I have an old Yubikey of:

Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x1050 Yubico.com
  idProduct          0x0112 Yubikey NEO(-N) CCID
  bcdDevice            3.34
  iManufacturer           1 Yubico
  iProduct                2 Yubikey NEO CCID
  iSerial                 0 
  bNumConfigurations      1

When I test this device on GNU/Linux (both of scdaemon with in-stock CCID driver, scdaemon with PC/SC service), if it is in use (USB Interrupt transfer is active to watch card status), suspend/resume makes it unusable.
I need to replug it.
If it is not in use (USB interrupt transfer is not active), suspend/resume causes no problem.

Part of the problem is Yubikey side, I suppose. (Because my implementation of Gnuk Token has no problem for suspend/resume if it's in-use.)

Even if it's the problem of USB device, it's better for an application to work with that. However... for now:

For GNU/Linux, I think I have nothing which I can do in the application code of scdaemon:

For macOS, it seems that it works somehow.
For Windows, if there is some way(s) for application to detect the event of suspend/resume, I'm happy to use the feature. Currently, I don't know. Please help.

  • There was same problem in yubico-piv-tool and it was solved by detecting error state (0x80100068) and reconnecting to the smart card if necessary [1]
  • There is also a thread in OpenSC discussing this issue [2] and relevant PRs [3]
  • I also found a project that claims to fix SCARD_W_RESET_CARD by disabling exclusive access to the card before asking for PIN (and then they enable exclusive access again) [4]

Not sure if any of it will be useful to you.

[1]: https://github.com/Yubico/yubico-piv-tool/pull/115/commits/93accb2777e1872979e9fef4a450f67c2c40e960#diff-cc3a72b93fd5207ef403046d601829b8R308
[2]: https://github.com/OpenSC/OpenSC/pull/842#issuecomment-239347714
[3]: https://github.com/OpenSC/OpenSC/pulls?utf8=%E2%9C%93&q=reset+in%3Atitle+author%3Adengert+
[4]: https://github.com/Fedict/commons-eid/commit/946147f3a093f0990af7002b2d6e63b956b54953

Thanks a lot for pointers and suggestion.
Well, the problem of Yubikey itself cannot be solved by others, we can put some workaround for the error recovery.
So, this is another try of mine to improve error recovery.

While it can't detect the event of suspend/resume, we can reconnect reader when we encounter fatal errors.

gniibe added a comment.EditedMar 13 2018, 4:58 AM

After resume, because resume is not detected, some user interaction is required to cause an error.
gpg --card-status (which will only show partial information) is enough. Or, ssh failure. After failure, scdaemon reconnects the token.
Then, you can use it again without plug-off/plug-in.

Hi, that works as advertised. If this is the best solution yubikey permits us I am ok with it.

Log that shows fail after wake up and reconnecting to the reader:

2018-03-13 14:20:05 scdaemon[11104] pcsc_transmit failed: reset card (0x80100068)
2018-03-13 14:20:05 scdaemon[11104] apdu_send_simple(0) failed: general error
2018-03-13 14:20:05 scdaemon[11104] operation auth result: General error
2018-03-13 14:20:05 scdaemon[11104] DBG: enter: apdu_get_status: slot=0 hang=0
2018-03-13 14:20:05 scdaemon[11104] app_auth failed: General error
2018-03-13 14:20:05 scdaemon[11104] DBG: pcsc_get_status_change:  changed present excl inuse
2018-03-13 14:20:05 scdaemon[11104] DBG: chan_0x00000170 -> ERR 100663297 General error <SCD>
2018-03-13 14:20:05 scdaemon[11104] DBG: leave: apdu_get_status => sw=0x1000c status=0
2018-03-13 14:20:05 scdaemon[11104] triggering event 154 (0x00000154) for client -1
2018-03-13 14:20:05 scdaemon[11104] DBG: Removal of a card: 0
2018-03-13 14:20:05 scdaemon[11104] DBG: enter: apdu_close_reader: slot=0
2018-03-13 14:20:05 scdaemon[11104] DBG: enter: apdu_disconnect: slot=0
2018-03-13 14:20:05 scdaemon[11104] DBG: leave: apdu_disconnect => sw=0x0
2018-03-13 14:20:05 scdaemon[11104] DBG: leave: apdu_close_reader => 0x0 (close_reader)
2018-03-13 14:20:05 scdaemon[11104] DBG: chan_0x00000170 <- RESTART
2018-03-13 14:20:05 scdaemon[11104] DBG: chan_0x00000170 -> OK
2018-03-13 14:20:10 scdaemon[11104] DBG: chan_0x00000170 <- SERIALNO
2018-03-13 14:20:10 scdaemon[11104] DBG: enter: apdu_open_reader: portstr=(null)
2018-03-13 14:20:10 scdaemon[11104] detected reader 'Yubico Yubikey 4 OTP+U2F+CCID 0'

Thanks for the fix!

vovcacik added a comment.EditedMar 13 2018, 3:03 PM

I've contacted Yubico to review this ticket.

gniibe claimed this task.Mar 28 2018, 1:29 AM
gniibe closed this task as Resolved.Apr 11 2018, 1:59 AM

Workaround is implemented in 2.2.6.