Skip to content

Commit 3ee9f87

Browse files
committed
Add X25519 non-blocking support for key gen and shared secret
## Summary - Add non-blocking (incremental) Curve25519 key generation and shared secret via `WC_X25519_NONBLOCK`, modeled after the existing ECC non-blocking pattern (`WC_ECC_NONBLOCK`) - Implement `curve25519_nb()` and `fe_inv__distinct_nb()` in `fe_low_mem.c` as state-machine variants that return `FP_WOULDBLOCK` to yield after each field multiply - Add `wc_curve25519_set_nonblock()` API to attach/detach non-blocking context to a key - Integrate X25519 non-blocking with TLS 1.2/1.3 key share generation and shared secret in `tls.c` and `internal.c` (behind `WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW`) - Add `--enable-curve25519=nonblock` configure option (auto-enables `--enable-asynccrypt` and `--enable-asynccrypt-sw`) - Add X25519 async software dispatch cases in `async.c` and types in `async.h` - Fix async guard in `curve25519.c` to require `WOLFSSL_ASYNC_CRYPT_SW` (matching other algorithms) - Overhaul `examples/async/` client/server: non-blocking I/O via `WOLFSSL_USER_IO`, standalone `Makefile`, X25519/ECC mode selection, CI-friendly ready-file sync - Add `examples/configs/user_settings_curve25519nonblock.h` and CI coverage in `os-check.yml` and new `async-examples.yml` workflow - Add wolfcrypt test and API test coverage for X25519 non-blocking
1 parent 492ff38 commit 3ee9f87

28 files changed

Lines changed: 2403 additions & 438 deletions
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
name: Async Examples
2+
3+
on:
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ '*' ]
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
async_examples:
15+
if: github.repository_owner == 'wolfssl'
16+
runs-on: ubuntu-24.04
17+
timeout-minutes: 10
18+
steps:
19+
- uses: actions/checkout@v4
20+
name: Checkout wolfSSL
21+
22+
- name: Build async examples (no configure)
23+
run: |
24+
make -C examples/async clean
25+
make -C examples/async
26+
27+
- name: Run async examples
28+
run: |
29+
set -euo pipefail
30+
31+
MIN_PENDING=100
32+
33+
run_pair() {
34+
local label="$1"
35+
shift
36+
local args="$*"
37+
local ready="/tmp/wolfssl_async_ready_${label}"
38+
rm -f "$ready"
39+
40+
WOLFSSL_ASYNC_READYFILE="$ready" \
41+
./examples/async/async_server $args \
42+
> "/tmp/async_server_${label}.log" 2>&1 &
43+
local pid=$!
44+
45+
WOLFSSL_ASYNC_READYFILE="$ready" \
46+
./examples/async/async_client $args 127.0.0.1 11111 \
47+
> "/tmp/async_client_${label}.log" 2>&1
48+
local rc=$?
49+
50+
kill "$pid" >/dev/null 2>&1 || true
51+
wait "$pid" >/dev/null 2>&1 || true
52+
53+
if [ "$rc" -ne 0 ]; then
54+
echo "FAIL: $label (exit=$rc)"
55+
return 1
56+
fi
57+
58+
# Validate WC_PENDING_E count is a proper value
59+
local count
60+
count=$(awk '/WC_PENDING_E count:/ {print $NF}' \
61+
"/tmp/async_client_${label}.log")
62+
if [ -z "$count" ] || [ "$count" -lt "$MIN_PENDING" ]; then
63+
echo "FAIL: $label - WC_PENDING_E count too low:" \
64+
"${count:-missing} (expected >= $MIN_PENDING)"
65+
return 1
66+
fi
67+
echo "PASS: $label (WC_PENDING_E: $count)"
68+
return 0
69+
}
70+
71+
# TLS 1.3
72+
run_pair ecc_tls13 --ecc
73+
run_pair x25519_tls13 --x25519
74+
75+
# TLS 1.2
76+
run_pair ecc_tls12 --tls12 --ecc
77+
run_pair x25519_tls12 --tls12 --x25519
78+
79+
# BELOW ARE NOT WORKING YET
80+
# TLS 1.3 mutual auth
81+
#run_pair ecc_tls13_mutual --mutual --ecc
82+
#run_pair x25519_tls13_mutual --mutual --x25519
83+
84+
85+
- name: Print async logs
86+
if: ${{ failure() }}
87+
run: |
88+
for f in /tmp/async_server_*.log /tmp/async_client_*.log; do
89+
if [ -f "$f" ]; then
90+
echo "==> $f"
91+
cat "$f"
92+
fi
93+
done

.github/workflows/os-check.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ jobs:
8484
'--enable-all CPPFLAGS=-DWOLFSSL_NO_CLIENT_AUTH',
8585
'--enable-all CPPFLAGS=''-DNO_WOLFSSL_CLIENT -DWOLFSSL_NO_CLIENT_AUTH''',
8686
'--enable-all CPPFLAGS=''-DNO_WOLFSSL_SERVER -DWOLFSSL_NO_CLIENT_AUTH''',
87+
'--enable-curve25519=nonblock --enable-ecc=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK"',
88+
'--enable-certreq --enable-certext --enable-certgen --disable-secure-renegotiation-info CPPFLAGS="-DNO_TLS"',
8789
]
8890
name: make check
8991
if: github.repository_owner == 'wolfssl'
@@ -130,6 +132,7 @@ jobs:
130132
'examples/configs/user_settings_dtls13.h',
131133
'examples/configs/user_settings_EBSnet.h',
132134
'examples/configs/user_settings_eccnonblock.h',
135+
'examples/configs/user_settings_curve25519nonblock.h',
133136
'examples/configs/user_settings_min_ecc.h',
134137
'examples/configs/user_settings_openssl_compat.h',
135138
'examples/configs/user_settings_pkcs7.h',

.wolfssl_known_macro_extras

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ MUTEX_DURING_INIT
350350
NEED_THREADX_TYPES
351351
NETX_DUO
352352
NET_SECURE_MODULE_EN
353+
NET_GETDEVRANDOM
353354
NOTE_TRIGGER
354355
NO_AES_DECRYPT
355356
NO_ARDUINO_DEFAULT
@@ -615,13 +616,13 @@ WC_ASYNC_NO_SHA256
615616
WC_ASYNC_NO_SHA3
616617
WC_ASYNC_NO_SHA384
617618
WC_ASYNC_NO_SHA512
619+
WC_ASYNC_NO_X25519
618620
WC_ASYNC_THREAD_BIND
619621
WC_CACHE_RESISTANT_BASE64_TABLE
620622
WC_DILITHIUM_CACHE_PRIV_VECTORS
621623
WC_DILITHIUM_CACHE_PUB_VECTORS
622624
WC_DILITHIUM_FIXED_ARRAY
623625
WC_DISABLE_RADIX_ZERO_PAD
624-
WC_ECC_NONBLOCK_ONLY
625626
WC_FLAG_DONT_USE_AESNI
626627
WC_FORCE_LINUXKM_FORTIFY_SOURCE
627628
WC_LMS_FULL_HASH
@@ -637,7 +638,6 @@ WC_RSA_NONBLOCK
637638
WC_RSA_NONBLOCK_TIME
638639
WC_RSA_NO_FERMAT_CHECK
639640
WC_RWLOCK_OPS_INLINE
640-
WC_SHA3_HARDEN
641641
WC_SHA384
642642
WC_SHA384_DIGEST_SIZE
643643
WC_SHA512

configure.ac

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4816,11 +4816,18 @@ ENABLED_ED25519_SMALL=no
48164816

48174817
# CURVE25519
48184818
AC_ARG_ENABLE([curve25519],
4819-
[AS_HELP_STRING([--enable-curve25519],[Enable Curve25519 (default: disabled)])],
4819+
[AS_HELP_STRING([--enable-curve25519],[Enable Curve25519 (default: disabled). Set to "nonblock" to enable non-blocking support for key gen and shared secret])],
48204820
[ ENABLED_CURVE25519=$enableval ],
48214821
[ ENABLED_CURVE25519=no ]
48224822
)
48234823

4824+
# Handle curve25519 nonblock option - enable asynccrypt and asynccrypt-sw early
4825+
if test "$ENABLED_CURVE25519" = "nonblock"
4826+
then
4827+
test -z "$enable_asynccrypt" && enable_asynccrypt=yes
4828+
test -z "$enable_asynccrypt_sw" && enable_asynccrypt_sw=yes
4829+
fi
4830+
48244831
if test "$ENABLED_CURVE25519" = "no" && test "$ENABLED_QUIC" = "yes" && test "$ENABLED_FIPS" = "no"
48254832
then
48264833
ENABLED_CURVE25519=yes
@@ -10328,12 +10335,17 @@ fi
1032810335
1032910336
if test "$ENABLED_CURVE25519" != "no"
1033010337
then
10331-
if test "$ENABLED_CURVE25519" = "small" || test "$ENABLED_LOWRESOURCE" = "yes"
10338+
if test "$ENABLED_CURVE25519" = "small" || test "$ENABLED_CURVE25519" = "nonblock" || test "$ENABLED_LOWRESOURCE" = "yes"
1033210339
then
1033310340
AM_CFLAGS="$AM_CFLAGS -DCURVE25519_SMALL"
1033410341
ENABLED_CURVE25519_SMALL=yes
1033510342
fi
1033610343
10344+
if test "$ENABLED_CURVE25519" = "nonblock"
10345+
then
10346+
AM_CFLAGS="$AM_CFLAGS -DWC_X25519_NONBLOCK"
10347+
fi
10348+
1033710349
if test "$ENABLED_CURVE25519" = "no128bit" || test "$ENABLED_32BIT" = "yes"
1033810350
then
1033910351
AM_CFLAGS="$AM_CFLAGS -DNO_CURVED25519_128BIT"

examples/async/Makefile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
CC ?= gcc
2+
AR ?= ar
3+
RM ?= rm -f
4+
5+
WOLFSSL_TOP ?= $(abspath ../..)
6+
OBJDIR ?= build
7+
8+
CFLAGS ?= -O0 -g
9+
CFLAGS += -I.
10+
CFLAGS += -I$(WOLFSSL_TOP)
11+
CFLAGS += -I$(WOLFSSL_TOP)/wolfssl
12+
CFLAGS += -I$(WOLFSSL_TOP)/wolfssl/wolfcrypt
13+
CFLAGS += -Wall -Wextra -Wpedantic -Werror
14+
CFLAGS += -DWOLFSSL_USER_SETTINGS
15+
CFLAGS += -DHAVE_SYS_TIME_H
16+
CFLAGS += -DUSE_CERT_BUFFERS_256
17+
18+
LDFLAGS ?=
19+
LDLIBS ?=
20+
21+
TARGETS = async_client async_server
22+
23+
WOLFSSL_SRC := $(wildcard $(WOLFSSL_TOP)/src/*.c)
24+
WOLFCRYPT_SRC := $(wildcard $(WOLFSSL_TOP)/wolfcrypt/src/*.c)
25+
LOCAL_SRC := async_client.c async_server.c async_tls.c
26+
27+
WOLFSSL_OBJS := $(patsubst $(WOLFSSL_TOP)/%, $(OBJDIR)/%, $(WOLFSSL_SRC:.c=.o))
28+
WOLFCRYPT_OBJS := $(patsubst $(WOLFSSL_TOP)/%, $(OBJDIR)/%, $(WOLFCRYPT_SRC:.c=.o))
29+
LOCAL_OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(LOCAL_SRC))
30+
31+
ASYNC_CLIENT_OBJS := $(OBJDIR)/async_client.o $(OBJDIR)/async_tls.o
32+
ASYNC_SERVER_OBJS := $(OBJDIR)/async_server.o $(OBJDIR)/async_tls.o
33+
34+
all: $(TARGETS)
35+
36+
async_client: $(ASYNC_CLIENT_OBJS) $(WOLFSSL_OBJS) $(WOLFCRYPT_OBJS)
37+
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
38+
39+
async_server: $(ASYNC_SERVER_OBJS) $(WOLFSSL_OBJS) $(WOLFCRYPT_OBJS)
40+
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
41+
42+
$(OBJDIR)/%.o: %.c user_settings.h
43+
@mkdir -p $(dir $@)
44+
$(CC) $(CFLAGS) -c $< -o $@
45+
46+
$(OBJDIR)/%.o: $(WOLFSSL_TOP)/%.c
47+
@mkdir -p $(dir $@)
48+
$(CC) $(CFLAGS) -c $< -o $@
49+
50+
# Possibly empty files (avoids "warning: ISO C forbids an empty translation unit")
51+
$(OBJDIR)/wolfcrypt/src/ecc_fp.o: CFLAGS += -Wno-pedantic
52+
$(OBJDIR)/wolfcrypt/src/fips.o: CFLAGS += -Wno-pedantic
53+
$(OBJDIR)/wolfcrypt/src/fips_test.o: CFLAGS += -Wno-pedantic
54+
$(OBJDIR)/wolfcrypt/src/selftest.o: CFLAGS += -Wno-pedantic
55+
$(OBJDIR)/wolfcrypt/src/wolfcrypt_first.o: CFLAGS += -Wno-pedantic
56+
$(OBJDIR)/wolfcrypt/src/wolfcrypt_last.o: CFLAGS += -Wno-pedantic
57+
58+
clean:
59+
$(RM) -r $(OBJDIR) $(TARGETS)

examples/async/README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,23 @@ Tested with:
1515
* `./configure --enable-asynccrypt --enable-pkcallbacks --disable-rsa --enable-ecc`
1616

1717
```
18-
make
19-
./examples/async/async_server
20-
./examples/async/async_client 127.0.0.1
18+
make -C examples/async
19+
./examples/async/async_server --ecc
20+
./examples/async/async_client --ecc 127.0.0.1 11111
21+
./examples/async/async_client --x25519 ecc256.badssl.com 443
2122
```
2223

24+
Optional ready-file sync (CI-friendly, avoids sleeps):
25+
```
26+
export WOLFSSL_ASYNC_READYFILE=/tmp/wolfssl_async_ready
27+
./examples/async/async_server --ecc
28+
WOLFSSL_ASYNC_READYFILE=/tmp/wolfssl_async_ready ./examples/async/async_client --ecc 127.0.0.1 11111
29+
```
30+
31+
Porting the TCP/IP stack:
32+
Define `NET_USER_HEADER` to include your network shim and provide the
33+
`NET_*` macros plus `NET_IO_SEND_CB` / `NET_IO_RECV_CB`.
34+
2335
## Asynchronous Cryptography Design
2436

2537
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.

0 commit comments

Comments
 (0)