Writing a pre-flight check for burning the cert. Let me know if something seems off. I’m not transporting with a CRC or anything because I assume a corrupt cert won’t verify:
Is the cert valid against the public key?
Does the cert serial match the RPi serial?
Are the pages we’re going to use already protected?**
Are the rows we plan to use empty?
Burn and verify each row (burn is actually very slow!)
Number of OTP pages required: 7
Protection pages: 004 : 00a
First protection row to program: f89
Last protection row to program: f95
Cert write to OTP: 32
**Code to determine what to protect seems to be working. Return status 32 means OTP not blank (because I have a cert there )
One issue with my current approach is that I use the first row (2 bytes) to store the length of the cert. I don’t believe the length is consistent. So I need to:
Reshuffle all the math to account for an extra row, or
We’ve discussed some kind of directory structure with entries starting from the last free page and moving forward. If that contains the data length, then we wouldn’t need to start the cert with it.
Leading to a few concerns:
The protection fuses are not very granular, so the directory table would be unprotected (only soft protection) and could become corrupted rendering everything useless.
Perhaps the “really important stuff” like cert, any hardware/manufacturing info should have a fixed location (along with a directory entry) so it can survive a corrupt directory table
Looping us back to needing the cert length at in the first row of the cert.
EDIT: it seems like if only the serial and validity change the cert is the same length, but what if we update a field in the future? Think the issue still applies.
The DER format has the length encoded at the beginning!
The first byte is 0x30
The next byte is the length (maybe):
If the length is less than 128 bytes, then the length is second byte (up to 0x80).
If the length is 128 to 256, then you’ll have 0x81 for the second byte and the third byte will be the number of bytes from 128 to 256 (0x81 XX)
If the length is greater than 256, then byte 2 is 0x82 and the next two bytes are the length: 0x82 XX XX
If I look at the post above where you’re showing the row data, I see:
Row 0x101 is 0x8230 - correcting for endianness, that’s 0x30, 0x82. This is a DER (0x30 in first byte), length is > 256 bytes (0x82) in the second byte
Row 0x102 is 0x0203; changing endianness makes is 0x0302 or 770 decimal
(I think that means read the next 770 bytes as cert info; you’re already past the first four bytes).
I see Row 0x100 is 0x0603, little endian for decimal 774 which matches the above stuff.
Parsing ASN.1 stuff is strange with rules like that
Oh excellent, thank you! I assume for the pub key as well. Will add that. It also gives a way to search for the cert if the directory is corrupted I suppose.
The packing of the bytes was entirely my choice, but I did so thinking I can do some fancy magic to pull it back together. Currently it’s just << | , and there really isn’t any shame in that either.
Cert pages locked. One full cycle completed, and one PICO2 sacrificed
The code is an absolute mess, but now I know how to put it all together this weekend.
Some things:
Will extract the length from the cert instead of burning it at the beginning of the cert
I’m going to run with cert starts at row 0x100 until suggested otherwise
Need to look at what Henry proposed for the directory system and implement that
I’m going to expand the “model” to include the revision, but there’s a little bug somewhere I may need Henry to have a look at, we’ll see
We have a field “manufacturing data” in the whitelabel space, it appears as the board-ID. I’m planning to program the RPi unique ID here as ASCII numbers so the board can be identified even if a firmware won’t load.
Looked into this. I don’t see the ability to do per file protections in github, but I can make the public key a submodule in a repo where we lock the main branch and don’t accept pull requests.
If it’s necessary to get the cert, it would just be a matter of getting all of OTP and pulling it out. Even just displaying it all as hex in the terminal and copy/pasting for a Python script or something to extract. A fun exercise for someone
I’m thinking maybe store these as ASCII text with a beginning token and null termination. It is redundant, but I would prefer not to parse the cert to get at that info. Especially if there are ever clone devices without a valid cert. We could just trust the cert even if not valid, but I would think an invalid cert shouldn’t be trusted.
There are 128bytes in the page, any other info that should go in there?
Getting the raw individual OID values turned out to be quite the adventure, but the info section now seems to be parsing out of the cert data correctly:
IIRC, per-file protections are possible (branch protection rules?) … I’ll take a look in the next few days. Submodules increase complexity for non-expert git users … I’ve found it a support headache and generally recommend avoiding it where possible.