wolfSSL was OpenWrt’s default TLS library from the 21.02 release until 23.05, when OpenWrt switched to Mbed TLS. One of the reasons given was that Mbed TLS is “considerably smaller”. In part one, I compared wolfSSL, Mbed TLS and OpenSSL on a 650 MHz MIPS router. There, the wolfSSL image came out within 13 KB of the Mbed TLS one, needed about half the heap for an HTTPS download, and made a TLS 1.3 handshake to the router’s web interface 4.7x faster.
The router is a good test of a small device, but I also wanted to see how things look on a fast 64-bit ARM board, so this time it’s the turn of the Raspberry Pi 5.
The short version: on the Pi, wolfSSL still needs less than half the heap of Mbed TLS, and with its ARM64 assembly turned on it is the fastest of the three at X25519, P-384, RSA-2048 signing and SHA-256. That speed costs flash, though: the image is 1.18 MB larger than the Mbed TLS one, but still 428 KB smaller than OpenSSL’s.
The Patches
The images use the same custom patches as part one, which make an OpenWrt image run entirely on wolfSSL. They are not part of OpenWrt yet, but we are looking to upstream them in the near future. The patches add a single build option, USE_WOLFSSL, which switches every default package that uses Mbed TLS to a wolfSSL equivalent:
- HTTPS for uclient-fetch, the uhttpd web server and the LuCI web interface, through ustream-ssl, which gets a new native wolfSSL backend
- Wi-Fi security in hostapd and wpa_supplicant: WPA2, WPA3-SAE, OWE and 802.11r/w
- The apk package manager, with a new wolfCrypt backend
- px5g, which generates the certificate for LuCI’s HTTPS
With the option turned on, there is no Mbed TLS left in the image. The wolfSSL package also gets a minimal build mode, which only builds the features those packages need, and uses wolfSSL’s fast single-precision (SP) code for P-256 by default. On aarch64, that SP code is wolfSSL’s ARM64 assembly.
Test Setup
The board is a Raspberry Pi 5: four Cortex-A76 cores at 2.4 GHz with the ARMv8 crypto extensions, and 4 GB RAM.
All the images were built from the same OpenWrt revision, using wolfSSL 5.9.4, Mbed TLS 3.6.7 and OpenSSL 3.5.9 with each package’s default options (for wolfSSL, the minimal build from the patches, plus the two extras below). Each image was flashed fresh and measured from a clean boot. A few notes on how things were measured:
- Heap figures come from a small heap-tracking library loaded into each process.
- TLS 1.3 handshakes are the median of 20, from my laptop to the Pi’s web server, which signs with its P-256 certificate every time.
- WPA3 timings use the image’s own hostapd and wpa_supplicant talking over simulated radios (mac80211_hwsim), so all the crypto runs on the Pi’s CPU.
- Crypto benchmarks use each library’s own benchmark tool. Each tool uses a different block size by default, so I set or patched them to all process the same sizes (1 KB and 16 KB), with 13 bytes of additional data on the AEAD ciphers, just like a TLS record.
One thing worth knowing: OpenWrt compiles Mbed TLS at -O2, because Mbed TLS’s own build files override OpenWrt’s setting. wolfSSL and OpenSSL are compiled at the size-optimised -Os, so the raw crypto numbers favour Mbed TLS a little.
Building wolfSSL for the Pi
For the figures below, I built wolfSSL with two extras that the patches don’t turn on for this board. The first is wolfSSL’s ARMv8 crypto code, which does AES, GCM and SHA-2 using the CPU’s crypto instructions. OpenWrt’s wolfSSL package doesn’t currently build it for Raspberry Pi targets, because older Pis don’t have those instructions, but wolfSSL 5.9.4 detects them at run time. Without it, wolfSSL’s AES-128-GCM manages 76 MiB/s, well behind Mbed TLS, which does use the instructions. Enabling it for Raspberry Pi is something we want to look at as part of upstreaming.
The second is the fast SP code, in ARM64 assembly, for P-384, P-521 and RSA as well as P-256. This is still compiled at OpenWrt’s size-optimised -Os.
Performance
With its ARM64 assembly, wolfSSL is level with or ahead of OpenSSL at almost everything TLS and WPA3 use, and well ahead of Mbed TLS.
| Raspberry Pi 5, ms (lower is better) | Mbed TLS | wolfSSL, ARMv8 crypto and fast SP | OpenSSL |
|---|---|---|---|
| TLS 1.3 handshake, X25519 / P-256 | 2.8 / 2.5 | 0.7 / 0.8 | 1.1 / 1.0 |
| X25519 key agreement | 0.787 | 0.140 | 0.182 |
| P-256 ECDSA sign / verify | 0.452 / 1.52 | 0.063 / 0.172 | 0.057 / 0.189 |
| P-384 ECDSA sign / verify | 0.836 / 3.02 | 0.225 / 0.599 | 2.42 / 1.93 |
| RSA-2048 sign | 20.75 | 3.21 | 3.54 |
P-256 signing is 7x faster than Mbed TLS and verification 9x faster, which puts wolfSSL level with OpenSSL’s hand-tuned ARMv8 P-256 assembly. With the SP code, wolfSSL is the fastest of the three at P-384, 3x to 11x faster than the others, and at RSA-2048 signing, 3.21 ms against OpenSSL’s 3.54 ms. WPA3 on P-384 and P-521 benefits too: the access point spends 4 and 6 ms of CPU on each connection, against 9 and 17 ms with Mbed TLS and 12 and 26 ms with OpenSSL.
| Raspberry Pi 5, MiB/s with 1 KB / 16 KB blocks (higher is better) | Mbed TLS | wolfSSL, ARMv8 crypto and fast SP | OpenSSL |
|---|---|---|---|
| AES-128-GCM | 410 / 428 | 1,837 / 2,087 | 1,207 / 2,194 |
| ChaCha20-Poly1305 | 212 / 229 | 410 / 541 | 648 / 673 |
| SHA-256 | 188 / 202 | 1,265 / 1,451 | 925 / 1,413 |
wolfSSL is also the fastest at X25519, SHA-256, and AES-GCM on 1 KB records, and level with OpenSSL on AES-GCM at 16 KB. OpenSSL is ahead on ChaCha20-Poly1305. Handshakes are fast with every library on this CPU; at these speeds the network and the client are a big part of each figure, but Mbed TLS is clearly the slowest.
Memory and Flash
| Raspberry Pi 5 | Mbed TLS | wolfSSL, ARMv8 crypto and fast SP | OpenSSL |
|---|---|---|---|
| HTTPS download, peak heap, bytes | 517,272 | 248,372 | 1,203,177 |
| Web server, 4 connections at a time, peak heap, bytes | 282,688 | 121,486 | 899,271 |
| Root filesystem, bytes | 5,867,744 | 7,050,428 | 7,478,276 |
The memory story is the same as on the router in part one. wolfSSL needs less than half the heap of Mbed TLS for an HTTPS download and for the web server under load. OpenSSL needs 4.8x and 7.4x more than wolfSSL for those.
The extra speed costs flash. The SP assembly for P-384, P-521 and three RSA key sizes is large, so the wolfSSL image here is 1.18 MB larger than the Mbed TLS one, though still 428 KB smaller than OpenSSL’s. With only the package’s default fast P-256 code plus the ARMv8 crypto code, it was 170 KB larger than Mbed TLS, and with everything compiled from C it was 26 KB smaller. On a Pi with an SD card that hardly matters, but on a router with 16 MB of flash it would, which is why the patches only use fast P-256 code by default.
What’s Next
On the Raspberry Pi 5, wolfSSL with its ARMv8 crypto and SP assembly turned on is level with or ahead of OpenSSL everywhere except ChaCha20-Poly1305, and needs a fraction of the heap of either Mbed TLS or OpenSSL. On a board with an SD card, the extra flash is a small price to pay for that.
The next step is getting the patches upstream into OpenWrt, along with a few improvements to wolfSSL itself that came out of this work, and looking at enabling the ARMv8 crypto code for Raspberry Pi targets as part of that.
If you are interested in wolfSSL on OpenWrt, or have questions about any of the above, please contact us at facts@wolfssl.com or call us at +1 425 245 8247.
Download wolfSSL Now

