Request for Guidance and Documentation on ERASEPROTECT/APPROTECT/SECUREAPPROTECT

Hi,

We've created an application for the nRF9160 non secure image with TF-M and are looking to add in ERASEPROTECT/APPROTECT/SECUREAPPROTECT functionality. From reading the Production Programming document I can see that when enabling ERASEPROTECT, APPROTECT, and SECUREAPPROTECT, the only way to recover the device is "if the installed firmware and the debugger both write the same non-zero 32-bit KEY value to ERASPROTECT.DISABLE (0x01C)"

My understanding is that since we already have a application that we want to build for non secure (for example, if it was the Blinky sample built for the nrf9160dk_nrf9160_ns with TF-M), we would need to create a separate secure image in order to write the non-zero 32-bit key value to ERASEPROTECT.DISABLE.

My questions are:

  1. How can we create a separate secure image with our nonsecure application? As I understand, the secure image should run first before handing over control of the execution to the nonsecure application. What would be the best way to add an additional secure image to something like the nonsecure Blinky sample? Would this be a child image?
  2. Is there any examples of how to interact with the ERASEPROTECT, APPROTECT, and SECUREAPPROTECT settings from the application side? I unfortunately don't have much experience working directly with various registers on the nRF9160 and would be happy to get any help possible, especially with regards to what needs to be provisioned to interact with the registers and if there is a getting started guide for tasks like this. I want to create a script that upon boot up of the nRF9160, the program: 
    1. Checks if any of the ERASEPROTECT, APPROTECT, and SECUREAPPROTECT functionalities are not enabled. If any of these are not enabled, the program will enable the protection and perform a reset of the device. On the next boot up, all three of the protections should be enabled.
    2. If ERASEPROTECT, APPROTECT, and SECUREAPPROTECT are all enabled, it will write a 32-bit key to ERASPROTECT.DISABLE. This way, if we need to recover the device, we can use the SWD to write in the 32-bit key to trigger an erase all
    3. Finally, hands over execution to our nonsecure program
  3. Our current application uses MCUBOOT and supports OTA. Would ERASEPROTECT affect the application's ability to download new application updates and boot up with the new updates?

I've found some previous posts which seem to be quite helpful, however I'm still unsure of how I would need to go about integrating it into an existing nonsecure application. 
This post seems fairly helpful in talking about how to create a non-ns script to remove erase protect. However, I'm having a bit of difficulty following/finding the documentation on modifying/reading contents for items like NRF_NVMC and NRF_UICR through the application, and what the particular bits like (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos) being set indicate. 

Thank you in advance!

Parents
  • Hi

    We have a GitHub script that should work for disabling eraseprotect that Sigurd links to in this ticket. Here he also links to the device protection Application note that can be usefult for additional information. Other than that we don't have a specific sample that does this I'm afraid.

    Best regards,

    Simon

  • Hi Simon,

    Similar to what Rory mentioned in editing MCUboot, is there an easy way to create a bootloader with the code to set the UICR registers in the secure domain that occurs before or after the MCUboot bootloader? 

    Alternatively, is there a way have a complied hex of a script of your linked ticket included to be run with a non secure application with a multi-image build? I've tried to follow the multi-image build instructions and some examples from the nrf sdk, but unfortunately I haven't had much luck in getting it to work. I can share a zip of what I am working on, if helpful.

    Another way I can think of this is to ask how one could add the ERASEPROTECT.disable key write into the nRF Asset Tracker V2 application? Would the best way still be to edit MCUboot directly?

    Edit to add:
    Is there possibly a good way in TFM to create a function that can execute in the secure environment that is invoked from the non-secure side? E.g. The non secure side calls function in secure side to write a value into the UICR ERASEPROTECT.disable?

    Thank you for your help!

  • Hi Edward

    Why do you need to change UICR data from the bootloader? It is recommended to leave the UICR alone, as bootloader addresses are stored there for example, so it's easy to tread wrong. If you have data that needs to be changed more often, I'd suggest using a dedicated flash page to store this instead of UICR. 

    Why exactly do you need to make changes to UICR during runtime?

    Best regards,

    Simon

  • Hi Simon, 

    My apologies in advance if I am incorrect about this, but I want to be able to write (or trigger a write for) a key to the ERASEPROTECT.disable register from my current application.

    To my knowledge, the major constricting requirements are that my application is required to be built for ns (i.e. nrf_modem_lib requires to be run from non-secure firmware), it uses TF-M, and uses MCUboot (for FOTA). I believe the nrf asset tracker v2 has a similar set of requirements, so it could be a good reference for what solution would be needed.

    From Rory's answer above, the best way we know of to set this consistently is through editing the MCUboot Bootloader main.c file to include the following write:


    if (NRF_UICR_S->ERASEPROTECT != UICR_ERASEPROTECT_PALL_Unprotected)
    {
        NRF_CTRL_AP_PERI_S->ERASEPROTECT.DISABLE = (uint32_t)0xDEADF00D;
    }

    I would need a consistent way to be able to set this information either before my application boots or to be triggered to be written, so it can still be recovered when all three of the erase protect, approtect, and secureapprotect functionalities are enabled. The downside of directly editing the MCUboot file is that this change is less portable -- if I were to have a coworker build my application, I would need to have them edit the MCUboot file in-tree. Additionally, the Bootloader isn't upgradable in this case, so the method for generating/setting the key cannot be changed over an OTA update. Furthermore, modifying the MCUBoot Bootloader directly with anything more complex seems risky, as I don't fully understand the MCUBoot Bootloader code. I have some additional logic I want to add for generating the key, but I am not sure if it is safe to add this logic to the Bootloader. 

    I've been able to replicate the ability to write this key in a couple of other ways, each with challenges to integrate into my application:

    - Creating a script built for the nrf9160dk_nrf9160 (not ns) to set the register, however I didn't have much luck integrating this into my current application, as my current application is built for nrf9160dk_nrf9160_ns. I attempted to build a child image with the goal of the secure child image to run and set the key before the main image boots, but was unsuccessful. I can attach a zip of this attempt if helpful.

    - Using the TF-M secure peripheral/partition examples to have the non secure partition send a request to execute some code on the secure environment. This doesn't appear to work in my case since different TF-M build profiles beyond the default don't seem to build with MCUboot. The TF-M secure peripheral/partition seems to require some customization to the TF-M profile settings.

    Thank you in advance for your help!

  • Hi,

    I will continue to help in this case.

    blasph said:
    My apologies in advance if I am incorrect about this, but I want to be able to write (or trigger a write for) a key to the ERASEPROTECT.disable register from my current application.

    Yes, that is a good idea.
    I would generally recommend writing your key to this register before enabling eraseprotect.
    This is so that you are sure that you never lock the device before a key is set.

    blasph said:
    that my application is required to be built for ns (i.e. nrf_modem_lib requires to be run from non-secure firmware)

    Correct

    blasph said:
    believe the nrf asset tracker v2 has a similar set of requirements, so it could be a good reference for what solution would be needed.

    Also yes.

    blasph said:

    From Rory's answer above, the best way we know of to set this consistently is through editing the MCUboot Bootloader main.c file to include the following write:

    Doing this in MCUboot is a valid option.

    blasph said:
    The downside of directly editing the MCUboot file is that this change is less portable -- if I were to have a coworker build my application, I would need to have them edit the MCUboot file in-tree.

    We will move from multi-image builds to sysbuild soon, and then I think it will be easier to do something like this.
    But we are not there yet, so for now, I agree, it is less portable.

    blasph said:
    Furthermore, modifying the MCUBoot Bootloader directly with anything more complex seems risky, as I don't fully understand the MCUBoot Bootloader code. I have some additional logic I want to add for generating the key, but I am not sure if it is safe to add this logic to the Bootloader. 

    I agree very much with this. It can be risky to do this inside MCUboot if you want to generate the

    blasph said:
    - Creating a script built for the nrf9160dk_nrf9160 (not ns) to set the register, however I didn't have much luck integrating this into my current application, as my current application is built for nrf9160dk_nrf9160_ns. I attempted to build a child image with the goal of the secure child image to run and set the key before the main image boots, but was unsuccessful. I can attach a zip of this attempt if helpful.

    I do not understand completely what you are trying to do here.
    If you want to write to secure registers when TF-M is enabled, you options are MCUboot or how it is done in the TF-M secure peripheral partition sample, by creating a Application RoT Service. See An Introduction to Trusted Firmware-M (TF-M) for more information on TF-M.

    blasph said:
    - Using the TF-M secure peripheral/partition examples to have the non secure partition send a request to execute some code on the secure environment. This doesn't appear to work in my case since different TF-M build profiles beyond the default don't seem to build with MCUboot. The TF-M secure peripheral/partition seems to require some customization to the TF-M profile settings.

    TF-M will build as part of your application, and does not know about MCUboot.
    Either set ERASEPROTECT.DISABLE from MCUboot or from TF-M.

    See TF-M secure peripheral partition sample.

    EDIT:

    Just want to add some nuance. While it is risky to do stuff in MCUboot, setting ERASEPROTECT.DISABLE later is also risky, as more things can go wrong before you can revert ERASEPROTECT.
    So in the end, I do not see any "perfect" place to do this operation. So you kindof need to decide if you want a more robust MCUboot, so you know you can DFU if anything fails. Or if you want a more robust ERASEPROTECT disable, so you can reprogram if anything fails.

    Regards,
    Sigurd Hellesvik

  • Hi Sigurd,

    Thank you for getting back to me!

    I would generally recommend writing your key to this register before enabling eraseprotect.
    This is so that you are sure that you never lock the device before a key is set.

    My impression was that the ERASEPROTECT.disable key had to be set on each reboot. Does the ERASEPROTECT.disable key persist across reboots, and only need to be set once then?

    We will move from multi-image builds to sysbuild soon, and then I think it will be easier to do something like this.
    But we are not there yet, so for now, I agree, it is less portable.

    Thank you for letting me know about this. I encountered a few examples in the 2.4.0 examples and wasn't sure what it was about.

    If you want to write to secure registers when TF-M is enabled, you options are MCUboot or how it is done in the TF-M secure peripheral partition sample, by creating a Application RoT Service. See An Introduction to Trusted Firmware-M (TF-M) for more information on TF-M.

    I am currently trying on implementing this and have been working on it for the last couple of days without success. I have been able to successfully able to use the example to create and set the Eraseprotect key for my device. However, I am having difficulty integrating it into my main application. 

    In my attempt to integrate it into my main application:

    - I copied over the relevant CMakeLists.txt additions from the tfm_secure_peripheral sample and merged them into my main CMakeLists.txt file

    - Modified the secure_peripheral_partition.c file to no longer use the sample peripherals and only generate and set the key (and removed the init and while loop from the tfm_spp_main, as I only need this code to run once at boot up and not again)

    - copied over my modified secure_peripheral_partition directory

    - copied over the prj.conf symbols CONFIG_TFM_IPC=y and CONFIG_TFM_ISOLATION_LEVEL=1 from the sample. The TFM_PROFILE_NOT_SET=y makes my project not build, but I've also removed this symbol from the sample and the sample still works

    When running my application, I see the key now gets set properly, but my main application fails to run. Would it be possible for me to create a private ticket to see if I could get some help with this final integration step? 

    I will continue doing some further testing and will get back to you as soon as I have new information.

    Thank you for the help!

  • blasph said:
    My impression was that the ERASEPROTECT.disable key had to be set on each reboot. Does the ERASEPROTECT.disable key persist across reboots, and only need to be set once then?

    Good catch!
    You are correct, so my suggestion is not really useful.

    Additionally, there is a bug in the docs on ERASEPROTECT.DISABLE: The register is not RW, but is R1.
    So you can not read out the value to verify that the data is set. (It will always read 0).

    blasph said:

    - I copied over the relevant CMakeLists.txt additions from the tfm_secure_peripheral sample and merged them into my main CMakeLists.txt file

    - Modified the secure_peripheral_partition.c file to no longer use the sample peripherals and only generate and set the key (and removed the init and while loop from the tfm_spp_main, as I only need this code to run once at boot up and not again)

    - copied over my modified secure_peripheral_partition directory

    - copied over the prj.conf symbols CONFIG_TFM_IPC=y and CONFIG_TFM_ISOLATION_LEVEL=1 from the sample. The TFM_PROFILE_NOT_SET=y makes my project not build, but I've also removed this symbol from the sample and the sample still works

    From just reading the steps, they seem reasonable to me.

    blasph said:
    When running my application, I see the key now gets set properly, but my main application fails to run. Would it be possible for me to create a private ticket to see if I could get some help with this final integration step? 

    Definitely! Just create a ticket and reference this one.

Reply
  • blasph said:
    My impression was that the ERASEPROTECT.disable key had to be set on each reboot. Does the ERASEPROTECT.disable key persist across reboots, and only need to be set once then?

    Good catch!
    You are correct, so my suggestion is not really useful.

    Additionally, there is a bug in the docs on ERASEPROTECT.DISABLE: The register is not RW, but is R1.
    So you can not read out the value to verify that the data is set. (It will always read 0).

    blasph said:

    - I copied over the relevant CMakeLists.txt additions from the tfm_secure_peripheral sample and merged them into my main CMakeLists.txt file

    - Modified the secure_peripheral_partition.c file to no longer use the sample peripherals and only generate and set the key (and removed the init and while loop from the tfm_spp_main, as I only need this code to run once at boot up and not again)

    - copied over my modified secure_peripheral_partition directory

    - copied over the prj.conf symbols CONFIG_TFM_IPC=y and CONFIG_TFM_ISOLATION_LEVEL=1 from the sample. The TFM_PROFILE_NOT_SET=y makes my project not build, but I've also removed this symbol from the sample and the sample still works

    From just reading the steps, they seem reasonable to me.

    blasph said:
    When running my application, I see the key now gets set properly, but my main application fails to run. Would it be possible for me to create a private ticket to see if I could get some help with this final integration step? 

    Definitely! Just create a ticket and reference this one.

Children
Related