wolfssl/examples/async
Juliusz Sosinowicz aab3257de8 Add compile-time crypto callback async poll for record ciphers
A crypto callback that returns WC_PENDING_E for a TLS record cipher
silently corrupted records: Encrypt()/Decrypt() advance the cipher
state to CIPHER_STATE_END before the pending check, so on resume the
record is shipped without re-running the cipher.

WOLF_CRYPTO_CB_ASYNC_POLL gives crypto callback devices the QAT/Nitrox
"poll to fill output" completion model. On WC_PENDING_E the async event
stays queued; wolfSSL_AsyncPoll() re-enters the device with the new
WC_ALGO_TYPE_ASYNC_POLL (wc_CryptoCb_Poll) to finish the job and fill
the output buffer. The re-entry only polls while the event is still
pending, and a device that cannot complete the job (no poll support, or
it reports nothing pending) hard-fails with WC_HW_E rather than
reporting the op done with an unfilled buffer. Only the two async record
ciphers (AES and 3DES markers) are routed to poll completion, and only
when crypto callbacks are the async backend (not QAT/Cavium/SW);
handshake PK keeps the re-invoke model. The wolfSSL_AsyncPop eviction is
gated for poll-capable devices so the existing resume-at-CIPHER_STATE_END
path becomes correct with no record state-machine changes.

Without the feature (and without a software/QAT/Cavium backend) a
pending bulk cipher op now errors out with ASYNC_OP_E instead of
corrupting the record, and configure/cryptocb.c warn about the
unsupported combination.

Tests in tests/api/test_async.c cover direct AES-GCM/CBC/CCM and 3DES
poll completion in both directions at multiple pend depths, negative
cases for cipher types defined but not dispatched (ChaCha, single DES),
and full TLS 1.3 handshake+echo: an encrypt-offload run, a both-
directions run that offloads encrypt and decrypt on both peers using a
per-peer device, and the no-poll failure path.
2026-07-24 16:14:35 +00:00
..
Makefile Fix async examples build for asn_orig.c 2026-03-23 15:27:47 -07:00
README.md Add tests for async with crypto callbacks 2026-02-27 14:35:02 -08:00
async_client.c Add WOLFSSL_ASYNC_CERT_YIELD opt-in for per-certificate WC_PENDING_E yield during async TLS chain processing 2026-06-18 16:51:25 -07:00
async_server.c Add WOLFSSL_ASYNC_CERT_YIELD opt-in for per-certificate WC_PENDING_E yield during async TLS chain processing 2026-06-18 16:51:25 -07:00
async_tls.c Fix code comment - peer review 2026-03-02 08:16:53 -08:00
async_tls.h update Copyright year 2026-02-18 09:52:21 -07:00
include.am
user_settings.h Add compile-time crypto callback async poll for record ciphers 2026-07-24 16:14:35 +00:00

README.md

wolfSSL Asynchronous Cryptography support

Supported with:

  • Intel QuickAssist
  • Marvell (Cavium) Nitrox
  • Crypto Callbacks (--enable-cryptocb)
  • PK Callbacks (--enable-pkcallbacks)

Tested with:

  • ./configure --enable-asynccrypt --enable-rsa --disable-ecc
  • ./configure --enable-asynccrypt --disable-rsa --enable-ecc
  • ./configure --enable-asynccrypt --enable-cryptocb --enable-rsa --disable-ecc
  • ./configure --enable-asynccrypt --enable-cryptocb --disable-rsa --enable-ecc
  • ./configure --enable-asynccrypt --enable-pkcallbacks --enable-rsa --disable-ecc
  • ./configure --enable-asynccrypt --enable-pkcallbacks --disable-rsa --enable-ecc

Build Modes

The async examples support two mutually exclusive async modes controlled via the ASYNC_MODE Makefile variable:

Software Async Mode (default)

Uses WOLFSSL_ASYNC_CRYPT_SW with non-blocking ECC (WC_ECC_NONBLOCK):

make -C examples/async
# or explicitly:
make -C examples/async ASYNC_MODE=sw

Crypto Callback Mode

Uses WOLF_CRYPTO_CB with the AsyncTlsCryptoCb callback that simulates hardware crypto delays by returning WC_PENDING_E for a configurable number of iterations:

make -C examples/async ASYNC_MODE=cryptocb

To adjust the simulated pending count (default is 2), define TEST_PEND_COUNT:

make -C examples/async ASYNC_MODE=cryptocb EXTRA_CFLAGS="-DTEST_PEND_COUNT=5"

To enable crypto callback debug output:

make -C examples/async ASYNC_MODE=cryptocb EXTRA_CFLAGS="-DDEBUG_CRYPTOCB"

Note: WOLFSSL_ASYNC_CRYPT_SW and WOLF_CRYPTO_CB are mutually exclusive in the async polling code (async.c uses #elif).

Running the Examples

./examples/async/async_server --ecc
./examples/async/async_client --ecc 127.0.0.1 11111
./examples/async/async_client --x25519 ecc256.badssl.com 443

Optional ready-file sync (CI-friendly, avoids sleeps):

export WOLFSSL_ASYNC_READYFILE=/tmp/wolfssl_async_ready
./examples/async/async_server --ecc
WOLFSSL_ASYNC_READYFILE=/tmp/wolfssl_async_ready ./examples/async/async_client --ecc 127.0.0.1 11111

Porting the TCP/IP stack: Define NET_USER_HEADER to include your network shim and provide the NET_* macros plus NET_IO_SEND_CB / NET_IO_RECV_CB.

Asynchronous Cryptography Design

When a cryptographic call is handed off to hardware it return WC_PENDING_E up to caller. Then it can keep calling until the operation completes. For some platforms it is required to call wolfSSL_AsyncPoll. At the TLS layer a "devId" (Device ID) must be set using wolfSSL_CTX_SetDevId to indicate desire to offload cryptography.

For further design details please see: https://github.com/wolfSSL/wolfAsyncCrypt#design

Support

For questions please email support@wolfssl.com