diff --git a/.github/workflows/cryptocb-only.yml b/.github/workflows/cryptocb-only.yml index 2d645e9343..e139c79803 100644 --- a/.github/workflows/cryptocb-only.yml +++ b/.github/workflows/cryptocb-only.yml @@ -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/make-pub/check-key) including the ge/fe curve math and tables; 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 \ diff --git a/doc/dox_comments/header_files/cryptocb.h b/doc/dox_comments/header_files/cryptocb.h index 95fb22e078..b5e716ef6b 100644 --- a/doc/dox_comments/header_files/cryptocb.h +++ b/doc/dox_comments/header_files/cryptocb.h @@ -341,3 +341,55 @@ int wc_CryptoCb_EccMakePub(ecc_key* key, ecc_point* pubOut); \sa wc_ecc_check_key */ int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder, int checkPriv); + +/*! + \ingroup CryptoCb + + \brief Offload deriving an Ed25519 public key from its private key to a + CryptoCB device. + + Used by wc_ed25519_make_public (and so by key generation and private-key + import). The boundary is byte-oriented: the device writes the compressed + public key into wc_CryptoInfo.pk.ed25519makepub (\c pubOut / + \c pubOutSz, always ED25519_PUB_KEY_SIZE). The private key is taken from + the ed25519_key (resident in a secure element, or key->k). On success the + caller marks the public key set. + + \param key Ed25519 key providing the device id, heap hint and the + private key + \param pubKey [out] resulting compressed public key + \param pubKeySz size of pubKey buffer, must be ED25519_PUB_KEY_SIZE + + \return 0 on success + \return CRYPTOCB_UNAVAILABLE if no device handles the operation, or key or + pubKey is NULL or pubKeySz is wrong (wolfCrypt falls back to + software, which reports the argument error) + + \sa wc_CryptoCb_RegisterDevice + \sa wc_ed25519_make_public +*/ +int wc_CryptoCb_Ed25519MakePub(ed25519_key* key, byte* pubKey, + word32 pubKeySz); + +/*! + \ingroup CryptoCb + + \brief Offload validating an Ed25519 key to a CryptoCB device. + + Used by wc_ed25519_check_key and the key import validation paths. The + public key crosses the callback boundary as its compressed wire bytes in + wc_CryptoInfo.pk.ed25519checkkey (\c pubKey / \c pubKeySz), so a device + handler only deals with byte arrays. The dispatch only runs when a public + key is present; \c checkPriv is 1 when a private key is also set and the + device should additionally validate priv/pub consistency. + + \param key Ed25519 key to validate + + \return 0 if the key is valid + \return CRYPTOCB_UNAVAILABLE if no device handles the operation (wolfCrypt + falls back to software) + + \sa wc_CryptoCb_RegisterDevice + \sa wc_ed25519_check_key +*/ +int wc_CryptoCb_Ed25519CheckKey(ed25519_key* key); diff --git a/tests/api.c b/tests/api.c index eed600c040..d1c723d88e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -29146,7 +29146,8 @@ static int test_SSL_CIPHER_get_current_kx(void) #if defined(WOLF_CRYPTO_CB) && defined(HAVE_IO_TESTS_DEPENDENCIES) && \ (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ - !defined(WOLF_CRYPTO_CB_ONLY_SHA512)) + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) static int load_pem_key_file_as_der(const char* privKeyFile, DerBuffer** pDer, int* keyFormat) @@ -30151,7 +30152,8 @@ static int test_wc_CryptoCb(void) #if defined(WOLF_CRYPTO_CB) && \ (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ - !defined(WOLF_CRYPTO_CB_ONLY_SHA512)) + !defined(WOLF_CRYPTO_CB_ONLY_SHA512) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) #if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) int tlsVer; diff --git a/tests/swdev/README.md b/tests/swdev/README.md index eedbe1e5a1..0cf5ce2fde 100644 --- a/tests/swdev/README.md +++ b/tests/swdev/README.md @@ -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: diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index 0a02295c32..3b69a74cba 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -40,6 +40,9 @@ #ifndef NO_AES #include #endif +#ifdef HAVE_ED25519 +#include +#endif static int swdev_initialized = 0; @@ -238,6 +241,83 @@ 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 + +#ifdef HAVE_ED25519_MAKE_KEY +static int swdev_ed25519_make_pub(wc_CryptoInfo* info) +{ + if (info->pk.ed25519makepub.pubOutSz != ED25519_PUB_KEY_SIZE) + return BUFFER_E; + return wc_ed25519_make_public(info->pk.ed25519makepub.key, + info->pk.ed25519makepub.pubOut, info->pk.ed25519makepub.pubOutSz); +} +#endif + +static int swdev_ed25519_check_key(wc_CryptoInfo* info) +{ + ed25519_key* key = info->pk.ed25519checkkey.key; + int ret = 0; + int validatedFromWire = 0; + +#ifdef HAVE_ED25519_KEY_IMPORT + { + WC_DECLARE_VAR(pubOnly, ed25519_key, 1, key->heap); + + /* vault-style consumption: rebuild a public-only key from the wire + * bytes and validate it, proving the serialized form is sufficient. + * trusted=0 runs the full public-key validation during import. */ + WC_ALLOC_VAR(pubOnly, ed25519_key, 1, key->heap); + if (!WC_VAR_OK(pubOnly)) + return MEMORY_E; + ret = wc_ed25519_init_ex(pubOnly, key->heap, INVALID_DEVID); + if (ret == 0) { + ret = wc_ed25519_import_public_ex(info->pk.ed25519checkkey.pubKey, + info->pk.ed25519checkkey.pubKeySz, pubOnly, 0); + } + wc_ed25519_free(pubOnly); + WC_FREE_VAR(pubOnly, key->heap); + validatedFromWire = 1; + } +#endif + /* private part (and public-only validation when the import path is + * unavailable): validate via the key handle */ + if (ret == 0 && (!validatedFromWire || + info->pk.ed25519checkkey.checkPriv)) { + ret = wc_ed25519_check_key(key); + } + return ret; +} +#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 +913,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 +944,26 @@ 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 + #ifdef HAVE_ED25519_MAKE_KEY + case WC_PK_TYPE_ED25519_MAKE_PUB: + return swdev_ed25519_make_pub(info); + #endif + case WC_PK_TYPE_ED25519_CHECK_KEY: + return swdev_ed25519_check_key(info); + #endif /* HAVE_ED25519 */ default: return CRYPTOCB_UNAVAILABLE; } diff --git a/tests/swdev/user_settings.h b/tests/swdev/user_settings.h index c04f056b02..46076d5007 100644 --- a/tests/swdev/user_settings.h +++ b/tests/swdev/user_settings.h @@ -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" diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index c3067b97b8..e7e8eaf70d 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -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 @@ -156,6 +157,8 @@ static const char* GetPkTypeStr(int pk) case WC_PK_TYPE_EC_GET_SIG_SIZE: return "ECC GetSigSize"; case WC_PK_TYPE_EC_MAKE_PUB: return "ECC MakePub"; case WC_PK_TYPE_EC_CHECK_PUB_KEY: return "ECC CheckPubKey"; + case WC_PK_TYPE_ED25519_MAKE_PUB: return "ED25519 MakePub"; + case WC_PK_TYPE_ED25519_CHECK_KEY: return "ED25519 CheckKey"; } return NULL; } @@ -1167,6 +1170,60 @@ int wc_CryptoCb_Ed25519Verify(const byte* sig, word32 sigLen, return wc_CryptoCb_TranslateErrorCode(ret); } + +int wc_CryptoCb_Ed25519MakePub(ed25519_key* key, byte* pubKey, word32 pubKeySz) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (key == NULL || pubKey == NULL || pubKeySz != ED25519_PUB_KEY_SIZE) + return ret; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_ED25519_MAKE_PUB; + cryptoInfo.pk.ed25519makepub.key = key; + cryptoInfo.pk.ed25519makepub.pubOut = pubKey; + cryptoInfo.pk.ed25519makepub.pubOutSz = pubKeySz; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_Ed25519CheckKey(ed25519_key* key) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (key == NULL) + return ret; + + /* locate registered callback */ + dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_ED25519_CHECK_KEY; + cryptoInfo.pk.ed25519checkkey.key = key; + /* key->p is already the compressed wire form; cross it as bytes so a + * device can validate the actual input without touching key internals + */ + cryptoInfo.pk.ed25519checkkey.pubKey = key->p; + cryptoInfo.pk.ed25519checkkey.pubKeySz = ED25519_PUB_KEY_SIZE; + cryptoInfo.pk.ed25519checkkey.checkPriv = key->privKeySet ? 1 : 0; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} #endif /* HAVE_ED25519 */ #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 3cf8d807fe..cb7abcc9de 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -207,6 +207,7 @@ static int ed25519_hash(ed25519_key* key, const byte* in, word32 inLen, return ret; } +#ifndef WOLF_CRYPTO_CB_ONLY_ED25519 /* Reject small-order Ed25519 public keys: h*A vanishes during verification * so any (R = [S]B, S) verifies for an arbitrary message. */ static int ed25519_is_small_order(const byte p[ED25519_PUB_KEY_SIZE]) @@ -264,6 +265,7 @@ static int ed25519_is_small_order(const byte p[ED25519_PUB_KEY_SIZE]) } return 0; } +#endif /* !WOLF_CRYPTO_CB_ONLY_ED25519 */ #ifdef HAVE_ED25519_MAKE_KEY #if FIPS_VERSION3_GE(6,0,0) @@ -320,10 +322,12 @@ int wc_ed25519_make_public(ed25519_key* key, unsigned char* pubKey, word32 pubKeySz) { int ret = 0; +#ifndef WOLF_CRYPTO_CB_ONLY_ED25519 ALIGN16 byte az[ED25519_PRV_KEY_SIZE]; #if !defined(FREESCALE_LTC_ECC) ge_p3 A; #endif +#endif /* !WOLF_CRYPTO_CB_ONLY_ED25519 */ if (key == NULL || pubKey == NULL || pubKeySz != ED25519_PUB_KEY_SIZE) ret = BAD_FUNC_ARG; @@ -332,6 +336,32 @@ int wc_ed25519_make_public(ed25519_key* key, unsigned char* pubKey, ret = ECC_PRIV_KEY_E; } +#ifdef WOLF_CRYPTO_CB + /* Device-first: offload the public-key derivation. Fall through to the + * software path below only when the device reports the operation + * unavailable. */ + #ifndef WOLF_CRYPTO_CB_FIND + if ((ret == 0) && (key->devId != INVALID_DEVID)) + #else + if (ret == 0) + #endif + { + ret = wc_CryptoCb_Ed25519MakePub(key, pubKey, pubKeySz); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) { + if (ret == 0) + key->pubKeySet = 1; + return ret; + } + ret = 0; /* device declined the offload; fall back */ + } +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_ED25519 + /* software derivation is stripped and no device handled the op; + * fail closed */ + if (ret == 0) + ret = NO_VALID_DEVID; +#else if (ret == 0) ret = ed25519_hash(key, key->k, ED25519_KEY_SIZE, az); if (ret == 0) { @@ -354,6 +384,7 @@ int wc_ed25519_make_public(ed25519_key* key, unsigned char* pubKey, key->pubKeySet = 1; } +#endif /* WOLF_CRYPTO_CB_ONLY_ED25519 */ return ret; } @@ -376,7 +407,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 +418,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 +444,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 +472,31 @@ 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) + (void)ed25519Ctx; + 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 +524,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)) @@ -597,9 +663,10 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, ForceZero(az, sizeof(az)); ForceZero(nonce, sizeof(nonce)); -#endif /* WOLFSSL_SE050 */ #ifdef WOLFSSL_EDDSA_CHECK_PRIV_ON_SIGN + /* belongs to the software path: orig_k snapshots the key the software + * math read, so there is nothing to compare when a device signs */ if (ret == 0) { int i; byte c = 0; @@ -610,6 +677,7 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, } ForceZero(orig_k, sizeof(orig_k)); #endif +#endif /* WOLFSSL_SE050 */ return ret; } @@ -696,7 +764,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 +996,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 +1040,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 +1083,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)) @@ -1160,7 +1255,8 @@ int wc_ed25519_init_ex(ed25519_key* key, void* heap, int devId) #endif key->heap = heap; -#ifndef FREESCALE_LTC_ECC +/* no field math is linked when all Ed25519 ops route through the callback */ +#if !defined(FREESCALE_LTC_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519) fe_init(); #endif @@ -1289,6 +1385,23 @@ int wc_ed25519_import_public_ex(const byte* in, word32 inLen, ed25519_key* key, key->pointY[i] = *(in + 2*ED25519_KEY_SIZE - i); } XMEMCPY(key->p, key->pointY, ED25519_KEY_SIZE); +#elif defined(WOLF_CRYPTO_CB_ONLY_ED25519) + { + /* Compress without the stripped curve math: y crosses reversed + * with its top bit replaced by the parity of x. Same byte + * transform as ge_compress_key minus the canonical reduction + * (as in the ED25519_SMALL variant); the key check below + * rejects non-canonical keys. This inlined code avoids pulling + * in ge_compress_key(), etc. */ + const byte* xIn = in + 1; + const byte* yIn = in + 1 + ED25519_PUB_KEY_SIZE; + int i; + + for (i = 0; i < ED25519_PUB_KEY_SIZE; i++) { + key->p[i] = yIn[ED25519_PUB_KEY_SIZE - 1 - i]; + } + key->p[0] = (byte)((key->p[0] & 0x7f) | ((xIn[0] & 1) << 7)); + } #else /* pass in (x,y) and store compressed key */ ret = ge_compress_key(key->p, in+1, @@ -1566,6 +1679,30 @@ int wc_ed25519_check_key(ed25519_key* key) ret = PUBLIC_KEY_E; } +#ifdef WOLF_CRYPTO_CB + /* Device-first: let a configured device validate the key. Fall through + * to the software checks below only when the device reports the + * operation unavailable. */ + #ifndef WOLF_CRYPTO_CB_FIND + if ((ret == 0) && (key->devId != INVALID_DEVID)) + #else + if (ret == 0) + #endif + { + ret = wc_CryptoCb_Ed25519CheckKey(key); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + ret = 0; /* device declined; fall through to software */ + } +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_ED25519 + /* Software validation is stripped; the device-first check above either + * handled the key or reported the op unavailable, so fail closed rather + * than accept an unvalidated key. */ + if (ret == 0) + ret = NO_VALID_DEVID; +#else /* Reject small-order pub key before the priv-vs-pub compare so the * diagnostic isn't masked by a "mismatch" error. */ if ((ret == 0) && ed25519_is_small_order(key->p)) { @@ -1621,6 +1758,7 @@ int wc_ed25519_check_key(ed25519_key* key) } } } +#endif /* WOLF_CRYPTO_CB_ONLY_ED25519 */ return ret; } diff --git a/wolfcrypt/src/fe_low_mem.c b/wolfcrypt/src/fe_low_mem.c index 61b8876904..2839ea3e93 100644 --- a/wolfcrypt/src/fe_low_mem.c +++ b/wolfcrypt/src/fe_low_mem.c @@ -23,7 +23,10 @@ /* Based from Daniel Beer's public domain work. */ -#if defined(HAVE_CURVE25519) || defined(HAVE_ED25519) +/* under WOLF_CRYPTO_CB_ONLY_ED25519 the callback device does all Ed25519 + * field math, so Ed25519 alone no longer pulls this file in */ +#if defined(HAVE_CURVE25519) || \ + (defined(HAVE_ED25519) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) #if defined(CURVE25519_SMALL) || defined(ED25519_SMALL) /* use slower code that takes less memory */ #include diff --git a/wolfcrypt/src/fe_operations.c b/wolfcrypt/src/fe_operations.c index 51bf6fdf74..d80bc01e4a 100644 --- a/wolfcrypt/src/fe_operations.c +++ b/wolfcrypt/src/fe_operations.c @@ -23,7 +23,10 @@ /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */ -#if defined(HAVE_CURVE25519) || defined(HAVE_ED25519) +/* under WOLF_CRYPTO_CB_ONLY_ED25519 the callback device does all Ed25519 + * field math, so Ed25519 alone no longer pulls this file in */ +#if defined(HAVE_CURVE25519) || \ + (defined(HAVE_ED25519) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) #if !defined(CURVE25519_SMALL) && !defined(ED25519_SMALL) #include diff --git a/wolfcrypt/src/ge_low_mem.c b/wolfcrypt/src/ge_low_mem.c index 940bae91e4..1a245239ec 100644 --- a/wolfcrypt/src/ge_low_mem.c +++ b/wolfcrypt/src/ge_low_mem.c @@ -23,7 +23,9 @@ /* Based from Daniel Beer's public domain work. */ -#ifdef HAVE_ED25519 +/* under WOLF_CRYPTO_CB_ONLY_ED25519 the callback device does all Ed25519 + * group math, so this file compiles out */ +#if defined(HAVE_ED25519) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519) #ifdef ED25519_SMALL /* use slower code that takes less memory */ #include diff --git a/wolfcrypt/src/ge_operations.c b/wolfcrypt/src/ge_operations.c index 5d3157628d..a59a8e4846 100644 --- a/wolfcrypt/src/ge_operations.c +++ b/wolfcrypt/src/ge_operations.c @@ -26,7 +26,11 @@ #include -#if defined(HAVE_ED25519) || defined(WOLFSSL_CURVE25519_USE_ED25519) +/* under WOLF_CRYPTO_CB_ONLY_ED25519 the callback device does all Ed25519 + * group math, so this file (and its large precomputed tables) compiles out + * unless curve25519 also needs it */ +#if (defined(HAVE_ED25519) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) || \ + defined(WOLFSSL_CURVE25519_USE_ED25519) #ifndef ED25519_SMALL /* run when not defined to use small memory math */ #include diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ed80cd4e96..b47ae99ad6 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -3128,7 +3128,8 @@ options: [-s max_relative_stack_bytes] [-m max_relative_heap_memory_bytes]\n\ TEST_PASS("CURVE25519 test passed!\n"); #endif -#ifdef HAVE_ED25519 +#if defined(HAVE_ED25519) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ED25519) || defined(WOLFSSL_SWDEV)) PRIVATE_KEY_UNLOCK(); if ( (ret = ed25519_test()) != 0) TEST_FAIL("ED25519 test failed!\n", ret); @@ -75017,6 +75018,162 @@ static wc_test_ret_t aes_onlycb_test(myCryptoDevCtx *ctx) } #endif /* WOLF_CRYPTO_CB_ONLY_AES */ +#ifdef WOLF_CRYPTO_CB_ONLY_ED25519 +/* Exercise Ed25519 dispatch under CB_ONLY_ED25519: cb-handled then + * cb-delegated. */ +static wc_test_ret_t ed25519_onlycb_test(myCryptoDevCtx *ctx) +{ + wc_test_ret_t ret = 0; + ed25519_key key; +#if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_VERIFY) + byte sig[ED25519_SIG_SIZE]; + const byte msg[] = "abc"; +#endif +#ifdef HAVE_ED25519_SIGN + word32 sigLen = (word32)sizeof(sig); +#endif +#ifdef HAVE_ED25519_VERIFY + int res = 0; +#endif +#ifdef HAVE_ED25519_MAKE_KEY + WC_RNG rng; +#endif +#ifdef HAVE_ED25519_KEY_IMPORT + byte keyBytes[ED25519_KEY_SIZE]; +#ifdef HAVE_ED25519_MAKE_KEY + byte pub[ED25519_PUB_KEY_SIZE]; +#endif +#endif + +#if defined(HAVE_ED25519_SIGN) || defined(HAVE_ED25519_VERIFY) + XMEMSET(sig, 0, sizeof(sig)); +#endif + + ret = wc_ed25519_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + +#ifdef HAVE_ED25519_MAKE_KEY + ret = wc_InitRng(&rng); + if (ret != 0) { + wc_ed25519_free(&key); + return WC_TEST_RET_ENC_EC(ret); + } + + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* HAVE_ED25519_MAKE_KEY */ + +#ifdef HAVE_ED25519_SIGN + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_ed25519_sign_msg(msg, (word32)sizeof(msg) - 1, sig, &sigLen, + &key); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_ed25519_sign_msg(msg, (word32)sizeof(msg) - 1, sig, &sigLen, + &key); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* HAVE_ED25519_SIGN */ + +#ifdef HAVE_ED25519_VERIFY + /* cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_ed25519_verify_msg(sig, (word32)sizeof(sig), msg, + (word32)sizeof(msg) - 1, &res, &key); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_ed25519_verify_msg(sig, (word32)sizeof(sig), msg, + (word32)sizeof(msg) - 1, &res, &key); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* HAVE_ED25519_VERIFY */ + +#ifdef HAVE_ED25519_KEY_IMPORT + /* seed key state for the make-public/check-key dispatch tests. Neither + * import validates here: private-only import has no public key to check + * against yet and the public import is flagged trusted. */ + XMEMSET(keyBytes, 1, sizeof(keyBytes)); + ret = wc_ed25519_import_private_only(keyBytes, (word32)sizeof(keyBytes), + &key); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + ret = wc_ed25519_import_public_ex(keyBytes, (word32)sizeof(keyBytes), + &key, 1); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + +#ifdef HAVE_ED25519_MAKE_KEY + /* make_public: cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_ed25519_make_public(&key, pub, (word32)sizeof(pub)); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_ed25519_make_public(&key, pub, (word32)sizeof(pub)); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* HAVE_ED25519_MAKE_KEY */ + + /* check_key: cb handles the op, expects 0(success) */ + ctx->exampleVar = 99; + ret = wc_ed25519_check_key(&key); + if (ret != 0) + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + + /* cb delegates to software, expects NO_VALID_DEVID(failure) */ + ctx->exampleVar = 1; + ret = wc_ed25519_check_key(&key); + if (ret != WC_NO_ERR_TRACE(NO_VALID_DEVID)) { + ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_onlycb); + } else { + ret = 0; + } +#endif /* HAVE_ED25519_KEY_IMPORT */ + +#if defined(HAVE_ED25519_MAKE_KEY) || defined(HAVE_ED25519_SIGN) || \ + defined(HAVE_ED25519_VERIFY) || defined(HAVE_ED25519_KEY_IMPORT) +exit_onlycb: +#endif +#ifdef HAVE_ED25519_MAKE_KEY + wc_FreeRng(&rng); +#endif + wc_ed25519_free(&key); + (void)ctx; + return ret; +} +#endif /* WOLF_CRYPTO_CB_ONLY_ED25519 */ + #if defined(HAVE_ECC) && !defined(WOLFSSL_NO_MALLOC) && \ defined(HAVE_ECC_KEY_EXPORT) /* Serialize pub to X9.63 uncompressed (0x04 || X || Y) using the curve size @@ -75432,10 +75589,20 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) info->pk.curve25519.private_key->devId = devIdArg; } #endif /* HAVE_CURVE25519 */ - #if defined(HAVE_ED25519) && defined(HAVE_ED25519_MAKE_KEY) + #ifdef HAVE_ED25519 + #ifdef HAVE_ED25519_MAKE_KEY if (info->pk.type == WC_PK_TYPE_ED25519_KEYGEN) { /* set devId to invalid, so software is used */ info->pk.ed25519kg.key->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_ED25519) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->pk.ed25519kg.key->devId = devIdArg; + return 0; + } + #endif ret = wc_ed25519_make_key(info->pk.ed25519kg.rng, info->pk.ed25519kg.size, info->pk.ed25519kg.key); @@ -75443,10 +75610,21 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* reset devId */ info->pk.ed25519kg.key->devId = devIdArg; } + else + #endif #ifdef HAVE_ED25519_SIGN - else if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) { + if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) { /* set devId to invalid, so software is used */ info->pk.ed25519sign.key->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_ED25519) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->pk.ed25519sign.key->devId = devIdArg; + return 0; + } + #endif ret = wc_ed25519_sign_msg_ex( info->pk.ed25519sign.in, info->pk.ed25519sign.inLen, @@ -75457,11 +75635,21 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* reset devId */ info->pk.ed25519sign.key->devId = devIdArg; } + else #endif #ifdef HAVE_ED25519_VERIFY - else if (info->pk.type == WC_PK_TYPE_ED25519_VERIFY) { + if (info->pk.type == WC_PK_TYPE_ED25519_VERIFY) { /* set devId to invalid, so software is used */ info->pk.ed25519verify.key->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_ED25519) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->pk.ed25519verify.key->devId = devIdArg; + return 0; + } + #endif ret = wc_ed25519_verify_msg_ex( info->pk.ed25519verify.sig, info->pk.ed25519verify.sigLen, @@ -75473,7 +75661,49 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx) /* reset devId */ info->pk.ed25519verify.key->devId = devIdArg; } + else + #endif + #ifdef HAVE_ED25519_MAKE_KEY + if (info->pk.type == WC_PK_TYPE_ED25519_MAKE_PUB) { + /* set devId to invalid, so software is used */ + info->pk.ed25519makepub.key->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_ED25519) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->pk.ed25519makepub.key->devId = devIdArg; + return 0; + } + #endif + + ret = wc_ed25519_make_public(info->pk.ed25519makepub.key, + info->pk.ed25519makepub.pubOut, + info->pk.ed25519makepub.pubOutSz); + + /* reset devId */ + info->pk.ed25519makepub.key->devId = devIdArg; + } + else #endif + if (info->pk.type == WC_PK_TYPE_ED25519_CHECK_KEY) { + /* set devId to invalid, so software is used */ + info->pk.ed25519checkkey.key->devId = INVALID_DEVID; + #if defined(WOLF_CRYPTO_CB_ONLY_ED25519) + #ifdef DEBUG_WOLFSSL + printf("CryptoDevCb: exampleVar %d\n", myCtx->exampleVar); + #endif + if (myCtx->exampleVar == 99) { + info->pk.ed25519checkkey.key->devId = devIdArg; + return 0; + } + #endif + + ret = wc_ed25519_check_key(info->pk.ed25519checkkey.key); + + /* reset devId */ + info->pk.ed25519checkkey.key->devId = devIdArg; + } #endif /* HAVE_ED25519 */ #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) if (info->pk.type == WC_PK_TYPE_PQC_STATEFUL_SIG_KEYGEN) { @@ -77603,12 +77833,19 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void) if (ret == 0) ret = lms_test(); #endif -#ifdef HAVE_ED25519 +#if defined(HAVE_ED25519) && \ + (!defined(WOLF_CRYPTO_CB_ONLY_ED25519) || defined(WOLFSSL_SWDEV)) PRIVATE_KEY_UNLOCK(); if (ret == 0) ret = ed25519_test(); PRIVATE_KEY_LOCK(); #endif +#if defined(WOLF_CRYPTO_CB_ONLY_ED25519) && !defined(WOLFSSL_SWDEV) + PRIVATE_KEY_UNLOCK(); + if (ret == 0) + ret = ed25519_onlycb_test(&myCtx); + PRIVATE_KEY_LOCK(); +#endif #ifdef HAVE_CURVE25519 if (ret == 0) ret = curve25519_test(); diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 3de89680e6..9146c1999c 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -308,6 +308,19 @@ typedef struct wc_CryptoInfo { const byte* context; byte contextLen; } ed25519verify; + struct { + ed25519_key* key; /* routing (devId), heap, private key + * in key->k (or device-resident) */ + byte* pubOut; /* [out] compressed public key */ + word32 pubOutSz; /* buffer size, ED25519_PUB_KEY_SIZE */ + } ed25519makepub; + struct { + ed25519_key* key; /* routing, heap, resident/sw priv */ + const byte* pubKey; /* compressed public key (key->p) */ + word32 pubKeySz; /* ED25519_PUB_KEY_SIZE */ + int checkPriv; /* 1: private key present; also check + * priv/pub consistency */ + } ed25519checkkey; #endif #if defined(WOLFSSL_HAVE_MLKEM) struct { @@ -814,6 +827,9 @@ WOLFSSL_LOCAL int wc_CryptoCb_Ed25519Sign(const byte* in, word32 inLen, WOLFSSL_LOCAL int wc_CryptoCb_Ed25519Verify(const byte* sig, word32 sigLen, const byte* msg, word32 msgLen, int* res, ed25519_key* key, byte type, const byte* context, byte contextLen); +WOLFSSL_LOCAL int wc_CryptoCb_Ed25519MakePub(ed25519_key* key, byte* pubKey, + word32 pubKeySz); +WOLFSSL_LOCAL int wc_CryptoCb_Ed25519CheckKey(ed25519_key* key); #endif /* HAVE_ED25519 */ #if defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS) diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index f17c69d6dd..7f4480de93 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -5585,6 +5585,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) && \ diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index aad0ad68b4..3d41339076 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1621,8 +1621,10 @@ enum wc_PkType { #endif WC_PK_TYPE_EC_MAKE_PUB = 34, WC_PK_TYPE_EC_CHECK_PUB_KEY = 35, + WC_PK_TYPE_ED25519_MAKE_PUB = 36, + WC_PK_TYPE_ED25519_CHECK_KEY = 37, #undef _WC_PK_TYPE_MAX - #define _WC_PK_TYPE_MAX WC_PK_TYPE_EC_CHECK_PUB_KEY + #define _WC_PK_TYPE_MAX WC_PK_TYPE_ED25519_CHECK_KEY WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX };