Closed darconeous closed 7 years ago
Key wrapping is a good idea but I decided against it at the start of the project. The token was designed to be cheap and secure. So it has a secure chip that only does P256 ECC and just enough memory to do U2F and USB HID. So no AES/other secure crypto KDFs can be implemented as the resources are not there. My though was, if a user needs more than 15 registrations, he can afford to get two keys because they are cheap.
Now I see it's caused more frustration than I thought it would. So a new revision that does key wrapping would require a new chip with ~8KB more memory and slightly better throughput.
I currently can't work on another revision. I'd love to hand the project off to someone else that would be interested.
Also relevant: https://github.com/conorpp/u2f-zero/issues/9
For what it's worth, you don't need AES to implement a scheme like what Yubico is using: you just need SHA2, which is provided by your secure element.
And implement an HMAC to derive key? Good point, there should be enough memory to add that.
Just added support for this. A 256 bit master secret is stored write-only on the ATECC508 so the security level and isolation should be the same as before. New key pairs are generated based on a sha256 hmac with the 256 bit master key, 32 bit random number, and appid. The 32 bit random number is stored in the keyid along with sha256(private-key + some constants) which acts as a MAC to write a new private key to the ATECC508.
Private keys are written to the ATECC508 are masked with another random secret stored on the USB MCU. This is done so an eavesdropper on the I2C bus cannot see the private key. The ATECC508 supports unmasking it.
If anyone sees any potential issues, please share them here.
Well I think that even the master key is not sufficient to make do an identical token?
I make awaraness about TREZOR feature:
When logging into a website, you generally authenticate yourself by providing a user name and a password. With TREZOR and U2F, you will have to additionally confirm the login with a click on your TREZOR device. Unlike some other tokens, TREZOR always uses a unique signature for each and every user account registered. Additionally, TREZOR brings U2F to a completely new level:
- Easy to back up and recover. TREZOR requires you to back up your so-called recovery seed during the initial setup of the device. This is a one-time process for all functions of the device. The recovery seed represents all the secrets (private keys) generated by the device and can be used to restore your hardware wallet at any time. (…)
@ad-m I'm not sure your point. The master key is only located on the token which means you cannot make an identical token by design. If you are programming on your own, you can choose to keep a copy of the master secret to allow copies to be made.
Allowing a user to change the master secret and make backups should be a separate issue.
@conorpp , thanks for you opinion. I'm not sure all terms, hence my wrong impression. But I try to get to know about it. I might go back to backup issue later in the future, but first I have to know well the source code and U2F implementations details.
Thanks for your works and project development.
One thing I was thinking about was using some of the unused key slots for multiple attestation certificate keys---the goal being to further obscure the relationship between registrations on multiple websites with the same token.
Whenever a new service is registered, it would use a different attestation certificate. The first attestation certificate used would be picked at random, and then it would go in a round-robbin.
For each new batch of keys, maybe the two oldest attestation certificates would be retired. This would make it much more ambiguous as to even which batch a key came from.
Ideally we would have a collection of counters as well and we would use a random one for each service. Unfortunately there are only two secure hardware counters...
Anyway, implementing both mechanisms would almost completely eliminate any ability to correlate the token across services.
I was having a look at 01e8528e30f2b97003444425990b33bcff600c8e.
Unless I'm reading this wrong, I don't seem to see where you are using a nonce in the calculation of the private key. Without a random nonce, using the same key on the same service for different accounts would yield the same key handle! This would make it trivial for a service to determine if two accounts are using the same token.
Could you describe the algorithm you are using for deriving the keys?
Key generation can be seen here. It is done using a 256-bit master secret for a sha256 digest that is generated offline during setup/programming of the token. See script and setup-firmware. A 32 bit random number and the appid is also included in the sha256 calculation.
Ah, I see. Looks reasonable.
But what's the purpose of And why is the implementation of RMASK
and WMASK
?u2f_appid_eq()
commented out?
EDIT: Nevermind about the RMASK
/WMASK
bit, I just saw this from above:
Private keys are written to the ATECC508 are masked with another random secret stored on the USB MCU. This is done so an eavesdropper on the I2C bus cannot see the private key. The ATECC508 supports unmasking it.
While 15-sites is a lot of sites, the limit is frustrating because there is no easy way to manage these keys without erasing all of them. It also isn't clear what happens when you reach this limit (I assume some sort of failure indication?).
Having such a limit is unnecessary if you use key wrapping to store the key inside of the key handle (or use a mechanism similar to what Yubico uses to securely derive the keys from the key handle) instead of storing the keys locally.