Only offload a key-owned X448 private scalar to that key's own device

wc_curve448_make_key and wc_curve448_export_public_ex derived the public
point through the keyless wc_curve448_make_pub, which dispatches to the
first registered device; route them through a devId-carrying helper.
pull/11209/head
night1rider 2026-08-20 08:25:56 -06:00
parent 93d71fdda9
commit 06abdc18e6
4 changed files with 98 additions and 24 deletions

View File

@ -953,6 +953,7 @@ int test_wc_curve448_make_pub_generic(void)
typedef struct curve448SpyCtx {
int kgSeen;
int ssSeen;
int mpSeen;
int decline;
int forceErr;
int zeroSecret;
@ -984,6 +985,10 @@ static int curve448_test_crypto_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
info->pk.curve448kg.size, info->pk.curve448kg.key);
info->pk.curve448kg.key->devId = save;
}
if (info->pk.type == WC_PK_TYPE_CURVE448_MAKE_PUB) {
/* count, then decline so the software path produces the point */
spy->mpSeen++;
}
if (info->pk.type == WC_PK_TYPE_CURVE448) {
int save = info->pk.curve448.private_key->devId;
spy->ssSeen++;
@ -1022,6 +1027,7 @@ int test_wc_curve448_cryptocb(void)
curve448_key keyB;
byte ssAB[CURVE448_PUB_KEY_SIZE];
byte ssBA[CURVE448_PUB_KEY_SIZE];
byte pubTmp[CURVE448_PUB_KEY_SIZE];
word32 ssABLen = (word32)sizeof(ssAB);
word32 ssBALen = (word32)sizeof(ssBA);
#ifndef WC_NO_CONSTRUCTORS
@ -1100,6 +1106,28 @@ int test_wc_curve448_cryptocb(void)
spy.zeroSecret = 0;
#endif
#if !defined(WOLF_CRYPTO_CB_FIND) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE448)
/* a key bound to no device must not have its private scalar handed to
* whichever device happens to be registered: keygen derives the public
* point in software without dispatching make_pub */
{
curve448_key unbound;
int mpBefore = spy.mpSeen;
XMEMSET(&unbound, 0, sizeof(unbound));
ExpectIntEQ(wc_curve448_init(&unbound), 0);
ExpectIntEQ(wc_curve448_make_key(&rng, CURVE448_KEY_SIZE, &unbound),
0);
ExpectIntEQ(spy.mpSeen, mpBefore);
/* the keyless public API has no devId to respect, so it still
* reaches the device */
ExpectIntEQ(wc_curve448_make_pub((int)sizeof(pubTmp), pubTmp,
(int)sizeof(unbound.k), unbound.k), 0);
ExpectIntGT(spy.mpSeen, mpBefore);
wc_curve448_free(&unbound);
}
#endif
/* constructor arg checks */
ExpectIntEQ(wc_curve448_init_ex(NULL, HEAP_HINT, devId),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));

View File

@ -1516,7 +1516,7 @@ int wc_CryptoCb_Curve448(curve448_key* private_key,
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_Curve448MakePub(int public_size, byte* pub,
int wc_CryptoCb_Curve448MakePub(int devId, int public_size, byte* pub,
int private_size, const byte* priv)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
@ -1525,9 +1525,11 @@ int wc_CryptoCb_Curve448MakePub(int public_size, byte* pub,
if (pub == NULL || priv == NULL)
return ret;
/* try the find callback first, else grab the first registered device */
dev = wc_CryptoCb_FindDevice(INVALID_DEVID, WC_ALGO_TYPE_PK);
if (dev == NULL || dev->cb == NULL)
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK);
/* only a caller that selected no device settles for the first registered
* one; a devId names the single device allowed to see the scalar */
if ((dev == NULL || dev->cb == NULL) && (devId == INVALID_DEVID))
dev = wc_CryptoCb_FindDeviceByIndex(0);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
@ -1545,7 +1547,7 @@ int wc_CryptoCb_Curve448MakePub(int public_size, byte* pub,
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_Curve448Generic(int public_size, byte* pub,
int wc_CryptoCb_Curve448Generic(int devId, int public_size, byte* pub,
int private_size, const byte* priv, int basepoint_size,
const byte* basepoint)
{
@ -1555,9 +1557,11 @@ int wc_CryptoCb_Curve448Generic(int public_size, byte* pub,
if (pub == NULL || priv == NULL || basepoint == NULL)
return ret;
/* try the find callback first, else grab the first registered device */
dev = wc_CryptoCb_FindDevice(INVALID_DEVID, WC_ALGO_TYPE_PK);
if (dev == NULL || dev->cb == NULL)
/* locate registered callback */
dev = wc_CryptoCb_FindDevice(devId, WC_ALGO_TYPE_PK);
/* only a caller that selected no device settles for the first registered
* one; a devId names the single device allowed to see the scalar */
if ((dev == NULL || dev->cb == NULL) && (devId == INVALID_DEVID))
dev = wc_CryptoCb_FindDeviceByIndex(0);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;

View File

@ -65,8 +65,18 @@ static WC_INLINE int curve448_priv_clamp_check(const byte* priv)
return ret;
}
int wc_curve448_make_pub(int public_size, byte* pub, int private_size,
const byte* priv)
/* Compute pub = priv * basepoint(5).
*
* devId [in] Device to offload to, INVALID_DEVID for the caller's choice.
* cbOk [in] Whether the private scalar may be offered to a crypto
* callback at all. The keyless public API sets this, since it
* has no key to take a devId from; a key-owned scalar only sets
* it when the key is actually bound to a device, so an unbound
* key is never offloaded to whichever device happens to be
* registered first.
*/
static int curve448_make_pub_ex(int public_size, byte* pub, int private_size,
const byte* priv, int devId, int cbOk)
{
int ret;
#ifndef WOLF_CRYPTO_CB_ONLY_CURVE448
@ -87,10 +97,16 @@ int wc_curve448_make_pub(int public_size, byte* pub, int private_size,
return ret;
#ifdef WOLF_CRYPTO_CB
ret = wc_CryptoCb_Curve448MakePub(public_size, pub, private_size, priv);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall-through when unavailable */
if (cbOk) {
ret = wc_CryptoCb_Curve448MakePub(devId, public_size, pub,
private_size, priv);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall-through when unavailable */
}
#else
(void)devId;
(void)cbOk;
#endif
#ifdef WOLF_CRYPTO_CB_ONLY_CURVE448
@ -105,6 +121,33 @@ int wc_curve448_make_pub(int public_size, byte* pub, int private_size,
return ret;
}
/* Derive a key's public point from its own private scalar. */
static int curve448_key_make_pub(curve448_key* key)
{
#ifdef WOLF_CRYPTO_CB
#ifdef WOLF_CRYPTO_CB_FIND
/* the find callback gets to route unbound keys */
const int cbOk = 1;
#else
const int cbOk = (key->devId != INVALID_DEVID);
#endif
return curve448_make_pub_ex((int)sizeof(key->p), key->p,
(int)sizeof(key->k), key->k, key->devId, cbOk);
#else
return curve448_make_pub_ex((int)sizeof(key->p), key->p,
(int)sizeof(key->k), key->k, INVALID_DEVID, 0);
#endif
}
int wc_curve448_make_pub(int public_size, byte* pub, int private_size,
const byte* priv)
{
/* no key, so no device was selected: any registered one may serve it */
return curve448_make_pub_ex(public_size, pub, private_size, priv,
INVALID_DEVID, 1);
}
/* Is every byte of the curve448 result zero? Only reached when the caller's
* basepoint is of small order, which leaks the result to anyone watching. */
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
@ -146,8 +189,9 @@ int wc_curve448_generic(int public_size, byte* pub,
return ret;
#ifdef WOLF_CRYPTO_CB
ret = wc_CryptoCb_Curve448Generic(public_size, pub, private_size, priv,
basepoint_size, basepoint);
/* no key, so no device was selected: any registered one may serve it */
ret = wc_CryptoCb_Curve448Generic(INVALID_DEVID, public_size, pub,
private_size, priv, basepoint_size, basepoint);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
#ifndef WOLFSSL_NO_ECDHX_SHARED_ZERO_CHECK
/* RFC 7748: reject an all-zero result from the callback too */
@ -232,8 +276,7 @@ int wc_curve448_make_key(WC_RNG* rng, int keysize, curve448_key* key)
key->k[CURVE448_KEY_SIZE-1] |= 0x80;
/* compute public */
ret = wc_curve448_make_pub((int)sizeof(key->p), key->p,
(int)sizeof(key->k), key->k);
ret = curve448_key_make_pub(key);
if (ret == 0) {
key->pubSet = 1;
}
@ -435,8 +478,7 @@ int wc_curve448_export_public_ex(curve448_key* key, byte* out, word32* outLen,
if (ret == 0) {
/* calculate public if missing */
if (!key->pubSet) {
ret = wc_curve448_make_pub((int)sizeof(key->p), key->p,
(int)sizeof(key->k), key->k);
ret = curve448_key_make_pub(key);
key->pubSet = (ret == 0);
}
}

View File

@ -989,10 +989,10 @@ WOLFSSL_LOCAL int wc_CryptoCb_Curve448Gen(WC_RNG* rng, int keySize,
curve448_key* key);
WOLFSSL_LOCAL int wc_CryptoCb_Curve448(curve448_key* private_key,
curve448_key* public_key, byte* out, word32* outlen, int endian);
WOLFSSL_LOCAL int wc_CryptoCb_Curve448MakePub(int public_size, byte* pub,
int private_size, const byte* priv);
WOLFSSL_LOCAL int wc_CryptoCb_Curve448Generic(int public_size, byte* pub,
int private_size, const byte* priv, int basepoint_size,
WOLFSSL_LOCAL int wc_CryptoCb_Curve448MakePub(int devId, int public_size,
byte* pub, int private_size, const byte* priv);
WOLFSSL_LOCAL int wc_CryptoCb_Curve448Generic(int devId, int public_size,
byte* pub, int private_size, const byte* priv, int basepoint_size,
const byte* basepoint);
#endif /* HAVE_CURVE448 */