wolfSSL now supports the SEC security engine on NXP’s QorIQ PowerPC T-series processors. SEC is the QorIQ name for the same CAAM block that wolfSSL has long supported on i.MX, and both are covered here: a new bare-metal port for the T-series, and a Linux user space backend for the existing CAAM driver. AES, AES-GCM, ECDSA, ECDH, RSA and finite-field Diffie-Hellman all run on the engine, reached through wolfCrypt’s crypto callback layer with no application changes.
On a T2080 this takes RSA-2048 private key operations from 532 ms to 17 ms, and AES-GCM from 8 MiB/s to 107 MiB/s.
It also lands on a platform wolfSSL already covers end to end. wolfBoot has bare-metal secure boot targets for the T2080 and the T1024 and T1040, including 64-bit RTOS handoff, and wolfIP runs over the FMan mEMAC/MDIO datapath those targets bring up, hardware-verified on all three boards. So a QorIQ design can do verified boot, networking and now accelerated TLS from one stack.
Why it matters
The QorIQ T-series is everywhere in long-lived embedded and aerospace systems: VPX single-board computers, network appliances, industrial controllers. These designs run for decades, and many are now being asked to do TLS at line rate on a CPU that was never fast at it.
The e5500 and e6500 cores predate the PowerPC vector-crypto instructions, so there is nothing to accelerate AES or GHASH with and both fall back to table lookups and shifts. On a 1.2 GHz T2080 with a plain C build, AES-GCM runs at a flat 7 to 8 MiB/s regardless of key size.
Meanwhile these SoCs ship with a perfectly good crypto accelerator sitting idle, and wolfSSL’s CAAM port had no way to reach it: it targets only i.MX, under QNX, INTEGRITY or the i.MX8 SECO firmware.
What the port does
The new port lives in wolfcrypt/src/port/nxp/ and is self-contained: it builds none of the existing CAAM code.
| Accelerator | Support |
|---|---|
| AESA | AES-128/192/256 in CBC, CTR and ECB |
| AESA | AES-GCM with AAD; the engine verifies the tag itself on decrypt |
| PKHA | ECDSA sign and verify, ECDH, on any prime curve wolfCrypt carries |
| PKHA | RSA public and private operations up to 4096 bit |
| PKHA | Finite-field Diffie-Hellman key agreement on the fixed FFDHE groups |
| RNG4 | Instantiated by the driver, used to seed the wolfCrypt DRBG |
Anything the engine cannot do returns CRYPTOCB_UNAVAILABLE and falls back to software, including run-time failures such as a non-contiguous buffer or a full job ring, so an unsupported case is a performance question rather than a correctness one.
./configure --host=powerpc-linux-gnu CC=powerpc-linux-gnu-gcc \
--enable-sec-qoriq=baremetal --enable-aesgcm
Benchmarks
Both boards run wolfcrypt/benchmark with BENCH_EMBEDDED (1 KB buffers), printing the software and engine rows from the same binary over the same buffers. Read the two tables separately, though: the T2080 figures are the engine against plain C, the T1040 figures against the PowerPC assembly wolfSSL has for AES and SHA on this core. That is why the T1040 speedups look smaller. They are the more conservative comparison, and the one to quote if you already build with assembly enabled.
T2080E (e6500, 1.2 GHz), engine vs plain C
| Algorithm | Software | SEC | Speedup |
|---|---|---|---|
| RSA-2048 private | 1.88 | 58.29 ops/s | 31.0x |
| DH-2048 agree | 16.49 | 477.11 ops/s | 28.9x |
| AES-256-GCM-enc | 6.94 | 102.50 MiB/s | 14.8x |
| AES-128-GCM-enc | 8.07 | 107.42 MiB/s | 13.3x |
| ECDSA P-256 verify | 49.39 | 591.98 ops/s | 12.0x |
| RSA-2048 public | 416.61 | 4006.02 ops/s | 9.6x |
| ECDSA P-256 sign | 89.53 | 785.66 ops/s | 8.8x |
| ECDHE P-256 agree | 100.18 | 803.40 ops/s | 8.0x |
| AES-128-CBC-enc | 21.96 | 122.83 MiB/s | 5.6x |
| AES-128-CTR | 22.08 | 119.06 MiB/s | 5.4x |
T1040E (e5500, 1.4 GHz), engine vs PowerPC assembly
| Algorithm | Software (asm) | SEC | Speedup |
|---|---|---|---|
| RSA-2048 private | 1.71 | 17.19 ops/s | 10.1x |
| DH-2048 agree | 15.23 | 146.0 ops/s | 9.6x |
| ECDSA P-256 verify | 43.46 | 350.17 ops/s | 8.1x |
| ECDSA P-256 sign | 79.40 | 488.03 ops/s | 6.1x |
| ECDHE P-256 agree | 87.89 | 496.57 ops/s | 5.7x |
| RSA-2048 public | 589.6 | 1781.2 ops/s | 3.0x |
| AES-256-GCM-enc | 28.18 | 85.11 MiB/s | 3.0x |
| AES-128-GCM-enc | 35.80 | 91.92 MiB/s | 2.6x |
| AES-256-CBC-enc | 40.94 | 87.75 MiB/s | 2.1x |
| AES-128-CBC-enc | 56.86 | 100.15 MiB/s | 1.8x |
Two things stand out beyond the raw numbers.
Public key beats bulk crypto for payoff. Even against assembly, the AES gains are 2 to 3x while ECDSA verify is 8x and RSA private is 10x. Public key is where these cores hurt most, and where the engine helps most. For a TLS server, that is the difference between a handshake dominated by one modular exponentiation and one you stop noticing.
AES-256 is nearly free on the engine. In software, moving from AES-128 to AES-256 costs 28% on the T1040 (56.86 to 40.94 MiB/s CBC). On the SEC it costs 12% (100.15 to 87.75). Offload makes the stronger key size close to a non-decision.
Where offload does not pay
There is a fixed cost per job of roughly 3.5 microseconds on a 1.2 GHz T2080, covering descriptor setup, cache maintenance and the round trip to the engine. A size sweep shows what that does to small buffers:
| Algorithm | 64 B | 256 B | ~1400 B | 16 KB |
|---|---|---|---|---|
| AES-128-GCM | 2.30x | 6.24x | 19.77x | 38.50x |
| SHA-384 | 2.39x | 4.47x | 8.74x | 13.66x |
| SHA-256 | 0.84x | 1.76x | 4.85x | 9.17x |
| AES-128-CBC | 0.61x | 1.38x | 3.90x | 7.30x |
Below roughly 128 bytes, SHA-256 and AES-CBC are faster in software. The port acts on this: SEC_QORIQ_MIN_OFFLOAD_SZ (256 bytes, tunable) keeps small AES buffers in software, while GCM is always taken.
The same engine from Linux, and why it is slower
The port above is bare metal. A separate piece of work (PR 11197) gave that existing CAAM port a Linux user space backend, so the same driver core drives the QorIQ SEC from a normal process. AES-CBC/CTR/ECB and the TRNG are accelerated, enabled with –enable-caam=linux.
Two platform facts make that harder than it sounds, and both belong to the system rather than the driver. The in-tree caam driver claims all four job rings at boot and sets MCFGR[PS] for 64-bit descriptor pointers, and MCFGR is global to the block, so a user space driver cannot share the engine: you take the whole thing or nothing. And ordinary user pages are neither physically contiguous nor below 4 GB on a 36-bit part, so engine buffers come from a reserved range that Linux is told not to manage with mem=.
The measurements are worth publishing precisely because they are unflattering. On a T1040 at 1.4 GHz, same binary, same buffers:
| Buffer | Software | CAAM | Ratio |
|---|---|---|---|
| 512 B | 42.69 MiB/s | 21.61 MiB/s | 0.51x |
| 4 KB | 45.67 MiB/s | 27.09 MiB/s | 0.59x |
| 16 KB | 46.31 MiB/s | 27.75 MiB/s | 0.60x |
Hardware sits flat at about 28 MiB/s because the per-job cost dominates, plus two bounce copies to stage operands in and out of the reserved pool. Software climbs with buffer size, and the e5500’s AES is quick. Bare metal has no bounce copy at all, which is the whole difference between this table and the ones above.
So the reason to turn this on under Linux is the TRNG as a real entropy source and moving work off the core, not throughput. Closing the gap means letting callers allocate from the pool directly, pushing transfers toward the SEC’s 64 KB per-descriptor limit, and completing on an interrupt instead of a poll.
One thing worth knowing before you port
The built-in curve table does not work on this silicon. A descriptor is supposed to be able to name one of a handful of preloaded curves by index, carrying only key material, and wolfSSL’s i.MX CAAM port relies on that. On the QorIQ parts every flag position crossed with every curve index (288 combinations swept on real hardware) is refused. The port supplies the domain parameters explicitly instead: four extra descriptor words, and any prime curve wolfCrypt carries rather than the five built in.
Offloading DH at all also needed a new crypto callback hook, since WC_PK_TYPE_DH was in the enum but had no dispatch behind it. That hook is part of this work, with the SP 800-56A group and peer-key validation hoisted above the callback so it applies to every device rather than depending on each driver.
Verification
wolfcrypt_test() passes in full on both boards with the engine enabled, including AES, AES-GCM, RSA, DH and ECC, pushing about 3.4 million descriptors through the job ring on the T2080. The T2080 has PKHA v2 and the T1040 PKHA v1, the likeliest place for the two parts to diverge, and they do not: the same driver passes on both, unchanged.
One measurement discipline is worth stating, because it caught us once: wolfcrypt_test() passed in full with the device registered while the engine did nothing at all, every job quietly refused and run in software, exactly as designed. The tell was the benchmark, where the hardware and software rows came out identical (RSA-2048 public 790.6 against 788.9 ops/s). A passing test suite is not evidence of offload. The port therefore ships offload counters, so “is this actually being accelerated?” is answered by reading a number, with the negative control alongside it: unregister the device, run the same binary, and require the figures to move.
Supported hardware
The driver does not carry a table of part numbers. It reads the SEC’s own capability registers at run time, so what matters is whether the part has the engine at all, and every QorIQ T-series part does. NXP’s device trees put SEC 5.2 on the T2080 and SEC 5.0 on the rest.
| Part | SEC | wolfBoot | wolfIP | This port |
|---|---|---|---|---|
| T2080 | 5.2 | yes | yes | validated (T2080E, Curtiss-Wright VPX3-152) |
| T1040, T1042 | 5.0 | yes | yes | validated on T1040E (NXP T1040D4RDB) |
| T1023, T1024 | 5.0 | yes | yes | should work, untested |
| T4240, T4160, T4080 | 5.0 | no target yet | no | should work, untested |
Both wolfBoot QorIQ target sections above document the flash layout, the FMan microcode slot and the wolfIP bring-up for these parts. The T1023/T1024 case is the one most likely to just work: it is the same e5500 core and the same SEC 5.0 as the T1040 this was validated on, and wolfBoot already has a target and an FMan datapath for it. The T4 family shares SEC 5.0 too, but has no wolfBoot target today.
One caveat when specifying hardware: QorIQ parts ship in security-enabled and security-disabled variants, and only the “E” SKUs have the engine. The driver checks the SVR at runtime and declines cleanly on a part without it; U-Boot shows the same as a trailing E on the CPU name, for example CPU0: T2080E.
What is next
Streaming hash, so SHA can carry bulk data. Scatter-gather, so fragmented TLS records need not be linearised. Sixty-four-bit descriptor pointers, which is what the Linux backend needs before it can reach ordinary pages instead of a reserved pool. And key blobs, wrapping keys to a device-unique key for a hardware root of trust.
Availability
Both pieces are open for review now, each with its configuration macros and every known limitation documented in its directory’s README.md:
| Change | Source | Pull request |
|---|---|---|
| QorIQ SEC port, bare metal (–enable-sec-qoriq) | wolfcrypt/src/port/nxp/ | wolfSSL#11199 |
| Linux user space backend for the CAAM port (–enable-caam=linux) | wolfcrypt/src/port/caam/ | wolfSSL#11197 |
| Bare-metal test apps that exercise the engine (SEC_QORIQ=1) | wolfBoot test-app/ | wolfBoot#864 |
If you are running wolfSSL on QorIQ, or on any part with an accelerator you would like to see put to work, we would love to hear about it. Tell us what you are building and what you need from it; use cases like yours are what shape where this work goes next. Reach us any time at facts@wolfssl.com or call us at +1 425 245 8247.
Download wolfSSL Now

