diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 1376cff2a03..86af752a070 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -9439,6 +9439,14 @@ int wc_ecc_import_point_der_ex(const byte* in, word32 inLen, return ECC_BAD_ARG_E; } + /* validate point format byte before any memory operations */ + pointType = in[0]; + if (pointType != ECC_POINT_UNCOMP && + pointType != ECC_POINT_COMP_EVEN && + pointType != ECC_POINT_COMP_ODD) { + return ASN_PARSE_E; + } + /* clear if previously allocated */ mp_clear(point->x); mp_clear(point->y); @@ -9460,16 +9468,17 @@ int wc_ecc_import_point_der_ex(const byte* in, word32 inLen, SAVE_VECTOR_REGISTERS(return _svr_ret;); - /* check for point type (4, 2, or 3) */ - pointType = in[0]; - if (pointType != ECC_POINT_UNCOMP && pointType != ECC_POINT_COMP_EVEN && - pointType != ECC_POINT_COMP_ODD) { - err = ASN_PARSE_E; - } - + /* pointType already validated above; check for compressed format */ if (pointType == ECC_POINT_COMP_EVEN || pointType == ECC_POINT_COMP_ODD) { #ifdef HAVE_COMP_KEY - compressed = 1; + /* Compressed point must be exactly 1 + field_element_size bytes. + * Reject truncated inputs (e.g. a bare 0x02/0x03 byte). */ + if (inLen == (word32)ecc_sets[curve_idx].size + 1) { + compressed = 1; + } + else { + err = ECC_BAD_ARG_E; + } #else err = NOT_COMPILED_IN; #endif diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 9aaefbef2b0..97993c7c0c0 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -4010,24 +4010,65 @@ int wolfSSL_EVP_PKEY_cmp(const WOLFSSL_EVP_PKEY *a, const WOLFSSL_EVP_PKEY *b) #endif /* !NO_RSA */ #ifdef HAVE_ECC case WC_EVP_PKEY_EC: - if (a->ecc == NULL || a->ecc->internal == NULL || - b->ecc == NULL || b->ecc->internal == NULL || - wc_ecc_size((ecc_key*)a->ecc->internal) <= 0 || - wc_ecc_size((ecc_key*)b->ecc->internal) <= 0 || + { + ecc_key* ecc_key_a; + ecc_key* ecc_key_b; + + if (a->ecc == NULL || b->ecc == NULL || a->ecc->group == NULL || b->ecc->group == NULL) { return ret; } + /* Ensure internal ecc_key is synced from external representation. + * After d2i_PrivateKey, the external BIGNUMs may be set but the + * internal ecc_key.pubkey may not be populated. */ + if (a->ecc->inSet == 0) { + if (SetECKeyInternal((WOLFSSL_EC_KEY*)a->ecc) != 1) { + return ret; + } + } + if (b->ecc->inSet == 0) { + if (SetECKeyInternal((WOLFSSL_EC_KEY*)b->ecc) != 1) { + return ret; + } + } + + if (a->ecc->internal == NULL || b->ecc->internal == NULL || + wc_ecc_size((ecc_key*)a->ecc->internal) <= 0 || + wc_ecc_size((ecc_key*)b->ecc->internal) <= 0) { + return ret; + } + + ecc_key_a = (ecc_key*)a->ecc->internal; + ecc_key_b = (ecc_key*)b->ecc->internal; + + /* If a key was imported as private-only (e.g. RFC 5915 without the + * optional public key), the pubkey point will not be populated. + * Derive it from the private key so the comparison can succeed. */ + if (ecc_key_a->type == ECC_PRIVATEKEY_ONLY) { + if (wc_ecc_make_pub(ecc_key_a, NULL) != MP_OKAY) { + return ret; + } + ecc_key_a->type = ECC_PRIVATEKEY; + } + if (ecc_key_b->type == ECC_PRIVATEKEY_ONLY) { + if (wc_ecc_make_pub(ecc_key_b, NULL) != MP_OKAY) { + return ret; + } + ecc_key_b->type = ECC_PRIVATEKEY; + } + /* check curve */ if (a->ecc->group->curve_idx != b->ecc->group->curve_idx) { return WS_RETURN_CODE(ret, WOLFSSL_FAILURE); } - if (wc_ecc_cmp_point(&((ecc_key*)a->ecc->internal)->pubkey, - &((ecc_key*)b->ecc->internal)->pubkey) != 0) { + if (wc_ecc_cmp_point(&ecc_key_a->pubkey, + &ecc_key_b->pubkey) != 0) { return WS_RETURN_CODE(ret, WOLFSSL_FAILURE); } break; + } #endif /* HAVE_ECC */ default: return WS_RETURN_CODE(ret, -2);