What is the impact of having ENABLE_APPROTECT define with nRF5 SDK but not setting UICR->APPROTECT to 0x00?

In order to enable the APPROTECT mechanism on Rev F nRF52840 boards, two steps are required:

1) In early boot, the MDK included with the v17.1.0 SDK automatically sets APPROTECT->FORCEPROTECT to 0x00 if ENABLE_APPROTECT  is defined, which the nRF52840 datasheet says will "force enable APPROTECT mechanism".

2) Either using the debugger or firmware, UICR->APPROTECT must be set to 0x00 and then a power-on reset / hard reset / or brown-out reset must be performed.

My question is, what is the impact on the behavior of the MCU and the DAP / CTRL-AP interface if Step #1 is completed but Step #2 is never completed? Does setting APPROTECT->FORCEPROTECT to 0x00 actually do anything by itself? My question is primarily related to debugging code that was built with ENABLE_APPROTECT defined but for which UICR->APPROTECT is never enabled?

  • Hi,

    The debug interface is locked down both when it is done in UICR.APPROTECT and in APPROTECT.FORCEPROTECT. However, there is a fundamental difference. UICR.APPROTECT is persistent, and the only way to change it is to perform an erase all operation, erasing the content of both the flash and RAM. APPROTECT.FORCEPROTECT on the other hand is not persistent, and needs to be written to upon every boot. That does not mean that the debug interface will be open after boot though, as you also have the APPROTECT.DISABLE register, which is also reset on every boot, enabling the access port protection mechanism by default.

    So, even without writing to UICR.APPROTECT the access port is still locked down as long as your firmware does not write to APPROTECT.DISABLE, but the attack surface is larger in case an attacker is able to write to these registers in another way. So I would strongly recommend that you also write to UICR.APPROTECT during your production programming. This way you have two separate mechanisms that causes the access port to stay locked down, and that is the way we designed it to be used.

    (Note that the default behavior in the nRF Connect SDK is to open the debug interface, so you will want to build your code with CONFIG_NRF_APPROTECT=y, which will handle writing to APPROTECT.DISABLE  and APPROTECT.FORCEPROTECT for you).

  • Einar,

    Thank you for your response. I think the APPROTECT documentation for the Rev Fx0 nRF52840 is hard to understand with respect to the various controls, but I think I get it now. I'm going to tell you how I think it works, and you can tell me if I'm wrong, in case this is helpful to other people.

    On the Rev Fx0 nRF52840, every time the MCU resets, APPROTECT is always automatically enabled in hardware (nothing has to be done in software to enable it). And there is no way to permanently prevent the MCU _hardware_ from enabling APPROTECT on every reset.

    However, there are two ways that APPROTECT can be disabled temporarily (until the next MCU reset):

    • You can issue an ERASEALL via CTRL-AP (for instance, using the "Erase All" button in nRF Connect Desktop Programmer)
    • You can persistently write 0x5A to UICR.APPROTECT (not supported by nRF Connect Desktop Programmer) and then have software write 0x5A to the APPROTECT.DISABLE register (which gets reset when the MCU next resets).

    In the case where UICR.APPROTECT has been set to 0x5A, the APPROTECT.FORCEPROTECT register can be set to 0x00 to override APPROTECT.DISABLE, which will reenable APPROTECT if it has been disabled, and will prevent software from disabling it until after the next reset.

    In the cases where UICR.APPROTECT is set to 0xFF or 0x00, APPROTECT is always enabled in hardware and cannot be disabled by software, so the APPROTECT.FORCEPROTECT and APPROTECT.DISABLE registers do nothing and have no effect.

    The MDK in the v17.1.0 nRF5 SDK will handle automatically setting these two registers as follows:

    • If ENABLE_APPROTECT is defined, APPROTECT.FORCEPROTECT is set to 0x00, preventing APPROTECT from being disabled until the next reset. This only is relevant if UICR.APPROTECT is 0x5A.
    • If ENABLE_APPROTECT is not defined and UICR.APPROTECT is 0x5A, APPROTECT.DISABLE is set to 0x5A, automatically disabling APPROTECT after each boot

    Finally, it's important to understand that, while APPROTECT is automatically enabled on the Rev Fx0 nRF52840 MCU even if UICR.APPROTECT has not been programmed, this still leaves the system in a vulnerable state, since this register could still be set to 0x5A. For this reason, UICR.APPROTECT should always be set to 0x00 in production to ensure APPROTECT can't be disabled except by issuing an ERASEALL via CTRL-AP.

    But as long as you set UICR.APPROTECT to 0x00, it doesn't matter how the MDK or nRF Connect SDK is configured; for instance, you can leave ENABLE_APPROTECT undefined in the MDK, the MCU Flash and RAM and registers will be fully protected via the DAP, and there will still be no way for anyone to disable APPROTECT other than issuing ERASEALL via CTRL-AP. Is that correct?

    ----------------------------------------------------------------

    Assuming my description is correct, there is one thing about the APPROTECT functionality in the MDK that seems unnecessary. What actually happens when ENABLE_APPROTECT is not defined is that APPROTECT.DISABLE is set to the value of UICR.APPROTECT, which as I said above, will cause APPROTECT.DISABLE to be set to 0x5A if UICR.APPROTECT is 0x5A.

    But this code also has the effect of setting APPROTECT.DISABLE even if UICR.APPROTECT is not 0x5A. Specifically:

    • APPROTECT.DISABLE will be set to 0xFF if ERASEALL has been performed and UICR.APPROTECT is 0xFF, but this is an undefined value for that register
    • APPROTECT.DISABLE will be set to 0x00 -- which is already its default value -- if UICR.APPROTECT is 0x00

    My assumption is that these two operations are either unnecessary or have no effect on the system, because APPROTECT is always enabled in hardware unless UICR.APPROTECT is 0x5A, so APPROTECT.DISABLE is ignored in these cases. Is that correct?

  • Hi,

    Your understanding is correct. Though I would perhaps not completely agree with this part:

    ntennies said:
    But as long as you set UICR.APPROTECT to 0x00, it doesn't matter how the MDK or nRF Connect SDK is configured; for instance, you can leave ENABLE_APPROTECT undefined in the MDK, the MCU Flash and RAM and registers will be fully protected via the DAP, and there will still be no way for anyone to disable APPROTECT other than issuing ERASEALL via CTRL-AP. Is that correct?

    You are right that when access port protection is enabled in UICR, it is enabled regardless of the state of APPROTECT.DISABLE or APPROTECT.FORCEPROTECT. However, I would recommend writing to APPROTECT.FORCEPROTECT non the less (by defining ENABLE_APPROTECT for your nRF5 SDK project), as this reduces the attack surface in case there is any unknown issue with the UICR approach. I have no reason to be believe there is, but I see few good reasons to not be on the safe side.

    ntennies said:
    My assumption is that these two operations are either unnecessary or have no effect on the system, because APPROTECT is always enabled in hardware unless UICR.APPROTECT is 0x5A, so APPROTECT.DISABLE is ignored in these cases. Is that correct?

    That is correct. The only value that will unlock the debug port is 0x5A. Any other value (including 0xFF and 0x00) are treated the same, and will not unlock the debug interface.

  • Einar,

    Thank you very much for your help.

    FYI, it sounds to me like there is one scenario where it could be useful to _not_ define ENABLE_APPROTECT, which is in your application firmware project, as long as you define it in your bootloader project (assuming your production units require a bootloader that you've built). 

    If you do this, then during application development and testing on boards  with the Rev F nRF52840 without a bootloader in place, the APPROTECT enable state will be automatically derived from the UICR.APPROTECT state, with the MDK automatically disabling APPROTECT on boot if UICR.APPROTECT has been set to 0x5A.

    The advantage of this is that it isolates the software control over APPROTECT for the system in one place (the bootloader). If the bootloader dictates that APPROTECT should be enabled, it will be regardless of what the application MDK does. Or if you need to debug the bootloader and application together, you can do so just by undefining ENABLE_APPROTECT in the bootloader, since the application MDK will always try to disable APPROTECT when UICR.APPROTECT is 0x5A.

Related