Merge pull request #10394 from dgarske/sp_nonblock_rsa_dh

Add RSA/DH SP non-blocking support for C/Small 2048/3072/4096
This commit is contained in:
Sean Parkinson
2026-05-12 13:25:43 +10:00
committed by GitHub
14 changed files with 4417 additions and 26 deletions
+8 -1
View File
@@ -107,7 +107,14 @@ jobs:
'CPPFLAGS=-DNO_WOLFSSL_SERVER',
'--enable-lms=small,verify-only --enable-xmss=small,verify-only',
'--enable-opensslall --enable-ecc CPPFLAGS="-DWC_ALLOW_ECC_ZERO_HASH"',
'--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"',
# Minimal DTLS 1.3 client-only build. The SHA-224/384/512/3
# disables are deliberately omitted: --disable-sha384 alone
-1
View File
@@ -673,7 +673,6 @@ WC_PROTECT_ENCRYPTED_MEM
WC_PUF_SHA3
WC_RNG_BANK_NO_DEFAULT_SUPPORT
WC_RNG_BLOCKING
WC_RSA_NONBLOCK
WC_RSA_NONBLOCK_TIME
WC_RSA_NO_FERMAT_CHECK
WC_RWLOCK_OPS_INLINE
+27 -2
View File
@@ -5009,6 +5009,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
@@ -5525,7 +5534,7 @@ 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 ]
)
@@ -5533,6 +5542,17 @@ AC_ARG_ENABLE([rsa],
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"
@@ -5612,7 +5632,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 ]
)
@@ -5625,6 +5645,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"
+66
View File
@@ -8305,6 +8305,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 */
@@ -8360,6 +8369,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 */
@@ -8390,6 +8408,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;
@@ -8469,6 +8495,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
@@ -8556,6 +8602,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:
+67 -2
View File
@@ -8021,6 +8021,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 */
@@ -8096,8 +8116,16 @@ static int TLSX_KeyShare_GenDhKey(WOLFSSL *ssl, KeyShareEntry* kse)
/* Always release the DH key to free up memory.
* The DhKey will be setup again in TLSX_KeyShare_ProcessDh */
if (dhKey != NULL)
if (dhKey != NULL) {
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
if (dhKey->nb != NULL) {
XFREE(dhKey->nb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
dhKey->nb = NULL;
}
#endif
wc_FreeDhKey(dhKey);
}
XFREE(kse->key, ssl->heap, DYNAMIC_TYPE_DH);
kse->key = NULL;
@@ -9062,6 +9090,15 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
list = current->next;
if (WOLFSSL_NAMED_GROUP_IS_FFDHE(current->group)) {
#ifndef NO_DH
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
if (current->key != NULL &&
((DhKey*)current->key)->nb != NULL) {
XFREE(((DhKey*)current->key)->nb, heap,
DYNAMIC_TYPE_TMP_BUFFER);
((DhKey*)current->key)->nb = NULL;
}
#endif
wc_FreeDhKey((DhKey*)current->key);
if (current->privKey != NULL && current->privKeyLen > 0) {
ForceZero(current->privKey, current->privKeyLen);
@@ -9321,6 +9358,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
@@ -9361,8 +9418,16 @@ static int TLSX_KeyShare_ProcessDh(WOLFSSL* ssl, KeyShareEntry* keyShareEntry)
}
/* done with key share, release resources */
if (dhKey)
if (dhKey) {
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_DH)
if (dhKey->nb != NULL) {
XFREE(dhKey->nb, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
dhKey->nb = NULL;
}
#endif
wc_FreeDhKey(dhKey);
}
XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_DH);
keyShareEntry->key = NULL;
if (keyShareEntry->privKey) {
+100 -9
View File
@@ -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;
}
@@ -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)
{
@@ -2030,19 +2051,81 @@ static int wc_DhAgree_Sync(DhKey* key, byte* agree, word32* agreeSz,
if (mp_iseven(&key->p) == MP_YES) {
return MP_VAL;
}
/* Non-blocking re-entry: the same wc_DhAgree call repeats until the
* SP state machine completes, so cache the per-op key validation
* results instead of re-running them each yield. The cache is
* scoped to non-blocking, non-const-time callers only. */
#ifdef WC_DH_NONBLOCK
if (key->nb == NULL || ct || !key->nb->pubKeyValidated)
#endif
{
#ifdef WOLFSSL_VALIDATE_FFC_IMPORT
if (wc_DhCheckPrivKey(key, priv, privSz) != 0) {
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPrivKey failed");
return DH_CHECK_PRIV_E;
if (wc_DhCheckPrivKey(key, priv, privSz) != 0) {
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPrivKey failed");
return DH_CHECK_PRIV_E;
}
#endif
/* Always validate peer public key (2 <= y <= p-2) per SP 800-56A */
if (wc_DhCheckPubKey(key, otherPub, pubSz) != 0) {
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPubKey failed");
return DH_CHECK_PUB_E;
}
#ifdef WC_DH_NONBLOCK
if (key->nb != NULL && !ct) {
key->nb->pubKeyValidated = 1;
}
#endif
}
#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) {
int nb_ret = MP_OKAY;
int dispatched = 0;
#ifndef WOLFSSL_SP_NO_2048
if (mp_count_bits(&key->p) == 2048) {
nb_ret = sp_DhExp_2048_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
dispatched = 1;
}
#endif
#ifndef WOLFSSL_SP_NO_3072
if (!dispatched && mp_count_bits(&key->p) == 3072) {
nb_ret = sp_DhExp_3072_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
dispatched = 1;
}
#endif
#ifdef WOLFSSL_SP_4096
if (!dispatched && mp_count_bits(&key->p) == 4096) {
nb_ret = sp_DhExp_4096_nb(&key->nb->sp_ctx, otherPub, pubSz,
priv, privSz, &key->p, agree, agreeSz);
dispatched = 1;
}
#endif
if (dispatched) {
/* Op finished (or hit a hard error) - clear the cached
* validation so the next op on this DhNb re-runs the
* SP 800-56A peer-key check. MP_WOULDBLOCK keeps it. */
if (nb_ret != WC_NO_ERR_TRACE(MP_WOULDBLOCK)) {
key->nb->pubKeyValidated = 0;
}
return nb_ret;
}
/* size not nb-supported - the blocking path below completes in
* one call, so the cached validation is single-use. Clear it
* here so the next agree on this DhNb re-validates. */
key->nb->pubKeyValidated = 0;
/* fall through to blocking path */
}
#endif
/* Always validate peer public key (2 <= y <= p-2) per SP 800-56A */
if (wc_DhCheckPubKey(key, otherPub, pubSz) != 0) {
WOLFSSL_MSG("wc_DhAgree wc_DhCheckPubKey failed");
return DH_CHECK_PUB_E;
}
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
y = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_DH);
if (y == NULL)
@@ -2304,6 +2387,11 @@ 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 wolfAsync_DoSw (wolfcrypt/src/
* async.c) re-enters the compute path, wc_DhAgree_Async dispatches
* to the SP nonblock wrapper if key->nb is attached, and per-yield
* FP_WOULDBLOCK (alias of MP_WOULDBLOCK) is translated to
* WC_PENDING_E by wolfAsync_DoSw so the TLS event loop drives it. */
if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_DH) {
ret = wc_DhAgree_Async(key, agree, agreeSz, priv, privSz, otherPub,
pubSz);
@@ -2311,6 +2399,9 @@ int wc_DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv,
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);
}
+91 -2
View File
@@ -2289,12 +2289,69 @@ static int wc_RsaFunctionNonBlock(const byte* in, word32 inLen, byte* out,
word32* outLen, int type, RsaKey* key)
{
int ret = 0;
#ifdef USE_FAST_MATH
word32 keyLen, len;
#endif
/* SP non-blocking RSA wrappers depend on sp_<N>_mod_exp_<W>_nb,
* which the SP generator only emits when (!RSA_PUBLIC_ONLY ||
* HAVE_SP_DH). Match that gate here so the dispatch is omitted when
* those symbols are not available. */
#if defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_SP_NONBLOCK) && \
defined(WOLFSSL_SP_SMALL) && !defined(WOLFSSL_SP_FAST_MODEXP) && \
(!defined(WOLFSSL_RSA_PUBLIC_ONLY) || defined(WOLFSSL_HAVE_SP_DH))
int bits;
#endif
if (key == NULL || key->nb == NULL) {
return BAD_FUNC_ARG;
}
#if defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_SP_NONBLOCK) && \
defined(WOLFSSL_SP_SMALL) && !defined(WOLFSSL_SP_FAST_MODEXP) && \
(!defined(WOLFSSL_RSA_PUBLIC_ONLY) || defined(WOLFSSL_HAVE_SP_DH))
bits = mp_count_bits(&key->n);
#ifndef WOLFSSL_SP_NO_2048
if (bits == 2048) {
if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
return sp_RsaPublic_2048_nb(&key->nb->sp_ctx, in, inLen,
&key->e, &key->n, out, outLen);
}
#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \
(defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM))
return sp_RsaPrivate_2048_nb(&key->nb->sp_ctx, in, inLen,
&key->d, &key->n, out, outLen);
#endif
}
#endif
#ifndef WOLFSSL_SP_NO_3072
if (bits == 3072) {
if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
return sp_RsaPublic_3072_nb(&key->nb->sp_ctx, in, inLen,
&key->e, &key->n, out, outLen);
}
#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \
(defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM))
return sp_RsaPrivate_3072_nb(&key->nb->sp_ctx, in, inLen,
&key->d, &key->n, out, outLen);
#endif
}
#endif
#ifdef WOLFSSL_SP_4096
if (bits == 4096) {
if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
return sp_RsaPublic_4096_nb(&key->nb->sp_ctx, in, inLen,
&key->e, &key->n, out, outLen);
}
#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \
(defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM))
return sp_RsaPrivate_4096_nb(&key->nb->sp_ctx, in, inLen,
&key->d, &key->n, out, outLen);
#endif
}
#endif
#endif /* SP nonblock RSA */
#ifdef USE_FAST_MATH
if (key->nb->exptmod.state == TFM_EXPTMOD_NB_INIT) {
if (mp_init(&key->nb->tmp) != MP_OKAY) {
ret = MP_INIT_E;
@@ -2358,6 +2415,18 @@ static int wc_RsaFunctionNonBlock(const byte* in, word32 inLen, byte* out,
}
mp_clear(&key->nb->tmp);
#else
/* No non-blocking backend available for this build. The SP non-block
* dispatch above only matches enabled key sizes; if we reach this
* point the key is not 2048/3072/4096 (or SP RSA itself isn't built)
* and TFM fastmath isn't compiled in either. */
(void)in;
(void)inLen;
(void)out;
(void)outLen;
(void)type;
ret = NOT_COMPILED_IN;
#endif /* USE_FAST_MATH */
return ret;
}
@@ -3153,6 +3222,18 @@ static int wc_RsaFunctionAsync(const byte* in, word32 inLen, byte* out,
}
#endif /* WOLFSSL_ASYNC_CRYPT_SW */
#ifdef WC_RSA_NONBLOCK
/* When a non-blocking context is attached and the SP nonblock backend
* is available, drive the chunked state machine here. wolfAsync_DoSw
* (line "if (ret == FP_WOULDBLOCK) ret = WC_PENDING_E;" at the bottom
* of the SW switch in wolfcrypt/src/async.c, FP_WOULDBLOCK aliases
* MP_WOULDBLOCK) translates per-yield MP_WOULDBLOCK into WC_PENDING_E
* so the TLS / async event loop can drive the operation to completion. */
if (key->nb != NULL) {
return wc_RsaFunctionNonBlock(in, inLen, out, outLen, type, key);
}
#endif
switch (type) {
#ifndef WOLFSSL_RSA_PUBLIC_ONLY
case RSA_PRIVATE_DECRYPT:
@@ -3518,12 +3599,20 @@ static int wc_RsaFunction_ex(const byte* in, word32 inLen, byte* out,
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
key->n.raw.len > 0) {
/* wc_RsaFunctionAsync dispatches to the SP nonblock state machine
* in its compute path when key->nb is attached - wolfAsync_DoSw
* (in wolfcrypt/src/async.c) translates per-yield FP_WOULDBLOCK
* (alias of MP_WOULDBLOCK) into WC_PENDING_E so the TLS / async
* event loop can drive completion. */
ret = wc_RsaFunctionAsync(in, inLen, out, outLen, type, key, rng);
}
else
#endif
#ifdef WC_RSA_NONBLOCK
if (key->nb) {
/* Direct (non-async) nonblock dispatch - the caller (e.g. wolfcrypt
* test) drives the loop on MP_WOULDBLOCK directly. Reached when no
* async marker is set on the key. */
ret = wc_RsaFunctionNonBlock(in, inLen, out, outLen, type, key);
}
else
@@ -5766,7 +5855,7 @@ int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb)
return 0;
}
#ifdef WC_RSA_NONBLOCK_TIME
#if defined(WC_RSA_NONBLOCK_TIME) && defined(USE_FAST_MATH)
int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs, word32 cpuMHz)
{
if (key == NULL || key->nb == NULL) {
@@ -5778,7 +5867,7 @@ int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs, word32 cpuMHz)
return 0;
}
#endif /* WC_RSA_NONBLOCK_TIME */
#endif /* WC_RSA_NONBLOCK_TIME && USE_FAST_MATH */
#endif /* WC_RSA_NONBLOCK */
#ifndef WOLFSSL_RSA_PUBLIC_ONLY
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+56 -2
View File
@@ -24363,8 +24363,10 @@ static wc_test_ret_t rsa_nb_test(RsaKey* key, const byte* in, word32 inLen, byte
if (ret != 0)
return ret;
#ifdef WC_RSA_NONBLOCK_TIME
/* Enable time based RSA blocking. 8 microseconds max (3.1GHz) */
#if defined(WC_RSA_NONBLOCK_TIME) && defined(USE_FAST_MATH)
/* Enable time based RSA blocking. 8 microseconds max (3.1GHz).
* Only available with USE_FAST_MATH; SP-only WC_RSA_NONBLOCK
* builds do not expose this entry point. */
ret = wc_RsaSetNonBlockTime(key, 8, 3100);
if (ret != 0)
return ret;
@@ -27806,6 +27808,14 @@ static wc_test_ret_t dh_ffdhe_test(WC_RNG *rng, int name)
#endif
word32 agreeSz = MAX_DH_KEY_SZ;
word32 agreeSz2 = MAX_DH_KEY_SZ;
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_HAVE_SP_DH) && \
defined(WOLFSSL_SP_NONBLOCK) && defined(WOLFSSL_SP_SMALL) && \
!defined(WOLFSSL_SP_FAST_MODEXP)
DhNb dhNb;
word32 nbAgreeSz;
int nbCount;
wc_test_ret_t nb_ret;
#endif
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
if ((priv == NULL) ||
@@ -27892,6 +27902,50 @@ static wc_test_ret_t dh_ffdhe_test(WC_RNG *rng, int name)
ERROR_OUT(WC_TEST_RET_ENC_NC, done);
}
#if defined(WC_DH_NONBLOCK) && defined(WOLFSSL_HAVE_SP_DH) && \
defined(WOLFSSL_SP_NONBLOCK) && defined(WOLFSSL_SP_SMALL) && \
!defined(WOLFSSL_SP_FAST_MODEXP)
nbAgreeSz = MAX_DH_KEY_SZ;
nbCount = 0;
XMEMSET(agree2, 0, MAX_DH_KEY_SZ);
nb_ret = wc_DhSetNonBlock(key, &dhNb);
if (nb_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(nb_ret), done);
do {
nb_ret = wc_DhAgree(key, agree2, &nbAgreeSz, priv, privSz,
pub2, pubSz2);
nbCount++;
#if defined(WOLFSSL_ASYNC_CRYPT)
/* When async crypt is enabled, the SW shim returns WC_PENDING_E
* on the first call (init phase) and wc_AsyncWait drives the SP
* non-block state machine to completion. wc_AsyncSimulate
* translates each per-yield MP_WOULDBLOCK from sp_DhExp_<size>_nb
* into WC_PENDING_E internally so the wait loop polls until the
* operation finishes. */
if (nb_ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
nb_ret = wc_AsyncWait(nb_ret, &key->asyncDev,
WC_ASYNC_FLAG_NONE);
}
#endif
} while (nb_ret == WC_NO_ERR_TRACE(MP_WOULDBLOCK) ||
nb_ret == WC_NO_ERR_TRACE(WC_PENDING_E));
if (nb_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(nb_ret), done);
#if defined(DEBUG_WOLFSSL) || defined(WOLFSSL_DEBUG_NONBLOCK)
printf("DH non-block agree: %d times\n", nbCount);
#endif
if (nbAgreeSz != agreeSz || XMEMCMP(agree, agree2, agreeSz))
ERROR_OUT(WC_TEST_RET_ENC_NC, done);
nb_ret = wc_DhSetNonBlock(key, NULL);
if (nb_ret != 0)
ERROR_OUT(WC_TEST_RET_ENC_EC(nb_ret), done);
#endif /* WC_DH_NONBLOCK + SP nonblock */
/* wc_DhGeneratePublic_fips() was added in 5.2.3, but some customers are
* building with configure scripts that set version to 5.2.1, but with 5.2.3
* wolfCrypt sources. 5.3.0 is used for both fips-v5-ready and v5-kcapi,
+41
View File
@@ -49,6 +49,23 @@
#include <wolfssl/wolfcrypt/async.h>
#endif
#ifdef WC_DH_NONBLOCK
/* Non-blocking DH currently requires the SP small backend with the
* non-blocking + no-malloc + non-fast-modexp trio. */
#if !defined(WOLFSSL_HAVE_SP_DH) || !defined(WOLFSSL_SP_NONBLOCK)
#error WC_DH_NONBLOCK requires WOLFSSL_HAVE_SP_DH + WOLFSSL_SP_NONBLOCK
#endif
#if !defined(WOLFSSL_SP_SMALL)
#error WC_DH_NONBLOCK requires WOLFSSL_SP_SMALL
#endif
#if !defined(WOLFSSL_SP_NO_MALLOC)
#error WC_DH_NONBLOCK requires WOLFSSL_SP_NO_MALLOC
#endif
#if defined(WOLFSSL_SP_FAST_MODEXP)
#error WC_DH_NONBLOCK is incompatible with WOLFSSL_SP_FAST_MODEXP
#endif
#endif
typedef struct DhParams {
#ifdef HAVE_FFDHE_Q
const byte* q;
@@ -60,6 +77,23 @@ typedef struct DhParams {
word32 g_len;
} DhParams;
#ifdef WC_DH_NONBLOCK
/* Non-blocking DH context. Holds the SP wrapper state across yields.
* Caller allocates one DhNb per active operation and binds it to a key
* via wc_DhSetNonBlock(). Lifetime must outlast the operation. */
typedef struct DhNb {
#if defined(WOLFSSL_HAVE_SP_DH) && defined(WOLFSSL_SP_NONBLOCK) && \
defined(WOLFSSL_SP_SMALL) && !defined(WOLFSSL_SP_FAST_MODEXP)
sp_dh_ctx_t sp_ctx;
#else
int unused;
#endif
/* Set once wc_DhCheckPubKey has succeeded for this op so subsequent
* MP_WOULDBLOCK retries skip re-validating the peer public key. */
byte pubKeyValidated;
} DhNb;
#endif
/* Diffie-Hellman Key */
struct DhKey {
mp_int p, g, q; /* group parameters */
@@ -75,6 +109,9 @@ struct DhKey {
#ifdef WOLFSSL_KCAPI_DH
struct kcapi_handle* handle;
#endif
#ifdef WC_DH_NONBLOCK
DhNb* nb; /* non-blocking context, NULL when not in non-block mode */
#endif
};
#ifndef WC_DH_TYPE_DEFINED
@@ -162,6 +199,10 @@ WOLFSSL_API int wc_DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g
WOLFSSL_API int wc_DhSetKey_ex(DhKey* key, const byte* p, word32 pSz,
const byte* g, word32 gSz, const byte* q, word32 qSz);
WOLFSSL_API int wc_DhSetNamedKey(DhKey* key, int name);
#ifdef WC_DH_NONBLOCK
WOLFSSL_API int wc_DhSetNonBlock(DhKey* key, DhNb* nb);
#endif
WOLFSSL_API int wc_DhGetNamedKeyParamSize(int name,
word32* p, word32* g, word32* q);
WOLFSSL_API word32 wc_DhGetNamedKeyMinSize(int name);
+38 -7
View File
@@ -44,14 +44,36 @@ RSA keys can be used to encrypt, decrypt, sign and verify data.
#endif
#if defined(WC_RSA_NONBLOCK)
/* enable support for fast math based non-blocking exptmod */
/* this splits the RSA function into many smaller operations */
#ifndef USE_FAST_MATH
#error RSA non-blocking mode only supported using fast math
/* Non-blocking RSA splits the operation into many smaller chunks so a
* bare-metal system loop stays responsive. Two backends are supported:
* - TFM fastmath (fp_exptmod_nb), the original implementation.
* - SP small (sp_RsaPublic_<n>_nb / sp_RsaPrivate_<n>_nb) when SP
* non-blocking is enabled. SP requires RSA_LOW_MEM (CRT not
* supported in non-block mode) and the small / no-malloc /
* non-blocking trio that drives the chunked state machine. */
#if !defined(USE_FAST_MATH) && \
!(defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_SP_NONBLOCK) && \
defined(WOLFSSL_SP_SMALL) && !defined(WOLFSSL_SP_FAST_MODEXP))
#error RSA non-blocking mode requires fast math or SP non-blocking
#endif
#ifndef TFM_TIMING_RESISTANT
#if defined(USE_FAST_MATH) && !defined(TFM_TIMING_RESISTANT)
#error RSA non-blocking mode only supported with timing resistance enabled
#endif
#if defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_SP_NONBLOCK)
#if !defined(WOLFSSL_SP_SMALL)
#error SP non-blocking RSA requires WOLFSSL_SP_SMALL
#endif
#if !defined(WOLFSSL_SP_NO_MALLOC)
#error SP non-blocking RSA requires WOLFSSL_SP_NO_MALLOC
#endif
#if defined(WOLFSSL_SP_FAST_MODEXP)
#error SP non-blocking RSA is incompatible with WOLFSSL_SP_FAST_MODEXP
#endif
#if !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \
!defined(SP_RSA_PRIVATE_EXP_D) && !defined(RSA_LOW_MEM)
#error SP non-blocking RSA requires RSA_LOW_MEM (CRT path is unsupported)
#endif
#endif
/* RSA bounds check is not supported with RSA non-blocking mode */
#undef NO_RSA_BOUNDS_CHECK
@@ -195,8 +217,14 @@ enum {
#ifdef WC_RSA_NONBLOCK
typedef struct RsaNb {
exptModNb_t exptmod; /* non-block expt_mod */
#ifdef USE_FAST_MATH
exptModNb_t exptmod; /* TFM non-block expt_mod state */
mp_int tmp;
#endif
#if defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_SP_NONBLOCK) && \
defined(WOLFSSL_SP_SMALL) && !defined(WOLFSSL_SP_FAST_MODEXP)
sp_rsa_ctx_t sp_ctx; /* SP non-block wrapper state */
#endif
} RsaNb;
#endif
@@ -422,7 +450,10 @@ WOLFSSL_API int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz,
#endif
#ifdef WC_RSA_NONBLOCK
WOLFSSL_API int wc_RsaSetNonBlock(RsaKey* key, RsaNb* nb);
#ifdef WC_RSA_NONBLOCK_TIME
/* maxBlockInst budget lives on the TFM exptModNb_t; only available
* with USE_FAST_MATH. SP-only WC_RSA_NONBLOCK builds do not expose
* this entry point. */
#if defined(WC_RSA_NONBLOCK_TIME) && defined(USE_FAST_MATH)
WOLFSSL_API int wc_RsaSetNonBlockTime(RsaKey* key, word32 maxBlockUs,
word32 cpuMHz);
#endif
+59
View File
@@ -107,6 +107,40 @@ WOLFSSL_LOCAL int sp_RsaPrivate_4096(const byte* in, word32 inLen,
#endif /* HAVE_FIPS_VERSION && HAVE_FIPS_VERSION == 2 && !WOLFSSL_SP_ARM[32|64]_ASM */
#if defined(WOLFSSL_SP_NONBLOCK) && defined(WOLFSSL_SP_SMALL) && \
!defined(WOLFSSL_SP_FAST_MODEXP)
#ifndef WOLFSSL_SP_NO_2048
WOLFSSL_LOCAL int sp_RsaPublic_2048_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* em, const mp_int* mm, byte* out,
word32* outLen);
#if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM)
WOLFSSL_LOCAL int sp_RsaPrivate_2048_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* dm, const mp_int* mm, byte* out,
word32* outLen);
#endif
#endif
#ifndef WOLFSSL_SP_NO_3072
WOLFSSL_LOCAL int sp_RsaPublic_3072_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* em, const mp_int* mm, byte* out,
word32* outLen);
#if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM)
WOLFSSL_LOCAL int sp_RsaPrivate_3072_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* dm, const mp_int* mm, byte* out,
word32* outLen);
#endif
#endif
#ifdef WOLFSSL_SP_4096
WOLFSSL_LOCAL int sp_RsaPublic_4096_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* em, const mp_int* mm, byte* out,
word32* outLen);
#if defined(SP_RSA_PRIVATE_EXP_D) || defined(RSA_LOW_MEM)
WOLFSSL_LOCAL int sp_RsaPrivate_4096_nb(sp_rsa_ctx_t* sp_ctx, const byte* in,
word32 inLen, const mp_int* dm, const mp_int* mm, byte* out,
word32* outLen);
#endif
#endif
#endif /* WOLFSSL_SP_NONBLOCK && WOLFSSL_SP_SMALL && !WOLFSSL_SP_FAST_MODEXP */
#endif /* WOLFSSL_HAVE_SP_RSA */
#if defined(WOLFSSL_HAVE_SP_DH) || defined(WOLFSSL_HAVE_SP_RSA)
@@ -167,6 +201,31 @@ WOLFSSL_LOCAL int sp_DhExp_4096(const mp_int* base, const byte* exp,
#endif /* HAVE_FIPS_VERSION && HAVE_FIPS_VERSION == 2 && !WOLFSSL_SP_ARM[32|64]_ASM */
#if defined(WOLFSSL_SP_NONBLOCK) && defined(WOLFSSL_SP_SMALL) && \
!defined(WOLFSSL_SP_FAST_MODEXP)
#ifndef WOLFSSL_SP_NO_2048
WOLFSSL_LOCAL int sp_DhExp_2048_nb(sp_dh_ctx_t* sp_ctx, const byte* base,
word32 baseSz, const byte* exp, word32 expLen, const mp_int* mod,
byte* out, word32* outLen);
WOLFSSL_LOCAL int sp_ModExp_2048_nb(sp_dh_ctx_t* sp_ctx, const mp_int* base,
const mp_int* exp, const mp_int* mod, mp_int* res);
#endif
#ifndef WOLFSSL_SP_NO_3072
WOLFSSL_LOCAL int sp_DhExp_3072_nb(sp_dh_ctx_t* sp_ctx, const byte* base,
word32 baseSz, const byte* exp, word32 expLen, const mp_int* mod,
byte* out, word32* outLen);
WOLFSSL_LOCAL int sp_ModExp_3072_nb(sp_dh_ctx_t* sp_ctx, const mp_int* base,
const mp_int* exp, const mp_int* mod, mp_int* res);
#endif
#ifdef WOLFSSL_SP_4096
WOLFSSL_LOCAL int sp_DhExp_4096_nb(sp_dh_ctx_t* sp_ctx, const byte* base,
word32 baseSz, const byte* exp, word32 expLen, const mp_int* mod,
byte* out, word32* outLen);
WOLFSSL_LOCAL int sp_ModExp_4096_nb(sp_dh_ctx_t* sp_ctx, const mp_int* base,
const mp_int* exp, const mp_int* mod, mp_int* res);
#endif
#endif /* WOLFSSL_SP_NONBLOCK && WOLFSSL_SP_SMALL && !WOLFSSL_SP_FAST_MODEXP */
#endif /* WOLFSSL_HAVE_SP_DH */
#ifdef WOLFSSL_HAVE_SP_ECC
+39
View File
@@ -401,6 +401,45 @@ typedef struct sp_ecc_ctx {
} sp_ecc_ctx_t;
#endif
#if defined(WOLFSSL_SP_NONBLOCK) && \
(defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH))
/* Non-blocking RSA / DH operation contexts. The wrapper state struct
* embeds the inner modexp ctx (which dominates the size) plus per-op
* buffers for the modulus, base/result, and exponent. Sized for the
* worst-case wrapper across C32/C64 word layouts at the largest
* enabled key size:
* 2048-bit: mod_exp td[3*144]*4 = 1728B + wrapper ~= 2960B
* 3072-bit: mod_exp td[3*216]*4 = 2592B + wrapper ~= 4400B
* 4096-bit: mod_exp td[3*284]*4 = 3408B + wrapper ~= 5760B
* Each tier carries a small safety margin for alignment / future
* generator changes. The compile-time ctx_size_test inside each
* sp_<size>_<op>_<words>_nb function asserts the buffer fits the
* generated wrapper. */
#if defined(WOLFSSL_HAVE_SP_RSA) && !defined(NO_RSA)
typedef struct sp_rsa_ctx {
#ifdef WOLFSSL_SP_4096
XALIGNED(8) byte data[6144];
#elif !defined(WOLFSSL_SP_NO_3072)
XALIGNED(8) byte data[4608];
#else
XALIGNED(8) byte data[3072];
#endif
} sp_rsa_ctx_t;
#endif
#if defined(WOLFSSL_HAVE_SP_DH) && !defined(NO_DH)
typedef struct sp_dh_ctx {
#ifdef WOLFSSL_SP_4096
XALIGNED(8) byte data[6144];
#elif !defined(WOLFSSL_SP_NO_3072)
XALIGNED(8) byte data[4608];
#else
XALIGNED(8) byte data[3072];
#endif
} sp_dh_ctx_t;
#endif
#endif /* WOLFSSL_SP_NONBLOCK && (WOLFSSL_HAVE_SP_RSA || WOLFSSL_HAVE_SP_DH) */
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
#include <wolfssl/wolfcrypt/random.h>