Add crypto callback only mode for ed25519

This commit is contained in:
Paul Adelsbach
2026-07-14 09:08:12 -07:00
parent 6722de5635
commit 5e784db069
7 changed files with 151 additions and 14 deletions
+5 -2
View File
@@ -105,9 +105,12 @@ jobs:
{"name": "aes-gcm-via-ecb",
"comment": "Same as aes but tells swdev to refuse AES-GCM (SWDEV_AES_ONLYECB). That forces the parent's CB_ONLY_AES host-side GCM software path: GHASH runs on the host while AES-CTR blocks dispatch back through cryptocb ECB. The aes entry instead has swdev handle GCM end-to-end, so the host-side GCM path is otherwise uncovered.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_AES -DSWDEV_AES_ONLYECB"]},
{"name": "ed25519",
"comment": "WOLF_CRYPTO_CB_ONLY_ED25519: strips software Ed25519 (keygen/sign/verify); swdev provides the software path via cryptocb. Streaming verify has no callback path and is left disabled.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_ED25519"]},
{"name": "all",
"comment": "All five ONLY_* macros at once: every supported software primitive is stripped and dispatched through cryptocb. Catches any cross-algorithm call that a single-strip entry would still resolve via the remaining software paths.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLF_CRYPTO_CB_ONLY_AES"]}
"comment": "All six ONLY_* macros at once: every supported software primitive is stripped and dispatched through cryptocb. Catches any cross-algorithm call that a single-strip entry would still resolve via the remaining software paths.",
"configure": ["CPPFLAGS=-DWOLF_CRYPTO_CB_ONLY_ECC -DWOLF_CRYPTO_CB_ONLY_RSA -DWOLF_CRYPTO_CB_ONLY_SHA256 -DWOLF_CRYPTO_CB_ONLY_SHA512 -DWOLF_CRYPTO_CB_ONLY_AES -DWOLF_CRYPTO_CB_ONLY_ED25519"]}
]}
EOF
.github/scripts/parallel-make-check.py \
+7 -5
View File
@@ -6,14 +6,16 @@ compiled separately from the main library, linked into the test
programs only, and exposes exactly two C symbols. **It is not a
production component and must not be linked into shipping binaries.**
The four switches it supports are:
The switches it supports are:
| Macro | Strips | Test target |
|--------------------------------|----------------|--------------------|
| `WOLF_CRYPTO_CB_ONLY_RSA` | software RSA | RSA via CryptoCb |
| `WOLF_CRYPTO_CB_ONLY_ECC` | software ECC | ECC via CryptoCb |
| `WOLF_CRYPTO_CB_ONLY_SHA256` | software SHA-256 | SHA-256 via CryptoCb |
| `WOLF_CRYPTO_CB_ONLY_SHA512` | software SHA-512 | SHA-512 via CryptoCb |
| `WOLF_CRYPTO_CB_ONLY_AES` | software AES | AES via CryptoCb |
| `WOLF_CRYPTO_CB_ONLY_ED25519` | software Ed25519 | Ed25519 via CryptoCb |
When a test program calls e.g. `wc_AesCbcEncrypt()` against a libwolfssl
built with `-DWOLF_CRYPTO_CB_ONLY_AES`, the software AES path is gone;
@@ -55,7 +57,7 @@ internal copy of the AES code, and returns the result.
| wc_SwDev_Callback(devId, info, ctx) |
| - swdev_ensure_init() lazy wolfCrypt_Init |
| - switch (info->algo_type): |
| PK -> RSA / ECC software impl |
| PK -> RSA / ECC / Ed25519 software impl |
| HASH -> SHA-256 software impl |
| CIPHER -> AES (CBC/CTR/ECB/GCM/CCM) software impl |
| |
@@ -70,10 +72,10 @@ internal copy of the AES code, and returns the result.
The whole mechanism rests on compiling the wolfcrypt sources twice:
1. **libwolfssl** is built normally with the user's `_ONLY_*` flags
set, so its software RSA/ECC/SHA-256/AES paths are gone.
set, so its software RSA/ECC/SHA-256/SHA-512/AES/Ed25519 paths are gone.
2. **swdev** recompiles the same source set under
`tests/swdev/user_settings.h`, which `#undef`s all four `_ONLY_*`
macros. swdev therefore contains the full software implementations.
`tests/swdev/user_settings.h`, which `#undef`s every `_ONLY_*`
macro. swdev therefore contains the full software implementations.
To prevent symbol collisions when both are linked into the same test
binary, `tests/swdev/Makefile` does the following:
+50 -1
View File
@@ -40,6 +40,9 @@
#ifndef NO_AES
#include <wolfssl/wolfcrypt/aes.h>
#endif
#ifdef HAVE_ED25519
#include <wolfssl/wolfcrypt/ed25519.h>
#endif
static int swdev_initialized = 0;
@@ -238,6 +241,38 @@ static int swdev_ecc_check_pub(wc_CryptoInfo* info)
#endif /* HAVE_ECC_CHECK_KEY */
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
#ifdef HAVE_ED25519_MAKE_KEY
static int swdev_ed25519_keygen(wc_CryptoInfo* info)
{
return wc_ed25519_make_key(info->pk.ed25519kg.rng,
info->pk.ed25519kg.size, info->pk.ed25519kg.key);
}
#endif
#ifdef HAVE_ED25519_SIGN
static int swdev_ed25519_sign(wc_CryptoInfo* info)
{
return wc_ed25519_sign_msg_ex(info->pk.ed25519sign.in,
info->pk.ed25519sign.inLen, info->pk.ed25519sign.out,
info->pk.ed25519sign.outLen, info->pk.ed25519sign.key,
info->pk.ed25519sign.type, info->pk.ed25519sign.context,
info->pk.ed25519sign.contextLen);
}
#endif
#ifdef HAVE_ED25519_VERIFY
static int swdev_ed25519_verify(wc_CryptoInfo* info)
{
return wc_ed25519_verify_msg_ex(info->pk.ed25519verify.sig,
info->pk.ed25519verify.sigLen, info->pk.ed25519verify.msg,
info->pk.ed25519verify.msgLen, info->pk.ed25519verify.res,
info->pk.ed25519verify.key, info->pk.ed25519verify.type,
info->pk.ed25519verify.context, info->pk.ed25519verify.contextLen);
}
#endif
#endif /* HAVE_ED25519 */
#ifndef NO_SHA256
/* Copy hash state between caller's wc_Sha256 and swdev's shadow, leaving
* admin fields (heap, devId, devCtx, W, async, HW ctx) per-side. */
@@ -833,7 +868,7 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info,
return ret;
switch (info->algo_type) {
#if !defined(NO_RSA) || defined(HAVE_ECC)
#if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)
case WC_ALGO_TYPE_PK:
switch (info->pk.type) {
#ifndef NO_RSA
@@ -864,6 +899,20 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info,
return swdev_ecc_check_pub(info);
#endif
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
#ifdef HAVE_ED25519_MAKE_KEY
case WC_PK_TYPE_ED25519_KEYGEN:
return swdev_ed25519_keygen(info);
#endif
#ifdef HAVE_ED25519_SIGN
case WC_PK_TYPE_ED25519_SIGN:
return swdev_ed25519_sign(info);
#endif
#ifdef HAVE_ED25519_VERIFY
case WC_PK_TYPE_ED25519_VERIFY:
return swdev_ed25519_verify(info);
#endif
#endif /* HAVE_ED25519 */
default:
return CRYPTOCB_UNAVAILABLE;
}
+1
View File
@@ -27,6 +27,7 @@
#undef WOLF_CRYPTO_CB_ONLY_SHA256
#undef WOLF_CRYPTO_CB_ONLY_SHA512
#undef WOLF_CRYPTO_CB_ONLY_AES
#undef WOLF_CRYPTO_CB_ONLY_ED25519
#ifndef WOLF_CRYPTO_CB
#error "wc_swdev requires the main build to define WOLF_CRYPTO_CB"
+1
View File
@@ -64,6 +64,7 @@ Crypto Callback Build Options:
* WOLF_CRYPTO_CB_ONLY_SHA256: Use only callbacks for SHA-256 default: off
* WOLF_CRYPTO_CB_ONLY_SHA512: Use only callbacks for SHA-512 default: off
* WOLF_CRYPTO_CB_ONLY_AES: Use only callbacks for AES default: off
* WOLF_CRYPTO_CB_ONLY_ED25519: Use only callbacks for Ed25519 default: off
*/
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
+68 -6
View File
@@ -376,7 +376,10 @@ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key)
key->pubKeySet = 0;
#ifdef WOLF_CRYPTO_CB
if (key->devId != INVALID_DEVID) {
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_Ed25519Gen(rng, keySz, key);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
@@ -384,6 +387,9 @@ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key)
}
#endif
#ifdef WOLF_CRYPTO_CB_ONLY_ED25519
return NO_VALID_DEVID;
#else
ret = wc_RNG_GenerateBlock(rng, key->k, ED25519_KEY_SIZE);
if (ret != 0)
return ret;
@@ -407,6 +413,7 @@ int wc_ed25519_make_key(WC_RNG* rng, int keySz, ed25519_key* key)
#endif
return ret;
#endif /* WOLF_CRYPTO_CB_ONLY_ED25519 */
}
#endif /* HAVE_ED25519_MAKE_KEY */
@@ -434,6 +441,30 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
(void)contextLen;
(void)type;
ret = se050_ed25519_sign_msg(in, inLen, out, outLen, key);
#elif defined(WOLF_CRYPTO_CB_ONLY_ED25519)
ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
if (in == NULL || out == NULL || outLen == NULL || key == NULL ||
(context == NULL && contextLen != 0)) {
return BAD_FUNC_ARG;
}
if ((type == Ed25519ph) &&
(inLen != WC_SHA512_DIGEST_SIZE))
{
return BAD_LENGTH_E;
}
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_Ed25519Sign(in, inLen, out, outLen, key, type,
context, contextLen);
}
if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
ret = NO_VALID_DEVID;
}
#else
#ifdef FREESCALE_LTC_ECC
ALIGN16 byte tempBuf[ED25519_PRV_KEY_SIZE];
@@ -461,7 +492,10 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
}
#ifdef WOLF_CRYPTO_CB
if (key->devId != INVALID_DEVID) {
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_Ed25519Sign(in, inLen, out, outLen, key, type,
context, contextLen);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
@@ -599,7 +633,8 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out,
ForceZero(nonce, sizeof(nonce));
#endif /* WOLFSSL_SE050 */
#ifdef WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN
#if defined(WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN) && \
!defined(WOLF_CRYPTO_CB_ONLY_ED25519)
if (ret == 0) {
int i;
byte c = 0;
@@ -696,7 +731,7 @@ int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out,
#endif /* HAVE_ED25519_SIGN */
#ifdef HAVE_ED25519_VERIFY
#ifndef WOLFSSL_SE050
#if !defined(WOLFSSL_SE050) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)
#ifdef WOLFSSL_CHECK_VER_FAULTS
static const byte sha512_empty[] = {
@@ -928,7 +963,7 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen,
return ret;
}
#endif /* WOLFSSL_SE050 */
#endif /* !WOLFSSL_SE050 && !WOLF_CRYPTO_CB_ONLY_ED25519 */
#if defined(WOLFSSL_ED25519_STREAMING_VERIFY) && !defined(WOLFSSL_SE050)
@@ -972,6 +1007,30 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg,
(void)contextLen;
(void)ed25519Ctx;
ret = se050_ed25519_verify_msg(sig, sigLen, msg, msgLen, key, res);
#elif defined(WOLF_CRYPTO_CB_ONLY_ED25519)
(void)ed25519Ctx;
ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
if (sig == NULL || msg == NULL || res == NULL || key == NULL ||
(context == NULL && contextLen != 0))
return BAD_FUNC_ARG;
if ((type == Ed25519ph) &&
(msgLen != WC_SHA512_DIGEST_SIZE))
{
return BAD_LENGTH_E;
}
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_Ed25519Verify(sig, sigLen, msg, msgLen, res, key,
type, context, contextLen);
}
if (ret == WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
ret = NO_VALID_DEVID;
}
#else
#ifdef WOLFSSL_ED25519_PERSISTENT_SHA
wc_Sha512 *sha;
@@ -991,7 +1050,10 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg,
}
#ifdef WOLF_CRYPTO_CB
if (key->devId != INVALID_DEVID) {
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_Ed25519Verify(sig, sigLen, msg, msgLen, res, key,
type, context, contextLen);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
+19
View File
@@ -5720,6 +5720,25 @@ blinding by defining WC_BLINDING_NO_RNG_ACKNOWLEDGE_WEAKNESS."
#if defined(WOLF_CRYPTO_CB_ONLY_AES) && !defined(WOLF_CRYPTO_CB)
#error "WOLF_CRYPTO_CB_ONLY_AES requires WOLF_CRYPTO_CB"
#endif
#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && !defined(WOLF_CRYPTO_CB)
#error "WOLF_CRYPTO_CB_ONLY_ED25519 requires WOLF_CRYPTO_CB"
#endif
#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && !defined(HAVE_ED25519)
#error "WOLF_CRYPTO_CB_ONLY_ED25519 requires HAVE_ED25519"
#endif
/* Software Ed25519 is stripped, so no in-tree Ed25519 backend may be present
* and the streaming verify API (which has no callback path) must be off. */
#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && defined(WOLFSSL_SE050)
#error "WOLF_CRYPTO_CB_ONLY_ED25519 is incompatible with WOLFSSL_SE050"
#endif
#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && defined(HAVE_FIPS)
#error "WOLF_CRYPTO_CB_ONLY_ED25519 is incompatible with FIPS builds"
#endif
#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && \
defined(WOLFSSL_ED25519_STREAMING_VERIFY)
#error "WOLF_CRYPTO_CB_ONLY_ED25519 is incompatible with " \
"WOLFSSL_ED25519_STREAMING_VERIFY"
#endif
/* Early Data / Session Rules */
#if !defined(WOLFCRYPT_ONLY) && defined(WOLFSSL_EARLY_DATA) && \