Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ MAX_WOLFSSL_FILE_SIZE
MCDC_FH_NO_SHA256
MCDC_FH_NO_SHA512
MCDC_FM_WITH_INIT
MCUXCL_FEATURE_ELS_PUK_INTERNAL
MDK_CONF_BARE_METAL
MDK_CONF_FS
MDK_CONF_RTX_TCP_FS
Expand Down
8 changes: 4 additions & 4 deletions IDE/MCUEXPRESSO/RW612/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# wolfSSL on NXP RW612 with EdgeLock (ELS)
# wolfSSL on NXP RW612 with EdgeLock (ELS + PKC)

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.
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, and RSA, X25519 and ECDSA to the PKC coprocessor.

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.

Expand Down Expand Up @@ -57,7 +57,7 @@ The same result from a source tarball or checkout. Note that no CI job builds th
./autogen.sh
./configure --host=arm-none-eabi --disable-shared --enable-static \
--enable-cryptonly --enable-cryptocb \
--enable-aesgcm --enable-cmac \
--enable-ecc --enable-aesgcm --enable-cmac --enable-curve25519 --enable-rsa \
--with-els-pkc=/path/to/els_pkc \
--with-mcux-sdk=/path/to/mcux-sdk-ng \
--disable-filesystem --enable-singlethreaded \
Expand Down Expand Up @@ -102,4 +102,4 @@ A hardware *failure* is treated differently on purpose: the port reports the err

`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.
Keys resident in the ELS key store are referenced rather than exported: attach a reference to a key with `wc_ElsPkc_EccUseSlot()`, `wc_ElsPkc_AesUseSlot()` or `wc_ElsPkc_CmacUseSlot()`. Those are the entry point - `wc_ElsPkc_MakeKeyRef()` is the primitive underneath them, and the ECC helper also pins the curve to P-256. See the port header for the key store operations and the reference format.
18 changes: 18 additions & 0 deletions IDE/MCUEXPRESSO/RW612/user_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern "C" {
#define WOLFSSL_ELS_PKC

#define WOLF_CRYPTO_CB
#define WOLF_CRYPTO_CB_KEYSTORE

/* Seed wolfCrypt's DRBG from the ELS hardware DRBG. */
#define HAVE_HASHDRBG
Expand All @@ -68,6 +69,23 @@ extern "C" {
#define WOLFSSL_AES_COUNTER
#define WOLFSSL_CMAC

#define HAVE_ECC
#define ECC_TIMING_RESISTANT
#define ECC_USER_CURVES
#define HAVE_ECC256
#define HAVE_ECC384
#define HAVE_CURVE25519
/* No Ed25519: the PKC does not serve EdDSA. */

/* SP math is per curve: keep this in step with the curve list above. */
#define WOLFSSL_SP_MATH_ALL
#define WOLFSSL_HAVE_SP_ECC
#define WOLFSSL_SP_384
#define WOLFSSL_HAVE_SP_RSA

#define WC_RSA_BLINDING
#define WOLFSSL_KEY_GEN

#define NO_DSA
#define NO_RC4
#define NO_MD4
Expand Down
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4355,7 +4355,8 @@ then
CPPFLAGS="$CPPFLAGS -I$mcux_sdk_dir/drivers/common"

# WOLF_CRYPTO_CB, and with it WOLF_PRIVATE_KEY_ID, is promoted further down.
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ELS_PKC"
# The key store ops are promoted here so they cannot be left out.
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ELS_PKC -DWOLF_CRYPTO_CB_KEYSTORE"
elif test "x$els_pkc_opt_given" = "xyes"
then
AC_MSG_WARN([--with-mcux-sdk and --with-els-pkc-platform do nothing without --with-els-pkc=PATH; the EdgeLock port is not being built])
Expand Down
97 changes: 89 additions & 8 deletions wolfcrypt/src/port/nxp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,13 +625,19 @@ kernel carrying NXP's downstream `ele_mu` driver; the upstream `fsl-se` driver
rejects userspace SAB writes with `EINVAL`. The enclave exposes no post-quantum
algorithms, so ML-KEM and ML-DSA stay on the CPU.

## NXP EdgeLock (ELS)
## NXP EdgeLock (ELS + PKC)

`els_pkc_port.c` offloads wolfCrypt to the EdgeLock subsystem found on the
RW612 and related parts, through the crypto callback interface. The ELS
peripheral serves SHA-256, SHA-384, SHA-512, AES (ECB/CBC/CTR), AES-GCM, CMAC
and the DRBG. NXP rates that DRBG at 128 bits of security strength, so where it
seeds wolfCrypt's Hash-DRBG, that DRBG is capped at 128 bits too.
peripheral serves SHA-256, SHA-384, SHA-512, AES (ECB/CBC/CTR), AES-GCM, CMAC,
the DRBG, every P-256 ECDSA verify, and P-256 signing with a key that names a
slot; the PKC coprocessor serves RSA, X25519, and the rest of ECDSA, P-256
signing with ordinary key material included. Five key store operations cover
importing and exporting wrapped keys, deriving one key from another, deleting
a key, and reading back what a slot holds. Generating happens through
`wc_ecc_make_key()` instead. NXP rates the ELS DRBG at 128 bits of security
strength, which caps wolfCrypt's Hash-DRBG at 128 bits where it supplies the
seed.

Anything the hardware does not serve is declined with `CRYPTOCB_UNAVAILABLE`
and completed in software, so an unsupported algorithm or key size costs
Expand All @@ -645,10 +651,11 @@ created without an explicit device still reaches the hardware.
`WC_NO_DEFAULT_DEVID` turns that off and leaves routing to the caller.

Keys that live in the ELS key store are referenced rather than exported.
`wc_ElsPkc_AesUseSlot()` and `wc_ElsPkc_CmacUseSlot()` attach a slot
reference to a key, so the key material never leaves the hardware. They are
the documented entry point: `wc_ElsPkc_MakeKeyRef()` is the lower-level
primitive they build on.
`wc_ElsPkc_EccUseSlot()`, `wc_ElsPkc_AesUseSlot()` and
`wc_ElsPkc_CmacUseSlot()` attach a slot reference to a key, so the private
key never leaves the hardware. They are the documented entry point:
`wc_ElsPkc_MakeKeyRef()` is the lower-level primitive they build on, and for
ECC the helper additionally pins the curve to P-256.

### Hardware behaviour worth knowing

Expand Down Expand Up @@ -689,11 +696,85 @@ finished before the last `wolfCrypt_Cleanup()`: with the device gone, wolfCrypt
carries on in software from the engine's state, and a hash returns a wrong
digest.

ELS takes a 32-byte ECDSA digest, so a longer one is truncated and a shorter
one zero-extended, as FIPS 186-4 6.4 does for a 256-bit order. A SHA-1 or
SHA-384 signature with a slot key therefore stays on ELS. ELS draws its own
nonce, so an RFC 6979 or set-k signature with a slot key fails with
`BAD_STATE_E`.

`wc_ecc_check_key()` on a slot key checks its public point, if it has one, in
software and that the slot holds a key of the referenced class. A signing slot
with a public point also signs and verifies a fixed digest, which shows the
two belong together; a key agreement slot cannot sign and gets the slot check
only.

**What the hardware declines**, so it runs in software instead: AES-192 (no
ELS key size), any trailing partial block, and an AES-GCM IV other than 12
bytes. A key in a slot has no software copy, so with one a partial block
fails with `BAD_LENGTH_E` and such an IV with `BAD_FUNC_ARG`.

**ECDH is not offloaded at all.** ELS deposits the agreed secret in a key
slot, which cannot be read back, while the wolfCrypt ECDH callback has to hand
a buffer to its caller - so the callback declines and software answers. A slot
key fails there with `ECC_BAD_ARG_E`, since its `ecc_key` holds only the
public point. An in-slot agreement would need `mcuxClEls_EccKeyExchange_Async`
exposed through a key store operation, which this port does not yet do, so a
slot generated as `WC_ELSPKC_KEY_ECC_DH` has no consumer here yet.

`wc_KeyStore_Derive()` drives the SP800-108 CMAC KDF only, as
`WC_KDF_TYPE_NONE`, from a `WC_ELSPKC_KEY_CKDF` source, in either of the two
sizes an ELS slot key can have - pass 16 or 32 bytes as `keySz`, or 0 for the
128-bit default. A 256-bit key spans the slot pair, so the reference must name
the first of two free slots, and a `WC_ELSPKC_KEY_ECC_SEED` target must be 256
bits, which 0 selects for it.

**The PKC uses the ELS DRBG where 128 bits are enough.** That is the ELS
DRBG's security strength on this part, and `mcuxClEcc_Sign` refuses P-384 and
P-521 with `RNG_ERROR` when given it - a failure that names the random source
rather than the curve. Signatures on curves over 256 bits and RSA-4096 private
operations therefore take a 256-bit CTR_DRBG, instantiated once and then kept.
Neither engine accepts a nonce from the caller, so an RFC 6979 or
`wc_ecc_sign_set_k()` signature stays in software. A plain
`wc_GenerateRandom()` is a different path and does reach the ELS DRBG
directly. The PKC workarea is a fixed hardware region shared by every PKC
consumer, which is why PKC work runs under the same lock as ELS.

**Key store permissions are per-purpose.** `uaes` and `ucmac` are separate
permission bits, so a slot holding both needs one reference per class, and
`wrpok` is set at creation and cannot be added later - a key not made
exportable can never leave. A generated key's public point is available only
at the moment of generation; the hardware will not hand it back afterwards.
An imported key whose container lacks the permission of the reference's
class is deleted again, and the import fails with `BAD_STATE_E`. Delete and
export refuse a reference whose class the slot's key does not carry, so a
stale reference cannot destroy a key that has since reused its slot.

**Two derivation rules the hardware enforces.** The ELS mixes the requested
property word into every CKDF, so the same parent and derivation data give a
different key when the protection bits or `wrpok` differ (`kactv` makes no
difference). A derived key therefore takes its privileged and secure bits from
its parent, as NXP's own recipes do, and a seeded key generation keeps the
seed's. And only the die unique key in slot 0 may parent a wrap-capable KWK:
deriving one from any other key trips the tamper controller, so
`wc_KeyStore_Derive()` refuses it with `BAD_STATE_E`. An unwrap-only KWK
(`WC_KEYSTORE_ATTR_UNWRAP_ONLY`) derives from any `WC_ELSPKC_KEY_CKDF` source.

**EdgeLock 2GO.** Keys provisioned through NXP's EdgeLock 2GO service descend
from `NXP_DIE_EL2GOOEM_MK_SK`, which the boot ROM leaves in slots 4 and 5 only
when secure boot is enabled (RW61x user manual UM11865, section 12.11, table
99). The port carries no EdgeLock 2GO code. An application derives the import
keys from that slot with `wc_KeyStore_Derive()`, checks each secure object's
CMAC with a slot bound through `wc_ElsPkc_CmacUseSlot()`, and unwraps the key
container with `wc_KeyStore_ImportWrapped()`; since the port copies the
parent's protection bits, the keys come out identical to those of NXP's RW61x
driver. A P-256 key arrives as a `WC_ELSPKC_KEY_ECC_SEED` holding the private
scalar, and `wc_ElsPkc_EccKeyGenFromSeed()` turns it into a key pair in the
same slots and returns the public point; the ELS marks the result
wrap-exportable by itself. If loading that point fails, the seed is already
consumed and the pair stays in the slots without it. The derivation data and
the secure object format are in NXP's EdgeLock 2GO agent,
https://github.com/NXP/el2go-agent.

### Vendor library

The port depends on NXP's CLNS library, `els_pkc`, which ships as an
Expand Down
Loading
Loading