mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 09:30:51 +02:00
Merge pull request #10663 from rizlik/pubkey_ecc_operation_cb
Introduce ECC Make PUB and ECC Check Pub crypto callbacks
This commit is contained in:
@@ -251,3 +251,63 @@ 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);
|
||||
|
||||
/*!
|
||||
\ingroup CryptoCb
|
||||
|
||||
\brief Offload validating an ECC key to a CryptoCB device.
|
||||
|
||||
Used by wc_ecc_check_key and the key generation / import validation paths.
|
||||
The public point crosses the (math-free) callback boundary as X9.63
|
||||
uncompressed bytes in wc_CryptoInfo.pk.ecc_check_pub (\c pubKey /
|
||||
\c pubKeySz); this wrapper serializes key->pubkey so a device handler only
|
||||
deals with byte arrays. When the key state is \c ECC_PRIVATEKEY_ONLY,
|
||||
\c pubKey is NULL and \c pubKeySz is 0 so the handler can distinguish "no
|
||||
public point" from an invalid zero-coordinate public point that must be
|
||||
validated and rejected. The caller's intent crosses in \c checkOrder and
|
||||
\c checkPriv.
|
||||
|
||||
\param key ECC key to validate (curve identity from key->dp)
|
||||
\param checkOrder when 1 the caller requested validation that the point
|
||||
has the curve order (point * order == infinity)
|
||||
\param checkPriv when 1 the caller also requested validation of the
|
||||
private part (scalar range, consistency with the public
|
||||
point)
|
||||
|
||||
\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_ecc_check_key
|
||||
*/
|
||||
int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder, int checkPriv);
|
||||
|
||||
@@ -153,6 +153,89 @@ 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;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
static int swdev_ecc_check_pub(wc_CryptoInfo* info)
|
||||
{
|
||||
ecc_key* key = info->pk.ecc_check_pub.key;
|
||||
int ret = 0;
|
||||
int validatedFromWire = 0;
|
||||
|
||||
if (info->pk.ecc_check_pub.pubKeySz == 0) {
|
||||
return ECC_INF_E;
|
||||
}
|
||||
#ifdef HAVE_ECC_KEY_IMPORT
|
||||
if (key->idx >= 0) {
|
||||
WC_DECLARE_VAR(pubOnly, ecc_key, 1, key->heap);
|
||||
WC_ALLOC_VAR(pubOnly, ecc_key, 1, key->heap);
|
||||
if (!WC_VAR_OK(pubOnly))
|
||||
ret = MEMORY_E;
|
||||
else
|
||||
ret = wc_ecc_init_ex(pubOnly, key->heap, INVALID_DEVID);
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_import_x963_ex(info->pk.ecc_check_pub.pubKey,
|
||||
info->pk.ecc_check_pub.pubKeySz, pubOnly, key->dp->id);
|
||||
if (ret == 0 &&
|
||||
wc_ecc_cmp_point(&pubOnly->pubkey, &key->pubkey) != MP_EQ) {
|
||||
/* wire bytes disagree with key->pubkey */
|
||||
ret = BAD_STATE_E;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = wc_ecc_check_key(pubOnly);
|
||||
wc_ecc_free(pubOnly);
|
||||
}
|
||||
WC_FREE_VAR(pubOnly, key->heap);
|
||||
validatedFromWire = 1;
|
||||
}
|
||||
#endif
|
||||
if (ret == 0 && (!validatedFromWire ||
|
||||
(info->pk.ecc_check_pub.checkPriv &&
|
||||
key->type == ECC_PRIVATEKEY))) {
|
||||
ret = wc_ecc_check_key(key);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* HAVE_ECC_CHECK_KEY */
|
||||
#endif /* HAVE_ECC */
|
||||
|
||||
#ifndef NO_SHA256
|
||||
@@ -712,6 +795,12 @@ 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);
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
case WC_PK_TYPE_EC_CHECK_PUB_KEY:
|
||||
return swdev_ecc_check_pub(info);
|
||||
#endif
|
||||
#endif /* HAVE_ECC */
|
||||
default:
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
|
||||
@@ -157,6 +157,8 @@ 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";
|
||||
case WC_PK_TYPE_EC_CHECK_PUB_KEY: return "ECC CheckPubKey";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -882,6 +884,127 @@ 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 = 1 + 2 * MAX_ECC_BYTES; /* buffer size on input */
|
||||
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);
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder, int checkPriv)
|
||||
{
|
||||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
CryptoCb* dev;
|
||||
|
||||
if (key == NULL || key->dp == NULL)
|
||||
return ret;
|
||||
|
||||
if (key->dp->size > MAX_ECC_BYTES)
|
||||
return ret;
|
||||
|
||||
/* locate registered callback */
|
||||
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;
|
||||
word32 xSz = curveSz;
|
||||
word32 ySz = curveSz;
|
||||
/* a key with no host-side public point is represented by
|
||||
* ECC_PRIVATEKEY_ONLY and crosses as pubKey = NULL / pubKeySz = 0.
|
||||
* If the key state says a public point exists, serialize it even when
|
||||
* the coordinates are invalid (e.g. 0,0) so the device can reject the
|
||||
* actual input instead of seeing "no public point". */
|
||||
int havePub = (key->type != ECC_PRIVATEKEY_ONLY);
|
||||
WC_DECLARE_VAR(buf, byte, (1 + 2 * MAX_ECC_BYTES), key->heap);
|
||||
|
||||
ret = MP_OKAY;
|
||||
if (havePub) {
|
||||
WC_ALLOC_VAR_EX(buf, byte, (1 + 2 * MAX_ECC_BYTES), key->heap,
|
||||
DYNAMIC_TYPE_ECC_BUFFER, return MEMORY_E);
|
||||
/* serialize key->pubkey to X9.63 uncompressed (0x04 || X || Y) */
|
||||
buf[0] = ECC_POINT_UNCOMP;
|
||||
ret = wc_export_int(key->pubkey.x, buf + 1, &xSz, curveSz,
|
||||
WC_TYPE_UNSIGNED_BIN);
|
||||
if (ret == MP_OKAY)
|
||||
ret = wc_export_int(key->pubkey.y, buf + 1 + curveSz, &ySz,
|
||||
curveSz, WC_TYPE_UNSIGNED_BIN);
|
||||
}
|
||||
|
||||
if (ret == MP_OKAY) {
|
||||
XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo));
|
||||
cryptoInfo.algo_type = WC_ALGO_TYPE_PK;
|
||||
cryptoInfo.pk.type = WC_PK_TYPE_EC_CHECK_PUB_KEY;
|
||||
cryptoInfo.pk.ecc_check_pub.key = key;
|
||||
cryptoInfo.pk.ecc_check_pub.pubKey = havePub ? buf : NULL;
|
||||
cryptoInfo.pk.ecc_check_pub.pubKeySz = havePub ? ptSz : 0;
|
||||
cryptoInfo.pk.ecc_check_pub.checkOrder = checkOrder;
|
||||
cryptoInfo.pk.ecc_check_pub.checkPriv = checkPriv;
|
||||
|
||||
ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx);
|
||||
}
|
||||
|
||||
if (havePub) {
|
||||
WC_FREE_VAR_EX(buf, key->heap, DYNAMIC_TYPE_ECC_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
return wc_CryptoCb_TranslateErrorCode(ret);
|
||||
}
|
||||
#endif /* HAVE_ECC_CHECK_KEY */
|
||||
#endif /* HAVE_ECC */
|
||||
|
||||
#ifdef HAVE_CURVE25519
|
||||
|
||||
+145
-53
@@ -293,8 +293,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
|
||||
@@ -5435,66 +5434,30 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key)
|
||||
}
|
||||
|
||||
|
||||
/* create the public ECC key from a private key
|
||||
#if defined(HAVE_ECC_MAKE_PUB) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
|
||||
/* compute the public key Q = d*G in software.
|
||||
*
|
||||
* key an initialized private key to generate public part from
|
||||
* curve [in]curve for key, cannot be NULL
|
||||
* pubOut [out]ecc_point holding the public key, if NULL then public key part
|
||||
* is cached in key instead.
|
||||
*
|
||||
* Note this function is local to the file because of the argument type
|
||||
* ecc_curve_spec. Having this argument allows for not having to load the
|
||||
* curve type multiple times when generating a key with wc_ecc_make_key().
|
||||
* For async the results are placed directly into pubOut, so this function
|
||||
* does not need to be called again
|
||||
* key private key holding the scalar d, must be present and in range
|
||||
* curve [in]curve for key, cannot be NULL
|
||||
* pub [out]initialized ecc_point receiving the public key
|
||||
* rng optional RNG for a timing-resistant point multiply, may be NULL
|
||||
*
|
||||
* returns MP_OKAY on success
|
||||
*/
|
||||
static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curve,
|
||||
ecc_point* pubOut, WC_RNG* rng)
|
||||
static int ecc_make_pub_sw(ecc_key* key, ecc_curve_spec* curve,
|
||||
ecc_point* pub, WC_RNG* rng)
|
||||
{
|
||||
int err = MP_OKAY;
|
||||
#ifdef HAVE_ECC_MAKE_PUB
|
||||
ecc_point* pub;
|
||||
#endif /* HAVE_ECC_MAKE_PUB */
|
||||
|
||||
(void)rng;
|
||||
|
||||
if (key == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC_MAKE_PUB
|
||||
/* if ecc_point passed in then use it as output for public key point */
|
||||
if (pubOut != NULL) {
|
||||
pub = pubOut;
|
||||
}
|
||||
else {
|
||||
/* caching public key making it a ECC_PRIVATEKEY instead of
|
||||
ECC_PRIVATEKEY_ONLY */
|
||||
pub = &key->pubkey;
|
||||
key->type = ECC_PRIVATEKEY_ONLY;
|
||||
}
|
||||
|
||||
if ((err == MP_OKAY) && (mp_iszero(ecc_get_k(key)) ||
|
||||
mp_isneg(ecc_get_k(key)) ||
|
||||
(mp_cmp(ecc_get_k(key), curve->order) != MP_LT))) {
|
||||
/* The private scalar must be in range for the base-point multiply
|
||||
* below. */
|
||||
if (mp_iszero(ecc_get_k(key)) || mp_isneg(ecc_get_k(key)) ||
|
||||
(mp_cmp(ecc_get_k(key), curve->order) != MP_LT)) {
|
||||
err = ECC_PRIV_KEY_E;
|
||||
}
|
||||
|
||||
if (err == MP_OKAY) {
|
||||
#ifndef ALT_ECC_SIZE
|
||||
err = mp_init_multi(pub->x, pub->y, pub->z, NULL, NULL, NULL);
|
||||
#else
|
||||
pub->x = (mp_int*)&pub->xyz[0];
|
||||
pub->y = (mp_int*)&pub->xyz[1];
|
||||
pub->z = (mp_int*)&pub->xyz[2];
|
||||
alt_fp_init(pub->x);
|
||||
alt_fp_init(pub->y);
|
||||
alt_fp_init(pub->z);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC_KEYGEN) && \
|
||||
defined(HAVE_INTEL_QA)
|
||||
if (err == MP_OKAY && key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_ECC) {
|
||||
@@ -5585,6 +5548,106 @@ static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curve,
|
||||
#endif /* WOLFSSL_SP_MATH */
|
||||
} /* END: Software Crypto */
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* HAVE_ECC_MAKE_PUB && !WOLF_CRYPTO_CB_ONLY_ECC */
|
||||
|
||||
/* create the public ECC key from a private key
|
||||
*
|
||||
* key an initialized private key to generate public part from
|
||||
* curve [in]curve for key, cannot be NULL
|
||||
* pubOut [out]ecc_point holding the public key, if NULL then public key part
|
||||
* is cached in key instead.
|
||||
*
|
||||
* Note this function is local to the file because of the argument type
|
||||
* ecc_curve_spec. Having this argument allows for not having to load the
|
||||
* curve type multiple times when generating a key with wc_ecc_make_key().
|
||||
* For async the results are placed directly into pubOut, so this function
|
||||
* does not need to be called again
|
||||
*
|
||||
* returns MP_OKAY on success
|
||||
*/
|
||||
static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curve,
|
||||
ecc_point* pubOut, WC_RNG* rng)
|
||||
{
|
||||
int err = MP_OKAY;
|
||||
#ifdef HAVE_ECC_MAKE_PUB
|
||||
ecc_point* pub;
|
||||
int doneInCb = 0;
|
||||
#endif /* HAVE_ECC_MAKE_PUB */
|
||||
|
||||
(void)rng;
|
||||
|
||||
if (key == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ECC_MAKE_PUB
|
||||
/* if ecc_point passed in then use it as output for public key point */
|
||||
if (pubOut != NULL) {
|
||||
pub = pubOut;
|
||||
}
|
||||
else {
|
||||
/* caching public key making it a ECC_PRIVATEKEY instead of
|
||||
ECC_PRIVATEKEY_ONLY */
|
||||
pub = &key->pubkey;
|
||||
key->type = ECC_PRIVATEKEY_ONLY;
|
||||
}
|
||||
|
||||
if (err == MP_OKAY) {
|
||||
#ifndef ALT_ECC_SIZE
|
||||
err = mp_init_multi(pub->x, pub->y, pub->z, NULL, NULL, NULL);
|
||||
#else
|
||||
pub->x = (mp_int*)&pub->xyz[0];
|
||||
pub->y = (mp_int*)&pub->xyz[1];
|
||||
pub->z = (mp_int*)&pub->xyz[2];
|
||||
alt_fp_init(pub->x);
|
||||
alt_fp_init(pub->y);
|
||||
alt_fp_init(pub->z);
|
||||
#endif
|
||||
}
|
||||
|
||||
#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
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
&& err != WC_NO_ERR_TRACE(WC_PENDING_E)
|
||||
@@ -10731,13 +10794,38 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(HAVE_ECC_CHECK_KEY) && \
|
||||
!defined(WOLFSSL_CAAM)
|
||||
/* Device-first: when a device is configured, let it validate the public
|
||||
* key. Fall through to the software/HW path below only when the
|
||||
* device reports the operation unavailable.
|
||||
* CAAM is excluded: it relies on the software order-check below to detect
|
||||
* whether an imported private key is an encrypted black key. */
|
||||
#ifndef WOLF_CRYPTO_CB_FIND
|
||||
if (key->devId != INVALID_DEVID)
|
||||
#endif
|
||||
{
|
||||
err = wc_CryptoCb_EccCheckPubKey(key, !partial, priv);
|
||||
if (err != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
|
||||
return err;
|
||||
/* device declined; fall through. Every software/HW path below
|
||||
* re-initializes err before reading it, so no reset is needed here. */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ECC_CHECK_PUBKEY_ORDER
|
||||
#ifdef WOLF_CRYPTO_CB_ONLY_ECC
|
||||
/* 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. */
|
||||
err = NO_VALID_DEVID;
|
||||
#else
|
||||
/* consider key check success on HW crypto
|
||||
* ex: ATECC508/608A, CryptoCell and Silabs
|
||||
*
|
||||
* consider key check success on most Crypt Cb only builds
|
||||
* ex: ATECC508/608A, CryptoCell and Silabs which validate the key
|
||||
* internally
|
||||
*/
|
||||
err = MP_OKAY;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
@@ -10879,6 +10967,10 @@ WOLFSSL_ABI
|
||||
int wc_ecc_check_key(ecc_key* key)
|
||||
{
|
||||
int ret;
|
||||
/* _ecc_validate_public_key is the single validation entry point: it is
|
||||
* device-first (offloads to the crypto callback when a device is
|
||||
* configured) and otherwise runs the software/HW checks, or fails closed
|
||||
* under WOLF_CRYPTO_CB_ONLY_ECC. */
|
||||
ret = _ecc_validate_public_key(key, 0, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+378
-1
@@ -42783,7 +42783,8 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void)
|
||||
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
|
||||
!defined(WOLFSSL_MICROCHIP_TA100) && \
|
||||
!defined(WOLFSSL_STM32_PKA) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \
|
||||
!defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(NO_ECC_SECP)
|
||||
(!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_SWDEV)) && \
|
||||
!defined(NO_ECC_SECP)
|
||||
ret = ecc_test_make_pub(&rng);
|
||||
if (ret != 0) {
|
||||
printf("ecc_test_make_pub failed!\n");
|
||||
@@ -72303,6 +72304,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t blob_test(void)
|
||||
/* Example custom context for crypto callback */
|
||||
typedef struct {
|
||||
int exampleVar; /* flag for testing if only crypt is enabled. */
|
||||
#ifdef HAVE_ECC
|
||||
int eccMakePubCount; /* EC make-pub callback invocations */
|
||||
int eccCheckPubCount; /* EC check-pubkey callback invocations */
|
||||
int eccMakePubBadFormat; /* when set, return a malformed (non-uncompressed)
|
||||
* point to exercise the wrapper's BUFFER_E path */
|
||||
int eccMakePubBadLen; /* when set, claim a result size different from the
|
||||
* curve's X9.63 length to exercise the wrapper's
|
||||
* size check */
|
||||
int eccCheckPubExpectZeroPoint; /* require serialized 0,0 input */
|
||||
int eccCheckPubSawZeroPoint; /* EC check-pubkey saw X9.63 0,0 */
|
||||
ecc_key* eccResidentKey; /* when set, the make-pub callback emits this key's
|
||||
* public point, simulating a private scalar
|
||||
* resident in the device (input key->k empty) */
|
||||
#endif
|
||||
} myCryptoDevCtx;
|
||||
|
||||
#ifdef WOLF_CRYPTO_CB_ONLY_RSA
|
||||
@@ -72895,6 +72910,33 @@ exit_onlycb:
|
||||
}
|
||||
#endif /* WOLF_CRYPTO_CB_ONLY_AES */
|
||||
|
||||
#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
|
||||
* from dp, so custom-curve keys (idx == ECC_CUSTOM_IDX) work too;
|
||||
* wc_ecc_export_point_der rejects negative curve indices. */
|
||||
static int myCryptoCbExportPointX963(const ecc_set_type* dp, ecc_point* pub,
|
||||
byte* out, word32* outSz)
|
||||
{
|
||||
int ret;
|
||||
word32 curveSz = (word32)dp->size;
|
||||
word32 ptSz = 1 + 2 * curveSz;
|
||||
word32 xSz = curveSz;
|
||||
word32 ySz = curveSz;
|
||||
|
||||
if (*outSz < ptSz)
|
||||
return BUFFER_E;
|
||||
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)
|
||||
*outSz = ptSz;
|
||||
return ret;
|
||||
}
|
||||
#endif /* HAVE_ECC && !WOLFSSL_NO_MALLOC && HAVE_ECC_KEY_EXPORT */
|
||||
|
||||
/* Example crypto dev callback function that calls software version */
|
||||
static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
@@ -73132,6 +73174,132 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
else if (info->pk.type == WC_PK_TYPE_EC_MAKE_PUB) {
|
||||
#if !defined(WOLFSSL_NO_MALLOC) && defined(HAVE_ECC_KEY_EXPORT)
|
||||
ecc_key* k = info->pk.ecc_make_pub.key;
|
||||
ecc_point* pub;
|
||||
if (myCtx->eccResidentKey != NULL) {
|
||||
/* Secure-element case: the private scalar lives in the device,
|
||||
* so the input key's k is empty. Emit the resident key's
|
||||
* public point directly. Reaching this code at all proves the
|
||||
* dispatch ran before ecc_make_pub_ex's software
|
||||
* private-scalar range check. */
|
||||
ecc_key* src = myCtx->eccResidentKey;
|
||||
ret = myCryptoCbExportPointX963(src->dp, &src->pubkey,
|
||||
info->pk.ecc_make_pub.pubOut,
|
||||
info->pk.ecc_make_pub.pubOutSz);
|
||||
myCtx->eccMakePubCount++;
|
||||
}
|
||||
else {
|
||||
/* set devId to invalid, so software is used */
|
||||
k->devId = INVALID_DEVID;
|
||||
pub = wc_ecc_new_point_h(HEAP_HINT);
|
||||
if (pub == NULL) {
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
else {
|
||||
/* derive Q = d*G then emit X9.63 uncompressed bytes */
|
||||
ret = wc_ecc_make_pub(k, pub);
|
||||
if (ret == 0)
|
||||
ret = myCryptoCbExportPointX963(k->dp, pub,
|
||||
info->pk.ecc_make_pub.pubOut,
|
||||
info->pk.ecc_make_pub.pubOutSz);
|
||||
/* negative test: corrupt the X9.63 tag so the wrapper
|
||||
* rejects the result with BUFFER_E instead of accepting
|
||||
* it */
|
||||
if (ret == 0 && myCtx->eccMakePubBadFormat)
|
||||
info->pk.ecc_make_pub.pubOut[0] = ECC_POINT_COMP_EVEN;
|
||||
/* negative test: claim a result size different from the
|
||||
* curve's X9.63 length so the wrapper rejects the result
|
||||
* with BUFFER_E instead of accepting it */
|
||||
if (ret == 0 && myCtx->eccMakePubBadLen)
|
||||
(*info->pk.ecc_make_pub.pubOutSz)++;
|
||||
wc_ecc_del_point_h(pub, HEAP_HINT);
|
||||
}
|
||||
myCtx->eccMakePubCount++;
|
||||
/* reset devId */
|
||||
k->devId = devIdArg;
|
||||
}
|
||||
#else
|
||||
ret = CRYPTOCB_UNAVAILABLE; /* no software emulation available */
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
else if (info->pk.type == WC_PK_TYPE_EC_CHECK_PUB_KEY) {
|
||||
ecc_key* k = info->pk.ecc_check_pub.key;
|
||||
int validatedFromWire = 0;
|
||||
myCtx->eccCheckPubCount++;
|
||||
if (info->pk.ecc_check_pub.pubKeySz == 0) {
|
||||
/* no host-side public point and this software device holds no
|
||||
* resident key, so there is nothing to validate (matches the
|
||||
* software answer for a missing public point) */
|
||||
ret = ECC_INF_E;
|
||||
}
|
||||
else {
|
||||
ret = 0;
|
||||
if (myCtx != NULL && myCtx->eccCheckPubExpectZeroPoint) {
|
||||
const byte* pub = info->pk.ecc_check_pub.pubKey;
|
||||
word32 curveSz = (word32)k->dp->size;
|
||||
word32 ptSz = 1 + 2 * curveSz;
|
||||
word32 i;
|
||||
|
||||
if (info->pk.ecc_check_pub.pubKeySz != ptSz ||
|
||||
pub[0] != ECC_POINT_UNCOMP) {
|
||||
ret = BAD_STATE_E;
|
||||
}
|
||||
for (i = 1; ret == 0 && i < ptSz; i++) {
|
||||
if (pub[i] != 0)
|
||||
ret = BAD_STATE_E;
|
||||
}
|
||||
if (ret == 0)
|
||||
myCtx->eccCheckPubSawZeroPoint = 1;
|
||||
}
|
||||
#ifdef HAVE_ECC_KEY_IMPORT
|
||||
/* vault-style consumption: rebuild the public key from the
|
||||
* wire bytes and validate the rebuilt key, proving the
|
||||
* serialized point is sufficient and consistent with
|
||||
* key->pubkey. The named-curve import does not apply to
|
||||
* custom-curve keys (idx == ECC_CUSTOM_IDX). */
|
||||
if (k->idx >= 0) {
|
||||
WC_DECLARE_VAR(pubOnly, ecc_key, 1, HEAP_HINT);
|
||||
WC_ALLOC_VAR(pubOnly, ecc_key, 1, HEAP_HINT);
|
||||
if (!WC_VAR_OK(pubOnly))
|
||||
ret = MEMORY_E;
|
||||
else
|
||||
ret = wc_ecc_init_ex(pubOnly, HEAP_HINT, INVALID_DEVID);
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_import_x963_ex(
|
||||
info->pk.ecc_check_pub.pubKey,
|
||||
info->pk.ecc_check_pub.pubKeySz, pubOnly,
|
||||
k->dp->id);
|
||||
if (ret == 0 && wc_ecc_cmp_point(&pubOnly->pubkey,
|
||||
&k->pubkey) != MP_EQ) {
|
||||
/* wire bytes disagree with key->pubkey */
|
||||
ret = BAD_STATE_E;
|
||||
}
|
||||
if (ret == 0)
|
||||
ret = wc_ecc_check_key(pubOnly);
|
||||
wc_ecc_free(pubOnly);
|
||||
}
|
||||
WC_FREE_VAR(pubOnly, HEAP_HINT);
|
||||
validatedFromWire = 1;
|
||||
}
|
||||
#endif
|
||||
/* private/resident part (and custom-curve keys, where the
|
||||
* named-curve import above is unavailable): validate via the
|
||||
* key handle */
|
||||
if (ret == 0 && (!validatedFromWire ||
|
||||
(info->pk.ecc_check_pub.checkPriv &&
|
||||
k->type == ECC_PRIVATEKEY))) {
|
||||
/* set devId to invalid, so software is used */
|
||||
k->devId = INVALID_DEVID;
|
||||
ret = wc_ecc_check_key(k);
|
||||
/* reset devId */
|
||||
k->devId = devIdArg;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif /* HAVE_ECC */
|
||||
#ifdef HAVE_CURVE25519
|
||||
if (info->pk.type == WC_PK_TYPE_CURVE25519_KEYGEN) {
|
||||
@@ -74943,6 +75111,15 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
|
||||
|
||||
/* example data for callback */
|
||||
myCtx.exampleVar = 1;
|
||||
#ifdef HAVE_ECC
|
||||
myCtx.eccMakePubCount = 0;
|
||||
myCtx.eccCheckPubCount = 0;
|
||||
myCtx.eccMakePubBadFormat = 0;
|
||||
myCtx.eccMakePubBadLen = 0;
|
||||
myCtx.eccCheckPubExpectZeroPoint = 0;
|
||||
myCtx.eccCheckPubSawZeroPoint = 0;
|
||||
myCtx.eccResidentKey = NULL;
|
||||
#endif
|
||||
|
||||
/* set devId to something other than INVALID_DEVID */
|
||||
devId = 1;
|
||||
@@ -74974,6 +75151,206 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
|
||||
if (ret == 0)
|
||||
ret = ecc_test();
|
||||
PRIVATE_KEY_LOCK();
|
||||
/* Confirm the new ECC pubkey callbacks were routed through the device and
|
||||
* not silently handled in software. The check-pubkey callback is only
|
||||
* exercised when wc_ecc_check_key is built (HAVE_ECC_CHECK_KEY) and the
|
||||
* ecc_test calls to it are not skipped (WC_TEST_SKIP_ECC_CHECK_KEY); the
|
||||
* counter legitimately stays 0 otherwise. CAAM is excluded because the
|
||||
* check-pubkey dispatch in _ecc_validate_public_key is compiled out there
|
||||
* (CAAM uses software validation failure to detect black keys). */
|
||||
#if !defined(WOLF_CRYPTO_CB_ONLY_ECC) && defined(HAVE_ECC_CHECK_KEY) && \
|
||||
!defined(WC_TEST_SKIP_ECC_CHECK_KEY) && !defined(WOLFSSL_CAAM)
|
||||
if (ret == 0 && myCtx.eccCheckPubCount == 0)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
#endif
|
||||
/* Regression: an explicit public point with zero coordinates must cross
|
||||
* the callback boundary as X9.63 0x04||0||0, not as pubKey = NULL. */
|
||||
#if !defined(WOLFSSL_SWDEV) && defined(HAVE_ECC_CHECK_KEY) && \
|
||||
!defined(WOLFSSL_CAAM) && !defined(NO_ECC256)
|
||||
if (ret == 0) {
|
||||
WC_DECLARE_VAR(zeroKey, ecc_key, 1, HEAP_HINT);
|
||||
int haveZeroKey = 0;
|
||||
|
||||
WC_ALLOC_VAR(zeroKey, ecc_key, 1, HEAP_HINT);
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
if (!WC_VAR_OK(zeroKey))
|
||||
ret = MEMORY_E;
|
||||
else
|
||||
ret = wc_ecc_init_ex(zeroKey, HEAP_HINT, devId);
|
||||
if (ret == 0) {
|
||||
haveZeroKey = 1;
|
||||
ret = wc_ecc_set_curve(zeroKey, 32, ECC_SECP256R1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
zeroKey->type = ECC_PUBLICKEY;
|
||||
myCtx.eccCheckPubExpectZeroPoint = 1;
|
||||
myCtx.eccCheckPubSawZeroPoint = 0;
|
||||
ret = wc_ecc_check_key(zeroKey);
|
||||
myCtx.eccCheckPubExpectZeroPoint = 0;
|
||||
|
||||
if (ret == 0) {
|
||||
ret = WC_TEST_RET_ENC_NC; /* invalid point was accepted */
|
||||
}
|
||||
else if (!myCtx.eccCheckPubSawZeroPoint) {
|
||||
ret = WC_TEST_RET_ENC_NC; /* callback saw NULL/other point */
|
||||
}
|
||||
else {
|
||||
ret = 0; /* expected validation failure after serialization */
|
||||
}
|
||||
}
|
||||
myCtx.eccCheckPubExpectZeroPoint = 0;
|
||||
if (haveZeroKey)
|
||||
wc_ecc_free(zeroKey);
|
||||
WC_FREE_VAR(zeroKey, HEAP_HINT);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
#endif
|
||||
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
|
||||
!defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
|
||||
!defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
|
||||
!defined(NO_ECC_SECP) && !defined(WOLFSSL_NO_MALLOC) && \
|
||||
!defined(WOLFSSL_CRYPTOCELL) && !defined(NO_ECC256) && \
|
||||
defined(HAVE_ECC_KEY_EXPORT)
|
||||
if (ret == 0 && myCtx.eccMakePubCount == 0)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
#endif
|
||||
/* Exercise the make-pub wrapper's device-result validation and the
|
||||
* resident-key dispatch path. Only meaningful where myCryptoDevCb (not
|
||||
* swdev) services the make-pub callback.
|
||||
*
|
||||
* WOLFSSL_SE050 is excluded: its wc_ecc_make_key generates the key in the
|
||||
* element, so srcKey has no host-side scalar (key->k) for the callback's
|
||||
* software Q = d*G derivation to use. */
|
||||
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
|
||||
!defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_STM32_PKA) && \
|
||||
!defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \
|
||||
!defined(WOLFSSL_SWDEV) && !defined(NO_ECC_SECP) && \
|
||||
!defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_CRYPTOCELL) && \
|
||||
!defined(WOLFSSL_SE050) && \
|
||||
!defined(NO_ECC256) && defined(HAVE_ECC_KEY_EXPORT) && !defined(WC_NO_RNG)
|
||||
if (ret == 0) {
|
||||
/* generated keypair: private scalar for the negative tests, public
|
||||
* point for the resident-key test */
|
||||
WC_DECLARE_VAR(srcKey, ecc_key, 1, HEAP_HINT);
|
||||
/* device-backed key with an empty private scalar */
|
||||
WC_DECLARE_VAR(resKey, ecc_key, 1, HEAP_HINT);
|
||||
WC_DECLARE_VAR(eccRng, WC_RNG, 1, HEAP_HINT);
|
||||
ecc_point* outPub = NULL;
|
||||
int haveSrc = 0, haveRes = 0, haveRng = 0;
|
||||
int beforeCount = 0;
|
||||
|
||||
WC_ALLOC_VAR(srcKey, ecc_key, 1, HEAP_HINT);
|
||||
WC_ALLOC_VAR(resKey, ecc_key, 1, HEAP_HINT);
|
||||
WC_ALLOC_VAR(eccRng, WC_RNG, 1, HEAP_HINT);
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
if (!WC_VAR_OK(srcKey) || !WC_VAR_OK(resKey) || !WC_VAR_OK(eccRng))
|
||||
ret = MEMORY_E;
|
||||
else
|
||||
ret = wc_InitRng_ex(eccRng, HEAP_HINT, devId);
|
||||
if (ret == 0) {
|
||||
haveRng = 1;
|
||||
ret = wc_ecc_init_ex(srcKey, HEAP_HINT, devId);
|
||||
}
|
||||
if (ret == 0) {
|
||||
haveSrc = 1;
|
||||
ret = wc_ecc_make_key(eccRng, 32, srcKey);
|
||||
}
|
||||
if (ret == 0) {
|
||||
outPub = wc_ecc_new_point_h(HEAP_HINT);
|
||||
if (outPub == NULL)
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
/* Negative test: when the device returns a malformed
|
||||
* (non-uncompressed) point, wc_CryptoCb_EccMakePub must reject it
|
||||
* with BUFFER_E rather than accept a bad public key. */
|
||||
if (ret == 0) {
|
||||
myCtx.eccMakePubBadFormat = 1;
|
||||
ret = wc_ecc_make_pub(srcKey, outPub);
|
||||
myCtx.eccMakePubBadFormat = 0;
|
||||
/* expect the wrapper to reject the malformed point */
|
||||
if (ret == WC_NO_ERR_TRACE(BUFFER_E))
|
||||
ret = 0;
|
||||
else if (ret == 0)
|
||||
ret = WC_TEST_RET_ENC_NC; /* must not silently succeed */
|
||||
else
|
||||
ret = WC_TEST_RET_ENC_EC(ret); /* unexpected error */
|
||||
}
|
||||
/* Negative test: when the device claims a result size different from
|
||||
* the curve's X9.63 length, wc_CryptoCb_EccMakePub must reject it
|
||||
* with BUFFER_E rather than silently truncate it. */
|
||||
if (ret == 0) {
|
||||
myCtx.eccMakePubBadLen = 1;
|
||||
ret = wc_ecc_make_pub(srcKey, outPub);
|
||||
myCtx.eccMakePubBadLen = 0;
|
||||
if (ret == WC_NO_ERR_TRACE(BUFFER_E))
|
||||
ret = 0;
|
||||
else if (ret == 0)
|
||||
ret = WC_TEST_RET_ENC_NC; /* must not silently succeed */
|
||||
else
|
||||
ret = WC_TEST_RET_ENC_EC(ret); /* unexpected error */
|
||||
}
|
||||
/* Regression: a key whose private scalar is resident in the device
|
||||
* (the input key's k is empty here) must still produce its public
|
||||
* key. The make-pub dispatch has to run before ecc_make_pub_ex's
|
||||
* software private-scalar range check; otherwise this returns
|
||||
* ECC_PRIV_KEY_E and the callback is never reached. */
|
||||
if (ret == 0)
|
||||
ret = wc_ecc_init_ex(resKey, HEAP_HINT, devId);
|
||||
if (ret == 0) {
|
||||
haveRes = 1;
|
||||
/* device-backed key: same curve, but no private scalar present */
|
||||
ret = wc_ecc_set_curve(resKey, 32, ECC_SECP256R1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* device serves make-pub from srcKey's resident public point */
|
||||
myCtx.eccResidentKey = srcKey;
|
||||
beforeCount = myCtx.eccMakePubCount;
|
||||
ret = wc_ecc_make_pub(resKey, NULL);
|
||||
myCtx.eccResidentKey = NULL;
|
||||
|
||||
if (ret != 0) {
|
||||
/* before the fix this is ECC_PRIV_KEY_E: the empty scalar was
|
||||
* rejected before the dispatch could run */
|
||||
ret = WC_TEST_RET_ENC_EC(ret);
|
||||
}
|
||||
else if (myCtx.eccMakePubCount != beforeCount + 1) {
|
||||
ret = WC_TEST_RET_ENC_NC; /* callback was bypassed */
|
||||
}
|
||||
else if (wc_ecc_cmp_point(&resKey->pubkey, &srcKey->pubkey)
|
||||
!= MP_EQ) {
|
||||
ret = WC_TEST_RET_ENC_NC; /* wrong public point produced */
|
||||
}
|
||||
}
|
||||
#ifdef WOLFSSL_CUSTOM_CURVES
|
||||
/* Regression: make-pub via the device for a custom-curve key
|
||||
* (idx == ECC_CUSTOM_IDX): the handler must serialize the point
|
||||
* using key->dp->size, not ecc_sets[key->idx]. Reuse srcKey's P-256
|
||||
* parameters under a custom-curve identity. */
|
||||
if (ret == 0)
|
||||
ret = wc_ecc_set_custom_curve(srcKey,
|
||||
wc_ecc_get_curve_params(srcKey->idx));
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_make_pub(srcKey, outPub);
|
||||
if (ret != 0)
|
||||
ret = WC_TEST_RET_ENC_EC(ret);
|
||||
else if (wc_ecc_cmp_point(outPub, &srcKey->pubkey) != MP_EQ)
|
||||
ret = WC_TEST_RET_ENC_NC; /* wrong public point produced */
|
||||
}
|
||||
#endif /* WOLFSSL_CUSTOM_CURVES */
|
||||
if (outPub != NULL)
|
||||
wc_ecc_del_point_h(outPub, HEAP_HINT);
|
||||
if (haveRes)
|
||||
wc_ecc_free(resKey);
|
||||
if (haveSrc)
|
||||
wc_ecc_free(srcKey);
|
||||
if (haveRng)
|
||||
wc_FreeRng(eccRng);
|
||||
WC_FREE_VAR(srcKey, HEAP_HINT);
|
||||
WC_FREE_VAR(resKey, HEAP_HINT);
|
||||
WC_FREE_VAR(eccRng, HEAP_HINT);
|
||||
PRIVATE_KEY_LOCK();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLFSSL_SWDEV)
|
||||
PRIVATE_KEY_UNLOCK();
|
||||
|
||||
@@ -245,6 +245,25 @@ 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;
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
struct {
|
||||
ecc_key* key; /* routing, curve, heap, resident priv */
|
||||
const byte* pubKey; /* X9.63 0x04||X||Y of key->pubkey; NULL
|
||||
* when key state is ECC_PRIVATEKEY_ONLY */
|
||||
word32 pubKeySz; /* 0 when pubKey is NULL */
|
||||
int checkOrder; /* 1: validate the point has the curve
|
||||
* order (point * order == infinity) */
|
||||
int checkPriv; /* 1: also validate the private part
|
||||
* (scalar range, consistency with the
|
||||
* public point) */
|
||||
} ecc_check_pub; /* distinct from ecc_check (priv-key cmp) */
|
||||
#endif
|
||||
#endif /* HAVE_ECC */
|
||||
#ifdef HAVE_CURVE25519
|
||||
struct {
|
||||
@@ -748,6 +767,12 @@ 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);
|
||||
#ifdef HAVE_ECC_CHECK_KEY
|
||||
WOLFSSL_LOCAL int wc_CryptoCb_EccCheckPubKey(ecc_key* key, int checkOrder,
|
||||
int checkPriv);
|
||||
#endif
|
||||
#endif /* HAVE_ECC */
|
||||
|
||||
#ifdef HAVE_CURVE25519
|
||||
|
||||
@@ -1595,6 +1595,10 @@ 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,
|
||||
WC_PK_TYPE_EC_CHECK_PUB_KEY = 35,
|
||||
#undef _WC_PK_TYPE_MAX
|
||||
#define _WC_PK_TYPE_MAX WC_PK_TYPE_EC_CHECK_PUB_KEY
|
||||
WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user