1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Merge pull request #11248 from night1rider/ASU-ECIES-Improvements

Asu ecies improvements
This commit is contained in:
JacobBarthelmeh
2026-08-24 16:42:06 -06:00
committed by GitHub
5 changed files with 131 additions and 38 deletions

View File

@@ -1679,8 +1679,9 @@ int test_wc_ecc_ctx_set_info(void)
/*
* Testing the crypto-callback context accessors wc_ecc_ctx_get_algo,
* wc_ecc_ctx_get_kdf_salt, wc_ecc_ctx_get_info, wc_ecc_ctx_get_mac_salt and
* wc_ecc_ctx_get_protocol (built only when WOLF_CRYPTO_CB is enabled).
* wc_ecc_ctx_get_kdf_salt, wc_ecc_ctx_get_info, wc_ecc_ctx_get_mac_salt,
* wc_ecc_ctx_get_protocol and wc_ecc_ctx_get_rng (built only when
* WOLF_CRYPTO_CB is enabled).
*/
int test_wc_ecc_ctx_getters(void)
{
@@ -1807,6 +1808,39 @@ int test_wc_ecc_ctx_getters(void)
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
/* get_rng: the caller's RNG must come back out unchanged. The ASU ECIES
* offload uses it for the GCM nonce instead of standing up its own DRBG,
* so a getter that returned NULL or a different RNG would silently change
* where that nonce comes from. */
{
WC_RNG rng2;
WC_RNG* gotRng = NULL;
XMEMSET(&rng2, 0, sizeof(rng2));
/* Point the out-parameter somewhere else first, so the checks fail if
* the getter never writes it. */
gotRng = &rng2;
ExpectIntEQ(wc_ecc_ctx_get_rng(ctx, &gotRng), 0);
ExpectPtrEq(gotRng, &rng);
/* wc_ecc_ctx_reset() swaps the RNG, and the getter has to follow. */
ExpectIntEQ(wc_InitRng(&rng2), 0);
ExpectIntEQ(wc_ecc_ctx_reset(ctx, &rng2), 0);
gotRng = NULL;
ExpectIntEQ(wc_ecc_ctx_get_rng(ctx, &gotRng), 0);
ExpectPtrEq(gotRng, &rng2);
/* Put the original RNG back so rng2 can be freed here. */
ExpectIntEQ(wc_ecc_ctx_reset(ctx, &rng), 0);
DoExpectIntEQ(wc_FreeRng(&rng2), 0);
/* bad args: NULL ctx / NULL out-parameter */
ExpectIntEQ(wc_ecc_ctx_get_rng(NULL, &gotRng),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_rng(ctx, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
wc_ecc_ctx_free(ctx);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif

View File

@@ -15094,6 +15094,18 @@ int wc_ecc_ctx_get_protocol(ecEncCtx* ctx, int* protocol)
return 0;
}
/* Read the RNG a caller set on the context, for backends that need one
* instead of standing up a DRBG of their own. */
int wc_ecc_ctx_get_rng(ecEncCtx* ctx, WC_RNG** rng)
{
if (ctx == NULL || rng == NULL)
return BAD_FUNC_ARG;
*rng = ctx->rng;
return 0;
}
#endif /* WOLF_CRYPTO_CB */

View File

@@ -39,7 +39,8 @@ The BSP must have the `xilasu` and `xilmailbox` libraries enabled.
Anything outside this list is declined and wolfSSL runs it in software. That
includes AES-192, partial AES blocks, SHA-512/224 and 512/256, Keccak padding,
SHAKE128, deterministic ECDSA, and the older ECIES layouts.
SHAKE128 and deterministic ECDSA. The older ECIES layouts are different: the
port is not built at all, see below.
## Settings
@@ -86,6 +87,9 @@ only with firmware that front-pads.
**ECIES needs the KDF context path.** See below.
**ECIES needs `WOLFSSL_ECIES_GEN_IV`, and only offloads one direction.** See
below.
## ECIES on hardware
The ASU runs ECIES as one command: ECDH, then HKDF, then AES-GCM. It has no
@@ -115,12 +119,14 @@ What the offload requires:
| Setting | Value |
| --- | --- |
| Build | `WOLFSSL_ECIES_GEN_IV`, with neither `WOLFSSL_ECIES_OLD` nor `WOLFSSL_ECIES_ISO18033` |
| RNG | one on the key or on the context, see below |
| Scheme | `ecAES_128_GCM` or `ecAES_256_GCM` with `ecHKDF_SHA256` |
| KDF salt | `wc_ecc_ctx_set_kdf_salt`, passed through as given |
| KDF context | `wc_ecc_ctx_set_info`, must not be empty |
| MAC salt | must be empty, so no `wc_ecc_ctx_set_peer_salt` |
| Protocol | `REQ_RESP_CLIENT` to encrypt, `REQ_RESP_SERVER` to decrypt |
| Curves | P-256, P-384, Brainpool P-256, P-320, P-384, P-512 |
| Curves | P-192, P-256, P-384, Brainpool P-256, P-320, P-384, P-512 |
`wc_ecc_ctx_set_peer_salt` is the usual wolfSSL way to key ECIES, and it sets a
MAC salt as a side effect. wolfSSL feeds that salt to AES-GCM as extra
@@ -140,6 +146,24 @@ exchange works and matches software on the wire, but the key you passed in does
not appear in the result. Decrypt is not affected, and uses the private key you
supply.
## What ECIES needs to reach the ASU
Two things on top of the table above.
**The build must use `WOLFSSL_ECIES_GEN_IV`.** The ASU puts the GCM nonce in
the message, which is what that mode does. `WOLFSSL_ECIES_OLD` and
`WOLFSSL_ECIES_ISO18033` keep the nonce elsewhere, so in those modes the port
is not built at all and wolfSSL never calls it.
**Only one direction offloads.** Client and server each use their own half of
the derived key. The ASU always uses the first half, which is the half the
client encrypts with and the server decrypts with. So a client encrypting, or
a server decrypting, runs on hardware. The reply going back uses the second
half and runs in software.
Encrypt needs an RNG, on the key or on the context, or it returns
`MISSING_RNG_E`. Decrypt does not, since the nonce arrives in the message.
## Files
```

View File

@@ -156,6 +156,10 @@ static int wc_AsuEciesCurve(ecc_key* key, u8* curveType, u8* keyLen)
return CRYPTOCB_UNAVAILABLE;
}
switch (key->dp->id) {
case ECC_SECP192R1:
*curveType = (u8)XASU_ECC_NIST_P192;
*keyLen = (u8)XASU_ECC_P192_SIZE_IN_BYTES;
break;
case ECC_SECP256R1:
*curveType = (u8)XASU_ECC_NIST_P256;
*keyLen = (u8)XASU_ECC_P256_SIZE_IN_BYTES;
@@ -285,6 +289,12 @@ static int wc_AsuEciesEncrypt(wc_CryptoInfo* info)
word32 need;
word32 status;
word32 addl = 0;
const byte* macSalt = NULL;
const byte* infoP = NULL;
word32 macSaltSz = 0;
word32 infoSz = 0;
int proto = 0;
WC_RNG* rng = NULL;
int ret;
/* Return the decline code, not an error, so wolfSSL can use software. */
@@ -309,27 +319,29 @@ static int wc_AsuEciesEncrypt(wc_CryptoInfo* info)
}
/* Only GCM here. The ASU cannot take extra salt and needs a context, so
* software handles those cases. */
{
const byte* macSalt = NULL;
const byte* infoP = NULL;
word32 macSaltSz = 0;
word32 infoSz = 0;
int proto = 0;
(void)wc_ecc_ctx_get_mac_salt(ctx, &macSalt, &macSaltSz);
(void)wc_ecc_ctx_get_info(ctx, &infoP, &infoSz);
(void)wc_ecc_ctx_get_protocol(ctx, &proto);
if (macSaltSz > 0U) {
return CRYPTOCB_UNAVAILABLE;
}
if (infoSz == 0U) {
WC_ASU_PRINTF("[ASU] ecies: GCM needs a non-empty KDF context\r\n");
return CRYPTOCB_UNAVAILABLE;
}
/* The ASU always uses the first half of the derived key, which is the
* client half. A context is never built with protocol zero. */
if (proto != REQ_RESP_CLIENT) {
return CRYPTOCB_UNAVAILABLE;
}
ret = wc_ecc_ctx_get_mac_salt(ctx, &macSalt, &macSaltSz);
if (ret != 0) {
return ret;
}
ret = wc_ecc_ctx_get_info(ctx, &infoP, &infoSz);
if (ret != 0) {
return ret;
}
ret = wc_ecc_ctx_get_protocol(ctx, &proto);
if (ret != 0) {
return ret;
}
if (macSaltSz > 0U) {
return CRYPTOCB_UNAVAILABLE;
}
if (infoSz == 0U) {
WC_ASU_PRINTF("[ASU] ecies: GCM needs a non-empty KDF context\r\n");
return CRYPTOCB_UNAVAILABLE;
}
/* The ASU always uses the first half of the derived key, which is the
* client half. A context is never built with protocol zero. */
if (proto != REQ_RESP_CLIENT) {
return CRYPTOCB_UNAVAILABLE;
}
/* The caller passes a key here, but the ASU makes its own. */
if (privKey == NULL) {
@@ -374,21 +386,30 @@ static int wc_AsuEciesEncrypt(wc_CryptoInfo* info)
wc_AsuEciesReqFree(&mem);
return ret;
}
/* Make the GCM nonce with a local RNG on the ASU device id. */
{
WC_RNG rng;
ret = wc_InitRng_ex(&rng, NULL, WOLFSSL_VERSAL_GEN2_ASU_DEVID);
if (ret == 0) {
ret = wc_RNG_GenerateBlock(&rng, mem.req->iv,
WC_ASU_ECIES_NONCE_SZ);
wc_FreeRng(&rng);
}
}
/* Nonce from the caller's RNG, key first then context, as software does.
* A private DRBG here would ignore the RNG the application chose. */
ret = wc_ecc_ctx_get_rng(ctx, &rng);
if (ret != 0) {
/* That RNG needs a seed source this build may not have, so decline
* and let wolfSSL try again in software. */
wc_AsuEciesReqFree(&mem);
return CRYPTOCB_UNAVAILABLE;
return ret;
}
#ifdef ECC_TIMING_RESISTANT
/* The key's own RNG wins when it has one, which is what software uses. */
if (privKey->rng != NULL) {
rng = privKey->rng;
}
#endif
if (rng == NULL) {
/* Software will not invent a nonce either, so report the missing RNG
* rather than declining and having it rediscover the same thing. */
WC_ASU_PRINTF("[ASU] ecies enc: no RNG for the GCM nonce\r\n");
wc_AsuEciesReqFree(&mem);
return MISSING_RNG_E;
}
ret = wc_RNG_GenerateBlock(rng, mem.req->iv, WC_ASU_ECIES_NONCE_SZ);
if (ret != 0) {
wc_AsuEciesReqFree(&mem);
return ret;
}
wc_AsuEciesFillParams(&mem.req->params, ctx, curveType, keyLen, aesKeySize,

View File

@@ -1129,6 +1129,8 @@ WOLFSSL_API
int wc_ecc_ctx_get_mac_salt(ecEncCtx* ctx, const byte** salt, word32* sz);
WOLFSSL_API
int wc_ecc_ctx_get_protocol(ecEncCtx* ctx, int* protocol);
WOLFSSL_API
int wc_ecc_ctx_get_rng(ecEncCtx* ctx, WC_RNG** rng);
#endif /* WOLF_CRYPTO_CB */
WOLFSSL_API
const byte* wc_ecc_ctx_get_own_salt(ecEncCtx* ctx);