wolfSSL is one of the smallest commercial TLS / crypto libraries available. Pulling the right configuration levers is the biggest challenge. This post is a short tour of the ten biggest knobs.
Two ways to configure the build
Every define and flag below can be supplied through either of these paths:
- Autoconf / configure(./configure): Pass –enable-X / –disable-X switches and CFLAGS=”-DSOME_DEFINE” to ./configure. The resulting choices are written to wolfssl/options.h, which settings.h includes automatically. This is the standard path for desktop, server, and Linux-embedded builds.
- WOLFSSL_USER_SETTINGS + user_settings.h: For IDE projects and cross-compiled MCU builds, just define WOLFSSL_USER_SETTINGS globally and supply all build options in your own user_settings.h header. settings.h will include it automatically. See examples/configs/ for example templates. You can also use ./configure –enable-usersettings for use with autoconf.
-
Start from a config template
The fastest path to a small build is to not start from the kitchen-sink defaults. examples/configs/ ships a dozen ready-made profiles; two matter most for footprint work:
- user_settings_baremetal.h: no filesystem, static memory, SINGLE_THREADED, WOLFSSL_USER_IO, WOLFSSL_SP_MATH, WOLFSSL_SP_SMALL, WOLFCRYPT_ONLY, ECC P-256 only, AES-GCM, SHA-256, HKDF, everything else off. The right start for a crypto-only device.
- user_settings_tinytls13.h: the smallest TLS 1.3 profile. Tip 2.
Copy one as your user_settings.h, build with –enable-usersettings, and most of the tips below are already on.
-
–enable-tinytls13: the smallest TLS 1.3 footprint
–enable-tinytls13 (or WOLFSSL_TINY_TLS13) is an umbrella that expands in settings.h into the smallest coherent TLS 1.3 configuration: TLS 1.3 only, PSK + ECDHE over X25519, AES-128-GCM, SHA-256, SP math small, no ASN.1 or X.509 at all, and the –enable-lowresource bundle switched on for you. Everything above that floor is an opt-in adder, either as a comma-separated sub-option (–enable-tinytls13=cert,p256,sha384) or a define in examples/configs/user_settings_tinytls13.h: cert (minimal X.509 ECDSA P-256 verify), mutualauth, rsaverify, p256, asm (assembly instead of small-C), sha384, mldsa (ML-DSA-44 verify-only), plus WOLFSSL_TINY_TLS13_SERVER and WOLFSSL_TINY_TLS13_STATIC_MEM. Measured on Cortex-M4 with -Os -flto -Wl,–gc-sections, the PSK floor links at 35 KB of .text and the cert profile at 73 KB, against 84 KB for that same feature set hand-tuned with every other tip in this post, so the umbrella finds ~11 KB careful hand-tuning misses, and dropping X.509 entirely is worth ~50 KB. One caveat: the cert profile is a deliberately reduced-security verify path (no name constraints, relaxed ASN.1, no CRL), intended for a known or pinned CA rather than public-internet PKI.
-
WOLFCRYPT_ONLY: drop the TLS layer entirely
If the device only needs crypto primitives (bootloader signature verification, secure-storage encryption, COSE / JWS signing), define WOLFCRYPT_ONLY or pass –enable-cryptonly. This removes src/internal.c, src/ssl.c, the TLS state machine, cipher-suite plumbing, and the TLS 1.2 / 1.3 record layer entirely.
-
Single Precision math only: WOLFSSL_SP_MATH + WOLFSSL_SP_SMALL
WOLFSSL_SP_MATH replaces the general big-integer library (sp_int.c / integer.c / tfm.c) with fixed-width routines for the key sizes you actually use. WOLFSSL_SP_SMALL selects the compact (looped) variant instead of the unrolled one. The single largest lever for a crypto-only build. Configure with –enable-sp=small –enable-sp-math.
The tinytls13 umbrella sets both for you; this tip is for builds that don’t use it.
-
Disable deprecated / unused algorithms and features
If building with ./configure these are disabled by default, however if you are using user_settings.h they are not and you must add these manually:
#define NO_DES3 #define NO_MD5 #define NO_RC4 #define NO_DSA #define NO_DH /* if you only use ECDHE */ #define NO_PWDBASED #define NO_PKCS12
–enable-lowresource bundles the matching small-code defines in one shot: RSA_LOW_MEM, CURVE25519_SMALL, ED25519_SMALL, GCM_SMALL, WOLFSSL_AES_SMALL_TABLES, WOLFSSL_AES_NO_UNROLL, USE_SLOW_SHA / USE_SLOW_SHA256 / USE_SLOW_SHA512, WOLFSSL_SMALL_CERT_VERIFY, WOLFSSL_NO_ASYNC_IO, NO_SESSION_CACHE (typically 5-15 KB combined). Inline notes in user_settings_baremetal.h quote the individual deltas: AES unroll ~2 KB, USE_SLOW_SHA256 ~1 KB, WOLFSSL_AES_SMALL_TABLES a few KB. –enable-tinytls13 turns this bundle on automatically.
-
Narrow ECC curves and key sizes
By default wolfSSL compiles every NIST curve and every common RSA / DH size. Most products use one:
#define ECC_USER_CURVES /* only P-256 enabled by default */ /* #define NO_ECC256 */ /* leave NO_ECC192 / NO_ECC224 / NO_ECC384 / NO_ECC521 in effect */
For verify-only paths (bootloaders, image authenticators) add NO_ECC_SIGN, NO_ECC_DHE, NO_ECC_KEY_EXPORT. The verify-only path is meaningfully smaller. Same idea on RSA / DH: if you only need 2048-bit, leave WOLFSSL_SP_3072 and WOLFSSL_SP_4096 undefined so the larger SP-math tables never compile in.
-
Turn off the diagnostics before you ship
DEBUG_WOLFSSL (–enable-debug) is the most expensive thing commonly left switched on after bring-up: 21.8 KB of .text on the baseline client above (86,249 to 108,097 B). Only ~15.5 KB of that is wolfSSL’s logging code and format strings; the other ~6.3 KB is the printf machinery it drags into an image that otherwise never links stdio at all. If you need logs in the field, route them to your own sink with wolfSSL_SetLoggingCb() or WOLFSSL_USER_LOG / WOLFSSL_DEBUG_PRINTF_FN rather than paying for stdio. Its companion is NO_ERROR_STRINGS (–disable-errorstrings), which drops a 12.4 KB table of human-readable error text. Though with –gc-sections a build that never formats an error string already discards it (the define saved 88 bytes on my rig). It earns its keep when you aren’t collecting sections, or when your app really does call the error-string APIs. Grep the map file for vfprintf and wc_ErrorString before shipping.
-
Compiler and linker flags
Toolchain matters as much as configure flags:
CFLAGS += -Os -ffunction-sections -fdata-sections LDFLAGS += -Wl,--gc-sections -flto
-Os typically trims another 5-10% over -O2 on Cortex-M. –gc-sections drops unreferenced functions and data instead of pulling whole .o files in. -flto folds inlining decisions across translation units for another few percent. Independent of any wolfSSL define, applies to every other library you link.
Not optional if you want the tip 2 numbers: those are dead-code-eliminated LTO links.
-
Use the on-chip crypto accelerator
When the MCU has an AES / HASH / RNG peripheral, route wolfCrypt through it and the software implementation drops out of the link. On STM32 that is WOLFSSL_STM32_BARE (direct-register) or WOLFSSL_STM32_CUBEMX (HAL) plus STM32_CRYPTO / STM32_HASH / STM32_RNG / WOLFSSL_STM32_PKA. Measured: forcing the rig back to pure software grew the final image by ~37 KB. Same idea applies to Arm v8-M crypto extensions, NXP CAU/MMCAU, Microchip ATECC, etc.
-
Reduce TLS code size
When TLS stays in and tinytls13 isn’t a fit (you need TLS 1.2, a full X.509 path, or a feature outside the profile), trim the handshake state machine and the X.509 / ASN.1 surface by hand:
#define WOLFSSL_NO_CLIENT /* server-only build */ #define WOLFSSL_NO_SERVER /* client-only build (mutually exclusive) */ #define NO_OLD_TLS /* drop TLS 1.0 / 1.1 */ #define WOLFSSL_NO_TLS12 /* TLS 1.3 only */ #define WOLFSSL_AEAD_ONLY /* AEAD cipher suites only */ #define NO_SESSION_CACHE
WOLFSSL_NO_CLIENT / WOLFSSL_NO_SERVER remove the half of the handshake you don’t ship. WOLFSSL_NO_TLS12 + NO_OLD_TLS leave only TLS 1.3, the smallest record layer. NO_CERTS / NO_ASN drop the cert chain when both endpoints use pre-shared keys.
The tinytls13 umbrella sets all of these, and still lands ~11 KB smaller.
Putting it together
| Lever | Saved |
|---|---|
| –enable-tinytls13 vs. hand-tuned equivalent | ~11 KB final image (~50 KB if you can drop X.509) |
| WOLFSSL_SP_SMALL | ~130 KB on libwolfssl.a |
| NO_RSA + NO_DH + NO_DES3 | ~62 KB on libwolfssl.a |
| DEBUG_WOLFSSL left on | ~22 KB final image |
| On-chip crypto offload | ~37 KB final image |
| –enable-lowresource bundle | ~5-15 KB |
| ECC_USER_CURVES + NO_ECC_SIGN, WOLFSSL_SMALL_STACK, NO_FILESYSTEM, TLS trims | bundled into the above |
| Compiler -Os + –gc-sections + -flto | toolchain-dependent, typically 5-15% on top |
If you speak TLS 1.3 and control both endpoints, start at –enable-tinytls13 and add back only what you need. If you don’t speak TLS at all, start at WOLFCRYPT_ONLY and user_settings_baremetal.h. Either way, read the template once: every flag above is one line.
For benchmarking, build with BENCH_EMBEDDED to keep the test harness from pulling in large block sizes.
If you 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

