Yubico / yubikit-ios

Yubico Mobile iOS SDK - YubiKit
Apache License 2.0
198 stars 44 forks source link

MFI: 5Ci gets stuck in a bad state when used for (HMACSHA1) requiring touch #34

Closed mmcguill closed 4 years ago

mmcguill commented 4 years ago

Hi,

I have an issue with the 5Ci which I'm integrating with at the moment for use in an iOS app of mine (I've already integrated against the NFC side of things and that works well). I'm using the HMACSHA1 Challenge Response feature of these devices to unlock KeePass databases.

The issue only really exhibits itself when the 5Ci has one of it's slots programmed (for HMACSHA1) to require touch.

Here's what can normally happens:

1) Check accessory state, see it's not OPEN -> call startSession 2) Display a nice UI popup (using your SharedUI component) telling the user to insert/touch their key (depending on whether key is inserted) 3) Wait for session to go into OPEN state which it does v quickly 4) Use YKFKeyChallengeResponseService sendChallenge to request a response from the key 5) This is blocked until the user touches the key. 6) User touches key 7) Receive response and close session with stopSession, dismiss the nice UI popup.

This works well and is repeatable which is great. The problem now comes when I hit the Cancel button on the nice UI Popup while awaiting a user touch...

Problem Reproduction Steps 1) Check accessory state, see it's not OPEN -> call startSession 2) Display a nice UI popup (using your SharedUI component) telling the user to insert/touch their key (depending on whether key is inserted) 3) Wait for session to go into OPEN state which it does v quickly 4) Use YKFKeyChallengeResponseService sendChallenge to request a response from the key 5) This is blocked until the user touches the key. 6) User DOES NOT touch key but taps the Cancel button on the popup. 7) Close session with stopSession, dismiss the nice UI popup.

From this point out the Key is in a bad state, or my app is or something at least is in a bad state and I can't get the key to go into the OPEN state again without removing the key and reinserting. Here's what happens from this point out:

1) Check accessory state, see it's not OPEN -> call startSession 2) Display a nice UI popup (using your SharedUI component) telling the user to insert/touch their key (depending on whether key is inserted) 3) Wait for session to go into OPEN state which it never does, it remains in an OPENING state. 4) Call stopSession, cancelCommands etc resets the state to Closed but then we can go back to 1) and never get the state in OPEN.

Note: Touching the key has no effect. A call to startSessionSync instead of startSession will indicate that startSession has failed (returns false eventually).

So 2 questions...

1) How do I reset the key to a good state when the user taps Cancel, or how to I prevent it from getting into a bad state? 2) How can I tell if an MFI 5Ci key requires a Touch so I can display a better interface?

imakhalova commented 4 years ago

Hello @mmcguill , Thank you so much for reporting the issue. I've got a question for you: what firmware version of YubiKey you've got? You can check version with Yubico Manager on desktop (or iOS Yubico Authenticator app if using a phone).

And answers to your question: 1) Currently there is no way to cancel running requested operation on the key. But if you invoke cancelCommands() for accessorySession. This operation will stop listening/waiting for response from the Key.

Challenge-response with touch actually suppose to timeout. So it should get out of "bad state" automatically. If you wait til key stops blinking you're in a good state.

But I was able to reproduce the "bad state" if I send another request before the first one gets timeout (while key still blinks). This requires some time for investigation on why this happens and whether it can be worked around somehow...

2) Unfortunately, there is no way to do it with APDU commands as far as I know. I can suggest you the workaround with timer (check if response is not there within .5 sec than ask user to touch YubiKey). I understand that it's not ideal, but might worth considering.

mmcguill commented 4 years ago

Thanks for getting back to me... It's 5.2.4.

This is a screenshot from the Personalization tool:

image

imakhalova commented 4 years ago

Hey @mmcguill ,

Thank you for your response. And I'm very sorry that you experiencing such issue, but the only good suggestion I come up with: hide cancellation button for this operation, because it's not actually cancellable.

We're going to fix the cause of going into "bad state" in new YubiKey firmware, so that key won't hang (thank you so much for reporting that issue). But since this operation is not cancellable, key will ignore all subsequent calls from the phone. And you still won't be able to do anything unless user touches the button or operation expires. I also put the item in backlog to create such operation on YubiKey so that we can support it in SDK.

mmcguill commented 4 years ago

Thank you!

Can you help me with my second question above, how can I tell if a slot requires a touch or not?

imakhalova commented 4 years ago

@mmcguill this is currently not supported as well. Read the answer 2 in my first response for workaround. I added this as feature request to backlog. We will support it in SDK if YubiKey starts to support it.

mmcguill commented 4 years ago

Thanks @imakhalova - feel free to close if you like