Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/os-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,14 @@ jobs:
'CPPFLAGS=-DNO_WOLFSSL_CLIENT',
'CPPFLAGS=-DNO_WOLFSSL_SERVER',
'--enable-lms=small,verify-only --enable-xmss=small,verify-only',
'--enable-curve25519=nonblock --enable-ecc=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK"',
# Non-blocking ECC + Curve25519 + RSA + DH on the default SP word
# size for the host (sp_c64.c on x86_64). RSA/DH non-block require
# RSA_LOW_MEM (CRT path is not supported in non-block mode).
'--enable-curve25519=nonblock --enable-ecc=nonblock --enable-rsa=nonblock --enable-dh=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK -DRSA_LOW_MEM"',
# Same configuration but force SP_WORD_SIZE=32 to exercise sp_c32.c
# on a 64-bit host. The two builds together cover both generated
# variants of mod_exp_<words>_nb / RSA / DH wrappers.
'--enable-curve25519=nonblock --enable-ecc=nonblock --enable-rsa=nonblock --enable-dh=nonblock --enable-sp=yes,nonblock CPPFLAGS="-DWOLFSSL_PUBLIC_MP -DWOLFSSL_DEBUG_NONBLOCK -DRSA_LOW_MEM -DSP_WORD_SIZE=32"',
'--enable-certreq --enable-certext --enable-certgen --disable-secure-renegotiation-info CPPFLAGS="-DNO_TLS"',
]
name: make check linux
Expand Down
29 changes: 27 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -4880,6 +4880,15 @@ then
test -z "$enable_asynccrypt_sw" && enable_asynccrypt_sw=yes
fi

# Handle RSA/DH nonblock - the SP non-blocking dispatch wants the same
# WOLFSSL_ASYNC_CRYPT_SW shim that ECC/Curve25519 nonblock use so the
# TLS layer can manage per-SSL nb contexts and yield MP_WOULDBLOCK.
if test "$enable_rsa" = "nonblock" || test "$enable_dh" = "nonblock"
then
test -z "$enable_asynccrypt" && enable_asynccrypt=yes
test -z "$enable_asynccrypt_sw" && enable_asynccrypt_sw=yes
fi

if test "$ENABLED_CURVE25519" = "no" && test "$ENABLED_QUIC" = "yes" && test "$ENABLED_FIPS" = "no"
then
ENABLED_CURVE25519=yes
Expand Down Expand Up @@ -5396,14 +5405,25 @@ fi

# RSA
AC_ARG_ENABLE([rsa],
[AS_HELP_STRING([--enable-rsa],[Enable RSA (default: enabled)])],
[AS_HELP_STRING([--enable-rsa],[Enable RSA (default: enabled). Set to "nonblock" to enable non-blocking RSA via TFM fp_exptmod_nb or SP small mod_exp_nb])],
[ ENABLED_RSA=$enableval ],
[ ENABLED_RSA=yes ]
)

if test "$ENABLED_RSA" = "no"
then
AM_CFLAGS="$AM_CFLAGS -DNO_RSA"
elif test "$ENABLED_RSA" = "nonblock"
then
AM_CFLAGS="$AM_CFLAGS -DWC_RSA_NONBLOCK"
ENABLED_RSA=yes
ENABLED_CERTS=yes
# asynccrypt + asynccrypt-sw are auto-enabled earlier in this file when
# --enable-rsa=nonblock is detected, so the TLS layer can pick up the
# per-SSL nb context and yield MP_WOULDBLOCK. RSA_LOW_MEM is left as a
# user choice - the SP non-block backend's compile-time check in
# wolfssl/wolfcrypt/rsa.h enforces it for SP, while the TFM (fastmath)
# backend supports the CRT path without it.
else
# turn off RSA if leanpsk or leantls on
if test "$ENABLED_LEANPSK" = "yes" || test "$ENABLED_LEANTLS" = "yes"
Expand Down Expand Up @@ -5483,7 +5503,7 @@ fi

# DH
AC_ARG_ENABLE([dh],
[AS_HELP_STRING([--enable-dh],[Enable DH (default: enabled)])],
[AS_HELP_STRING([--enable-dh],[Enable DH (default: enabled). Set to "nonblock" to enable non-blocking DH key agreement via SP small mod_exp_nb])],
[ ENABLED_DH=$enableval ],
[ ENABLED_DH=yes ]
)
Expand All @@ -5496,6 +5516,11 @@ fi
if test "$ENABLED_DH" = "no"
then
AM_CFLAGS="$AM_CFLAGS -DNO_DH"
elif test "$ENABLED_DH" = "nonblock"
then
AM_CFLAGS="$AM_CFLAGS -DWC_DH_NONBLOCK"
ENABLED_DH=yes
# asynccrypt + asynccrypt-sw are auto-enabled earlier in this file.
else
# turn off DH if leanpsk or leantls on
if test "$ENABLED_LEANPSK" = "yes" || test "$ENABLED_LEANTLS" = "yes"
Expand Down
66 changes: 66 additions & 0 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -8300,6 +8300,15 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey)
switch (type) {
#ifndef NO_RSA
case DYNAMIC_TYPE_RSA:
#if defined(WC_RSA_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_RSA)
if (((RsaKey*)*pKey)->nb != NULL) {
XFREE(((RsaKey*)*pKey)->nb, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
((RsaKey*)*pKey)->nb = NULL;
}
#endif /* WC_RSA_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_RSA */
wc_FreeRsaKey((RsaKey*)*pKey);
break;
#endif /* ! NO_RSA */
Expand Down Expand Up @@ -8355,6 +8364,15 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey)
#endif /* HAVE_DILITHIUM */
#ifndef NO_DH
case DYNAMIC_TYPE_DH:
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
if (((DhKey*)*pKey)->nb != NULL) {
XFREE(((DhKey*)*pKey)->nb, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
((DhKey*)*pKey)->nb = NULL;
}
#endif /* WC_DH_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_DH */
wc_FreeDhKey((DhKey*)*pKey);
break;
#endif /* !NO_DH */
Expand Down Expand Up @@ -8385,6 +8403,14 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW)
x25519_nb_ctx_t* x25519NbCtx;
#endif /* WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW */
#if !defined(NO_RSA) && defined(WC_RSA_NONBLOCK) && \
defined(WOLFSSL_ASYNC_CRYPT_SW) && defined(WC_ASYNC_ENABLE_RSA)
RsaNb* rsaNb;
#endif
#if !defined(NO_DH) && defined(WC_DH_NONBLOCK) && \
defined(WOLFSSL_ASYNC_CRYPT_SW) && defined(WC_ASYNC_ENABLE_DH)
DhNb* dhNb;
#endif

if (ssl == NULL || pKey == NULL) {
return BAD_FUNC_ARG;
Expand Down Expand Up @@ -8464,6 +8490,26 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
#ifndef NO_RSA
case DYNAMIC_TYPE_RSA:
ret = wc_InitRsaKey_ex((RsaKey*)*pKey, ssl->heap, ssl->devId);
#if defined(WC_RSA_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_RSA)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on MP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
rsaNb = (RsaNb*)XMALLOC(sizeof(RsaNb), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (rsaNb == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_RsaSetNonBlock((RsaKey*)*pKey, rsaNb);
if (ret != 0) {
XFREE(rsaNb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_RSA_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_RSA */
break;
#endif /* ! NO_RSA */
#ifdef HAVE_ECC
Expand Down Expand Up @@ -8551,6 +8597,26 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
#ifndef NO_DH
case DYNAMIC_TYPE_DH:
ret = wc_InitDhKey_ex((DhKey*)*pKey, ssl->heap, ssl->devId);
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on MP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
dhNb = (DhNb*)XMALLOC(sizeof(DhNb), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (dhNb == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_DhSetNonBlock((DhKey*)*pKey, dhNb);
if (ret != 0) {
XFREE(dhNb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_DH_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_DH */
break;
#endif /* !NO_DH */
default:
Expand Down
40 changes: 40 additions & 0 deletions src/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -8010,6 +8010,26 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
ret = wc_DhSetNamedKey(dhKey, kse->group);
#endif
}
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on MP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
DhNb* dhNb = (DhNb*)XMALLOC(sizeof(DhNb), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (dhNb == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_DhSetNonBlock((DhKey*)kse->key, dhNb);
if (ret != 0) {
XFREE(dhNb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_DH_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_DH */
}

/* Allocate space for the private and public key */
Expand Down Expand Up @@ -9297,6 +9317,26 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
ret = wc_DhSetNamedKey(dhKey, keyShareEntry->group);
#endif
}
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on MP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
DhNb* dhNb = (DhNb*)XMALLOC(sizeof(DhNb), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (dhNb == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_DhSetNonBlock((DhKey*)keyShareEntry->key, dhNb);
if (ret != 0) {
XFREE(dhNb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_DH_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_DH */
}

if (ret == 0
Expand Down
58 changes: 58 additions & 0 deletions wolfcrypt/src/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,10 @@ int wc_InitDhKey_ex(DhKey* key, void* heap, int devId)
key->handle = NULL;
#endif

#ifdef WC_DH_NONBLOCK
key->nb = NULL;
#endif

return ret;
}

Expand All @@ -980,6 +984,23 @@ int wc_InitDhKey(DhKey* key)
return wc_InitDhKey_ex(key, NULL, INVALID_DEVID);
}

#ifdef WC_DH_NONBLOCK
int wc_DhSetNonBlock(DhKey* key, DhNb* nb)
{
if (key == NULL)
return BAD_FUNC_ARG;

if (nb != NULL) {
XMEMSET(nb, 0, sizeof(DhNb));
}

/* Pass NULL to disable non-blocking mode. */
key->nb = nb;

return 0;
}
#endif


int wc_FreeDhKey(DhKey* key)
{
Expand Down Expand Up @@ -2043,6 +2064,36 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
return DH_CHECK_PUB_E;
}

#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_HAVE_SP_DH) && \
defined(WOLFSSL_SP_NONBLOCK) && defined(WOLFSSL_SP_SMALL) && \
!defined(WOLFSSL_SP_FAST_MODEXP)
/* Non-blocking dispatch bypasses the mp_int dance entirely - the SP
* wrapper takes byte buffers and persists across yields. The constant-
* time fold-back (ct branch) is intentionally not applied here; nb
* callers should use the standard wc_DhAgree(). */
if (key->nb != NULL && !ct) {
#ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(&key->p) == 2048) {
return sp_DhExp_2048_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
}
#endif
#ifndef WOLFSSL_SP_NO_3072
if (mp_count_bits(&key->p) == 3072) {
return sp_DhExp_3072_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
}
#endif
#ifdef WOLFSSL_SP_4096
if (mp_count_bits(&key->p) == 4096) {
return sp_DhExp_4096_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
}
#endif
/* size not nb-supported - fall through to blocking path */
}
#endif

#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (y == NULL)
Expand Down Expand Up @@ -2304,13 +2355,20 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
ret = KcapiDh_SharedSecret(key, otherPub, pubSz, agree, agreeSz);
#else
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_DH)
/* Async marker takes precedence: when wc_AsyncSimulate re-enters the
* compute path, wc_DhAgree_Async dispatches to the SP nonblock wrapper
* if key->nb is attached, and per-yield MP_WOULDBLOCK is translated to
* WC_PENDING_E by wc_AsyncSimulate so the TLS event loop drives it. */
Comment on lines +2358 to +2361
if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_DH) {
ret = wc_DhAgree_Async(key, agree, agreeSz, priv, privSz, otherPub,
pubSz);
}
else
#endif
{
/* wc_DhAgree_Sync handles key->nb internally; no separate dispatch
* needed here. wc_DhAgree_ct (constant-time fold-back) bypasses
* this function entirely so passing ct=0 is correct. */
ret = wc_DhAgree_Sync(key, agree, agreeSz, priv, privSz, otherPub,
pubSz, 0);
}
Expand Down
Loading
Loading