Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpage description infinite web credentials? #82

Open
lanmarc77 opened this issue Dec 22, 2024 · 12 comments
Open

Webpage description infinite web credentials? #82

lanmarc77 opened this issue Dec 22, 2024 · 12 comments

Comments

@lanmarc77
Copy link

Hi,
might it be possible to elaborate on that a bit more detailed?
As I understood there is a physical limit for the number of resident keys of 256. Doesn't this mean that a pico-fido can then only store this amount of (discoverable) web credentials aka passkey logins? And if so, might larger flashs support even more?

I might have missunderstood some basic principles though.
Thanks.

@polhenarejos
Copy link
Owner

This figure is orientative. For ESP32 it is fixed as it depends on a predefined partition. In Raspberry Pico it depends on the flash size. The larger, the more keys can host. The real number of avilable keys depends on the firmware size, information of the credentials and other parameters. But for a typical 4MB flash it can host thousands of resident keys.

@lanmarc77
Copy link
Author

Ah I see.
Would you be able to give a rule of thumb calculation based on average lengths for credentials?

@polhenarejos
Copy link
Owner

It is hard to say as it depends on the length of userId, the number of extensions and options or the rpId. Assuming that all string values are around 32 chars, without extensions, it spans around 224 bytes. There's room for the maximum credential length, which is 1024.

@lanmarc77
Copy link
Author

Would it be possible to add something to the tooling so that at one could determine the amount of the current entries or percentage usage and the overall space still available?

@polhenarejos
Copy link
Owner

Yes, but it will show the free available space in Kb, not the number of available keys.

@lanmarc77
Copy link
Author

Awesome.
As you said you have no reliable way to determine how many more keys could be stored. It would be nice though if the number of keys currently stored is also output. So the user has at least an indicator based on the users individual values.

polhenarejos added a commit that referenced this issue Dec 23, 2024
@polhenarejos
Copy link
Owner

I added it to pico-fido-tool.

Note that, regardless the size of flash, the maximum number of resident credentials is 256, where the worst case is 256 kB. However, the filesystem accepts 256 files, which are shared by resident credentials but also for system files like PIN, metadata, certificates, etc.

Besides all of these numbers, I do not know how the overall system performs when all memory/files are occupied. If you will, you can check it.

It will be released in v6.2 but you can try nightly development build.

@lanmarc77
Copy link
Author

lanmarc77 commented Dec 26, 2024

Thank you and Merry Christmas.
It works. I noticed some models that do not compile. They start with gen4_rp2350.

So did I understood correctly now that even though my waveshare zero shows around 1MiB usable flash for key storage a maximum 256 entries would be used (10 it says currently). Assuming 1kiB for each entry then a lot of this 1MiB would currently stay unused?
grafik

@polhenarejos
Copy link
Owner

The limit of 256 is for dynamic files. The number of shown files is the number of elements in the flash memory, which can be static or dynamic. Static are the ones like PIN, options, meta data, etc. Dynamic are mainly the ones you generate, which are primarily resident keys and, perhaps, some certificates.
Assuming 1 kB per credential, it would take near 25% of space plus the static files, which might be negligible. So yes, with 1 MB there would be around 75% of free space.

@lanmarc77
Copy link
Author

Ok. After glancing (very fast) at the fs implementation I guess the reason for this limitation is that you can not know how big the program will become and you somehow must make sure that a new program version is not overwriting the space of the fs. As nice as U2F is it will not protect against this.
You seem to let the fs grow from the bottom of the flash to half of the available flash memory to avoid that issue even further. And you implemented the fs from scratch! 💪

I am unsure if 256 entries will eventually become an issue. I think the Yubikeys only support 100 entries. It surely will not become an issue very soon. Maybe I leave some of my thoughts here for you to consider which includes just ignoring them.

As you can not avoid that the program will eventually get bigger/too big we need to accept that it eventually might overwrite the fs. Users can be at least made aware of this e.g. by allowing the tooling to calculate if a new version would be a problem. The tool could check the latest github release and size and use this for the calculation. Maybe also showing which entries will be lost so that the user can prepare to register a different passkey before the update.
In addition any new version could be able to detect if it has overwritten parts of the fs. For this some kind of CRCs/markers could be placed in the fs info structure and checked during program start to achieve this detection which includes what entries are not correct anymore and only use the still complete ones. Instead of half of the chips available flash more memory can then safely be assigned to the fs.
Thank you for this project and a happy new year.

@polhenarejos
Copy link
Owner

This is a compromise. I don't know how big will be the firmware but I can have a barely idea. Currently it spans near 500 kB in the flash and I don't think it will increase very much unless I implement something bigger. So, assuming 1 MB of firmware is really conservative and probably very far from the future.
All started with RP2040, which didn't have support for partitions. I decided to put the data at the end of flash and increasing from bottom to up, like a common stack. Whilst the firmware grows from top to bottom, putting the data at the end and growing up reversely guarantees the maximum free space for both things.
Later I introduced support for ESP32, which brought support for partitions. ESP32 has smaller flash and it requires multiple partitions a part from firmware and data, so I drew a partition table with 1 MB for firmware and 1 MB for data. This works with ESP32-S3 because flash memory is embedded and is always 4 MB. But now RP2350 appeared and it also brings support for partitions.
However, with RP2350 the flash is external and may be up to 32 MB. The drawback is the partition scheme is static and done offline. Yesterday, I refactored it for 1 MB for firmware and 2 MB for data with an empty partition in the middle. This is just in case in the future I need to enlarge fw or data partitions independently. In case the external flash is less than 4 MB, it will suppose a problem since it falls off the flash but I don't know what happens in this situation: either a segmentation fault, the data is not saved properly or nothing special. I didn't see any board with less than 4 MB but my advice is to go for at least 4 MB. If it is bigger, the remaining upper space +4 MB will not be used, since the data partition is fixed to 2 MB. If you acquire a bigger flash and you want to take profit of all space for data, then you have to modify the partition table and build the firmware with the new partition table.
To wrap up, the differences between MCU are:

  • RP2040 has no limit on space (except on the physical space of course). All flash can be used for fw & data.
  • ESP32-S3 is 4 MB and only 1 MB can be used for data and 1 MB for fw.
  • RP2350 has 1 MB of fw and 2 MB of data. If your board is less than 4 MB, it will not work. If it has larger space, then it will take no advantage from the remaining space but it will work normally. If you want to use all the space, you must modify partition table from the very beginning; otherwise, if you used previously and have key material, you will loose it.

Except for RP2040, Instead of having a single partition to use the maximum space, I prefer having partitions to avoid problems like overlapping areas. With partitions, the data partition is never overwritten by the fw. So, no need for integrity check. The only problem about integrity could happen if a power cut happens between the clear and the program stages. When you want to write a block to flash, you first clear that region and then you program it. If a power cut happens in between, you'll clear but nothing will be stored. Usually, you only write the flash when you generate a key, so in this improbable case, you'd get an error and regenerate the key again. The only critical case is when you change the PIN in Pico HSM/OpenPGP since the data is encrypted using this PIN. But this is specific to a project and not to the hardware itself. In this sense, Pico Fido is safe.

In this sense, I remark that for ESP32-S3 and RP2350 no overwrite will ever happen between data and firmware; and for RP2040 it will eventually become obsolete.

The FS scheme is really rudimentary. It doesn't have anti-corruption mechanism, integrity checks or similar. The data is saved sequentially with a pair of pointers for previous-next entries, a header for permissions (rarely used BTW), type of file, type of access, the parent node (rarely used) and the pointer to the data.
Static files are the known by the system and its structure is already hardcoded. Once booted, the data pointer is updated accordingly to locate the data. Dynamic files, instead, are loaded on boot to but they do not occupy static table but a dynamic table with a maximum of 256 entries. I wrote 256 as a compromise between the expected use and the memory used. I really don't know how each MCU will respond having 512 or 1024 entries. Perhaps it works without major problems. In case you need to have more entries, it is easiest as changing the macro MAX_DYNAMIC_FILES from 256 to whatever number you consider.

To summarize, there's a room to expand the number of supported keys by far without worries. It might penalize the performance, but nothing far from this.

@lanmarc77
Copy link
Author

Ah I see.
Indeed then my assumption only applies to the RP2040 which eventually will phase out.
And if the others have partitions then you could switch to an already existing fs later if you want. The ESP32 has SPIFFS which includes CRC and also wear leveling. I don’t know about the RP2350 but I would wonder if they do not have something similar.
Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@lanmarc77 @polhenarejos and others