Merge pull request #9721 from dgarske/x25519_nb

Add X25519 non-blocking support and async example improvements
This commit is contained in:
Sean Parkinson
2026-02-12 07:56:58 +10:00
committed by GitHub
39 changed files with 2727 additions and 564 deletions
+51 -15
View File
@@ -6117,7 +6117,7 @@ static int X25519SharedSecret(WOLFSSL* ssl, curve25519_key* priv_key,
#ifdef WOLFSSL_ASYNC_CRYPT
/* initialize event */
ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN);
ret = wolfSSL_AsyncInit(ssl, &priv_key->asyncDev, WC_ASYNC_FLAG_NONE);
if (ret != 0)
return ret;
#endif
@@ -8189,6 +8189,13 @@ void FreeKey(WOLFSSL* ssl, int type, void** pKey)
#endif /* HAVE_ED25519 */
#ifdef HAVE_CURVE25519
case DYNAMIC_TYPE_CURVE25519:
#if defined(WC_X25519_NONBLOCK) && \
defined(WOLFSSL_ASYNC_CRYPT_SW)
if (((curve25519_key*)*pKey)->nb_ctx != NULL) {
XFREE(((curve25519_key*)*pKey)->nb_ctx, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_curve25519_free((curve25519_key*)*pKey);
break;
#endif /* HAVE_CURVE25519 */
@@ -8236,8 +8243,14 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
#endif /* HAVE_ECC */
#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
ecc_nb_ctx_t* nbCtx;
#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && WC_ASYNC_ENABLE_ECC*/
ecc_nb_ctx_t* eccNbCtx;
#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW && WC_ASYNC_ENABLE_ECC */
#ifdef HAVE_CURVE25519
curve25519_key* x25519Key;
#endif /* HAVE_CURVE25519 */
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW)
x25519_nb_ctx_t* x25519NbCtx;
#endif /* WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW */
if (ssl == NULL || pKey == NULL) {
return BAD_FUNC_ARG;
@@ -8323,23 +8336,26 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
case DYNAMIC_TYPE_ECC:
eccKey = (ecc_key*)*pKey;
ret = wc_ecc_init_ex(eccKey, ssl->heap, ssl->devId);
if (ret == 0) {
#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
nbCtx = (ecc_nb_ctx_t*)XMALLOC(sizeof(ecc_nb_ctx_t),
eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (nbCtx == NULL) {
#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on FP_WOULDBLOCK, so
* let the WC_ECC_NONBLOCK_ONLY blocking fallback handle it instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
eccNbCtx = (ecc_nb_ctx_t*)XMALLOC(sizeof(ecc_nb_ctx_t),
eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (eccNbCtx == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_ecc_set_nonblock(eccKey, nbCtx);
ret = wc_ecc_set_nonblock(eccKey, eccNbCtx);
if (ret != 0) {
XFREE(nbCtx, eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(eccNbCtx, eccKey->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_ECC */
}
#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_ECC */
break;
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
@@ -8350,8 +8366,28 @@ int AllocKey(WOLFSSL* ssl, int type, void** pKey)
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_CURVE25519
case DYNAMIC_TYPE_CURVE25519:
wc_curve25519_init_ex((curve25519_key*)*pKey, ssl->heap, ssl->devId);
ret = 0;
x25519Key = (curve25519_key*)*pKey;
ret = wc_curve25519_init_ex(x25519Key, ssl->heap, ssl->devId);
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_X25519)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on FP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
x25519NbCtx = (x25519_nb_ctx_t*)XMALLOC(sizeof(x25519_nb_ctx_t),
ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (x25519NbCtx == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_curve25519_set_nonblock(x25519Key, x25519NbCtx);
if (ret != 0) {
XFREE(x25519NbCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_X25519 */
break;
#endif /* HAVE_CURVE25519 */
#ifdef HAVE_ED448
+5
View File
@@ -31,6 +31,7 @@
#include <wolfssl/internal.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/coding.h>
#include <wolfssl/wolfcrypt/kdf.h>
#ifdef NO_INLINE
@@ -3904,6 +3905,10 @@ int wolfSSL_get_error(WOLFSSL* ssl, int ret)
return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */
else if (ssl->error == WC_NO_ERR_TRACE(SOCKET_PEER_CLOSED_E))
return WOLFSSL_ERROR_SYSCALL; /* convert to OpenSSL type */
#endif
#ifdef WOLFSSL_ASYNC_CRYPT
else if (ssl->error == WC_NO_ERR_TRACE(MP_WOULDBLOCK))
return WC_PENDING_E; /* map non-blocking crypto */
#endif
return ssl->error;
}
+178 -44
View File
@@ -8002,18 +8002,54 @@ static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse)
/* Make an Curve25519 key. */
ret = wc_curve25519_init_ex((curve25519_key*)kse->key, ssl->heap,
INVALID_DEVID);
ssl->devId);
if (ret == 0) {
/* setting "key" means okay to call wc_curve25519_free */
key = (curve25519_key*)kse->key;
kse->keyLen = CURVE25519_KEYSIZE;
}
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_X25519)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on FP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
x25519_nb_ctx_t* nb_ctx = (x25519_nb_ctx_t*)XMALLOC(
sizeof(x25519_nb_ctx_t), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (nb_ctx == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_curve25519_set_nonblock(key, nb_ctx);
if (ret != 0) {
XFREE(nb_ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_X25519_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_X25519 */
if (ret == 0) {
#ifdef WOLFSSL_STATIC_EPHEMERAL
ret = wolfSSL_StaticEphemeralKeyLoad(ssl, WC_PK_TYPE_CURVE25519, kse->key);
if (ret != 0)
if (ret != 0) /* on failure, fallback to local key generation */
#endif
{
#ifdef WOLFSSL_ASYNC_CRYPT
/* initialize event */
ret = wolfSSL_AsyncInit(ssl, &key->asyncDev,
WC_ASYNC_FLAG_NONE);
if (ret != 0)
return ret;
#endif
ret = wc_curve25519_make_key(ssl->rng, CURVE25519_KEYSIZE, key);
/* Handle async pending response */
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
return wolfSSL_AsyncPush(ssl, &key->asyncDev);
}
#endif /* WOLFSSL_ASYNC_CRYPT */
}
}
}
@@ -8050,8 +8086,14 @@ static int TLSX_KeyShare_GenX25519Key(WOLFSSL *ssl, KeyShareEntry* kse)
/* Data owned by key share entry otherwise. */
XFREE(kse->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
kse->pubKey = NULL;
if (key != NULL)
if (key != NULL) {
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW)
if (key->nb_ctx != NULL) {
XFREE(key->nb_ctx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_curve25519_free(key);
}
XFREE(kse->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
kse->key = NULL;
}
@@ -8237,6 +8279,28 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
/* Initialize an ECC key struct for the ephemeral key */
ret = wc_ecc_init_ex((ecc_key*)kse->key, ssl->heap, ssl->devId);
#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
/* Only set non-blocking context when async device is active. With
* INVALID_DEVID there is no async loop to retry on FP_WOULDBLOCK, so
* skip non-blocking setup and use blocking mode instead. */
if (ret == 0 && ssl->devId != INVALID_DEVID) {
ecc_nb_ctx_t* eccNbCtx = (ecc_nb_ctx_t*)XMALLOC(
sizeof(ecc_nb_ctx_t), ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
if (eccNbCtx == NULL) {
ret = MEMORY_E;
}
else {
ret = wc_ecc_set_nonblock((ecc_key*)kse->key, eccNbCtx);
if (ret != 0) {
XFREE(eccNbCtx, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
}
}
}
#endif /* WC_ECC_NONBLOCK && WOLFSSL_ASYNC_CRYPT_SW &&
WC_ASYNC_ENABLE_ECC */
if (ret == 0) {
kse->keyLen = keySize;
kse->pubKeyLen = keySize * 2 + 1;
@@ -8808,6 +8872,13 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
}
else if (current->group == WOLFSSL_ECC_X25519) {
#ifdef HAVE_CURVE25519
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW)
if (current->key != NULL &&
((curve25519_key*)current->key)->nb_ctx != NULL) {
XFREE(((curve25519_key*)current->key)->nb_ctx, heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_curve25519_free((curve25519_key*)current->key);
#endif
}
@@ -8851,6 +8922,15 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
}
else {
#ifdef HAVE_ECC
#if defined(WC_ECC_NONBLOCK) && \
defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
if (current->key != NULL &&
((ecc_key*)current->key)->nb_ctx != NULL) {
XFREE(((ecc_key*)current->key)->nb_ctx, heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_ecc_free((ecc_key*)current->key);
#endif
}
@@ -8858,6 +8938,14 @@ static void TLSX_KeyShare_FreeAll(KeyShareEntry* list, void* heap)
#endif
else {
#ifdef HAVE_ECC
#if defined(WC_ECC_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW) && \
defined(WC_ASYNC_ENABLE_ECC)
if (current->key != NULL &&
((ecc_key*)current->key)->nb_ctx != NULL) {
XFREE(((ecc_key*)current->key)->nb_ctx, heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_ecc_free((ecc_key*)current->key);
#endif
}
@@ -9101,67 +9189,113 @@ static int TLSX_KeyShare_ProcessX25519_ex(WOLFSSL* ssl,
unsigned char* ssOutput,
word32* ssOutSz)
{
int ret;
int ret = 0;
#ifdef HAVE_CURVE25519
curve25519_key* key = (curve25519_key*)keyShareEntry->key;
curve25519_key* peerX25519Key;
#ifdef HAVE_ECC
if (ssl->peerEccKey != NULL) {
wc_ecc_free(ssl->peerEccKey);
ssl->peerEccKey = NULL;
ssl->peerEccKeyPresent = 0;
}
#ifdef WOLFSSL_ASYNC_CRYPT
if (keyShareEntry->lastRet == 0) /* don't enter here if WC_PENDING_E */
#endif
{
#ifdef HAVE_ECC
if (ssl->peerEccKey != NULL) {
wc_ecc_free(ssl->peerEccKey);
ssl->peerEccKey = NULL;
ssl->peerEccKeyPresent = 0;
}
#endif
peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key), ssl->heap,
DYNAMIC_TYPE_TLSX);
if (peerX25519Key == NULL) {
WOLFSSL_MSG("PeerEccKey Memory error");
return MEMORY_ERROR;
}
ret = wc_curve25519_init(peerX25519Key);
if (ret != 0) {
XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
return ret;
}
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Peer Curve25519 Key");
WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
#endif
ssl->peerX25519Key = (curve25519_key*)XMALLOC(sizeof(curve25519_key),
ssl->heap, DYNAMIC_TYPE_TLSX);
if (ssl->peerX25519Key == NULL) {
WOLFSSL_MSG("PeerX25519Key Memory error");
return MEMORY_ERROR;
}
ret = wc_curve25519_init(ssl->peerX25519Key);
if (ret != 0) {
XFREE(ssl->peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
ssl->peerX25519Key = NULL;
return ret;
}
#ifdef WOLFSSL_DEBUG_TLS
WOLFSSL_MSG("Peer Curve25519 Key");
WOLFSSL_BUFFER(keyShareEntry->ke, keyShareEntry->keLen);
#endif
if (wc_curve25519_check_public(keyShareEntry->ke, keyShareEntry->keLen,
if (wc_curve25519_check_public(keyShareEntry->ke, keyShareEntry->keLen,
EC25519_LITTLE_ENDIAN) != 0) {
ret = ECC_PEERKEY_ERROR;
WOLFSSL_ERROR_VERBOSE(ret);
}
if (ret == 0) {
if (wc_curve25519_import_public_ex(keyShareEntry->ke,
keyShareEntry->keLen, peerX25519Key,
EC25519_LITTLE_ENDIAN) != 0) {
ret = ECC_PEERKEY_ERROR;
WOLFSSL_ERROR_VERBOSE(ret);
}
if (ret == 0) {
if (wc_curve25519_import_public_ex(keyShareEntry->ke,
keyShareEntry->keLen,
ssl->peerX25519Key,
EC25519_LITTLE_ENDIAN) != 0) {
ret = ECC_PEERKEY_ERROR;
WOLFSSL_ERROR_VERBOSE(ret);
}
}
if (ret == 0) {
ssl->ecdhCurveOID = ECC_X25519_OID;
ssl->peerX25519KeyPresent = 1;
}
}
if (ret == 0 && key == NULL)
ret = BAD_FUNC_ARG;
if (ret == 0) {
ssl->ecdhCurveOID = ECC_X25519_OID;
#ifdef WOLFSSL_CURVE25519_BLINDING
ret = wc_curve25519_set_rng(key, ssl->rng);
}
if (ret == 0) {
#endif
ret = wc_curve25519_shared_secret_ex(key, peerX25519Key,
ssOutput, ssOutSz, EC25519_LITTLE_ENDIAN);
#ifdef WOLFSSL_ASYNC_CRYPT
if (keyShareEntry->lastRet != WC_NO_ERR_TRACE(WC_PENDING_E))
#endif
{
#ifdef WOLFSSL_ASYNC_CRYPT
/* initialize event */
ret = wolfSSL_AsyncInit(ssl, &key->asyncDev,
WC_ASYNC_FLAG_CALL_AGAIN);
if (ret != 0)
return ret;
#endif
ret = wc_curve25519_shared_secret_ex(key, ssl->peerX25519Key,
ssOutput, ssOutSz, EC25519_LITTLE_ENDIAN);
#ifdef WOLFSSL_ASYNC_CRYPT
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
return wolfSSL_AsyncPush(ssl, &key->asyncDev);
}
#endif
}
/* On CALL_AGAIN re-entry (lastRet == PENDING): the block above
* is skipped entirely, so wc_curve25519_shared_secret_ex is not
* called again. ret stays 0 from initialization, and execution
* falls through to the cleanup code below. */
}
wc_curve25519_free(peerX25519Key);
XFREE(peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
wc_curve25519_free((curve25519_key*)keyShareEntry->key);
XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
keyShareEntry->key = NULL;
/* done with key share, release resources */
if (ssl->peerX25519Key != NULL) {
wc_curve25519_free(ssl->peerX25519Key);
XFREE(ssl->peerX25519Key, ssl->heap, DYNAMIC_TYPE_TLSX);
ssl->peerX25519Key = NULL;
ssl->peerX25519KeyPresent = 0;
}
if (keyShareEntry->key != NULL) {
#if defined(WC_X25519_NONBLOCK) && defined(WOLFSSL_ASYNC_CRYPT_SW)
if (((curve25519_key*)keyShareEntry->key)->nb_ctx != NULL) {
XFREE(((curve25519_key*)keyShareEntry->key)->nb_ctx, ssl->heap,
DYNAMIC_TYPE_TMP_BUFFER);
}
#endif
wc_curve25519_free((curve25519_key*)keyShareEntry->key);
XFREE(keyShareEntry->key, ssl->heap, DYNAMIC_TYPE_PRIVATE_KEY);
keyShareEntry->key = NULL;
}
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
keyShareEntry->ke = NULL;
#else