Digital Signatures for Security

Yes, RDP only prevents readout using JTAG. You also need to disable DFU mode, which can only be done currently by making a modified version of the bootloader.

That is described here:

However then you also need to find a way to disable listening mode, because otherwise while in listening mode you could flash a bootloader with DFU enabled. You’ll probably need to disable or modify safe mode as well.

2 Likes

Thank you very much for your quick reply. It is greatly appreciated, since we are trying to finalize firmware for a product release.

I have checked your notes on how to disable listening mode via the bootloader code. In order to disable listening mode and safe mode, can we make a similar modification to the bootloader code? Or, do we need to make this modification in the user firmware?

I haven’t verified for sure that this will work, but I don’t think you really need to disable listening mode and safe mode. Plus, disabling safe mode would make it difficult to upgrade system firmware.

The trick I think will be to intercept the call to OTA_Flash_Reset() in the bootloader main file if the file is the bootloader. In other words, instead of trying to prevent downloading a replacement bootloader, you just prevent it from installing. This also has the benefit of only requiring a bootloader change, which you already need to be doing anyway, as well. There shouldn’t be a need to modify system or user firmware if you do that.

Thanks @rickkas7. I think I understand what you are saying.

So, we will need to:
(1) Comment out “HAL_DFU_USB_Init();” to disable DFU
(2) Comment out “OTA_Flash_Reset();” after we have already flashed our desired user firmware, which will be locked down

Please correct me if I am misunderstanding anything.

That seems right. I can’t guarantee it will work as I’ve never tried it, but it seems promising.

@rickkas7

It may have worked! (but not 100% sure yet)

I think my P0 now has a modified bootloader (bootloader_noDFU.bin), which has DFU disabled, and OTA_Flash_Reset() disabled.

However, I can still write the original bootloader to 0x08000000. But I am pretty sure the P0 is not actually using the original bootloader. I think the P0 is still using bootloader_noDFU.bin, even though the original bootloader gets written to 0x08000000. Does that make any sense?

What happens when OTA_Flash_Reset() is called?

In particular, what happens after the bootloader is written to 0x08000000?

Unfortunately, I don’t think disabling “OTA_Flash_Reset();” achieved the desired affect. It was worth a shot.

So, I guess my best solution is to disable DFU mode, disable SAFE mode, and automatically exit LISTENING mode as soon as it is detected. Then, I will also enable RDP level 2. Do you think this will be sufficient to protect against the read-out of user firmware?

Yes, that will probably work. I think the problem is that flashing the bootloader might be a special case. Normally parts are written to the OTA sector then moved into their correct place at boot, but now that I think about it, that would be a problem for the bootloader because the bootloader can’t replace itself because the STM32 does XIP (execute-in-place). That’s also why you can’t write the bootloader in DFU mode.

So the STM32 has an internal root of trust for verifying the bootloader. Are particles bootloaders cryptographically signed so they can be verified? Are firmware images (DeviceOS and User parts) that come in via OTA signed against the STM32 root of trust?

No, the STM32 has no internal root of trust; there is no mask ROM that verifies a first stage loader in flash is correct before executing. The main security feature on STM’s is that flash is on-die, so hard (not impossible) to disturb as long as all the security features are enabled such as RDP2.

It is possible to glitch RDP2 devices into RDP1 (see https://chip.fail ) which doesn’t give code readout but does enable JTAG and allow RAM contents at the time of reset to be read; the gitch just needs to flip a single bit in the flash config register to do this. Whilst in theory you could glitch it into RDP0 with the same trick, you need to flip multiple bits just the right way… exponentially harder.

In RDP2 mode, the system ROM DFU mode is disabled as is JTAG/SWD. However, code running on the device can still jump to the system ROM DFU code and hence enable it, but this sounds like particle behavior not inherent to the STM32.

Note that there is generally no way back from RDP2, which means if a device ever got to a point where it required particle doctor when in RDP2, it’d be a brick and unrecoverable. When you use RDP2 you need to be really, really sure that you’re never ever going to need DFU or JTAG ever again.

I don’t believe particle images are signed, though they are sent over the encrypted channel. On electric imp devices, OS upgrades are both AES encrypted and RSA signed, with the private key being stored in a FIPS140-2 HSM that requires multifactor physical authentication to perform a signing. Some imp devices like the imp005 do validate encrypted boot images using mask ROM code, but STM32-based ones are using RDP2 and a bootloader to validate OTA upgrades as they are applied because there aren’t any other ways to do it.

Security is hard!

Thanks!
I think I made a faulty assumption due to this application note.

It implies that the STM32 has secure boot and root of trust onboard, but re-reading it it sounds like they are speaking in a general sense. Or perhaps it only applies to specific models.

Assuming I had an off-chip crypto facility with a signing key stored in a locked region (no write after initial key store), would it be possible to use RDP2 mode with a bootloader that could only run signed code? I assume I’d need to replace particle’s bootloader, access the root of trust off chip and check that the code is signed with the key before jumping to execution?

I’m sure there are a ton of other considerations, but I’m just trying to scope the problem.
Certain markets require a high-degree of tamper-resistance.

From a quick skim, that doc refers to secure bootloaders as something that customers can write which are just normal application code that runs first at boot which then might mediate access to other codebases.

Having the root of trust off-chip for secure boot isn’t necessarily a great idea; sure, you get to put keys into a die which has protection against things DPA, but you still need to communicate with it over a channel which is easily observable and possibly MITM-able/replay-attackable.

You can protect this channel on many of the security chips, but that’s by storing secrets in the STM32 that are obtained from the security chip at PCBA test time, and then further locking the security chip down (eg: HMAC sign requests with a shared key, encrypt traffic with a shared symmetric key). You’ve added a pile of complexity, but the MCU that runs the code could still be hacked to ignore signatures regardless of the security chip.

With internal flash it’s MUCH easier to simply not allow code to be written to the internal flash unless it is cryptographically verified - put the burden on the upgrade process, not the boot process. In our case that means storing a public key within the device and using this to verify the upgrade has not been molested since it was signed (over whatever networks or servers it has traveled through). When, not if, this public key escapes, the integrity of the signing process is unaffected - this is why you use asymmetric crypto.

1 Like