ECIES: take the device id from the context instead of the ECC key

A context starts in software and only wc_ecc_ctx_set_dev_id() sends the ECIES callback and the KDF, AES and HMAC steps to a device; tests, benchmark, docs and the os-check matrix are updated to match.
pull/11399/head
night1rider 2026-09-15 10:18:02 -06:00
parent 252c3b1aa3
commit 2ed567c29c
13 changed files with 873 additions and 84 deletions

View File

@ -178,18 +178,22 @@
{"name": "ecies-sec1-gcm-static-nonce", "minutes": 2.0,
"comment": "ECIES with the AES-GCM DEM in the default SEC1 IV mode; WOLFSSL_ECIES_STATIC_GCM_NONCE opts into the fixed-nonce GCM path so the GCM KAT/round-trip and cryptocb tests run.",
"configure": ["--enable-eccencrypt", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen", "--enable-compkey",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "ecies-geniv-gcm-static-nonce", "minutes": 2.0,
"comment": "Same ECIES-GCM coverage in the WOLFSSL_ECIES_GEN_IV mode (random embedded nonce).",
"configure": ["--enable-eccencrypt=geniv", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen", "--enable-compkey",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "ecies-old-gcm-static-nonce", "minutes": 2.0,
"comment": "Same ECIES-GCM coverage in the legacy WOLFSSL_ECIES_OLD mode (KDF-derived nonce, no ephemeral pubkey prepended).",
"configure": ["--enable-eccencrypt=old", "--enable-aesgcm", "--enable-aesctr",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen", "--enable-compkey",
"CPPFLAGS=-DWOLFSSL_ECIES_STATIC_GCM_NONCE"]},
{"name": "ecies-gcm-only-geniv", "minutes": 2.0,
"comment": "ECIES with AES-GCM as the only cipher (AES-CBC off) in GEN_IV mode, so the ECIES tests take their GCM branches: no separate MAC step and a random embedded nonce.",
"configure": ["--enable-eccencrypt=geniv", "--enable-aesgcm", "--disable-aescbc",
"--enable-x963kdf", "--enable-cryptocb", "--enable-keygen", "--enable-compkey"]},
{"name": "opensslextra-x509small", "minutes": 2.0,
"configure": ["--enable-opensslextra=x509small"]},
{"name": "cryptocb-keygen-find", "minutes": 2.0,

View File

@ -104,6 +104,12 @@
#define USE_CERT_BUFFERS_256
#define BENCH_EMBEDDED
/* Adds a second set of ECIES benchmark rows, tagged -kdf, set up the way the
* ASU needs (KDF salt and info, no MAC salt). Without it the only ECIES rows
* are the salt-exchange ones, which the port always turns down, so the
* benchmark would show no ECIES number that reaches the hardware. */
#define WC_BENCH_ECIES_KDF
/* Uncomment for a build with only wolfCrypt (no TLS layer). */
/* #define WOLFCRYPT_ONLY */

View File

@ -1851,7 +1851,11 @@ void wc_ecc_ctx_free(ecEncCtx* ctx);
// do more secure communication
\endcode
\note The device id set with wc_ecc_ctx_set_dev_id() (WOLF_CRYPTO_CB
builds) is kept across the reset, like the heap hint.
\sa wc_ecc_ctx_new
\sa wc_ecc_ctx_set_dev_id
*/
int wc_ecc_ctx_reset(ecEncCtx* ctx, WC_RNG* rng); /* reset for use again w/o alloc/free */
@ -1888,6 +1892,70 @@ int wc_ecc_ctx_reset(ecEncCtx* ctx, WC_RNG* rng); /* reset for use again w/o al
int wc_ecc_ctx_set_algo(ecEncCtx* ctx, byte encAlgo, byte kdfAlgo,
byte macAlgo);
/*!
\ingroup ECC
\brief This function picks the device that ECIES operations using this
context run on. Only available when WOLF_CRYPTO_CB is defined. A context
starts at INVALID_DEVID, meaning software: ECIES does not copy the
device from the private key, so this must be called for a crypto
callback to be reached. The value is used both for the whole-operation
ECIES callback and for the KDF, AES and HMAC steps of the software path.
Passing a NULL context to wc_ecc_encrypt() or wc_ecc_decrypt() always
means software. When WOLF_CRYPTO_CB_FIND is defined, an unset device id
still goes through the registered finder, as it does for every other
wolfCrypt operation. The setting is kept across wc_ecc_ctx_reset().
\return 0 Returned upon successfully setting the device id.
\return BAD_FUNC_ARG Returned if the given context is NULL.
\param ctx pointer to the ecEncCtx for which to set the device id
\param devId device id to use, or INVALID_DEVID for software
_Example_
\code
ecEncCtx* ctx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
if (wc_ecc_ctx_set_dev_id(ctx, myDevId) != 0) {
// error setting device id
}
\endcode
\sa wc_ecc_ctx_get_dev_id
\sa wc_ecc_ctx_new
\sa wc_ecc_ctx_reset
*/
int wc_ecc_ctx_set_dev_id(ecEncCtx* ctx, int devId);
/*!
\ingroup ECC
\brief This function reads back the device id set with
wc_ecc_ctx_set_dev_id(). Crypto callback code can use it to learn which
device it was called for. Only available when WOLF_CRYPTO_CB is defined.
A context that was never given a device reads back INVALID_DEVID.
\return 0 Returned upon successfully reading the device id.
\return BAD_FUNC_ARG Returned if the given context or output pointer
is NULL.
\param ctx pointer to the ecEncCtx to read the device id from
\param devId pointer that receives the device id
_Example_
\code
int devId;
if (wc_ecc_ctx_get_dev_id(ctx, &devId) != 0) {
// error reading device id
}
\endcode
\sa wc_ecc_ctx_set_dev_id
\sa wc_ecc_ctx_new
*/
int wc_ecc_ctx_get_dev_id(ecEncCtx* ctx, int* devId);
/*!
\ingroup ECC
@ -2088,8 +2156,13 @@ int wc_ecc_ctx_set_info(ecEncCtx* ctx, const byte* info, int sz);
}
\endcode
\note The device this runs on comes from the context
(wc_ecc_ctx_set_dev_id), not from privKey->devId. A NULL context, or one
that was never given a device, runs in software.
\sa wc_ecc_encrypt_ex
\sa wc_ecc_decrypt
\sa wc_ecc_ctx_set_dev_id
*/
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
@ -2165,8 +2238,13 @@ int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
}
\endcode
\note The device this runs on comes from the context
(wc_ecc_ctx_set_dev_id), not from privKey->devId. A NULL context, or one
that was never given a device, runs in software.
\sa wc_ecc_encrypt
\sa wc_ecc_decrypt
\sa wc_ecc_ctx_set_dev_id
*/
int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
@ -2236,8 +2314,13 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
}
\endcode
\note The device this runs on comes from the context
(wc_ecc_ctx_set_dev_id), not from privKey->devId. A NULL context, or one
that was never given a device, runs in software.
\sa wc_ecc_encrypt
\sa wc_ecc_encrypt_ex
\sa wc_ecc_ctx_set_dev_id
*/
int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,

View File

@ -1680,7 +1680,8 @@ 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,
* wc_ecc_ctx_get_protocol and wc_ecc_ctx_get_rng (built only when
* wc_ecc_ctx_get_protocol, wc_ecc_ctx_get_rng and the
* wc_ecc_ctx_set_dev_id / wc_ecc_ctx_get_dev_id pair (built only when
* WOLF_CRYPTO_CB is enabled).
*/
int test_wc_ecc_ctx_getters(void)
@ -1841,6 +1842,51 @@ int test_wc_ecc_ctx_getters(void)
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
/* devId: the ECIES crypto callback and the AES/HMAC steps both use this,
* so a wrong value here sends the whole operation somewhere else. */
{
int gotDevId = 0;
/* A fresh context is software. ecc_ctx_init() zeroes the struct and
* devId 0 is a real device, so INVALID_DEVID has to be written on
* purpose. A 0 here means it was not. */
gotDevId = 0x5a5a;
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, &gotDevId), 0);
ExpectIntEQ(gotDevId, INVALID_DEVID);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(ctx, 0x1234), 0);
gotDevId = 0;
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, &gotDevId), 0);
ExpectIntEQ(gotDevId, 0x1234);
/* devId 0 is a legal device and must not read back as "unset" */
ExpectIntEQ(wc_ecc_ctx_set_dev_id(ctx, 0), 0);
gotDevId = 0x5a5a;
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, &gotDevId), 0);
ExpectIntEQ(gotDevId, 0);
/* the device is the caller's setting and is kept across a reset */
ExpectIntEQ(wc_ecc_ctx_set_dev_id(ctx, 0x4d43), 0);
ExpectIntEQ(wc_ecc_ctx_reset(ctx, &rng), 0);
gotDevId = 0;
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, &gotDevId), 0);
ExpectIntEQ(gotDevId, 0x4d43);
/* and can be set back to software */
ExpectIntEQ(wc_ecc_ctx_set_dev_id(ctx, INVALID_DEVID), 0);
gotDevId = 0;
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, &gotDevId), 0);
ExpectIntEQ(gotDevId, INVALID_DEVID);
/* bad args: NULL ctx / NULL out-parameter */
ExpectIntEQ(wc_ecc_ctx_set_dev_id(NULL, 0x1234),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_dev_id(NULL, &gotDevId),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_ecc_ctx_get_dev_id(ctx, NULL),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
}
wc_ecc_ctx_free(ctx);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
#endif
@ -2093,6 +2139,7 @@ int test_wc_ecc_ecies_gcm(void)
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
!defined(NO_SHA256) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
@ -2105,27 +2152,47 @@ static int myEciesApiCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
int* invoked = (int*)ctx;
(void)devIdArg;
if (info->algo_type == WC_ALGO_TYPE_PK) {
if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
ecEncCtx* eCtx = info->pk.eciesencrypt.ctx;
int savedDevId = INVALID_DEVID;
if (invoked != NULL)
*invoked = 1;
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
/* ECIES picks its device from the context devId, so clear that,
* not the caller's key, so the call back into wolfSSL stays in
* software. A NULL context is already software-only. */
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
info->pk.eciesencrypt.privKey->devId = devIdArg;
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
ecEncCtx* eCtx = info->pk.eciesdecrypt.ctx;
int savedDevId = INVALID_DEVID;
if (invoked != NULL)
*invoked = 1;
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
}
return ret;
@ -2140,6 +2207,7 @@ int test_wc_ecc_ecies_cryptocb(void)
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
!defined(NO_SHA256) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
@ -2148,6 +2216,11 @@ int test_wc_ecc_ecies_cryptocb(void)
ecc_key cliKey;
ecc_key srvKey;
WC_RNG rng;
ecEncCtx* cliCtx = NULL;
ecEncCtx* srvCtx = NULL;
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt = NULL;
byte msg[32];
byte out[256];
byte plain[64];
@ -2180,12 +2253,28 @@ int test_wc_ecc_ecies_cryptocb(void)
ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0);
ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0);
#endif
/* The keys name the device too, but that no longer picks where ECIES
* runs. The contexts below are what reach the callback. Leaving these
* set shows the two are independent. */
cliKey.devId = cbDevId;
srvKey.devId = cbDevId;
ExpectNotNull(cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng));
ExpectNotNull(srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng));
ExpectIntEQ(wc_ecc_ctx_set_dev_id(cliCtx, cbDevId), 0);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(srvCtx, cbDevId), 0);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx));
if (tmpSalt != NULL)
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx));
if (tmpSalt != NULL)
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt), 0);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt), 0);
cbInvoked = 0;
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
NULL), 0);
cliCtx), 0);
/* callback must have serviced the encrypt */
ExpectIntEQ(cbInvoked, 1);
@ -2194,15 +2283,17 @@ int test_wc_ecc_ecies_cryptocb(void)
* NULL and read the ephemeral key from the message. */
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain, &plainSz,
NULL), 0);
srvCtx), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz,
NULL), 0);
srvCtx), 0);
#endif
ExpectIntEQ(cbInvoked, 1);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
cliKey.devId = INVALID_DEVID;
srvKey.devId = INVALID_DEVID;
wc_ecc_free(&srvKey);
@ -2214,6 +2305,375 @@ int test_wc_ecc_ecies_cryptocb(void)
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_cryptocb */
/*
* ECIES used to take its device from privKey->devId. It now takes it from the
* context only. Both checks below fail silently if this breaks: the call
* still succeeds, it just runs somewhere else.
* 1. a key with a device, and a context with none, runs in software;
* 2. a NULL context is software-only no matter what the key says.
* ECDH is unchanged and still uses the key's device; that is not tested here.
*/
int test_wc_ecc_ecies_devid_not_inherited(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
!defined(NO_SHA256) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
const int cbDevId = 0x45434231; /* 'ECB1' */
ecc_key cliKey;
ecc_key srvKey;
WC_RNG rng;
ecEncCtx* cliCtx = NULL;
ecEncCtx* srvCtx = NULL;
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt = NULL;
byte msg[32];
byte out[256];
byte plain[64];
word32 outSz = (word32)sizeof(out);
word32 plainSz = (word32)sizeof(plain);
int i;
int registered = 0;
int cbInvoked = 0;
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&cliKey, 0, sizeof(cliKey));
XMEMSET(&srvKey, 0, sizeof(srvKey));
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(cbDevId, myEciesApiCryptoCb,
&cbInvoked), 0);
if (EXPECT_SUCCESS())
registered = 1;
ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_ecc_init(&cliKey), 0);
ExpectIntEQ(wc_ecc_init(&srvKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, KEY32, &cliKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, KEY32, &srvKey), 0);
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0);
ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0);
#endif
/* Both keys are bound to the device for the whole test. */
cliKey.devId = cbDevId;
srvKey.devId = cbDevId;
/* (1) contexts given, but no devId set: software, callback never called. */
ExpectNotNull(cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng));
ExpectNotNull(srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng));
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx));
if (tmpSalt != NULL)
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx));
if (tmpSalt != NULL)
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt), 0);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt), 0);
cbInvoked = 0;
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
cliCtx), 0);
ExpectIntEQ(cbInvoked, 0);
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain, &plainSz,
srvCtx), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz,
srvCtx), 0);
#endif
ExpectIntEQ(cbInvoked, 0);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
/* (2) no context at all: still software. */
cbInvoked = 0;
XMEMSET(plain, 0, sizeof(plain));
outSz = (word32)sizeof(out);
plainSz = (word32)sizeof(plain);
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
NULL), 0);
ExpectIntEQ(cbInvoked, 0);
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain, &plainSz,
NULL), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz,
NULL), 0);
#endif
ExpectIntEQ(cbInvoked, 0);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
/* (3) Check: same keys, device now set on the contexts. Without this
* step, (1) and (2) would also pass if the callback were never
* registered at all. */
ExpectIntEQ(wc_ecc_ctx_reset(cliCtx, &rng), 0);
ExpectIntEQ(wc_ecc_ctx_reset(srvCtx, &rng), 0);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(cliCtx, cbDevId), 0);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(srvCtx, cbDevId), 0);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx));
if (tmpSalt != NULL)
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx));
if (tmpSalt != NULL)
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt), 0);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt), 0);
cbInvoked = 0;
outSz = (word32)sizeof(out);
plainSz = (word32)sizeof(plain);
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg), out, &outSz,
cliCtx), 0);
ExpectIntEQ(cbInvoked, 1);
cbInvoked = 0;
XMEMSET(plain, 0, sizeof(plain));
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain, &plainSz,
srvCtx), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain, &plainSz,
srvCtx), 0);
#endif
ExpectIntEQ(cbInvoked, 1);
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
cliKey.devId = INVALID_DEVID;
srvKey.devId = INVALID_DEVID;
wc_ecc_free(&srvKey);
wc_ecc_free(&cliKey);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
if (registered)
wc_CryptoCb_UnRegisterDevice(cbDevId);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_devid_not_inherited */
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
!defined(NO_SHA256) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
/* Counts how often a device is asked to do a KDF, cipher or HMAC step. It
* always says no, so each step then runs in software. */
typedef struct EciesStepCount {
int kdf;
int cipher;
int hmac;
int kdfHandle; /* do the HKDF here instead of turning it down */
} EciesStepCount;
static int myEciesStepCountCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
EciesStepCount* cnt = (EciesStepCount*)ctx;
(void)devIdArg;
if (cnt != NULL) {
if (info->algo_type == WC_ALGO_TYPE_KDF) {
cnt->kdf++;
if (cnt->kdfHandle && info->kdf.type == WC_KDF_TYPE_HKDF) {
return wc_HKDF(info->kdf.hkdf.hashType, info->kdf.hkdf.inKey,
info->kdf.hkdf.inKeySz, info->kdf.hkdf.salt,
info->kdf.hkdf.saltSz, info->kdf.hkdf.info,
info->kdf.hkdf.infoSz, info->kdf.hkdf.out,
info->kdf.hkdf.outSz);
}
}
else if (info->algo_type == WC_ALGO_TYPE_CIPHER)
cnt->cipher++;
else if (info->algo_type == WC_ALGO_TYPE_HMAC)
cnt->hmac++;
}
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
}
#endif
/*
* The software ECIES path hands the context devId to its KDF, cipher and MAC
* steps. The other ECIES tests never see this: their callbacks take the whole
* job and clear the devId. Here the callback turns down the whole job but
* counts the KDF, cipher and HMAC steps. Three modes per direction:
* 0 no device: every count stays at zero;
* 1 the device turns the KDF down: the software HKDF then runs with the
* same device, so its own HMAC calls reach the callback as well;
* 2 the device does the KDF: the only HMAC calls left are the ECIES MAC,
* which GCM does not have.
* Both HKDF hashes run.
*/
int test_wc_ecc_ecies_ctx_devid_steps(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_ENCRYPT) && !defined(WC_NO_RNG) && \
defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC) && \
!defined(NO_SHA256) && \
(defined(HAVE_AES_CBC) || \
(defined(HAVE_AESGCM) && (defined(WOLFSSL_ECIES_GEN_IV) || \
defined(WOLFSSL_ECIES_OLD) || \
defined(WOLFSSL_ECIES_STATIC_GCM_NONCE)))) && defined(WOLFSSL_AES_128)
const int cbDevId = 0x45434232; /* 'ECB2' */
const byte kdfAlgos[] = {
ecHKDF_SHA256,
#ifndef NO_SHA
ecHKDF_SHA1,
#endif
};
EciesStepCount cnt;
ecc_key cliKey;
ecc_key srvKey;
WC_RNG rng;
ecEncCtx* cliCtx = NULL;
ecEncCtx* srvCtx = NULL;
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt = NULL;
byte encAlgo = 0;
byte macAlgo = 0;
byte msg[32];
byte out[256];
byte plain[64];
word32 outSz;
word32 plainSz;
int i;
int k;
int mode;
int useDev;
int isGcm = 0;
int registered = 0;
XMEMSET(&cnt, 0, sizeof(cnt));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&cliKey, 0, sizeof(cliKey));
XMEMSET(&srvKey, 0, sizeof(srvKey));
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = (byte)i;
ExpectIntEQ(wc_CryptoCb_RegisterDevice(cbDevId, myEciesStepCountCb,
&cnt), 0);
if (EXPECT_SUCCESS())
registered = 1;
ExpectIntEQ(wc_InitRng(&rng), 0);
/* Keys stay in software so only the context can reach the device. */
ExpectIntEQ(wc_ecc_init(&cliKey), 0);
ExpectIntEQ(wc_ecc_init(&srvKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, KEY32, &cliKey), 0);
ExpectIntEQ(wc_ecc_make_key(&rng, KEY32, &srvKey), 0);
#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
(!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
!defined(HAVE_SELFTEST)
ExpectIntEQ(wc_ecc_set_rng(&cliKey, &rng), 0);
ExpectIntEQ(wc_ecc_set_rng(&srvKey, &rng), 0);
#endif
ExpectNotNull(cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng));
ExpectNotNull(srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng));
/* keep the build's default cipher and MAC, only the KDF changes below */
ExpectIntEQ(wc_ecc_ctx_get_algo(cliCtx, &encAlgo, NULL, &macAlgo), 0);
#ifdef HAVE_AESGCM
/* GCM authenticates on its own, so ECIES skips the HMAC step for it. */
isGcm = (encAlgo == ecAES_128_GCM || encAlgo == ecAES_256_GCM);
#endif
for (k = 0; k < (int)sizeof(kdfAlgos) && EXPECT_SUCCESS(); k++) {
for (mode = 2; mode >= 0 && EXPECT_SUCCESS(); mode--) {
useDev = (mode != 0);
/* a context is single use, so start each message fresh */
ExpectIntEQ(wc_ecc_ctx_reset(cliCtx, &rng), 0);
ExpectIntEQ(wc_ecc_ctx_reset(srvCtx, &rng), 0);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(cliCtx,
useDev ? cbDevId : INVALID_DEVID), 0);
ExpectIntEQ(wc_ecc_ctx_set_dev_id(srvCtx,
useDev ? cbDevId : INVALID_DEVID), 0);
ExpectIntEQ(wc_ecc_ctx_set_algo(cliCtx, encAlgo, kdfAlgos[k],
macAlgo), 0);
ExpectIntEQ(wc_ecc_ctx_set_algo(srvCtx, encAlgo, kdfAlgos[k],
macAlgo), 0);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx));
if (tmpSalt != NULL)
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectNotNull(tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx));
if (tmpSalt != NULL)
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt), 0);
ExpectIntEQ(wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt), 0);
XMEMSET(plain, 0, sizeof(plain));
outSz = (word32)sizeof(out);
plainSz = (word32)sizeof(plain);
/* Count each direction on its own so neither can hide the other. */
XMEMSET(&cnt, 0, sizeof(cnt));
cnt.kdfHandle = (mode == 2);
ExpectIntEQ(wc_ecc_encrypt(&cliKey, &srvKey, msg, sizeof(msg),
out, &outSz, cliCtx), 0);
if (useDev) {
ExpectIntGT(cnt.kdf, 0);
ExpectIntGT(cnt.cipher, 0);
}
else {
ExpectIntEQ(cnt.kdf, 0);
ExpectIntEQ(cnt.cipher, 0);
}
if (mode == 1 || (mode == 2 && !isGcm)) {
ExpectIntGT(cnt.hmac, 0);
}
else {
ExpectIntEQ(cnt.hmac, 0);
}
XMEMSET(&cnt, 0, sizeof(cnt));
cnt.kdfHandle = (mode == 2);
#ifdef WOLFSSL_ECIES_OLD
ExpectIntEQ(wc_ecc_decrypt(&srvKey, &cliKey, out, outSz, plain,
&plainSz, srvCtx), 0);
#else
ExpectIntEQ(wc_ecc_decrypt(&srvKey, NULL, out, outSz, plain,
&plainSz, srvCtx), 0);
#endif
ExpectIntEQ(plainSz, sizeof(msg));
ExpectIntEQ(XMEMCMP(plain, msg, sizeof(msg)), 0);
if (useDev) {
ExpectIntGT(cnt.kdf, 0);
ExpectIntGT(cnt.cipher, 0);
}
else {
ExpectIntEQ(cnt.kdf, 0);
ExpectIntEQ(cnt.cipher, 0);
}
if (mode == 1 || (mode == 2 && !isGcm)) {
ExpectIntGT(cnt.hmac, 0);
}
else {
ExpectIntEQ(cnt.hmac, 0);
}
}
}
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
wc_ecc_free(&srvKey);
wc_ecc_free(&cliKey);
DoExpectIntEQ(wc_FreeRng(&rng), 0);
if (registered)
wc_CryptoCb_UnRegisterDevice(cbDevId);
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_ecies_ctx_devid_steps */
/*
* The ECIES AES-GCM DEM needs an RNG only in GEN_IV mode, where it generates a
* random per-message nonce (default mode uses a fixed nonce and OLD derives it

View File

@ -59,6 +59,8 @@ int test_wc_ecc_encryptDecrypt(void);
int test_wc_ecc_ecies_gcm(void);
int test_wc_ecc_ecies_gcm_no_rng(void);
int test_wc_ecc_ecies_cryptocb(void);
int test_wc_ecc_ecies_devid_not_inherited(void);
int test_wc_ecc_ecies_ctx_devid_steps(void);
int test_wc_ecc_del_point(void);
int test_wc_ecc_pointFns(void);
int test_wc_ecc_shared_secret_ssh(void);
@ -109,6 +111,8 @@ int test_wc_EccDecisionCoverage4(void);
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_gcm_no_rng), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_cryptocb), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_devid_not_inherited), \
TEST_DECL_GROUP("ecc", test_wc_ecc_ecies_ctx_devid_steps), \
TEST_DECL_GROUP("ecc", test_wc_ecc_del_point), \
TEST_DECL_GROUP("ecc", test_wc_ecc_pointFns), \
TEST_DECL_GROUP("ecc", test_wc_ecc_shared_secret_ssh), \

View File

@ -1063,38 +1063,40 @@ int main(void)
#endif
/* ---- ECIES encrypt/decrypt dispatch (HAVE_ECC_ENCRYPT) ----
* Both bodies resolve their device from privKey->devId and then take the
* Both bodies get their device from the devId parameter (the caller reads
* it off the ECIES context, not off privKey->devId) and then take the
* usual `if (dev && dev->cb)` guard, so the standard three-vector sweep
* applies. Nothing but privKey->devId is read before the guard, and the
* registered callback (wb_cb) ignores the wc_CryptoInfo it is handed and
* reports CRYPTOCB_UNAVAILABLE, so a zeroed ecc_key with no key material
* is sufficient and safe here -- no curve arithmetic runs. */
* works on a plain local devId. Nothing but that parameter is read before
* the guard, and the registered callback (wb_cb) ignores the wc_CryptoInfo
* it is handed and reports CRYPTOCB_UNAVAILABLE, so a zeroed ecc_key with
* no key material is enough and safe here -- no curve math runs. */
#ifdef HAVE_ECC_ENCRYPT
{
ecc_key ecPriv;
byte eciesMsg[16];
byte eciesOut[128];
word32 eciesOutSz;
int eciesDevId = INVALID_DEVID;
XMEMSET(&ecPriv, 0, sizeof(ecPriv));
XMEMSET(eciesMsg, 0x5e, sizeof(eciesMsg));
XMEMSET(eciesOut, 0, sizeof(eciesOut));
eciesOutSz = (word32)sizeof(eciesOut);
WB_DRIVE3(ecPriv.devId,
wc_CryptoCb_EciesEncrypt(&ecPriv, NULL, eciesMsg,
WB_DRIVE3(eciesDevId,
wc_CryptoCb_EciesEncrypt(eciesDevId, &ecPriv, NULL, eciesMsg,
(word32)sizeof(eciesMsg), eciesOut, &eciesOutSz, NULL, 0));
eciesOutSz = (word32)sizeof(eciesOut);
WB_DRIVE3(ecPriv.devId,
wc_CryptoCb_EciesDecrypt(&ecPriv, NULL, eciesMsg,
WB_DRIVE3(eciesDevId,
wc_CryptoCb_EciesDecrypt(eciesDevId, &ecPriv, NULL, eciesMsg,
(word32)sizeof(eciesMsg), eciesOut, &eciesOutSz, NULL));
/* privKey == NULL early return (both entry points). */
eciesOutSz = (word32)sizeof(eciesOut);
(void)wc_CryptoCb_EciesEncrypt(NULL, NULL, eciesMsg,
(void)wc_CryptoCb_EciesEncrypt(INVALID_DEVID, NULL, NULL, eciesMsg,
(word32)sizeof(eciesMsg), eciesOut, &eciesOutSz, NULL, 0);
(void)wc_CryptoCb_EciesDecrypt(NULL, NULL, eciesMsg,
(void)wc_CryptoCb_EciesDecrypt(INVALID_DEVID, NULL, NULL, eciesMsg,
(word32)sizeof(eciesMsg), eciesOut, &eciesOutSz, NULL);
WB_NOTE("ECIES Encrypt/Decrypt dev&&dev->cb three-vector driven");

View File

@ -15091,6 +15091,22 @@ static void bench_eccEncryptEx(int useDeviceID, int curveId, int ctxMode)
goto exit;
}
#ifdef WOLF_CRYPTO_CB
/* ECIES picks its device from the context, not the keys. Without
* this the -dev rows would time software but be labeled as device
* rows. bench_ecies_prep() resets the contexts each round, and a
* reset keeps the devId. */
if (useDeviceID) {
if (wc_ecc_ctx_set_dev_id(cliCtx, devId) != 0 ||
wc_ecc_ctx_set_dev_id(srvCtx, devId) != 0) {
printf("bench_eccEncrypt ctx set dev id failed\n");
wc_ecc_ctx_free(cliCtx);
wc_ecc_ctx_free(srvCtx);
goto exit;
}
}
#endif
for (c = 0; eciesCiphers[c].label != NULL; c++) {
byte algo = eciesCiphers[c].algo;
/* Tag the KDF rows so they do not read as the default ones. */

View File

@ -1169,7 +1169,7 @@ int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder, int checkPriv)
#endif /* HAVE_ECC_CHECK_KEY */
#ifdef HAVE_ECC_ENCRYPT
int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
int wc_CryptoCb_EciesEncrypt(int devId, ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx,
int compressed)
{
@ -1179,8 +1179,9 @@ int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
if (privKey == NULL)
return ret;
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(privKey->devId, WC_ALGO_TYPE_PK);
/* find the registered callback. The device comes from the ECIES
* context, not from privKey->devId. */
dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
@ -1201,7 +1202,7 @@ int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_EciesDecrypt(ecc_key* privKey, ecc_key* pubKey,
int wc_CryptoCb_EciesDecrypt(int devId, ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
@ -1210,8 +1211,9 @@ int wc_CryptoCb_EciesDecrypt(ecc_key* privKey, ecc_key* pubKey,
if (privKey == NULL)
return ret;
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(privKey->devId, WC_ALGO_TYPE_PK);
/* find the registered callback. The device comes from the ECIES
* context, not from privKey->devId. */
dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));

View File

@ -15097,6 +15097,11 @@ struct ecEncCtx {
word32 kdfSaltSz; /* size of kdfSalt */
word32 kdfInfoSz; /* size of kdfInfo */
word32 macSaltSz; /* size of macSalt */
#ifdef WOLF_CRYPTO_CB
/* Device for ECIES. Not copied from the ECC key: unset means software,
* or the WOLF_CRYPTO_CB_FIND finder, even if the key has a device. */
int devId;
#endif
void* heap; /* heap hint for memory used */
byte clientSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */
byte serverSalt[EXCHANGE_SALT_SZ]; /* for msg exchange */
@ -15199,6 +15204,30 @@ int wc_ecc_ctx_get_rng(ecEncCtx* ctx, WC_RNG** rng)
return 0;
}
/* Pick the device that ECIES uses; it is never copied from the ECC key. Unset
* means software, or the WOLF_CRYPTO_CB_FIND finder. Kept across ctx reset. */
int wc_ecc_ctx_set_dev_id(ecEncCtx* ctx, int devId)
{
if (ctx == NULL)
return BAD_FUNC_ARG;
ctx->devId = devId;
return 0;
}
/* Read back the device set above. Callback code can use this to learn
* which device it was called for. */
int wc_ecc_ctx_get_dev_id(ecEncCtx* ctx, int* devId)
{
if (ctx == NULL || devId == NULL)
return BAD_FUNC_ARG;
*devId = ctx->devId;
return 0;
}
#endif /* WOLF_CRYPTO_CB */
@ -15408,6 +15437,12 @@ static void ecc_ctx_init(ecEncCtx* ctx, int flags, WC_RNG* rng)
ctx->macAlgo = ecHMAC_SHA256;
ctx->protocol = (byte)flags;
ctx->rng = rng;
#ifdef WOLF_CRYPTO_CB
/* The XMEMSET above leaves this at 0, and 0 is a real devId. Start
* in software; the caller picks a device with
* wc_ecc_ctx_set_dev_id(). */
ctx->devId = INVALID_DEVID;
#endif
if (flags == REQ_RESP_CLIENT)
ctx->cliSt = ecCLI_INIT;
@ -15422,15 +15457,25 @@ WOLFSSL_ABI
int wc_ecc_ctx_reset(ecEncCtx* ctx, WC_RNG* rng)
{
void* heap;
#ifdef WOLF_CRYPTO_CB
int devId;
#endif
if (ctx == NULL || rng == NULL)
return BAD_FUNC_ARG;
/* ecc_ctx_init clears the whole context, so carry the heap hint over it.
* The context has to be freed to the heap it was allocated from. */
* The context has to be freed to the heap it was allocated from. Keep
* the device too: reset means "reuse this context", so it must stay. */
heap = ctx->heap;
#ifdef WOLF_CRYPTO_CB
devId = ctx->devId;
#endif
ecc_ctx_init(ctx, ctx->protocol, rng);
ctx->heap = heap;
#ifdef WOLF_CRYPTO_CB
ctx->devId = devId;
#endif
return ecc_ctx_set_salt(ctx, ctx->protocol);
}
@ -15445,6 +15490,11 @@ ecEncCtx* wc_ecc_ctx_new_ex(int flags, WC_RNG* rng, void* heap)
if (ctx) {
ctx->protocol = (byte)flags;
ctx->heap = heap;
#ifdef WOLF_CRYPTO_CB
/* wc_ecc_ctx_reset() below keeps devId across ecc_ctx_init(), so it
* needs a real value first. This memory starts out uninitialized. */
ctx->devId = INVALID_DEVID;
#endif
}
ret = wc_ecc_ctx_reset(ctx, rng);
@ -15674,21 +15724,22 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
byte* encKey = NULL;
byte* encIv = NULL;
byte* macKey = NULL;
/* devId to hand the DEM AES/HMAC primitives; ecc_key only carries a devId
* field with PLUTON_CRYPTO_ECC or WOLF_CRYPTO_CB, so default to INVALID. */
/* Device for the ECIES callback and the KDF/AES/HMAC steps. It comes
* only from the context; unset means software, or the CB_FIND finder. */
int eciesDevId = INVALID_DEVID;
if (privKey == NULL || pubKey == NULL || msg == NULL || out == NULL ||
outSz == NULL)
return BAD_FUNC_ARG;
#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB)
eciesDevId = privKey->devId;
#endif
#ifdef WOLF_CRYPTO_CB
/* Read this before ctx is swapped for the local default below. A NULL
* context has no device and stays INVALID_DEVID. */
if (ctx != NULL)
eciesDevId = ctx->devId;
#ifndef WOLF_CRYPTO_CB_FIND
if (privKey->devId != INVALID_DEVID)
if (eciesDevId != INVALID_DEVID)
#endif
{
/* Snapshot single-use state so we can tell whether the callback handled
@ -15696,8 +15747,8 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
* (which advances the state itself, below). */
byte cliStBefore = (ctx != NULL) ? ctx->cliSt : 0;
byte srvStBefore = (ctx != NULL) ? ctx->srvSt : 0;
ret = wc_CryptoCb_EciesEncrypt(privKey, pubKey, msg, msgSz, out, outSz,
ctx, compressed);
ret = wc_CryptoCb_EciesEncrypt(eciesDevId, privKey, pubKey, msg, msgSz,
out, outSz, ctx, compressed);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
/* Pure-hardware service left the state alone; enforce single-use
* here so the ctx can't be reused (nonce reuse for static-nonce
@ -15822,15 +15873,19 @@ int wc_ecc_encrypt_ex(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
sharedSz += pubKeySz;
#endif
switch (ctx->kdfAlgo) {
/* Use the _ex form so the KDF runs on the context's device, like
* the cipher and MAC do. wc_HKDF() would always use software.
* wc_X963_KDF() below takes no device, so it stays in software. */
case ecHKDF_SHA256 :
ret = wc_HKDF(WC_SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
keys, (word32)keysLen);
ret = wc_HKDF_ex(WC_SHA256, sharedSecret, sharedSz,
ctx->kdfSalt, ctx->kdfSaltSz, ctx->kdfInfo,
ctx->kdfInfoSz, keys, (word32)keysLen,
privKey->heap, eciesDevId);
break;
case ecHKDF_SHA1 :
ret = wc_HKDF(WC_SHA, sharedSecret, sharedSz, ctx->kdfSalt,
ret = wc_HKDF_ex(WC_SHA, sharedSecret, sharedSz, ctx->kdfSalt,
ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
keys, (word32)keysLen);
keys, (word32)keysLen, privKey->heap, eciesDevId);
break;
#if defined(HAVE_X963_KDF) && !defined(NO_HASH_WRAPPER)
case ecKDF_X963_SHA1 :
@ -16127,8 +16182,8 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
byte* encKey = NULL;
const byte* encIv = NULL;
byte* macKey = NULL;
/* devId to hand the DEM AES/HMAC primitives; ecc_key only carries a devId
* field with PLUTON_CRYPTO_ECC or WOLF_CRYPTO_CB, so default to INVALID. */
/* Device for the ECIES callback and the KDF/AES/HMAC steps. It comes
* only from the context; unset means software, or the CB_FIND finder. */
int eciesDevId = INVALID_DEVID;
@ -16139,13 +16194,14 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
return BAD_FUNC_ARG;
#endif
#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB)
eciesDevId = privKey->devId;
#endif
#ifdef WOLF_CRYPTO_CB
/* Read this before ctx is swapped for the local default below. A NULL
* context has no device and stays INVALID_DEVID. */
if (ctx != NULL)
eciesDevId = ctx->devId;
#ifndef WOLF_CRYPTO_CB_FIND
if (privKey->devId != INVALID_DEVID)
if (eciesDevId != INVALID_DEVID)
#endif
{
/* Snapshot single-use state so we can tell whether the callback handled
@ -16153,8 +16209,8 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
* (which advances the state itself, below). */
byte cliStBefore = (ctx != NULL) ? ctx->cliSt : 0;
byte srvStBefore = (ctx != NULL) ? ctx->srvSt : 0;
ret = wc_CryptoCb_EciesDecrypt(privKey, pubKey, msg, msgSz, out, outSz,
ctx);
ret = wc_CryptoCb_EciesDecrypt(eciesDevId, privKey, pubKey, msg, msgSz,
out, outSz, ctx);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
/* Pure-hardware service left the state alone; enforce single-use
* here. A re-entrant software callback already advanced it. */
@ -16335,15 +16391,19 @@ int wc_ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
sharedSz += pubKeySz;
#endif
switch (ctx->kdfAlgo) {
/* Use the _ex form so the KDF runs on the context's device, like
* the cipher and MAC do. wc_HKDF() would always use software.
* wc_X963_KDF() below takes no device, so it stays in software. */
case ecHKDF_SHA256 :
ret = wc_HKDF(WC_SHA256, sharedSecret, sharedSz, ctx->kdfSalt,
ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
keys, (word32)keysLen);
ret = wc_HKDF_ex(WC_SHA256, sharedSecret, sharedSz,
ctx->kdfSalt, ctx->kdfSaltSz, ctx->kdfInfo,
ctx->kdfInfoSz, keys, (word32)keysLen,
privKey->heap, eciesDevId);
break;
case ecHKDF_SHA1 :
ret = wc_HKDF(WC_SHA, sharedSecret, sharedSz, ctx->kdfSalt,
ret = wc_HKDF_ex(WC_SHA, sharedSecret, sharedSz, ctx->kdfSalt,
ctx->kdfSaltSz, ctx->kdfInfo, ctx->kdfInfoSz,
keys, (word32)keysLen);
keys, (word32)keysLen, privKey->heap, eciesDevId);
break;
#if defined(HAVE_X963_KDF) && !defined(NO_HASH_WRAPPER)
case ecKDF_X963_SHA1 :

View File

@ -13,13 +13,17 @@ Define this in `user_settings.h`:
#define WOLFSSL_VERSAL_GEN2_ASU
```
That is the whole setup. `wolfCrypt_Init()` registers the device and brings the
ASU client up, so an application needs no ASU calls of its own:
That is the whole setup for everything except ECIES. `wolfCrypt_Init()`
registers the device and brings the ASU client up, so an application needs no
ASU calls of its own:
```c
ret = wolfCrypt_Init(); /* opens the mailbox, calls XAsu_ClientInit */
```
ECIES is the one exception: it uses its own context's device id, which the
application has to set. See "What ECIES needs to reach the ASU" below.
The BSP must have the `xilasu` and `xilmailbox` libraries enabled.
## What runs on hardware
@ -35,7 +39,7 @@ The BSP must have the `xilasu` and `xilmailbox` libraries enabled.
| EdDSA | plain Ed25519 and Ed448 sign and verify |
| ECDH | the same curves as ECDSA |
| X25519 / X448 | key agreement, Vitis 2026.1 and later |
| ECIES | AES-GCM with HKDF-SHA256 |
| ECIES | AES-GCM with HKDF-SHA256; needs a context device id, see below |
| TRNG | seed and random block |
Anything outside this list is declined and wolfSSL runs it in software. That
@ -81,7 +85,9 @@ Other switches:
The port sets `WOLF_CRYPTO_CB`, `WOLF_CRYPTO_CB_CMD`, `WOLF_CRYPTO_CB_COPY` and
`WOLF_CRYPTO_CB_FREE` for you, and points `WC_USE_DEVID` at the ASU device so
the unmodified wolfCrypt test and benchmark route through it.
the unmodified wolfCrypt test and benchmark route through it. `WC_USE_DEVID`
lands on keys and crypto objects at init; ECIES does not read it from there, so
the test and benchmark hand it to each ECIES context themselves.
## Which Vitis release
@ -130,6 +136,11 @@ declines to software however long the message is. Build the benchmark with
`AES_AUTH_ADD_SZ` set to 16 to keep those rows on hardware; wolfSSL already
does that for the first-generation Versal port for the same reason.
**ECIES needs its own device id on the context.** A device id on the ECC key
does not count for ECIES; without `wc_ecc_ctx_set_dev_id` it runs in software
and gives no warning (with `WOLF_CRYPTO_CB_FIND` the finder still applies). See
below.
**ECIES needs the KDF context path.** See below.
**ECIES needs `WOLFSSL_ECIES_GEN_IV`, and only offloads one direction.** See
@ -146,6 +157,9 @@ Use `wc_ecc_ctx_set_kdf_salt`, not `wc_ecc_ctx_set_peer_salt`:
```c
ecEncCtx* ctx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
/* Required: ECIES uses the context's device, not the key's. */
wc_ecc_ctx_set_dev_id(ctx, WOLFSSL_VERSAL_GEN2_ASU_DEVID);
wc_ecc_ctx_set_algo(ctx, ecAES_256_GCM, ecHKDF_SHA256, ecHMAC_SHA256);
wc_ecc_ctx_set_kdf_salt(ctx, salt, saltSz);
wc_ecc_ctx_set_info(ctx, info, infoSz);
@ -159,12 +173,14 @@ context bytes, then calls `wc_ecc_decrypt`.
The wolfCrypt benchmark keys ECIES the other way by default, so its ECIES rows
run in software. Build the benchmark with `WC_BENCH_ECIES_KDF` to add a second
set of rows, tagged `-kdf`, that use the context shown above and reach the ASU.
The benchmark sets the context device id itself on its `-dev` rows.
What the offload requires:
| Setting | Value |
| --- | --- |
| Build | `WOLFSSL_ECIES_GEN_IV`, with neither `WOLFSSL_ECIES_OLD` nor `WOLFSSL_ECIES_ISO18033` |
| Device | `wc_ecc_ctx_set_dev_id` on the context; the key's devId is not used |
| 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 |
@ -179,8 +195,28 @@ authenticated data, which the ASU cannot accept, so the port declines and
wolfSSL runs ECIES in software. There is no way around this from the port.
Declining is not the same as running with no hardware. The software ECIES path
still passes the device id to the AES and HMAC underneath, so those operations
go to the ASU one at a time. Only the single-command ECIES is lost.
still passes the context's device id to the AES and to the MAC HMAC underneath,
so those operations go to the ASU one at a time. Only the single-command ECIES
is lost.
It helps to be exact about which pieces reach the ASU on that path, because
they use two different device ids:
| Stage | Uses | On the ASU? |
| --- | --- | --- |
| ECDH shared secret | the key's devId | yes, via `asu_ecdh.c` |
| HKDF-SHA256 KDF | the context devId | yes, via `asu_hmac.c` |
| AES-GCM / AES-CBC DEM | the context devId | yes, via `asu_cipher.c` |
| MAC HMAC | the context devId | yes, via `asu_hmac.c` |
All four need their device id set to reach the ASU, and the first one uses a
different id from the other three. So a context with no device id does not
mean "no hardware": the ECDH still lands on the ASU whenever the key carries
the device id, while the KDF, cipher and MAC fall back to software.
The X9.63 and plain-hash KDFs are the exception -- `wc_X963_KDF()` takes no
device id, so `ecKDF_X963_*` and `ecKDF_*` stay in software whatever is set.
The ASU path uses HKDF-SHA256, so this does not affect it.
**The private key passed to encrypt is not used.** `wc_ecc_encrypt` takes a
private key, and software derives the shared secret from it and puts its public
@ -193,7 +229,14 @@ supply.
## What ECIES needs to reach the ASU
Two things on top of the table above.
Three things on top of the table above.
**The context must carry the device id.** `wc_ecc_ctx_set_dev_id(ctx,
WOLFSSL_VERSAL_GEN2_ASU_DEVID)`, on every context, in both directions. ECIES
takes its device from the context and never from the ECC key, so a key opened
with `wc_ecc_init_ex(&key, heap, WOLFSSL_VERSAL_GEN2_ASU_DEVID)` is not enough
on its own. Miss it and ECIES still works, in software, with no warning,
unless a `WOLF_CRYPTO_CB_FIND` finder routes it to a device.
**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

View File

@ -47473,6 +47473,22 @@ done:
#if defined(HAVE_ECC_ENCRYPT) && defined(HAVE_AES_CBC) && \
(defined(WOLFSSL_AES_128) || defined(WOLFSSL_AES_256))
/* ECIES takes its device from the context, not from the keys, so each context
* has to be told which device to use. These tests build their keys with the
* global devId, which is a real device on ports that set WC_USE_DEVID or
* WOLFSSL_CAAM_DEVID. Without this the tests below would quietly run in
* software there and never touch the hardware path. Defined outside the
* guards below so every ECIES test in this file can use it. */
#ifdef WOLF_CRYPTO_CB
static wc_test_ret_t ecc_ctx_apply_devid(ecEncCtx* ctx)
{
int ret = wc_ecc_ctx_set_dev_id(ctx, devId);
return (ret == 0) ? 0 : WC_TEST_RET_ENC_EC(ret);
}
#else
#define ecc_ctx_apply_devid(ctx) (0)
#endif
#if !defined(WOLFSSL_NO_MALLOC)
#if ((! defined(HAVE_FIPS)) || FIPS_VERSION_GE(5,3))
@ -47551,6 +47567,11 @@ static wc_test_ret_t ecc_ctx_kdf_salt_test(WC_RNG* rng, ecc_key* a, ecc_key* b)
ret = WC_TEST_RET_ENC_NC;
}
if (ret == 0)
ret = ecc_ctx_apply_devid(aCtx);
if (ret == 0)
ret = ecc_ctx_apply_devid(bCtx);
/* set salt */
if (ret == 0) {
ret = wc_ecc_ctx_set_kdf_salt(aCtx, salt, sizeof(salt));
@ -47907,7 +47928,10 @@ static wc_test_ret_t ecc_encrypt_e2e_test(WC_RNG* rng, ecc_key* userA, ecc_key*
for (i = 0; i < (int)sizeof(msg); i++)
msg[i] = i;
/* encrypt msg to B */
/* encrypt msg to B. The NULL-context calls here and below run in software
* on purpose: ECIES takes its device from the context, so with no context
* there is nowhere to name one. The context-based exchange further down
* covers the device path. */
ret = wc_ecc_encrypt(userA, userB, msg, sizeof(msg), out, &outSz, NULL);
if (ret != 0) {
ret = WC_TEST_RET_ENC_EC(ret); goto done;
@ -47950,6 +47974,12 @@ static wc_test_ret_t ecc_encrypt_e2e_test(WC_RNG* rng, ecc_key* userA, ecc_key*
ret = WC_TEST_RET_ENC_ERRNO; goto done;
}
ret = ecc_ctx_apply_devid(cliCtx);
if (ret == 0)
ret = ecc_ctx_apply_devid(srvCtx);
if (ret != 0)
goto done;
ret = wc_ecc_ctx_set_algo(cliCtx, encAlgo, kdfAlgo, macAlgo);
if (ret != 0)
goto done;
@ -48046,6 +48076,12 @@ static wc_test_ret_t ecc_encrypt_e2e_test(WC_RNG* rng, ecc_key* userA, ecc_key*
ret = WC_TEST_RET_ENC_ERRNO; goto done;
}
ret = ecc_ctx_apply_devid(cliCtx);
if (ret == 0)
ret = ecc_ctx_apply_devid(srvCtx);
if (ret != 0)
goto done;
ret = wc_ecc_ctx_set_algo(cliCtx, encAlgo, kdfAlgo, macAlgo);
if (ret != 0)
goto done;
@ -48088,7 +48124,14 @@ static wc_test_ret_t ecc_encrypt_e2e_test(WC_RNG* rng, ecc_key* userA, ecc_key*
if (ret != 0)
goto done;
#ifndef WOLFSSL_ECIES_OLD
#ifdef WOLFSSL_ECIES_OLD
/* tmpKey still holds B's public key from the reply above. */
tmpKey->dp = userA->dp;
ret = wc_ecc_copy_point(&userA->pubkey, &tmpKey->pubkey);
if (ret != 0) {
ret = WC_TEST_RET_ENC_EC(ret); goto done;
}
#else
wc_ecc_free(tmpKey);
#endif
/* B decrypts msg (request) from A - out has a compressed public key */
@ -48325,6 +48368,8 @@ static wc_test_ret_t ecc_encrypt_gcm_kat_vec(WC_RNG* rng, byte encAlgo,
srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, rng);
if (srvCtx == NULL) { ret = WC_TEST_RET_ENC_ERRNO; break; }
ret = ecc_ctx_apply_devid(srvCtx);
if (ret != 0) break;
ret = wc_ecc_ctx_set_algo(srvCtx, encAlgo, kdfAlgo, ecHMAC_SHA256);
if (ret == 0) {
/* force our fixed own salt, then set the peer's fixed salt */
@ -48480,9 +48525,10 @@ static wc_test_ret_t ecc_encrypt_gcm_kat(WC_RNG* rng)
#endif /* GCM KAT guards */
#if defined(WOLF_CRYPTO_CB) && !defined(WOLFSSL_NO_MALLOC)
/* Minimal ECIES CryptoCb: with mode==1 it services the operation (forwarding to
* software after clearing devId) and records that it was invoked; with mode==0
* it returns CRYPTOCB_UNAVAILABLE so ECIES falls back to software. */
/* Minimal ECIES CryptoCb: with mode==1 it handles the operation (by calling
* software after clearing the context devId) and records that it was called;
* with mode==0 it returns CRYPTOCB_UNAVAILABLE so ECIES falls back to
* software. */
typedef struct EciesCbCtx {
int mode; /* 0 = force fallback, 1 = handle in callback */
int encryptInvoked; /* set when the callback services an ECIES encrypt */
@ -48499,8 +48545,13 @@ static int myEciesCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
EciesCbCtx* cbCtx = (EciesCbCtx*)ctx;
(void)devIdArg;
if (info->algo_type == WC_ALGO_TYPE_PK) {
if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
ecEncCtx* eCtx = info->pk.eciesencrypt.ctx;
int savedDevId = INVALID_DEVID;
if (cbCtx->mode == 0)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
cbCtx->encryptInvoked = 1;
@ -48517,24 +48568,38 @@ static int myEciesCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
*info->pk.eciesencrypt.outSz = needed;
return 0;
}
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
/* ECIES picks its device from the context devId, so clear that,
* not the caller's key, so the call back into wolfSSL stays in
* software. A NULL context is already software-only. */
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
info->pk.eciesencrypt.privKey->devId = devIdArg;
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
ecEncCtx* eCtx = info->pk.eciesdecrypt.ctx;
int savedDevId = INVALID_DEVID;
if (cbCtx->mode == 0)
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
cbCtx->decryptInvoked = 1;
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
}
@ -48610,6 +48675,13 @@ static wc_test_ret_t ecies_cryptocb_roundtrip(WC_RNG* rng, EciesCbCtx* cbCtx,
ret = wc_ecc_ctx_set_algo(srvCtx, encAlgo, ecHKDF_SHA256, ecHMAC_SHA256);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
/* ECIES picks its device from the context devId, not the key's, so the
* device has to be set here or the callback is never reached. */
ret = wc_ecc_ctx_set_dev_id(cliCtx, ECIES_CB_TEST_DEVID);
if (ret == 0)
ret = wc_ecc_ctx_set_dev_id(srvCtx, ECIES_CB_TEST_DEVID);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto rt_done; }
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL) { ret = WC_TEST_RET_ENC_NC; goto rt_done; }
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
@ -48673,6 +48745,12 @@ static wc_test_ret_t ecies_cryptocb_state_test(WC_RNG* rng, EciesCbCtx* cbCtx,
ret = WC_TEST_RET_ENC_NC; goto st_done;
}
/* ECIES picks its device from the context devId, not the key's. */
ret = wc_ecc_ctx_set_dev_id(cliCtx, ECIES_CB_TEST_DEVID);
if (ret == 0)
ret = wc_ecc_ctx_set_dev_id(srvCtx, ECIES_CB_TEST_DEVID);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto st_done; }
/* Salt exchange brings the client ctx to ecCLI_SALT_SET (encrypt-ready). */
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL) { ret = WC_TEST_RET_ENC_NC; goto st_done; }
@ -48696,11 +48774,16 @@ static wc_test_ret_t ecies_cryptocb_state_test(WC_RNG* rng, EciesCbCtx* cbCtx,
/* Second encrypt on the same ctx must be rejected: the hardware path must
* have advanced the single-use state. */
outSz = sizeof(out);
cbCtx->encryptInvoked = 0;
ret = wc_ecc_encrypt(userA, userB, msg, sizeof(msg), out, &outSz, cliCtx);
if (ret != WC_NO_ERR_TRACE(BAD_STATE_E)) {
ret = (ret == 0) ? WC_TEST_RET_ENC_NC : WC_TEST_RET_ENC_EC(ret);
goto st_done;
}
/* The reject has to come from the single-use check after the hardware
* handled the call, not from the callback being skipped and software
* rejecting it. Otherwise this passes for the wrong reason. */
if (cbCtx->encryptInvoked != 1) { ret = WC_TEST_RET_ENC_NC; goto st_done; }
ret = 0;
st_done:
@ -82738,23 +82821,39 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
}
#ifdef HAVE_ECC_ENCRYPT
else if (info->pk.type == WC_PK_TYPE_ECIES_ENCRYPT) {
/* set devId to invalid so the software path runs */
info->pk.eciesencrypt.privKey->devId = INVALID_DEVID;
/* ECIES picks its device from the context devId, so clear that,
* not the caller's key, so the software path runs instead of
* calling straight back into this callback. */
ecEncCtx* eCtx = info->pk.eciesencrypt.ctx;
int savedDevId = INVALID_DEVID;
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_encrypt_ex(info->pk.eciesencrypt.privKey,
info->pk.eciesencrypt.pubKey, info->pk.eciesencrypt.msg,
info->pk.eciesencrypt.msgSz, info->pk.eciesencrypt.out,
info->pk.eciesencrypt.outSz, info->pk.eciesencrypt.ctx,
info->pk.eciesencrypt.compressed);
/* reset devId */
info->pk.eciesencrypt.privKey->devId = devIdArg;
/* put back the caller's device */
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
else if (info->pk.type == WC_PK_TYPE_ECIES_DECRYPT) {
info->pk.eciesdecrypt.privKey->devId = INVALID_DEVID;
ecEncCtx* eCtx = info->pk.eciesdecrypt.ctx;
int savedDevId = INVALID_DEVID;
if (eCtx != NULL) {
(void)wc_ecc_ctx_get_dev_id(eCtx, &savedDevId);
(void)wc_ecc_ctx_set_dev_id(eCtx, INVALID_DEVID);
}
ret = wc_ecc_decrypt(info->pk.eciesdecrypt.privKey,
info->pk.eciesdecrypt.pubKey, info->pk.eciesdecrypt.msg,
info->pk.eciesdecrypt.msgSz, info->pk.eciesdecrypt.out,
info->pk.eciesdecrypt.outSz, info->pk.eciesdecrypt.ctx);
info->pk.eciesdecrypt.privKey->devId = devIdArg;
if (eCtx != NULL)
(void)wc_ecc_ctx_set_dev_id(eCtx, savedDevId);
}
#endif /* HAVE_ECC_ENCRYPT */
else if (info->pk.type == WC_PK_TYPE_EC_GET_SIZE) {

View File

@ -1075,11 +1075,15 @@ WOLFSSL_LOCAL int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder,
int checkPriv);
#endif
#ifdef HAVE_ECC_ENCRYPT
WOLFSSL_LOCAL int wc_CryptoCb_EciesEncrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx,
int compressed);
WOLFSSL_LOCAL int wc_CryptoCb_EciesDecrypt(ecc_key* privKey, ecc_key* pubKey,
const byte* msg, word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
/* devId is the ECIES context's device (see wc_ecc_ctx_set_dev_id), not
* privKey->devId. A key with a device does not by itself send ECIES to
* that device. INVALID_DEVID means software. */
WOLFSSL_LOCAL int wc_CryptoCb_EciesEncrypt(int devId, ecc_key* privKey,
ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz,
ecEncCtx* ctx, int compressed);
WOLFSSL_LOCAL int wc_CryptoCb_EciesDecrypt(int devId, ecc_key* privKey,
ecc_key* pubKey, const byte* msg, word32 msgSz, byte* out, word32* outSz,
ecEncCtx* ctx);
#endif
#endif /* HAVE_ECC */

View File

@ -1139,6 +1139,12 @@ 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);
/* Device that ECIES runs on; never copied from the ECC key. Unset means
* software, or the WOLF_CRYPTO_CB_FIND finder. Kept across ctx reset. */
WOLFSSL_API
int wc_ecc_ctx_set_dev_id(ecEncCtx* ctx, int devId);
WOLFSSL_API
int wc_ecc_ctx_get_dev_id(ecEncCtx* ctx, int* devId);
#endif /* WOLF_CRYPTO_CB */
WOLFSSL_API
const byte* wc_ecc_ctx_get_own_salt(ecEncCtx* ctx);