Yeah, NIST 800 level random numbers are hard to generate. Not impossible, but hard enough to want to avoid.
In my corporate job, we used a good number of HSMs to manage keys, do signing, randomization, etc. They were nice to use, but I’m glad it wasn’t on my nickel.
An md5 hash of something unique per unit(salted hash, many iterations) for the serial gives you a 16-byte value, 32 hex digits. Not too bad to store in a database; can be encoded as a bit string in an x509 extension. Likelihood of a hash collision is still low enough in this case not to be an issue.
32 hex chars might be a long value, but can be copy/pasted from the terminal. Or, if the cert is on the flash filesystem, it can be pulled to a host machine and the serial extracted with OpenSSL or Python.
Agreed. In this case, the stated purpose is to provide unique serial numbers to prevent competitive analysis of production numbers. To distill to specific requirements: (1) unique, and (2) unpredictable.
(1) can be guaranteed by leveraging your choice of database’s UNIQUE qualifier on that column type.
(2) needs to be informed by the use case. For discouraging competitive analysis, grabbing 8 bytes from /dev/urandom may suffice. If not, use your choice of crypto-hard random number generation (HSM, etc.).
If you concatenate a monotically increasing number (or timestamp?) + secret key (and perhaps a revision number) and hash that and use that as the serial number, it will be (1) unique, and (2) unpredictable by anyone who does not know the secret key. It would also be (3) authenticated by those that do.
But the board could not authenticate it. If this serial number was also signed by a private key, and a public key was on the board, the board could authenticate itself.
Someone could clone the board, and use their own key pair, of course. But the factory could authenticate the serial number. A database of serial numbers would not be required.
You still need a way to store and protect the secret key for hashing, and the private key used for signing.
And key revocation is an issue.
Could you help me understand why a separate serial number would be beneficial? For example, why better to add all that, vs. just using the RP2350/RP2040 unique ID, which is statistically unique. For validation purposes, just sign the data you want to validate (even if only that unique ID) with your private key, and store that signature in OTP. Public key crypto lets anyone validate it without letting them also sign it?
cert command now has options to display or save the cert and public keys in PEM format.
I didn’t initially conceive of having a unique serial beyond the one in the RPi chip, but up thread we discussed having this secondary ID. I searched for how people “normally” do this, and blowfish was the most common suggestion. It seemed cool to have a number we could reconstitute without a database.
Reading a bit more about the initialization value, it seems unhelpful towards that goal. It is changed each time so that identical ASCII text messages are not identical. That is the opposite of what I’m after, we want each to be guaranteed unique. However, as far as I can tell, it is still secure using the same IV if the data inside is never the same.
That still leaves the issue that there is potentially a security hole by which the actual ID can be found.
I feel my best option is probably creating a random number and inserting it into a UNIQUE database field. I dislike this because when IDs collide it slams the database until it can create a unique one - though this may be exceedingly rare.
We know ahead of time approximately how many certs we need to issue, so I can create random numbers in batches ahead of time. This removes any hypothetical lag doing it in real time while production is in progress. The database is prepopulated with ID, and we can use a locking update to avoid potential simultaneous updates to the same ID.
Yeah, the IV should be unique every usage (not necessarily truly random, but unique). Then the IV needs to also be included in the ciphertext, usually appended (sometimes pre-pended; implementation specific). The IV protects starting with the first encrypted block; without an IV, identical “beginning” data encrypted into the first block with the same key becomes a crib to help crack that key. Unique IVs help prevent that.
I thought someone mentioned that they had some chips without the rPI unique ID in them. Having both gives provenance of the device from the DP serial number, and the rPI number ties it to that particular Bus Pirate (assuming there was an rPI serial/ID). This prevents a counterfeiter from simply copying the entire OTP contents for all of their copies.
If all of the chips do indeed have a unique rPI number, then that would be all that’s needed - read it out, add it to the manufacturing database, put it into the birth certificate. Wouldn’t even need to hash it - we’d rely on rPI to make them non-significant and unique.
Yes, adding some value to something getting hashed is called “salting”. I used that word earlier without defining it; apologies for that. The salt doesn’t need to be anything special; the important thing is multiple hashing passes.
My thought was that the hash would be stored in the manufacturing database, not the information used to create it. It would never be necessary to re-hash anything; just look up the hashed value in the manufacturing DB.
Adding the serial to the certificate as an x509 extension is the important part here. The cert is signed with the Dangerous Prototype’s private key; the public key is included in the software to authenticate the cert, which also authenticates everything in that cert.
Yes, key rotation and revocation is always an issue to consider in any PKI.
Side note - this is why threat modeling exists; we’d be able to hash this all out in that process (pun intended)
One thought on this: “what prevents the counterfeiter from making their own cert with serial numbers and downloading the code from git and replacing the public key with their own?”
That cert would validate and it would look legit.
The only defense is: download the latest from the official git repo and do the internal validation; it will fail.
Also: every PR needs to be reviewed before merge to be sure that functionality and/or keys are not changed.
If the counterfeiter has a RP2350 without OTP page 0 (unique ID, etc.), and a real BP6 device, what prevents them from cloning anything you put into it?
I suppose you could also pull the flash chip’s unique ID, and include that in the certificate. That would raise the bar to requiring not only an unpersonalized RP2350, but also a flash chip allowing customer defined serial number.
So, if your threat model includes blocking the use of unpersonalized RP2350 exist, what is preventing the full clone of an existing BP6 device?
Yes! Agreement 100%. Private / Public key crypto is exactly for this purpose! The data within that signed certificate is implicitly protected from modification (without detection).
I submit that this is outside the threat model. A counterfeiter could load firmware that just skips the check altogether and prints whatever result it wants to console / LCD. Nothing should rely on this certificate. It’s entirely up to the user if they want to validate it.
If you really wanted to prevent counterfeits, you’re looking at code signing and code integrity enforced by the chip. I refer folks to the multi-stage bootloader used in the Xbox One (and later) for a good method.
Given the busPirate is a device targeting hackers (and custom firmware), preventing folks from loading their own certificates / custom firmware seems out-of-scope.
I didn’t mean that the cert affects any operation, just that it would be a step in, for example, a warranty claim. “Download latest from git, run the cert command, and copy/paste ID info into an email/form”. That’s assuming it powers up, of course.
100%! I always build the firmware and load it because I’ve been hacking on it.
As far as a user’s own cert, that’s fine, too. This is just about knowing if you have an “authentic BP”.
Does it sound like we can avoid the bus pirate specific serial and go with the unique chip ID?
I’ll make a new cert proposal tomorrow. I’d like to get it as short as possible. I believe the crashing we’re seeing is due to all the big variables involved, and it’s going to get worse when we have to load the cert into ram from OTP. Currently it’s in flash.
One thing that would reduce ram is if I wrote our own DER to PEM base64 encoder so we can save/display in a loop instead of into a huge buffer. I looked at the mbedtls code that’s doing it. Not too complicated but not high on my list to deal with.
Another option is to only print/save DER format only, but that feels like a cop out.
I got my shipment of a few Pico2 boards and wanted to play with the OTP and other stuff. Of course, the first thing I did was checkout the cert branch and give it a try!
True, although they are engineering samples, and not generally available in this form. Also of note, from the datasheet 13.5.4:
Page 0, known as the chip info page, is not a special page. Raspberry Pi sets page 0 to read-only during factory test, after writing chip identification and calibration values
Items in OTP Page0
64-bit ChipID
64-bit Per-device Random ID
Ring oscillator frequency (@ 1.1V, room temp, reset state, etc.)
Low-Power oscillator frequency (@ 1.1V…)
CRIT0 boot flags (permanent disabling of ARM and/or RISC cores)
Thus, although the unique IDs might be zero, it’s also highly likely that the calibration values for the two main oscillators are also unprogrammed. It’s unclear how the chips would operate (especially at boundary conditions) without proper values written there. Maybe there’s a way to write the proper values there manually, after testing to detect the right values? But … I wouldn’t trust anything timing sensitive, which is pretty much everything the BusPirate was built for. Or maybe that’s just me?