Skip to content

Commit 37c2652

Browse files
committed
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. Only the two async record ciphers (AES and 3DES markers) are routed to poll completion; 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 at multiple pend depths, negative cases for cipher types defined but not dispatched (ChaCha, single DES), and full TLS 1.3 handshake+echo including the no-poll failure path.
1 parent e19a1a4 commit 37c2652

16 files changed

Lines changed: 1113 additions & 11 deletions

File tree

.github/workflows/async-examples.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,25 @@ jobs:
188188
cat "$f"
189189
fi
190190
done
191+
192+
# Crypto-callback record-cipher poll completion (WOLF_CRYPTO_CB_ASYNC_POLL):
193+
# build the unit test with the feature macro and run the async test group.
194+
cryptocb_async_poll:
195+
if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
196+
runs-on: ubuntu-24.04
197+
timeout-minutes: 15
198+
name: Crypto-cb async poll completion
199+
steps:
200+
- uses: actions/checkout@v5
201+
name: Checkout wolfSSL
202+
203+
- name: Build with WOLF_CRYPTO_CB_ASYNC_POLL
204+
run: |
205+
./autogen.sh
206+
./configure --enable-asynccrypt --enable-cryptocb --enable-tls13 \
207+
--enable-des3 --enable-aesccm --enable-aesctr \
208+
CPPFLAGS=-DWOLF_CRYPTO_CB_ASYNC_POLL
209+
make
210+
211+
- name: Run async unit tests
212+
run: ./tests/unit.test --group async

.wolfssl_known_macro_extras

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ WOLFSSL_XILINX_PATCH
10661066
WOLFSSL_XIL_MSG_NO_SLEEP
10671067
WOLFSSL_ZEPHYR
10681068
WOLF_ALLOW_BUILTIN
1069+
WOLF_CRYPTO_CB_ASYNC_POLL
10691070
WOLF_CRYPTO_CB_CMD
10701071
WOLF_CRYPTO_DEV
10711072
WOLF_NO_TRAILING_ENUM_COMMAS

configure.ac

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11290,6 +11290,23 @@ then
1129011290
fi
1129111291
fi
1129211292
11293+
# Crypto callbacks with async crypt may not work for TLS unless
11294+
# WOLF_CRYPTO_CB_ASYNC_POLL is defined. Warn once here and silence the
11295+
# source-level #warning.
11296+
if test "$ENABLED_ASYNCCRYPT" = "yes" && test "x$ENABLED_CRYPTOCB" != "xno" &&
11297+
test "x$ENABLED_ASYNCCRYPT_SW" != "xyes" &&
11298+
test "x$ENABLED_CAVIUM" != "xyes" && test "x$ENABLED_INTEL_QA" != "xyes"
11299+
then
11300+
case "$CPPFLAGS $CFLAGS $AM_CFLAGS" in
11301+
*WOLF_CRYPTO_CB_ASYNC_POLL*)
11302+
;;
11303+
*)
11304+
AC_MSG_WARN([crypto callbacks with async crypt may not work for TLS. Define WOLF_CRYPTO_CB_ASYNC_POLL to enable it.])
11305+
AM_CFLAGS="$AM_CFLAGS -DWOLF_CRYPTO_CB_ASYNC_NO_WARN"
11306+
;;
11307+
esac
11308+
fi
11309+
1129311310
# check for async if using Intel QuckAssist or Cavium
1129411311
if test "x$ENABLED_INTEL_QA" = "xyes" || test "x$ENABLED_CAVIUM" = "xyes" ; then
1129511312
if test "x$ENABLED_ASYNCCRYPT" = "xno" ; then

examples/async/user_settings.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#define NO_FILESYSTEM
2929
#define WOLFSSL_IGNORE_FILE_WARN
3030

31+
#ifdef WOLF_CRYPTO_CB
32+
/* PK-only offload: silence pending-bulk-cipher warning. */
33+
#define WOLF_CRYPTO_CB_ASYNC_NO_WARN
34+
#endif
35+
3136
#define HAVE_ECC
3237
#define WC_ECC_NONBLOCK
3338
#define WC_ECC_NONBLOCK_ONLY

src/internal.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21583,7 +21583,16 @@ static WC_INLINE int Encrypt(WOLFSSL* ssl, byte* out, const byte* input,
2158321583
#ifdef WOLFSSL_ASYNC_CRYPT
2158421584
/* If pending, then leave and return will resume below */
2158521585
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
21586+
#if defined(WOLF_CRYPTO_CB) && \
21587+
!defined(WOLF_CRYPTO_CB_ASYNC_POLL) && \
21588+
!defined(WOLFSSL_ASYNC_CRYPT_SW) && \
21589+
!defined(HAVE_INTEL_QA) && !defined(HAVE_CAVIUM)
21590+
/* No completion path for a pending bulk cipher op. */
21591+
WOLFSSL_ERROR_VERBOSE(ASYNC_OP_E);
21592+
return ASYNC_OP_E;
21593+
#else
2158621594
return ret;
21595+
#endif
2158721596
}
2158821597
#endif
2158921598
}
@@ -22085,7 +22094,16 @@ static int DecryptTls(WOLFSSL* ssl, byte* plain, const byte* input, word16 sz)
2208522094
#ifdef WOLFSSL_ASYNC_CRYPT
2208622095
/* If pending, leave and return below */
2208722096
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
22097+
#if defined(WOLF_CRYPTO_CB) && \
22098+
!defined(WOLF_CRYPTO_CB_ASYNC_POLL) && \
22099+
!defined(WOLFSSL_ASYNC_CRYPT_SW) && \
22100+
!defined(HAVE_INTEL_QA) && !defined(HAVE_CAVIUM)
22101+
/* No completion path for a pending bulk cipher op. */
22102+
WOLFSSL_ERROR_VERBOSE(ASYNC_OP_E);
22103+
return ASYNC_OP_E;
22104+
#else
2208822105
return ret;
22106+
#endif
2208922107
}
2209022108
#endif
2209122109
}
@@ -27850,10 +27868,8 @@ int SendData(WOLFSSL* ssl, const void* data, size_t sz)
2785027868
#endif
2785127869
}
2785227870
if (sendSz < 0) {
27853-
#ifdef WOLFSSL_ASYNC_CRYPT
27854-
if (sendSz == WC_NO_ERR_TRACE(WC_PENDING_E))
27855-
ssl->error = sendSz;
27856-
#endif
27871+
/* Preserve the reason for wolfSSL_get_error(). */
27872+
ssl->error = sendSz;
2785727873
return BUILD_MSG_ERROR;
2785827874
}
2785927875

@@ -43928,7 +43944,13 @@ int wolfSSL_AsyncPop(WOLFSSL* ssl, byte* state)
4392843944
#if (defined(WOLF_CRYPTO_CB) || defined(HAVE_PK_CALLBACKS)) && \
4392943945
!defined(WOLFSSL_ASYNC_CRYPT_SW) && !defined(HAVE_INTEL_QA) && \
4393043946
!defined(HAVE_CAVIUM)
43931-
else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
43947+
else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)
43948+
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_ASYNC_POLL)
43949+
/* Poll-completed ops stay queued until the poll fills the
43950+
* output buffer. */
43951+
&& asyncDev->cryptocb.devId == INVALID_DEVID
43952+
#endif
43953+
) {
4393243954
/* Allow the underlying crypto API to be called again to trigger the
4393343955
* crypto or PK callback. The actual callback must be called, since
4393443956
* the completion is not detected in the poll like Intel QAT or

src/tls13.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2818,6 +2818,14 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
28182818

28192819
#ifdef WOLFSSL_ASYNC_CRYPT
28202820
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
2821+
#if defined(WOLF_CRYPTO_CB) && \
2822+
!defined(WOLF_CRYPTO_CB_ASYNC_POLL) && \
2823+
!defined(WOLFSSL_ASYNC_CRYPT_SW) && \
2824+
!defined(HAVE_INTEL_QA) && !defined(HAVE_CAVIUM)
2825+
/* No completion path for a pending bulk cipher op. */
2826+
WOLFSSL_ERROR_VERBOSE(ASYNC_OP_E);
2827+
return ASYNC_OP_E;
2828+
#else
28212829
/* if async is not okay, then block */
28222830
if (!asyncOkay) {
28232831
ret = wc_AsyncWait(ret, asyncDev, event_flags);
@@ -2826,6 +2834,7 @@ static int EncryptTls13(WOLFSSL* ssl, byte* output, const byte* input,
28262834
/* If pending, then leave and return will resume below */
28272835
return wolfSSL_AsyncPush(ssl, asyncDev);
28282836
}
2837+
#endif
28292838
}
28302839
#endif
28312840
}
@@ -3217,7 +3226,16 @@ int DecryptTls13(WOLFSSL* ssl, byte* output, const byte* input, word16 sz,
32173226
#ifdef WOLFSSL_ASYNC_CRYPT
32183227
/* If pending, leave now */
32193228
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
3229+
#if defined(WOLF_CRYPTO_CB) && \
3230+
!defined(WOLF_CRYPTO_CB_ASYNC_POLL) && \
3231+
!defined(WOLFSSL_ASYNC_CRYPT_SW) && \
3232+
!defined(HAVE_INTEL_QA) && !defined(HAVE_CAVIUM)
3233+
/* No completion path for a pending bulk cipher op. */
3234+
WOLFSSL_ERROR_VERBOSE(ASYNC_OP_E);
3235+
return ASYNC_OP_E;
3236+
#else
32203237
return ret;
3238+
#endif
32213239
}
32223240
#endif
32233241
}

tests/api.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@
214214
#include <tests/api/test_kdf.h>
215215
#include <tests/api/test_she.h>
216216
#include <tests/api/test_des3.h>
217+
#include <tests/api/test_async.h>
217218
#include <tests/api/test_chacha.h>
218219
#include <tests/api/test_poly1305.h>
219220
#include <tests/api/test_chacha20_poly1305.h>
@@ -37042,6 +37043,8 @@ TEST_CASE testCases[] = {
3704237043
#endif
3704337044

3704437045
/* Cipher */
37046+
/* Crypto callback async poll completion */
37047+
TEST_ASYNC_DECLS,
3704537048
/* Triple-DES */
3704637049
TEST_DES3_DECLS,
3704737050
/* Chacha20 */

tests/api/include.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ tests_unit_test_SOURCES += tests/api/test_kdf.c
2222
# SHE
2323
tests_unit_test_SOURCES += tests/api/test_she.c
2424
# Cipher
25+
tests_unit_test_SOURCES += tests/api/test_async.c
2526
tests_unit_test_SOURCES += tests/api/test_des3.c
2627
tests_unit_test_SOURCES += tests/api/test_chacha.c
2728
tests_unit_test_SOURCES += tests/api/test_poly1305.c
@@ -145,6 +146,7 @@ EXTRA_DIST += tests/api/test_hmac.h
145146
EXTRA_DIST += tests/api/test_cmac.h
146147
EXTRA_DIST += tests/api/test_kdf.h
147148
EXTRA_DIST += tests/api/test_she.h
149+
EXTRA_DIST += tests/api/test_async.h
148150
EXTRA_DIST += tests/api/test_des3.h
149151
EXTRA_DIST += tests/api/test_chacha.h
150152
EXTRA_DIST += tests/api/test_poly1305.h

0 commit comments

Comments
 (0)