Reliable, secure and versatile backup for U2F

I really like the level of security provided by U2F, but along with security, you need to consider a recovery plan. Losing access to your most important accounts, if something happens with the main U2F token, is a serious problem. At the same time, I would like to avoid using a backup that compromises the security provided by U2F.



yubikey






Popular backup methods



Today, it’s best practice to keep a second independent U2F token for backup; this token must be manually added to each service and stored in a "safe" place. Another common practice is to use the non-U2F method as a backup (OTP, recovery codes). Honestly, both of these methods are poor.



Independent U2F Token



This means that every time I register on some new service, I need to add both of my tokens. This fact raises a number of problems:





In my opinion, this “exemplary practice” is not very reliable, and rather burdensome. Let's look at another common practice.



Non-U2F method as backup



OTP:





Recovery Codes:





So, to summarize, all of these methods are non-universal, burdensome and not too safe.



The best backup method



Now, after I have sufficiently criticized the current state of affairs, I will finally say what I really want. I really want to have two U2F tokens: primary and backup, but they must be configured in a certain way:





Before we discuss the technical feasibility of this within the framework of U2F, I will explain why it is great and how I use it.



Why is it great



If we look at the criticism of the independent backup token described above, we can see that all the shortcomings of this method are eliminated:





And if something bad really happens with the main token, then I do the following:





At least for me personally, this strategy is a great compromise for a high level of security and an easy backup. It is safer and more reliable than any other method.



Implementation



U2F Protocol Overview



Before we can talk about implementation, we need to understand at a certain level how U2F works. Most manufacturers implement it as follows (not all of the following are present in the standard; some things are implementation details, but most existing implementations, as far as I know, work just that way):



device_secret



programmed in the U2F token, along with a 32-bit counter



, which can only be incremented. When we register a U2F token on a service, the following happens:





Subsequent authentication proceeds as follows:





Now let's outline the details that are directly related to the discussion.



Details of interest



The first is that the device does not store service_private_key



for each service: instead, it displays service_private_key



every time using HMAC-SHA256. This is very important for us: obviously, if each device would store unique keys separately for each service, then only this device could authenticate subsequently.



This, by the way, is not a requirement of U2F: U2F does not indicate exactly how keys should be stored, and some early U2F implementations did, in fact, store keys for each service separately. This approach has the disadvantage that the number of services for which the device can be used is limited. The derivation of service_private_key



eliminates this drawback.




And secondly, the device has counter



to prevent cloning.



At first glance, it might seem that this counter



does not allow us to implement the discussed backup strategy (at least, it seemed to me when I was trying to find a solution), but in fact, it only helps us! I'll explain now.



main idea



The idea is this: at the production stage, program two tokens in such a way that they both have the same device_secret



, but the backup token needs some correction: instead of using counter



in its pure form (as ordinary tokens do), it should add some big constant to counter



. For example, half the 32-bit range, i.e. approximately 2 000 000 000



, it looks reasonable: I’m unlikely to exhaust so many authentications in my entire life.



In fact, that’s all. Simple and effective.



Having two tokens programmed in this way, I hide the backup token in some really hard-to-reach place, and never touch it. If something terrible happens and I lose access to the main token, I still get to the backup token, and I can immediately use it on all services where I registered the main token, because The backup has the same device_secret



, and its counter



starts with a really large number, which I won’t get for the rest of my life.



Also, I draw attention to the fact that I do not propose making tokens cloned . Two tokens, although they have the same device_secret



, have different counters, and after programming device_secret



there should be no way to get it back from the device or create a clone in any other way.



A Note About Counter



An attentive reader may notice that there is the following security problem: what if an attacker gains access to the main token and somehow initiates 2,000,000,000 authentications? Then he gains access to the service even after the backup token has been used on this service.



Fortunately, this problem has a simple solution. In any case, the counter must be implemented in hardware (presumably on some crypto processor), and for safe implementation this hardware counter must have a range of less than 32 bits. For example, on the ATECC508A, counters can only count up to 2097151, so by setting the constant added to the counter to any value greater than the maximum counter value, we can be sure that the main token can never count to the counter in the backup token.



To clarify: let's say that our U2F token uses ATECC508A, and designate the counter inside the ATECC508A as hw_counter



. Then:





Please note that we do not modify the real hw_counter



inside the crypto processor; it will still count from 0 to 2097151. Instead, every time we need to get the counter value, we read hw_counter



from ATECC508A, then we add our constant and return it (for further calculations for U2F).



Thus, the range of counter values ​​in the main token will be [0, 2097151], while the range of counter values ​​in the backup token will be [2000000000, 2002097151]. The fact that these ranges do not overlap ensures the cancellation of the main token when using a backup (if the service uses counter



; the main services that I checked use it).



Actual implementation



None of the manufacturers of U2F tokens that I know about support the required customization today. But fortunately, there is an open-source implementation of the U2F token: SoloKeys .



I wrote my original article (in English) a year ago, and this part is a bit outdated: then SoloKeys was at the prototyping stage, and I used the previous iteration of the project: u2f-zero . Therefore, I will not translate this part now, since the only way to get a u2f-zero device is to solder it yourself, and it is hardly advisable to do this (although there are instructions on the github).



Nevertheless, all the details of the necessary modification of u2f-zero are given in the original article .



When my hands reach the solokeys, I will write instructions for its modification.



One way or another, this is the only way I know today to get a working U2F token with a reliable backup. Checking several services (at least google and github) showed that it works: by registering the main token on the service, we can also use backup, and after the first use of the backup, the main token stops working. Awwwwwww. <3



A warning



Despite the fact that this backup strategy is cool, I am not so sure of its specific implementation through u2f-zero or solokey. This path is the only way to get what you want, so I went that way; but assuming that the attacker is gaining physical access to the U2F device, I’m not sure that hacking the device (i.e. getting device_secret



from it) will be as difficult as it would be in the case of Yubikey or other major manufacturers. The authors of solokey claim that “the level of security is the same as in a modern car key,” but I did not conduct any examinations to confirm this.



However, to be honest, I'm not really worried about this. If an attacker simply steals a token without the intention of returning it, then the complexity of breaking it does not matter, because an attacker can simply use this token to access the account and, for example, simply revoke this token and add another. However, for this I must have other serious security problems as well. U2F token is only the second factor.



So, the only scenario where solokey may be less secure than something else is when an attacker tries to access the device for a short period of time, get device_secret



from it, and return the device back, invisibly to me. To do this, he needs to read the contents of the flash microcontroller (or RAM at the right time), and this is not very trivial.



Taking into account all the factors, I believe that for me personally to have a reliable backup is much more important than having an ultra-secure hardware implementation of a U2F device. The likelihood of problems with such a safe implementation and the lack of a good backup is higher than the likelihood of problems with u2f-zero (solokey) and backup.



Conclusion



The considered backup strategy outperforms the alternatives in all dimensions: it is universal, safer and more reliable than any other methods.



I will be glad if at least one of the main manufacturers implements this in their products, but there is no certainty yet. One Yubico support guy, James A., even told me that the backup is as I need, “is not possible with the way U2F is designed,” and after I set out the implementation details, it just stopped responding.



Fortunately, this was not as impossible as Yubico believes.






My original article in English: Reliable, Secure and Universal Backup for U2F Token . Because the author of the original article is myself, then, with your permission, I did not put this article in the category of “translation” .



All Articles