Skip to content

Commit 045c58e

Browse files
committed
pkcs7, tls, openssl: derive the public point for a private-only key
These decode SEC1 and then need the point. The static ECDH key derives after the key share's curve check, so the stored key stays as set. pk_ec.c tried before under an ecc.c-private guard it never sees.
1 parent b1cd683 commit 045c58e

9 files changed

Lines changed: 635 additions & 92 deletions

File tree

‎src/pk_ec.c‎

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3499,22 +3499,12 @@ WOLFSSL_EC_KEY* wolfSSL_d2i_ECPrivateKey(WOLFSSL_EC_KEY** key,
34993499
/* Internal EC key setup. */
35003500
ret->inSet = 1;
35013501

3502-
/* When the RFC 5915 DER encoding omits the optional publicKey field,
3503-
* wc_EccPrivateKeyDecode leaves type == ECC_PRIVATEKEY_ONLY with the
3504-
* public point uninitialised. Derive the public point now so that
3505-
* all downstream operations (sign, ECDH, export) have a valid key,
3506-
* matching the behaviour of OpenSSL's d2i_ECPrivateKey.
3507-
* In builds without HAVE_ECC_MAKE_PUB (e.g. hardware/CB-only),
3508-
* keep the historical import behaviour and leave the key as
3509-
* private-only instead of failing import. */
3510-
#ifdef HAVE_ECC_MAKE_PUB
3511-
if (((ecc_key*)ret->internal)->type == ECC_PRIVATEKEY_ONLY) {
3512-
if (wc_ecc_make_pub((ecc_key*)ret->internal, NULL) != 0) {
3513-
WOLFSSL_MSG("wc_ecc_make_pub error deriving public key");
3514-
err = 1;
3515-
}
3502+
/* RFC 5915 makes publicKey optional: derive the point, as OpenSSL
3503+
* does, so sign, ECDH and export have a full key. */
3504+
if (wc_ecc_derive_pub_if_needed((ecc_key*)ret->internal, NULL) != 0) {
3505+
WOLFSSL_MSG("error deriving public key");
3506+
err = 1;
35163507
}
3517-
#endif
35183508
}
35193509

35203510
if (!err) {
@@ -3696,8 +3686,46 @@ int wolfSSL_EC_KEY_LoadDer_ex(WOLFSSL_EC_KEY* key, const unsigned char* derBuf,
36963686
if (res == 1) {
36973687
/* Load into internal EC key based on key type option. */
36983688
if (opt == WOLFSSL_EC_KEY_LOAD_PRIVATE) {
3699-
ret = wc_EccPrivateKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
3700-
(word32)derSz);
3689+
ecc_key* cur = (ecc_key*)key->internal;
3690+
void* heap = cur->heap;
3691+
#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB)
3692+
int devId = cur->devId;
3693+
#else
3694+
int devId = INVALID_DEVID;
3695+
#endif
3696+
/* Decode into a new key so a rejected one leaves the internal key
3697+
* as it was. */
3698+
ecc_key* tmp = (ecc_key*)XMALLOC(sizeof(ecc_key), heap,
3699+
DYNAMIC_TYPE_ECC);
3700+
3701+
if (tmp == NULL) {
3702+
ret = MEMORY_E;
3703+
}
3704+
else {
3705+
ret = wc_ecc_init_ex(tmp, heap, devId);
3706+
if (ret == 0) {
3707+
#ifdef ECC_TIMING_RESISTANT
3708+
/* Caller-owned. devCtx is not carried over: freeing the
3709+
* old key tells the device to release it. */
3710+
tmp->rng = cur->rng;
3711+
#endif
3712+
ret = wc_EccPrivateKeyDecode(derBuf, &idx, tmp,
3713+
(word32)derSz);
3714+
/* RFC 5915 makes publicKey optional. */
3715+
if (ret == 0) {
3716+
ret = wc_ecc_derive_pub_if_needed(tmp, NULL);
3717+
}
3718+
if (ret == 0) {
3719+
/* Take ownership of new key - set tmp to the old
3720+
* key which will then be freed below. */
3721+
ecc_key* old = (ecc_key*)key->internal;
3722+
key->internal = tmp;
3723+
tmp = old;
3724+
}
3725+
wc_ecc_free(tmp);
3726+
}
3727+
XFREE(tmp, heap, DYNAMIC_TYPE_ECC);
3728+
}
37013729
}
37023730
else {
37033731
ret = wc_EccPublicKeyDecode(derBuf, &idx, (ecc_key*)key->internal,
@@ -4419,7 +4447,8 @@ int SetECKeyExternal(WOLFSSL_EC_KEY* eckey)
44194447
}
44204448

44214449
/* set the external privkey */
4422-
if ((ret == 1) && (key->type == ECC_PRIVATEKEY) &&
4450+
if ((ret == 1) && ((key->type == ECC_PRIVATEKEY) ||
4451+
(key->type == ECC_PRIVATEKEY_ONLY)) &&
44234452
(wolfssl_bn_set_value(&eckey->priv_key,
44244453
wc_ecc_key_get_priv(key)) != 1)) {
44254454
WOLFSSL_MSG("ec priv key error");

‎src/tls.c‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8906,6 +8906,13 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
89068906

89078907
#ifdef WOLFSSL_STATIC_EPHEMERAL
89088908
ret = wolfSSL_StaticEphemeralKeyLoad(ssl, WC_PK_TYPE_ECDH, kse->key);
8909+
if ((ret == 0) && (eccKey->dp->id == curveId)) {
8910+
/* SEC1 makes the public point optional, and the key share sends
8911+
* it. A failed derivation leaves the key private-only so the
8912+
* export below fails the handshake: returning the error would
8913+
* generate a key in place of the configured one. */
8914+
(void)wc_ecc_derive_pub_if_needed(eccKey, ssl->rng);
8915+
}
89098916
if (ret != 0 || eccKey->dp->id != curveId)
89108917
#endif
89118918
{

0 commit comments

Comments
 (0)