From b59e57c321bb0926bcd01dab12d9ae83a098a47f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Frauenschl=C3=A4ger?= Date: Wed, 9 Sep 2026 20:16:59 +0200 Subject: [PATCH] nxp: document the MCUXpresso build for the EdgeLock port An IDE/MCUEXPRESSO/RW612 directory with a known-good user_settings.h and the steps to build the port against the SDK rather than Zephyr, plus the port README's pointer to it. The README itself grew alongside the offloads it documents. --- IDE/MCUEXPRESSO/RW612/README.md | 105 ++++++++++++++++++++++++++ IDE/MCUEXPRESSO/RW612/user_settings.h | 83 ++++++++++++++++++++ wolfcrypt/src/port/nxp/README.md | 5 +- 3 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 IDE/MCUEXPRESSO/RW612/README.md create mode 100644 IDE/MCUEXPRESSO/RW612/user_settings.h diff --git a/IDE/MCUEXPRESSO/RW612/README.md b/IDE/MCUEXPRESSO/RW612/README.md new file mode 100644 index 0000000000..4c62ed2a46 --- /dev/null +++ b/IDE/MCUEXPRESSO/RW612/README.md @@ -0,0 +1,105 @@ +# wolfSSL on NXP RW612 with EdgeLock (ELS) + +This directory configures wolfSSL for the NXP RW612 with the EdgeLock crypto callback port, `wolfcrypt/src/port/nxp/els_pkc_port.c`, built from an MCUXpresso SDK project. It offloads SHA-256, AES, AES-GCM, CMAC and the DRBG to the ELS peripheral. + +Zephyr users do not need any of this: the wolfSSL Zephyr module supplies the same port through `CONFIG_WOLFSSL_ELS_PKC=y`, and the `els_pkc` Zephyr module supplies the vendor headers. This is the path for a project that uses the MCUXpresso SDK directly. + +## What els_pkc is + +`els_pkc` is NXP's CLNS (Crypto Library NXP Secure) middleware. It ships as an MCUXpresso SDK component under `components/els_pkc/` and is also published at . The Zephyr module it carries is an add-on; the SDK component is the primary form. + +wolfSSL never builds or vendors CLNS. The port calls into it and the application links it, exactly as the SE050 port does. Take either route: + +- build `els_pkc/src/comps` as part of your project, or +- link the prebuilt `els_pkc/static_library/rw61x/libclns.a`. + +**Licensing.** els_pkc is distributed under NXP's proprietary `LA_OPT_Online Code Hosting` license, not an open source license. Clause 3.7 forbids subjecting it to a license that would require source disclosure. Fetching it at build time is fine and is what both this setup and the Zephyr module do; copying it into a wolfSSL tree is not. + +## MCUXpresso IDE setup + +1. Create a project for your RW612 board (for example `frdm_rw612`). +2. In the SDK component selector, add **els_pkc**. That brings in `src/comps`, the `rw61x` platform layer, and the bundled CMSIS. +3. Add the wolfSSL sources to the project. `wolfcrypt/src/port/nxp/els_pkc_port.c` is compiled like every other wolfCrypt port and gates itself on `WOLFSSL_ELS_PKC`, so it costs nothing when the port is off. +4. Copy `user_settings.h` from this directory into your project and define `WOLFSSL_USER_SETTINGS` for the build. +5. Add these include paths, all inside the els_pkc component: `src/inc`, `src/compiler`, `src/comps/*/inc`, `src/comps/*/inc/internal`, `src/platforms/rw61x`, `src/platforms/rw61x/inc`, `src/platforms/rw61x/cmsis_cortex_m_5_5_1/inc`, `includes/platform/rw61x`. + +### Compiler flags that matter + +| Flag | Why | +| --- | --- | +| `-mcpu=cortex-m33+nodsp` | Without `+nodsp` the vendor CMSIS `core_cm33.h` aborts the build with "Compiler generates DSP (SIMD) instructions for a device without DSP extensions". `-D__DSP_PRESENT=1` does **not** work around it. | +| `-DCPU_RW612ETA2I` | `fsl_device_registers.h` selects the register map from the part number. Use the macro matching your part; only the A2 parts appear in its selector. | +| `-mcmse` | Matches how NXP builds CLNS. | +| `-DNO_THREAD_LS` | Required on bare metal. See below. | +| `-DWOLFSSL_NO_GETPID` | Required with newlib. See below. | + +### wolfCrypt_Init() returning -1000 + +`wolfCrypt_Init()` guards against recursive entry with a `__thread` variable whenever the toolchain advertises thread-local storage. On bare metal nothing sets the thread pointer, so that read returns garbage, the guard fires, and the call returns `DEADLOCK_AVERTED_E` (-1000) before initialising anything. Define `NO_THREAD_LS` unless your runtime really does set up TLS. + +### random.c and an implicit declaration of getpid() + +`--specs=nosys.specs` gives the linker a stub for every syscall, which is what +lets autoconf's link probes succeed without a board support package. It also +makes the probe for `getpid()` succeed, so `HAVE_GETPID` ends up defined even +though newlib's headers never declare the function, and `random.c` then fails +to compile on an implicit declaration. Define `WOLFSSL_NO_GETPID`; a bare metal +target has no processes to identify. + +Toolchains shipping picolibc rather than newlib, such as the Zephyr SDK's +`arm-zephyr-eabi`, declare `getpid()` and do not need this. + +## Building with autoconf instead + +The same result from a source tarball or checkout. Note that no CI job builds this port today - it needs the vendor library and the SoC headers, neither of which the CI images carry - so a green run says nothing about it: + +```sh +./autogen.sh +./configure --host=arm-none-eabi --disable-shared --enable-static \ + --enable-cryptonly --enable-cryptocb \ + --enable-aesgcm --enable-cmac \ + --with-els-pkc=/path/to/els_pkc \ + --with-mcux-sdk=/path/to/mcux-sdk-ng \ + --disable-filesystem --enable-singlethreaded \ + CFLAGS="-mcpu=cortex-m33+nodsp -mthumb -Os --specs=nosys.specs" \ + CPPFLAGS="-DWOLFSSL_NO_SOCK -DWOLFSSL_USER_IO -DNO_WRITEV -DNO_DEV_RANDOM \ + -DNO_THREAD_LS -DWOLFSSL_NO_GETPID" +make +``` + +`--with-mcux-sdk` wants a tree holding `devices/Wireless/RW/RW612` and `drivers/common`: your MCUXpresso SDK install, or a checkout of NXP's `mcux-sdk-ng`. The els_pkc platform layer includes `fsl_common.h`, `fsl_device_registers.h` and `fsl_ocotp.h` from it. + +The resulting `libwolfssl.a` carries unresolved `mcuxCl*` references. That is correct: the application links CLNS. + +To confirm the port really made it into the archive, check for its symbols rather than for the object file. The port compiles to an empty translation unit when `WOLFSSL_ELS_PKC` is missing, so a build can succeed with the port silently absent: + +```sh +arm-none-eabi-nm src/.libs/libwolfssl.a | grep wc_ElsPkc +``` + +## Using it + +`wolfCrypt_Init()` brings the port up and registers its crypto callback, so there is nothing to call by hand, and `wc_CryptoCb_DefaultDevID()` answers `WOLFSSL_ELS_PKC_DEVID`, so a context created without an explicit device is offloaded too: + +```c +#include + +wolfCrypt_Init(); + +wc_Sha256 sha; +wc_InitSha256(&sha); /* offloaded */ +wc_InitSha256_ex(&sha, NULL, WOLFSSL_ELS_PKC_DEVID); /* the same, explicitly */ +wc_InitSha256_ex(&sha, NULL, INVALID_DEVID); /* kept in software */ +``` + +Define `WC_NO_DEFAULT_DEVID` to switch the automatic routing off and require every context to name the device. Note it only reaches code that asks `wc_CryptoCb_DefaultDevID()` for a device: `wc_AesInit()` takes a `devId` argument directly, so pass `WOLFSSL_ELS_PKC_DEVID` there yourself. + +The DRBG seed comes from the ELS too, through `wc_GenerateSeed()`, so call `wolfCrypt_Init()` before the first `wc_InitRng()`. Before it, and after `wolfCrypt_Cleanup()`, seeding fails with `BAD_STATE_E`. NXP rates the ELS DRBG at 128 bits of security strength, which caps wolfCrypt's Hash-DRBG at 128 bits as well. + +Anything the hardware does not serve is *declined* with `CRYPTOCB_UNAVAILABLE` and completed in software, so an unsupported algorithm or key size is a performance question, never a failure. The exception is a key held in a slot, which has no software copy: there a shape the hardware cannot serve, such as a partial AES block, fails. + +A hardware *failure* is treated differently on purpose: the port reports the error rather than quietly finishing in software, because a caller that ignores the return would otherwise receive a confident bad result. Declining and failing are not the same thing. + +`wolfCrypt_Cleanup()` unregisters the callback and closes the port, keeping its mutex; `wc_ElsPkc_Init()` re-registers it if you need the port back afterwards. Finish or free every hash, CMAC and AES context the port has taken over before the last `wolfCrypt_Cleanup()`: with the device gone, wolfCrypt continues it in software from the engine's state, and a hash returns a wrong digest. + +Keys resident in the ELS key store are referenced rather than exported: attach a reference to a key with `wc_ElsPkc_AesUseSlot()` or `wc_ElsPkc_CmacUseSlot()`. Those are the entry point - `wc_ElsPkc_MakeKeyRef()` is the primitive underneath them. See the port header for the reference format. diff --git a/IDE/MCUEXPRESSO/RW612/user_settings.h b/IDE/MCUEXPRESSO/RW612/user_settings.h new file mode 100644 index 0000000000..5a51dc34cf --- /dev/null +++ b/IDE/MCUEXPRESSO/RW612/user_settings.h @@ -0,0 +1,83 @@ +/* user_settings.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* wolfSSL settings for the RW612 EdgeLock port in an MCUXpresso SDK project. + * See README.md. */ + +#ifndef USER_SETTINGS_H +#define USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define WOLFSSL_GENERAL_ALIGNMENT 4 +#define SINGLE_THREADED + +/* Bare-metal startup never sets the thread pointer wolfCrypt_Init() reads. */ +#define NO_THREAD_LS + +/* newlib does not declare getpid(); nosys.specs hides that from configure. */ +#define WOLFSSL_NO_GETPID +#define NO_FILESYSTEM +#define NO_WRITEV +#define WOLFSSL_NO_SOCK +#define WOLFSSL_USER_IO +#define NO_DEV_RANDOM /* entropy comes from the ELS DRBG, below */ +#define WOLFCRYPT_ONLY /* drop for TLS; then supply IO and time */ + +/* No RTC by default on this board. Supply a real time source and remove this + * if certificate validity has to be checked. */ +#define NO_ASN_TIME + +#define WOLFSSL_ELS_PKC + +#define WOLF_CRYPTO_CB + +/* Seed wolfCrypt's DRBG from the ELS hardware DRBG. */ +#define HAVE_HASHDRBG + +/* Anything not listed here falls back to software through the normal + * CRYPTOCB_UNAVAILABLE path. */ + +#define WOLFSSL_SHA256 +#define WOLFSSL_SHA384 +#define WOLFSSL_SHA512 + +#define HAVE_AESGCM +#define WOLFSSL_AES_DIRECT +#define HAVE_AES_ECB +#define WOLFSSL_AES_COUNTER +#define WOLFSSL_CMAC + +#define NO_DSA +#define NO_RC4 +#define NO_MD4 +#define NO_DES3 +#define NO_PSK +#define NO_OLD_TLS +#define WOLFSSL_SMALL_STACK + +#ifdef __cplusplus +} +#endif + +#endif /* USER_SETTINGS_H */ diff --git a/wolfcrypt/src/port/nxp/README.md b/wolfcrypt/src/port/nxp/README.md index 1b7b70da7a..c1353827cc 100644 --- a/wolfcrypt/src/port/nxp/README.md +++ b/wolfcrypt/src/port/nxp/README.md @@ -716,7 +716,10 @@ into a wolfSSL tree. supplied through `CONFIG_WOLFSSL_SETTINGS_FILE`, the feature Kconfigs do not apply and `WOLFSSL_ELS_PKC` has to be defined in that file instead. - **MCUXpresso SDK / autoconf.** `--with-els-pkc=PATH` and - `--with-mcux-sdk=PATH`. + `--with-mcux-sdk=PATH`. See + [IDE/MCUEXPRESSO/RW612](../../../IDE/MCUEXPRESSO/RW612) for the worked + setup, the compiler flags that matter, a known-good `user_settings.h`, and + the run-time API. Everything in the port is gated on `WOLFSSL_ELS_PKC`. Without that macro the file compiles to an empty translation unit and reaches no vendor header,