I am looking to create an open source implementation of the HMACSHA1 challenge and response for open source tokens like OnlyKey as we have had some interest in this feature. It looks like we can do it, but one thing I noticed is that with your current implementation of HMACSHA1 it appears that ykcore.c limits this to only Yubikey USB PIDs. Other devices with different vendor/product IDs will be ignored. So my question is, before I do the work here to create an open source implementation of this would you guys be willing to add additional USB VID/PIDs to this source file?
Not to that source file since that is owned by yubikey, but definitely interested in a common implementation of CR.
@droidmonkey Right, not to the file in the Yubikey repo I just provided that because I see that you require it. Since this is owned by Yubikey the only way to support a 3rd party device is to fork the Yubikey libraries to add USB VID/PID for other vendor devices.
Seems like a simple thing to do and test. Problem would come in that fork would have to be maintained and supplied to downstream repos (Debian, Fedora, etc) to support KeePassXC. Are you willing to do that?
@droidmonkey Yes a very simple thing to do to change the ykcore.c to support other devices. We could support a fork, it might be easier though to include the files required to support HMACsha1 in keepassxc rather than requiring external libraries. Or would this not be feasible?
We prefer to rely on libraries that can be updated independent of KeepassXC for security reasons. Unless we incorporate a wrapper which would enable the use of different keyfobs in addition to the yubikey standards. That wrapper would be incorporated into our code base.
We could maintain a fork of the library under the keepassxreboot umbrella organization, but it should stay a separate library for better portability and also to avoid packaging policy issues.
@phoerious Awesome! I will start working on this after OnlyKey's next firmware release.
@onlykey Any status on this?
@droidmonkey Still working on next OnlyKey firmware release. It will probably be November before I can work on this now.
OK we'll mark this for 2.5
@droidmonkey I have completed mapping out the USB communication in order to implement this in firmware. I learned some interesting things here if anyone is interested.
The hmac request and response is the same every time. I don't think this is news to anyone but this would mean that for example if a device is compromised and the attacker has admin/root access they may be able to extract the hmac from memory. It would be a nice feature to have the hmac change when the database is closed, if the USB device is available to generate a new hmac. There are still some threats here from an attacker but it would offer a bit better protection.
The USB communication is done via USB HID feature reports. This is interesting as it bypasses things like udev rules being required for USB communication. You will notice that the feature works on Linux without any udev rule. This same method has also been used for data exfiltration devices as one way that USB is secured is to only permit USB keyboards (Block mass storage devices like flash drives). Its commonly assumed that USB HID devices like USB keyboards only communicate one-way but that is obviously not the case here.
Other useful info
The hmac input is 32 bytes, this could be increased to up to 64 bytes
The hmac secret key is 20 bytes
Due to the way that this works with USB HID feature reports it will take a bit longer to implement a feature to do this. I expect I will have this ready to test in January.
Generating a new HMAC secret every time is not a good idea. There are too many scenarios were you would lose access to your database by accident and you cannot create backup keys.
Also 32 byte is enough if they are random. We use SHA-256 as hash function, so the end result wouldn't be longer anyway (not that 64 byte would hurt, though, but strictly speaking it's not HMAC-SHA1 anymore).
@droidmonkey @phoerious I have completed the open source implementation of HMACSHA1. The implementation is fully compatible with KeepassXC and should work on all HMACSHA1 apps that support Yubikey HMACSHA1. As mentioned we have to add the VID/PID of 3rd party devices to ykcore as this currently only allows Yubikey VID/PID to be used. Here is a quick video that shows using an OnlyKey with KeepassXC and the Yubikey personalization tool:
https://www.youtube.com/watch?v=ilA6mBafO2w
I will eventually do a blog post about this but here is a quick overview of how the firmware works:
Communication channel used is USB Keyboard feature reports. This is why Yubikey HMACSHA1 works on Linux without requiring a UDEV rule. 8 Byte set feature reports are used to send data (App to Device), 8 Byte get feature reports are used to receive data (Device to App).
The 8 byte reports are put together by the app/firmware to form a full message. A 2 byte CRC is used to ensure the integrity of the data sent/received. It took some effort to figure this out but Yubikey firmware uses CRC-16/X-25 while the app side uses CRC-16/MCRF4XX, not sure if this was intentional obfuscation or what but it was fun to figure out as this is closed source...
There are several message types used such as:
@phoerious Per your comment above, I agree 32 is enough if random. I went ahead and implemented support for both 32 and 64 size challenges. The HMACSHA1 response is always 20 bytes but the longer challenge may be used by other apps.
I have tested with Yubikey personalization tool and KeepassXC but if anyone would like to volunteer to test this out on additional apps please let me know and I will send some test firmware. Next I was hoping to get a volunteer to compile KeepassXC with the modified ykcore libraries ( I can provide these its really just one line of code added ) and then test out the final firmware. I expect we could be ready to release firmware supporting HMACSHA1 in the next month. What is KeepassXC's next release date? It would be great if we could get this feature into the next release as its a really minor change for KeepassXC.
Wow, that looks amazingly fast actually. Is it just the better hardware or is the firmware that much faster? The original Yubikey libs always take a second or two to load the key information.
We are in the process of wrapping up 2.4.0. Any further changes should be implemented within the next week, since we want to release a beta soon.
@phoerious The Yubikey uses a much slower processor so it probably takes a second or so to generate an HMACSHA1. This should be the only change required to the yubikey library - https://github.com/trustcrypto/yubikey-personalization/commit/10b0c052f24dde0fa0db58b0dcc7681ce81807d3
I don't expect further changes but I will need to replace the existing yubikey-personalization with this modified one and then build KeepassXC to do final testing. I will have it ready within the next week.
@phoerious @droidmonkey I tested it out. The way to do that is:
Follow instructions for setting up build environment here.
Replace ykpers with custom ykpers ( custom ykpers just checks for 3rd party device if no YubiKey is found )
$ git clone https://github.com/trustcrypto/yubikey-personalization.git
$ cd yubikey-personalization
$ autoreconf --install
$ ./configure
$ make check install
Other than the issue mentioned https://github.com/keepassxreboot/keepassxc/issues/2608 and https://github.com/keepassxreboot/keepassxc/issues/2609 its working well with OnlyKey.
I am not sure how to build on Windows though since it looks like you use the binary in the build guide here.
wget https://developers.yubico.com/yubikey-personalization/Releases/ykpers-1.19.0-win64.zip
Can you provide some guidance here this isn't really my area of expertise?
@droidmonkey @phoerious It took a bit of work to figure out how to compile ykpers for Windows. We have tested and generated a ykpers release that supports YubiKey and OnlyKey -
https://github.com/trustcrypto/yubikey-personalization/releases/tag/v1.19.1
Can we get this into the 2.4.0 release? I will volunteer to thoroughly test it out. I have already done some testing of the 2.4.0-beta1 and created a few issues. All you have to do is use the ykpers 1.19.1 library instead of the the ykpers-1.19.0 one.
I have provided build instructions here - https://github.com/trustcrypto/yubikey-personalization/wiki
Github does not do pull requests for git wikis so I am providing updated build instructions here -
https://github.com/trustcrypto/keepassxc/wiki/Set-up-Build-Environment-on-Windows
https://github.com/trustcrypto/keepassxc/wiki/Set-up-Build-Environment-on-OS-X
https://github.com/trustcrypto/keepassxc/wiki/Set-up-Build-Environment-on-Linux
Unfortunately not for 2.4.0. Did you submit your fix to Yubikey? Technically this is a new library. We will run afoul of Debian requirements.
@droidmonkey Its not a fix as there was nothing broken here, its a feature to support 3rd party devices. A very small change as the only thing changed here was to add additional USB VIDs. As Yubikey is a closed source proprietary product, adding support for 3rd party devices is very unlikely. If you let me know what Debian requirements you need I will make sure that is addressed.
To be honest with you, it would be far easier to just reimplement _ykusb_open_device in KeePassXC for use specifically to find 3rd party keys (just put it in the Yubikey.cpp as a function called findThirdPartyKey(int index). This would still return a YK_KEY which can then be passed to the Yubikey libraries for subsequent action. There is nothing fancy going on that would prevent you from doing this since YK_KEY is just a usb device handle.
@droidmonkey While this could work here the development of the challenge-response feature in firmware was not a small feat. Our goal with this is to offer an open source alternative to Yubikey in other projects as well so as you mentioned we will have to make this easy for other projects to use-
Seems like a simple thing to do and test. Problem would come in that fork would have to be maintained and supplied to downstream repos (Debian, Fedora, etc) to support KeePassXC. Are you willing to do that?
And we are willing to maintain this or if you maintained a fork that would work too as @phoerious mentioned.
We could maintain a fork of the library under the keepassxreboot umbrella organization, but it should stay a separate library for better portability and also to avoid packaging policy issues.
If you let me know what your requirements are I will work on making that happen and it will be ready for 2.5.0.
@onlykey I am a little confused. Your ykpers fork repository only has two small changes to ykcore.cpp. What is this firmware you speak of? Does that have anything to do with KeePassXC?
@droidmonkey Our project was to support an open source HMACSHA1 implementation, this includes two things, App side (ykpers library) and device side (open source USB device firmware). The later is what I was mentioning was not a small feat and no this really doesn't have anything to do with KeePassXC other than we created something that we want everyone to be able to use. I think switching out the ykpers library is the way to go here, rather than trying to implement different code changes to each and every open source project for adding 3rd party challenge response device support. This seems much more difficult than just maintaining a fork of ykpers. Thats why I am asking what requirements you need to switch out the ykpers library.
Also I took a look at _ykusb_open_device and your suggestion to reimplement this in Yubikey.cpp. This may work but I think the issue here will be that this would require libUSB to be able to communicate directly with USB devices (usb_open). There may be some challenges there I am not sure.
Perhaps we can find middle ground where you create a very small lib that does what I suggest in Yubikey.cpp that depends on the ykpers library. This small lib would be added to distros as a compliment to ykpers instead of a replacement.
Please let me know where I can buy a sample key that I can use to test with.
Edit: is this one good for testing? https://onlykey.io/collections/all/products/onlykey-color-secure-password-manager-and-2-factor-token-u2f-yubikey-otp-google-auth-make-password-hacking-obsolete?variant=469626486828
Edit 2: This POC worked with my Yubikey (didn't find OnlyKey, fell back to using ykcore). Can you test this with your OnlyKey? (NOTE: this is for Windows, you'll have to copy the libusb implementation if you are on Linux)
https://gist.github.com/droidmonkey/8ad519c02e8d48196636fb09e76f3be6
@droidmonkey I wish I had seen your response earlier. I went ahead and created a separate lib for OnlyKey https://github.com/keepassxreboot/keepassxc/pull/2754
Yes, the link you referenced is good for testing.
Edit: However, the firmware that comes on your OnlyKey does not support challenge-response as this is a new feature. Send me an email with shipping address and I will send a developer model OnlyKey with the correct firmware for testing challenge-response.
I think using the separate okcore library is the way to go here as there are minimal changes required in your Yubikey.cpp. I will put documentation together for building if we go this route. Do you still want me to look into the POC you put together or just use the separate library?
I think your separate library is exactly my POC. The only thing I would do is eliminate all the yk references and just make the ykcore.lib a dependency of your library. That would simplify the interactions significantly. This wouldn't change the KeePassXC interactions or your PR.
P.S. - I do not have your email address and its not on onlykey.io
@onlykey I received the OnlyKey's in the mail, thank you! Do I need a special desktop app to configure Challenge-Response? Doesn't look like the currently available one has it built in.
@droidmonkey You would just use the standard OnlyKey app to set a PIN. You don't have to go through the full config, just set one PIN and remove/reinsert OnlyKey. HMACSHA1 is enabled by default and there are two slots that will show up for use in KeepassXC. No configuration is necessary as the HMACSHA1 keys are derived from a derivation key generated from random input (like the touch button readings while you were setting the PIN). There is also the ability to change the HMACSHA1 key to a custom value for advanced users.
So to use it with KeepassXC you insert and your OnlyKey and unlock with PIN, create a new KeepassXC database, enter a password and select Yubikey slot 1 (or 2), when you select next the OnlyKey flashes yellow and you press any button to generate the response.
Edit: Here is a Windows Portable version of 2.4.0 Beta 2 that has the Yubikey libraries switched out with the ones here for testing with OnlyKey.
Great, I will test it ASAP
Works great, in fact I think it is more reliable than Yubikey itself. Very well done! A couple UI tweaks (replace Yubikey with Yubikey/OnlyKey) and this should be all set.
@droidmonkey Great! Let me know if you need me to do any more here. I briefly looking into the UI tweaks and it looks like this should be pretty straight forward.
@droidmonkey New PR - https://github.com/keepassxreboot/keepassxc/pull/3352
Its a very simple change now to add OnlyKey support, you will need to use ykpers v1.20.0 though which was just released today - https://github.com/Yubico/yubikey-personalization/releases
Most helpful comment
@droidmonkey New PR - https://github.com/keepassxreboot/keepassxc/pull/3352
Its a very simple change now to add OnlyKey support, you will need to use ykpers v1.20.0 though which was just released today - https://github.com/Yubico/yubikey-personalization/releases