cryptocb: add WC_PK_TYPE_EC_MAKE_PUB for ECC public-key derivation offload

Under WOLF_CRYPTO_CB_ONLY_ECC, HAVE_ECC_MAKE_PUB is now enabled and
backed by the dispatch alone, failing closed with NO_VALID_DEVID when
no device handles the operation (previously NOT_COMPILED_IN).
This commit is contained in:
Marco Oliverio
2026-06-11 14:20:39 +02:00
parent 2f38b856c2
commit f7877887d7
6 changed files with 186 additions and 6 deletions
+29
View File
@@ -251,3 +251,32 @@ void wc_CryptoCb_InfoString(wc_CryptoInfo* info);
\sa wc_AesInit
*/
int wc_CryptoCb_AesSetKey(Aes* aes, const byte* key, word32 keySz);
/*!
\ingroup CryptoCb
\brief Offload deriving an ECC public key Q = d*G from its private key to a
CryptoCB device.
Used by wc_ecc_make_pub / wc_ecc_make_pub_ex. The callback boundary is
math-free: the resulting public point crosses as X9.63 uncompressed bytes
(0x04 || X || Y, each ordinate zero-padded to the curve size) in
wc_CryptoInfo.pk.ecc_make_pub (\c pubOut / \c pubOutSz). This wrapper performs
all bignum (de)serialization, so a device handler only deals with byte arrays
and never with wolfCrypt's internal mp_int representation. The private scalar
is taken from the ecc_key (resident in a secure element, or key->k); curve
identity comes from key->dp.
\param key ECC key providing the device id, curve identity, heap hint and
the private scalar
\param pubOut [out] resulting affine public point Q = d*G
\return 0 on success
\return CRYPTOCB_UNAVAILABLE if no device handles the operation, or key or
pubOut is NULL (wolfCrypt falls back to software, which reports
the argument error)
\sa wc_CryptoCb_RegisterDevice
\sa wc_ecc_make_pub
*/
int wc_CryptoCb_EccMakePub(ecc_key* key, ecc_point* pubOut);
+43
View File
@@ -153,6 +153,47 @@ static int swdev_ecc_get_sig_size(wc_CryptoInfo* info)
*info->pk.ecc_get_sig_size.sigSize = sz;
return 0;
}
static int swdev_ecc_make_pub(wc_CryptoInfo* info)
{
int ret;
ecc_key* key = info->pk.ecc_make_pub.key;
ecc_point* pub = wc_ecc_new_point_h(key->heap);
if (pub == NULL)
return MEMORY_E;
/* derive Q = d*G in software, then emit X9.63 uncompressed bytes. The
* point is serialized with the curve size from key->dp so custom-curve
* keys (idx == ECC_CUSTOM_IDX) work too; wc_ecc_export_point_der rejects
* negative curve indices. */
ret = wc_ecc_make_pub(key, pub);
if (ret == 0) {
byte* out = info->pk.ecc_make_pub.pubOut;
word32 curveSz = (word32)key->dp->size;
word32 ptSz = 1 + 2 * curveSz;
word32 xSz = curveSz;
word32 ySz = curveSz;
if (*info->pk.ecc_make_pub.pubOutSz < ptSz) {
ret = BUFFER_E;
}
else {
out[0] = ECC_POINT_UNCOMP;
ret = wc_export_int(pub->x, out + 1, &xSz, curveSz,
WC_TYPE_UNSIGNED_BIN);
if (ret == MP_OKAY)
ret = wc_export_int(pub->y, out + 1 + curveSz, &ySz, curveSz,
WC_TYPE_UNSIGNED_BIN);
if (ret == MP_OKAY)
*info->pk.ecc_make_pub.pubOutSz = ptSz;
}
}
wc_ecc_del_point_h(pub, key->heap);
return ret;
}
#endif /* HAVE_ECC */
#ifndef NO_SHA256
@@ -712,6 +753,8 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info,
return swdev_ecc_get_size(info);
case WC_PK_TYPE_EC_GET_SIG_SIZE:
return swdev_ecc_get_sig_size(info);
case WC_PK_TYPE_EC_MAKE_PUB:
return swdev_ecc_make_pub(info);
#endif /* HAVE_ECC */
default:
return CRYPTOCB_UNAVAILABLE;
+60
View File
@@ -157,6 +157,7 @@ static const char* GetPkTypeStr(int pk)
case WC_PK_TYPE_EC_KEYGEN: return "ECC KeyGen";
case WC_PK_TYPE_EC_GET_SIZE: return "ECC GetSize";
case WC_PK_TYPE_EC_GET_SIG_SIZE: return "ECC GetSigSize";
case WC_PK_TYPE_EC_MAKE_PUB: return "ECC MakePub";
}
return NULL;
}
@@ -878,6 +879,65 @@ int wc_CryptoCb_EccGetSigSize(const ecc_key* key, int* sigSize)
return wc_CryptoCb_TranslateErrorCode(ret);
}
int wc_CryptoCb_EccMakePub(ecc_key* key, ecc_point* pubOut)
{
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
CryptoCb* dev;
if (key == NULL || pubOut == NULL || key->dp == NULL)
return ret;
if (key->dp->size > MAX_ECC_BYTES)
return ret;
dev = wc_CryptoCb_FindDevice(key->devId, WC_ALGO_TYPE_PK);
if (dev && dev->cb) {
wc_CryptoInfo cryptoInfo;
word32 curveSz = (word32)key->dp->size;
word32 ptSz = 1 + 2 * curveSz; /* X9.63 uncompressed length */
word32 outSz = ptSz;
WC_DECLARE_VAR(buf, byte, (1 + 2 * MAX_ECC_BYTES), key->heap);
WC_ALLOC_VAR_EX(buf, byte, (1 + 2 * MAX_ECC_BYTES), key->heap,
DYNAMIC_TYPE_ECC_BUFFER, return MEMORY_E);
/* zero the result buffer so a handler that returns success without
* writing output is rejected deterministically by the tag check */
XMEMSET(buf, 0, ptSz);
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
cryptoInfo.algo_type = WC_ALGO_TYPE_PK;
cryptoInfo.pk.type = WC_PK_TYPE_EC_MAKE_PUB;
cryptoInfo.pk.ecc_make_pub.key = key;
cryptoInfo.pk.ecc_make_pub.pubOut = buf;
cryptoInfo.pk.ecc_make_pub.pubOutSz = &outSz;
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
/* deserialize X9.63 uncompressed result into pubOut; reject a result
* whose size is not exactly the curve's X9.63 length */
if (ret == 0) {
if (outSz != ptSz || buf[0] != ECC_POINT_UNCOMP) {
ret = BUFFER_E;
}
else {
int err = mp_read_unsigned_bin(pubOut->x, buf + 1, curveSz);
if (err == MP_OKAY)
err = mp_read_unsigned_bin(pubOut->y, buf + 1 + curveSz,
curveSz);
if (err == MP_OKAY)
err = mp_set(pubOut->z, 1);
if (err != MP_OKAY)
ret = err;
}
}
WC_FREE_VAR_EX(buf, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
}
return wc_CryptoCb_TranslateErrorCode(ret);
}
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
+43 -6
View File
@@ -291,8 +291,7 @@ ECC Curve Sizes:
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
!defined(WOLFSSL_MICROCHIP_TA100) && \
!defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
!defined(WOLFSSL_KCAPI_ECC) && !defined(NO_ECC_MAKE_PUB) && \
!defined(WOLF_CRYPTO_CB_ONLY_ECC)
!defined(WOLFSSL_KCAPI_ECC) && !defined(NO_ECC_MAKE_PUB)
#undef HAVE_ECC_MAKE_PUB
#define HAVE_ECC_MAKE_PUB
#endif
@@ -5433,8 +5432,8 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key)
}
#ifdef HAVE_ECC_MAKE_PUB
/* compute the public key Q = d*G in software
#if defined(HAVE_ECC_MAKE_PUB) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
/* compute the public key Q = d*G in software.
*
* key private key holding the scalar d, must be present and in range
* curve [in]curve for key, cannot be NULL
@@ -5549,7 +5548,7 @@ static int ecc_make_pub_sw(ecc_key* key, ecc_curve_spec* curve,
return err;
}
#endif /* HAVE_ECC_MAKE_PUB */
#endif /* HAVE_ECC_MAKE_PUB && !WOLF_CRYPTO_CB_ONLY_ECC */
/* create the public ECC key from a private key
*
@@ -5572,6 +5571,7 @@ static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curve,
int err = MP_OKAY;
#ifdef HAVE_ECC_MAKE_PUB
ecc_point* pub;
int doneInCb = 0;
#endif /* HAVE_ECC_MAKE_PUB */
(void)rng;
@@ -5605,8 +5605,45 @@ static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curve,
#endif
}
if (err == MP_OKAY) {
#ifdef WOLF_CRYPTO_CB
/* offload Q = d*G to the device; fall through to software only when the
* device reports the operation unavailable.
*
* Under WOLF_CRYPTO_CB_FIND the devId gate is dropped so a find callback
* can route a key initialized with INVALID_DEVID. This helper is also
* shared by internal callers that compute a point from a transient scalar
* in key->k - the ECDSA software-sign nonce R = k*G (ecc_sign_hash_sw),
* keygen public-part derivation, and verify-time public-key recovery.
* Reaching the software signer means the device already declined to sign
* (the whole-sign offload wc_CryptoCb_EccSign ran first), so a find
* callback that hands this make-pub to a device notwithstanding the
* INVALID_DEVID is expected to likewise decline it. If it does not decline
* *and* the device ignores key->k (e.g. relying on an internal key
* representation), it returns d*G instead of the requested k*G and the
* resulting signature is wrong - but such a scenario is very unlikely. */
#ifndef WOLF_CRYPTO_CB_FIND
if ((err == MP_OKAY) && (key->devId != INVALID_DEVID))
#else
if (err == MP_OKAY)
#endif
{
err = wc_CryptoCb_EccMakePub(key, pub);
if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
doneInCb = 1;
else
err = MP_OKAY; /* device declined the offload; fall back */
}
#endif
if ((err == MP_OKAY) && !doneInCb) {
#ifdef WOLF_CRYPTO_CB_ONLY_ECC
/* software derivation is stripped and no device handled the op;
* fail closed */
(void)curve;
err = NO_VALID_DEVID;
#else
err = ecc_make_pub_sw(key, curve, pub, rng);
#endif
}
if (err != MP_OKAY
+8
View File
@@ -245,6 +245,12 @@ typedef struct wc_CryptoInfo {
const ecc_key* key;
int* sigSize;
} ecc_get_sig_size;
struct {
ecc_key* key; /* routing (devId), curve (key->dp), heap,
* resident/sw private scalar d */
byte* pubOut; /* [out] X9.63 0x04||X||Y, uncompressed */
word32* pubOutSz; /* in: buf size; out: bytes written */
} ecc_make_pub;
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
struct {
@@ -730,6 +736,8 @@ WOLFSSL_LOCAL int wc_CryptoCb_EccCheckPrivKey(ecc_key* key, const byte* pubKey,
WOLFSSL_LOCAL int wc_CryptoCb_EccGetSize(const ecc_key* key, int* keySize);
WOLFSSL_LOCAL int wc_CryptoCb_EccGetSigSize(const ecc_key* key, int* sigSize);
WOLFSSL_LOCAL int wc_CryptoCb_EccMakePub(ecc_key* key, ecc_point* pubOut);
#endif /* HAVE_ECC */
#ifdef HAVE_CURVE25519
+3
View File
@@ -1597,6 +1597,9 @@ enum wc_PkType {
#undef _WC_PK_TYPE_MAX
#define _WC_PK_TYPE_MAX WC_PK_TYPE_PQC_STATEFUL_SIG_SIGS_LEFT
#endif
WC_PK_TYPE_EC_MAKE_PUB = 34,
#undef _WC_PK_TYPE_MAX
#define _WC_PK_TYPE_MAX WC_PK_TYPE_EC_MAKE_PUB
WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX
};