nRF54L15 Security Features: TrustZone and CryptoCell and Secure Boot Explained

If you’re porting an nRF5340 design to nRF54L15 expecting the same dual-core security split, your first build is going to confuse you. The application core is gone. The network core is gone. There’s one Cortex-M33, and “CryptoCell” doesn’t exist anymore (the docs still say it does). The KMU you thought you knew has new slot semantics, and the first time you misprovision one, that slot is gone forever.
This is a hands-on guide to getting the nRF54L15 security stack (TrustZone-M, CRACEN, KMU, MCUboot/NSIB) configured in nRF Connect SDK v2.7+ without the foot-shooting. Production gotchas are called out inline.
The nRF54L15 Security Architecture at a Glance
Here’s what you’re actually working with:
┌─────────────────────────────────────────────┐
│ Cortex-M33 (single core) │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ Secure World │◄────►│ Non-Secure World │ │
│ │ (TF-M) │ NSC │ (Application) │ │
│ └──────┬───────┘ └──────────────────┘ │
└─────────┼───────────────────────────────────┘
│ PSA Crypto API
┌──────▼──────┐ ┌──────┐ ┌────────┐
│ CRACEN │ │ KMU │ │ TAMPC │
│ (crypto HW) │ │(keys)│ │(tamper)│
└─────────────┘ └──────┘ └────────┘Five blocks matter:
- Cortex-M33 with TrustZone-M: hardware isolation between Secure and Non-Secure worlds on a single core. Replaces the nRF5340’s dual-core split.
- CRACEN: the new crypto accelerator. Functionally replaces CryptoCell-312, but it’s a different IP block with a different driver.
- KMU: hardware key storage with push and read protection per slot. Expanded vs. nRF9160/nRF5340.
- TAMPC: tamper controller for glitch and intrusion detection.
- SICR: Security Information Configuration Registers, where lifecycle state and APPROTECT live.
Quick comparison:
| Feature | nRF52 | nRF5340 | nRF54L15 |
|---|---|---|---|
| Crypto HW | CryptoCell-310 | CryptoCell-312 | CRACEN |
| Secure isolation | None | Dual-core | TrustZone-M |
| Key storage | UICR / flash | KMU | KMU (expanded) |
| Secure boot | MCUboot | NSIB + MCUboot | NSIB + MCUboot + TF-M BL2 |
TrustZone-M and TF-M Setup
TF-M is the recommended Secure world implementation. Minimal prj.conf to get it building on nRF54L15:
CONFIG_BUILD_WITH_TFM=y
CONFIG_TFM_PROFILE_TYPE_MINIMAL=y
CONFIG_TFM_BL2=n # let NSIB handle root-of-trust instead
CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y
CONFIG_PSA_WANT_GENERATE_RANDOM=y
CONFIG_PSA_WANT_ALG_ECDSA=y
CONFIG_PSA_WANT_ALG_SHA_256=y
CONFIG_PSA_WANT_KEY_TYPE_ECC_KEY_PAIR=yUse TFM_PROFILE_TYPE_MINIMAL unless you actually need PSA Internal Trusted Storage, Protected Storage, or Initial Attestation. The full profile costs you roughly 40 KB of flash and a chunk of RAM you don’t have.
Partition split is done via Partition Manager with a pm_static.yml. Don’t try to hand-roll regions in devicetree; it’ll fight TF-M’s region generation.
Gotcha: Single-core means the TF-M Secure partition shares RAM with your app. On nRF5340 you had separate SRAM banks per core. Here, every byte TF-M takes is a byte you don’t have. Budget 20-30 KB SRAM for minimal TF-M before you start.
Gotcha: Every PSA call from Non-Secure traverses an NSC veneer, typically 50-200 cycles of overhead per call. If you’re doing per-packet AES on a hot path, batch your calls or move the work into a Secure partition.
CRACEN and PSA Crypto (the “nRF54 CryptoCell” Confusion)
You’ll still see “CryptoCell” in Nordic docs, sample names, and Kconfig help text on the nRF54L15. The hardware is CRACEN. The terminology lag leaks into search results, so a search for “nrf54 cryptocell” gets you mismatched advice.
The good news: PSA Crypto API is the same. The driver underneath is different.
CONFIG_NRF_SECURITY=y
CONFIG_PSA_CRYPTO_DRIVER_CRACEN=y
CONFIG_PSA_CRYPTO_DRIVER_OBERON=n # disable software fallback unless you need it
CONFIG_MBEDTLS_LEGACY_CRYPTO_C=n # do NOT mix legacy Mbed TLS APIMinimal AES-GCM example using PSA:
#include <psa/crypto.h>
psa_key_id_t key_id;
psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT);
psa_set_key_algorithm(&attr, PSA_ALG_GCM);
psa_set_key_type(&attr, PSA_KEY_TYPE_AES);
psa_set_key_bits(&attr, 256);
psa_import_key(&attr, key_material, 32, &key_id);
size_t out_len;
psa_aead_encrypt(key_id, PSA_ALG_GCM,
nonce, 12, aad, aad_len,
plaintext, pt_len,
ciphertext, ct_buf_size, &out_len);Gotcha: Leave legacy Mbed TLS enabled alongside the PSA CRACEN driver and you’ll get duplicate symbol errors, or worse, silent software-path crypto when you thought you were getting hardware. Pick one.
Gotcha: The CRACEN TRNG isn’t automatically your entropy source. Set CONFIG_PSA_WANT_GENERATE_RANDOM=y and confirm CONFIG_ENTROPY_CRACEN_CTR_DRBG=y (or equivalent in your NCS version) ends up in the build. Without this, you may fall back to a software PRNG seeded by something you don’t want to think about.
KMU: Key Provisioning Done Right
The KMU is where root keys, MCUboot verification keys, and your application secrets live. Each slot carries two independent properties: push-protection controls whether the slot can be pushed to a CRACEN register, and read-protection controls whether the CPU can read it back.
Provisioning workflow with nrfutil:
nrfutil device program \
--options chip_erase_mode=ERASE_NONE \
--firmware kmu_provision.hex \
--serial-number <SN>Or build a provisioning image that writes via the SDK’s KMU API and runs once at factory:
#include <hal/nrf_kmu.h>
nrf_kmu_metadata_t meta = {
.rpolicy = NRF_KMU_REVOKE_POLICY_LOCKED,
.dest_addr = (uint32_t)&NRF_CRACEN->KEY[0],
.perm = NRF_KMU_PERM_PUSH | NRF_KMU_PERM_READ_PROTECT,
};
nrf_kmu_slot_provision(SLOT_APP_AES_KEY, key_bytes, 32, &meta);Then reference it from PSA via a persistent key ID mapped to the slot.
Gotcha (the expensive one): KMU slots are effectively one-shot when you set push-protect + read-protect. Write the wrong key, write the wrong metadata, or set the wrong destination address, and that slot is dead. You don’t get it back. Provision against a dev board first, dump the SICR and KMU state, and only then run the same flow on production parts.
Gotcha: “ERASEALL wipes everything” isn’t quite true. KMU slots configured as persistent through SICR survive chip erase. The flip side: slots you assumed were persistent across dev cycles can vanish if your build flow does a full erase. Verify with nrfutil device read-info after every flash.
Secure Boot: NSIB, MCUboot, or Both
Two bootloader paths on nRF54L15:
- NSIB (Nordic Secure Immutable Bootloader): tiny, single-stage, ROM-anchored root-of-trust. Verifies the next stage with an ECDSA-P256 key.
- MCUboot: full-featured second-stage bootloader. Handles A/B updates, rollback protection, image confirmation.
The production chain typically looks like:
[Reset] → [NSIB] → [MCUboot/BL2] → [TF-M Secure] → [App NS]
│ │ │ │ │
ROT verify verify app isolate runtime
MCUboot + rollback secure
servicesKconfig to enable the chain:
CONFIG_SECURE_BOOT=y # enables NSIB
CONFIG_BOOTLOADER_MCUBOOT=y # MCUboot as second stage
CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
CONFIG_SB_SIGNING_KEY_FILE="keys/nsib_priv.pem"
CONFIG_BOOT_ECDSA_CRACEN=y # use CRACEN for signature verifySigning keys for NSIB and MCUboot are separate. You can embed the MCUboot verification key in the MCUboot image itself (the default), or push it from a KMU slot at boot. KMU-anchored MCUboot keys are the recommended production setup.
Gotcha: NCS ships with a default debug signing key. Build a release with that key still in CONFIG_SB_SIGNING_KEY_FILE and you’ve shipped a device that trusts anyone with the public NCS repo. Add a CI check that fails the build if the key path resolves to anything under nrf/.
Gotcha: Partition Manager will happily generate a layout where NSIB, MCUboot’s primary slot, MCUboot’s secondary slot, TF-M, and your app collectively overflow flash. Generate the partition report (partitions.yml is produced under build/) and review it before flashing. Flash collisions show up as cryptic boot failures, not clean errors.
Locking Down for Production
Three registers in UICR/SICR control debug access:
APPROTECT: locks debugger access to the Non-Secure side.SECUREAPPROTECT: locks debugger access to the Secure side.ERASEPROTECT: prevents chip erase from recovering the part.
Lock them at factory provisioning, not from firmware on first boot. If firmware does the lockdown, a bad first-boot image can ship parts with debug wide open. Doing the lockdown from factory tooling is verifiable on the test fixture.
TAMPC handles glitch detection, voltage/temperature excursions, and external tamper pins. Enable the detectors you care about and wire a response (typically: zeroize KMU slots, reset, log to SICR).
There’s no debug recovery on a fully locked nRF54L15. That’s the point. If you need field debug, build a signed “diagnostic image” path through MCUboot instead of leaving APPROTECT open.
Migration Checklist from nRF5340 / nRF52
Before your first nRF54L15 build:
- Replace
CONFIG_NRF_CC3XX_PLATFORMwithCONFIG_PSA_CRYPTO_DRIVER_CRACEN - Remove dual-core image configs (
hci_ipc, network core build) - Move secure services from network core to TF-M Secure partition
- Re-budget SRAM: TF-M Secure shares with your app
- Regenerate
pm_static.yml, don’t copy from nRF5340 - Replace any direct Mbed TLS calls with PSA Crypto
- Move keys from UICR/flash to KMU slots
- Replace debug signing keys before first production build
- Provision APPROTECT and SECUREAPPROTECT from factory tooling, not firmware
Build tfm_psa_test First, Read the Map Files
Get a dev kit, build the tfm/tfm_psa_test sample as-is, and read the generated partitions.yml and tfm_s.map before you write a line of your own code. Most of the painful surprises (RAM overrun, slot collisions, driver conflicts) are visible there before they become silent runtime failures.
Watch the Nordic DevZone tags nRF54L15 and KMU for the next few months. The provisioning flow in particular is still settling between NCS releases, and the threads catch driver changes faster than the release notes do.
If you’re building connected devices on nRF54L and want the BLE side to reach the cloud without adding cellular or Wi-Fi, the Hubble device SDK sits cleanly on top of the Non-Secure application partition and uses PSA Crypto for its encryption, so it inherits the CRACEN/KMU setup you just configured.
Hubble Network gives BLE devices global connectivity through PSA Crypto and your existing CRACEN/KMU setup—no cellular modem, no Wi-Fi credentials, no extra secure storage to provision. See how it works →