Secure Boot on Rock 5B

I’m trying to enable Secure Boot on Rock 5B by burning RSA public key to OTP fuse.
Following the Rockchip_Developer_Guide_Secure_Boot_Application_Note_EN.pdf guide I was able sign and upload the signed firmware to the devices. As per the doc, the first time a signed firmware boots it should burn fuses automatically, but apparently it doesn’t happen as I’m still able to boot with unsigned firmware.

Have tried the same approach on other RK3566/RK3568 boards with no luck.

At the same time on RK3399, I was able to burn keys with EFuseTool and everything works.

I couldn’t get it to Secure Boot either, I could be wrong but from what I gather it’s the lack of mini loader on my end, and I can’t find any code in the build repository that indicates that the trust files get packed in to the idbloader for any rk35xx build

From chapter “6.6 Programming OTP”:

If OTP program success, serial port print “otp write key success!!!”. If OTP program fail, serial
port print"otp write error: !!!".

I found out only the following loaders have the required logic:

$ grep -r "otp write key" rkbin/bin/rk35/
grep: rkbin/bin/rk35/rk3588_ramboot_v1.06.bin: binary file matches
grep: rkbin/bin/rk35/rk3568_miniloader_spinand_v1.15.bin: binary file matches
grep: rkbin/bin/rk35/rk356x_spl_nand_v1.14.bin: binary file matches

So for RK3588 the only suitable loader for enabling secure boot is rk3588_ramboot_v1.06.bin.

I created idbloader.img and signed it using the following commands:

$ ./uboot/bools/mkimage -n rk3588 -T rksd -d rk3588_ddr_lp4_2112MHz_lp5_2736MHz_v1.08.bin:rk3588_ramboot_v1.06.bin idbloader.img

$ rk_sign_tool ssr --key privateKey.pem --pubkey publicKey.pem --idb idbloader.img

but that doesn’t enable secure boot either (SecureMode = 0):

DDR Version V1.08 20220617
LPDDR4X, 2112MHz
channel[0] BW=16 Col=10 Bk=8 CS0 Row=17 CS=1 Die BW=16 Size=2048MB
channel[1] BW=16 Col=10 Bk=8 CS0 Row=17 CS=1 Die BW=16 Size=2048MB
channel[2] BW=16 Col=10 Bk=8 CS0 Row=17 CS=1 Die BW=16 Size=2048MB
channel[3] BW=16 Col=10 Bk=8 CS0 Row=17 CS=1 Die BW=16 Size=2048MB
Manufacturer ID:0xff 
CH0 RX Vref:27.7%, TX Vref:22.8%,0.0%
CH1 RX Vref:28.7%, TX Vref:23.8%,0.0%
CH2 RX Vref:28.7%, TX Vref:21.8%,0.0%
CH3 RX Vref:27.7%, TX Vref:22.8%,0.0%
change to F1: 528MHz
change to F2: 1068MHz
change to F3: 1560MHz
change to F0: 2112MHz
out
Boot1 Release Time: Feb 24 2022 10:23:56, version: 1.05 USB BOOT
ChipType = 0x32, 481
SecureMode = 0
atags_set_bootdev: ret:(0)
UsbBoot ...1079
powerOn 1340
Usb no Connecte. 6001342
Usb no Connecte. 12001344
Usb no Connecte. 18001349
Usb no Connecte. 24001357

@kirgene @ibebarrett Hi! Were you able to get the Secure Boot thing done? I was looking for some documentation and could not get anything more up-to-date than https://github.com/yunzhaoyu2050/rockchip_rv1126_rv1109_docs/blob/main/Kernel/NVM/Rockchip_Developer_Guide_Secure_Boot_Application_Note_EN.pdf

I messaged you on Discord as I saw you posted about this there…

I was able to fuse my RK3588S (not a RockPI 5B!) to secure boot enabled and now I can only run/flash code that is signed.

After trying to get the ram loader (ramboot_v1.06) to work, I gave up and reverse engineer how to do it manually and this resulted in success.

For the record, here’s how I think fusing secure boot should work:

  1. Boot with the ram loader
  2. Sign an image with “sign_flag=0x20” in settings.ini before signing. This is what triggers the first step of secure boot provisioning
  3. Use rkdevelop to send the image in 2 to ram loader over USB. This will tell ramloader to program the public key information hash and the secure boot enable flag into the OTP/fuses.

My problem is that I could not figure out the right incantation of that satisfied 3). I believe it should be rkdevelop ul bla.bin, but whatever bla.bin I sent, it was always rejected.

1 Like

Hi There, thank you for posting your results, good to know!

And did you try flashing it with dd? Something like this?
sudo dd if=./out/u-boot/idbloader.img of=/dev/mtdblock0 bs=512 seek=64
sudo dd if=./out/u-boot/u-boot.itb of=/dev/mtdblock0 bs=512 seek=16384

I don’t have flashing problems. The problem is only “ramboot” currently programs the OTP to enable secure boot. The proper incantation would be to send ramboot and then send a signed image, but ramboot is refusing any image sent to it.

For my board (Orange PI 5B), I wrote my own bootloader to program the OTP and now only signed files work (which is what I wanted).

1 Like

If anyone is interested in enabling Secure Boot on their RK3588 device, I’ve released instructions and tools at my github. I don’t recommend doing it if you’re not capable of understanding C code and compiling it. I’ve made it as simple as possible, but it’s still a bit convoluted. Since enabling SB has a risk of bricking (hasn’t happened to me but…) I’ve also made it “difficult” in a few places to make sure you read the instructions correctly. If you don’t, you cannot enable SB.

4 Likes

Currently I would advise against enabling Secure Boot because the bootloaders are not expecting it. The SPL from RockChip was not built with SB in mind and will spit out an error that CONFIG_SPL_FIT_SIGNATURE is not enabled and stop the boot process. After patching this check in SPL, u-boot complains about various avb things due to SB, all annoying to patch out.

Until Radxa / RockChip release bootloaders source or binaries supporting Secure Boot, it’s not worth the effort if you want to use existing released images.

2 Likes

For those interested, we’ve successfully enabled Secure Boot (on a different board not Rock 5B), along with full disk encryption, and everything seems to be working smoothly. But yes, as @DualTachyon pointed out it was quite a bit of effort. It is even frustrating to realize that while this feature is actually supported by the hardware, yet documentation is scarce, and all board manufacturers we talked to do not support this feature.

2 Likes

@gilbertchen and @DualTachyon can you please say what observation do you get when trying to load any unsigned bootloader after enabling secure boot using rkdeveloptool db xx.bin ? And @DualTachyon do you get a minimal uart output when loading your custom unsigned bootloader on a secured SoC?

We are trying to diagnose a board we have, that embeds RK3588S and refuses to load any bootloader, and while it gets recognized in maskrom, we have no clue why it is the case. Power and current are also in good figures. A different board can load any bootloader, rockchip binaries or DualTachyon’s custom one.

We have the feeling that the non-working one was locked up during manufacturing, or accidentally pre secured. So we’re trying to compare similar patterns to confirm. Ultimately we will try to enable secureboot on the working SoC and compare.
Lack of documentation and support from rockchip doesn’t make this easier.

There are multiple bootloaders in a typical RK3588 bootchain. I will talk about the first binary loaded by ROM, that RockChip calls “idbloader”.

If you load an unsigned binary, the RK3588 will appear as “dead”. It will do nothing. There are no printfs over the UART because the ROM doesn’t have any.

The first printf to show will always be from the DDR training, which will not run if the “idbloader” image is not signed correctly.

Try uploading the image “RK3588_SPL_Loader_v1.15.113.bin” from this link: https://docs.radxa.com/en/rock5/rock5a/low-level-dev/maskrom/linux

The DDR training part should run minimally if your device is not busted, even if it’s not compatible with Rock 5A.

If you cannot get some UART, then chances the RK3588 has issues.
In case your UART was not wired or setup correctly (Use 1_500_000 baud 8N1 for settings), you can try doing a “rkdeveloptool rid” after running “db” with the image. If this succeeds, then the RK3588 is working but maybe you have a problem with the UART connection.

No it won’t accept any loader or custom loader. I am not even trying to get to DDR training. I used your custom bootloader to just setup a uart and display a test message. I also doubt that the uart subsystem is not working as the SoC manages to also setup the pull-ups and pull-downs on the GPIOs within the same PMU and I could measure voltage on them. Also the fact that the USB enumeration and entering maskrom work fine, indicate that the CPU is working to a certain extent.

One behaviour that can give a hint here, is that when uploading the “471” binary part, the uploading would work the first time (always no uart output), but the second time it just hangs until I have to reset the board. Is a RK3588(S) with secure boot enabled, behaves the same way?

Hmm, for some reason I didn’t get a notification of your reply and only noticed now your reply.

  1. When you say “any loader”, do you mean “SPL loader”?

  2. You cannot upload 471 more than once without a reset/reboot, so trying it a second time will fail if the first one succeeded.

  3. Sending a good or bad 471 will appear to succeed even when SB is enabled but your file is not signed. Without UART, there’s no way to know which scenario is your case.

  4. JTAG/SWD is disabled in SB mode. You can test whether your RK3588 is SB enabled or not, by connecting to it while in forced Maskrom Mode. Check the schematics for Rock 5B and wire up a jlink/stlink to the SWD pins (GND = GND JTAG_TCK_M0=SWDCLK, JTAG_TMS_M0 = SWDIO) via the SD card slot (you can use something like this https://proto-pic.co.uk/product/microsd-sniffer-usd-breakout-board). You can invoke OpenOCD in the following way:

openocd -f interface/jlink_or_stlink.cfg -f target/rk3308.cfg

rk3308 is the wrong chip, but if the chip is somewhat working, it will at least detect the chip ID, which would mean it’s alive. If it is not able to connect at all, then the chip is either “dead” or SB enabled.

When I say forced maskrom mode, you have to hold the button / short the maskrom vias before supplying power to the Rock 5B. If you don’t do that, and assuming the chip is not dead, it will try to boot to Micro SD card before going to maskrom. the Micro SD boot mode will disable JTAG because they’re using the same pins and Maskrom mode doesn’t restore them.

First @DualTachyon, thanks for the work on the bootloader, it helped a lot with debugging. We are talking about SPL loaders. Now, I followed your instructions and we managed to connect through SWD to the booting board in both forced maskrom and also when loading the custom bootloader, which initializes the SWD interface.

However, the two boards that are not booting do not respond via SWD and openocd shows that it cannot connect to the target. While these boards are powered up and able to enumerate USB and enter maskrom, we believe that they are alive. But no SWD access strengthens the indication of being boot secured.

One remark here about sending 471 multiple times before reset. Yes it would work once and needs reset for the booting boards. But for the non booting ones, it always succeeds in uploading the 471 data without reset and libusb never returns any error. Do you observe that when loading the wrong unsigned loader to the boot secured SoC on your end?

Yes. As I mentioned in my bullet 3), sending 471 to a Secure Boot enabled device will always succeed, even if the image is not signed correctly.

Unfortunately, if the device is truly Secure Boot enabled, there’s nothing you can do with the device other than obtain signed artifacts or the private signing key, from whoever used or gave you the devices.

Regarding the problem of reading and writing OTP failure, perhaps the enable bl32 part of this document can be solved: https://docs.radxa.com/en/rock5/rock5b/low-level-dev/rk_anti_copy_board

We contacted the distributor. Otherwise, we will replace the SoC and try again. I will update about the results. Thank you.