diff --git a/src/wp_ecc_kmgmt.c b/src/wp_ecc_kmgmt.c index 4b5f31e2..5ebb0e1f 100644 --- a/src/wp_ecc_kmgmt.c +++ b/src/wp_ecc_kmgmt.c @@ -747,7 +747,7 @@ static int wp_ecc_get_params_enc_pub_key(wp_Ecc* ecc, OSSL_PARAM params[], p = OSSL_PARAM_locate(params, key); if (p != NULL) { int rc; - word32 outLen = (word32)p->return_size; + word32 outLen = (word32)p->data_size; if (ecc->hasPub == 0) { ok = 0; diff --git a/src/wp_ecx_kmgmt.c b/src/wp_ecx_kmgmt.c index b26df4ec..b9291a88 100644 --- a/src/wp_ecx_kmgmt.c +++ b/src/wp_ecx_kmgmt.c @@ -547,7 +547,7 @@ static int wp_ecx_get_params_enc_pub_key(wp_Ecx* ecx, OSSL_PARAM params[], p = OSSL_PARAM_locate(params, key); if (p != NULL) { - word32 outLen = (word32)p->return_size; + word32 outLen = (word32)p->data_size; if (p->data == NULL) { outLen = ecx->data->len; @@ -584,7 +584,7 @@ static int wp_ecx_get_params_priv_key(wp_Ecx* ecx, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY); if (p != NULL) { - word32 outLen = (word32)p->return_size; + word32 outLen = (word32)p->data_size; if (p->data == NULL) { outLen = ecx->data->len; diff --git a/test/test_ecc.c b/test/test_ecc.c index 58d816d9..18d4aa71 100644 --- a/test/test_ecc.c +++ b/test/test_ecc.c @@ -519,6 +519,83 @@ int test_eckeygen_p256(void *data) return err; } + +/* get_params for the ECC encoded public key must size the export buffer from + * data_size, not a stale/zero return_size. Compare a stale-return_size export + * against a known-good fresh export of the same key. */ +int test_ecc_p256_get_params_stale_ret(void *data) +{ + int err = 0; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *key = NULL; + unsigned char ref[128]; + unsigned char readback[128]; + size_t refLen = 0; + OSSL_PARAM params[2]; + + (void)data; + + PRINT_MSG("P-256 encoded pub key get_params with stale return_size"); + + err = (ctx = EVP_PKEY_CTX_new_from_name(wpLibCtx, "EC", NULL)) == NULL; + if (err == 0) { + err = EVP_PKEY_keygen_init(ctx) != 1; + } + if (err == 0) { + err = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, + NID_X9_62_prime256v1) != 1; + } + if (err == 0) { + err = EVP_PKEY_keygen(ctx, &key) != 1; + } + + /* Reference export via a fresh param. Its return_size defaults to + * OSSL_PARAM_UNMODIFIED, so this block succeeds even with the bug; the + * stale-return_size query below is the actual regression check. */ + if (err == 0) { + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, ref, sizeof(ref)); + params[1] = OSSL_PARAM_construct_end(); + if (EVP_PKEY_get_params(key, params) != 1) { + PRINT_ERR_MSG("reference encoded pub key get_params failed"); + err = 1; + } + else { + refLen = params[0].return_size; + } + } + if (err == 0 && (refLen == 0 || refLen > sizeof(ref))) { + PRINT_ERR_MSG("unexpected encoded pub key length: %zu", refLen); + err = 1; + } + + /* Same query with return_size forced to 0 to mimic a reused param. */ + if (err == 0) { + memset(readback, 0, sizeof(readback)); + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, readback, sizeof(readback)); + params[0].return_size = 0; + params[1] = OSSL_PARAM_construct_end(); + if (EVP_PKEY_get_params(key, params) != 1) { + PRINT_ERR_MSG("encoded pub key get_params failed with stale " + "return_size"); + err = 1; + } + } + if (err == 0 && params[0].return_size != refLen) { + PRINT_ERR_MSG("encoded pub key return_size wrong: %zu vs %zu", + params[0].return_size, refLen); + err = 1; + } + if (err == 0 && memcmp(readback, ref, refLen) != 0) { + PRINT_ERR_MSG("encoded pub key bytes not returned correctly"); + err = 1; + } + + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(ctx); + return err; +} #endif /* WP_HAVE_EC_P256 */ #ifdef WP_HAVE_EC_P384 diff --git a/test/test_ecx.c b/test/test_ecx.c index d316446e..c8a4d689 100644 --- a/test/test_ecx.c +++ b/test/test_ecx.c @@ -758,6 +758,109 @@ int test_ecx_x25519_raw_priv_roundtrip(void *data) return err; } +/* get_params must size the export buffer from the caller's data_size, not + * return_size. A reused param can carry a stale/zero return_size from a prior + * size query; using it would truncate or fail the export. */ +int test_ecx_x25519_get_params_stale_ret(void *data) +{ + int err = 0; + EVP_PKEY *pkey = NULL; + static const unsigned char privKey[] = { + 0x77, 0x07, 0x6d, 0x0a, 0x73, 0x18, 0xa5, 0x7d, + 0x3c, 0x16, 0xc1, 0x72, 0x51, 0xb2, 0x66, 0x45, + 0xdf, 0x4c, 0x2f, 0x87, 0xeb, 0xc0, 0x99, 0x2a, + 0xb1, 0x77, 0xfb, 0xa5, 0x1d, 0xb9, 0x2c, 0x2a + }; + /* RFC 7748 Section 6.1 Alice public key, derived from privKey above. */ + static const unsigned char pubKey[] = { + 0x85, 0x20, 0xf0, 0x09, 0x89, 0x30, 0xa7, 0x54, + 0x74, 0x8b, 0x7d, 0xdc, 0xb4, 0x3e, 0xf7, 0x5a, + 0x0d, 0xbf, 0x3a, 0x0d, 0x26, 0x38, 0x1a, 0xf4, + 0xeb, 0xa4, 0xa9, 0x8e, 0xaa, 0x9b, 0x4e, 0x6a + }; + unsigned char readback[32]; + OSSL_PARAM params[2]; + + (void)data; + + PRINT_MSG("X25519 get_params with stale (zero) return_size"); + + pkey = EVP_PKEY_new_raw_private_key_ex(wpLibCtx, "X25519", NULL, + privKey, sizeof(privKey)); + if (pkey == NULL) { + PRINT_ERR_MSG("Failed to import X25519 private key"); + err = 1; + } + + /* Private key: full 32-byte buffer but return_size forced to 0. */ + if (err == 0) { + memset(readback, 0, sizeof(readback)); + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PRIV_KEY, readback, sizeof(readback)); + params[0].return_size = 0; + params[1] = OSSL_PARAM_construct_end(); + if (EVP_PKEY_get_params(pkey, params) != 1) { + PRINT_ERR_MSG("priv key get_params failed with stale return_size"); + err = 1; + } + } + if (err == 0 && params[0].return_size != sizeof(privKey)) { + PRINT_ERR_MSG("priv key return_size wrong: %zu", params[0].return_size); + err = 1; + } + if (err == 0 && memcmp(readback, privKey, sizeof(privKey)) != 0) { + PRINT_ERR_MSG("priv key bytes not returned correctly"); + err = 1; + } + + /* Public key: same stale-return_size condition on the export path. */ + if (err == 0) { + memset(readback, 0, sizeof(readback)); + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_PUB_KEY, readback, sizeof(readback)); + params[0].return_size = 0; + params[1] = OSSL_PARAM_construct_end(); + if (EVP_PKEY_get_params(pkey, params) != 1) { + PRINT_ERR_MSG("pub key get_params failed with stale return_size"); + err = 1; + } + } + if (err == 0 && params[0].return_size != sizeof(pubKey)) { + PRINT_ERR_MSG("pub key return_size wrong: %zu", params[0].return_size); + err = 1; + } + if (err == 0 && memcmp(readback, pubKey, sizeof(pubKey)) != 0) { + PRINT_ERR_MSG("pub key bytes not returned correctly"); + err = 1; + } + + /* Encoded public key: same helper, exercised via its own key string. */ + if (err == 0) { + memset(readback, 0, sizeof(readback)); + params[0] = OSSL_PARAM_construct_octet_string( + OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, readback, sizeof(readback)); + params[0].return_size = 0; + params[1] = OSSL_PARAM_construct_end(); + if (EVP_PKEY_get_params(pkey, params) != 1) { + PRINT_ERR_MSG("enc pub key get_params failed with stale " + "return_size"); + err = 1; + } + } + if (err == 0 && params[0].return_size != sizeof(pubKey)) { + PRINT_ERR_MSG("enc pub key return_size wrong: %zu", + params[0].return_size); + err = 1; + } + if (err == 0 && memcmp(readback, pubKey, sizeof(pubKey)) != 0) { + PRINT_ERR_MSG("enc pub key bytes not returned correctly"); + err = 1; + } + + EVP_PKEY_free(pkey); + return err; +} + /* A zero-length private key octet string must be rejected without an * out-of-bounds read (privData[len-1] with len==0). */ int test_ecx_import_zero_priv(void *data) diff --git a/test/unit.c b/test/unit.c index c802390c..c8afafb0 100644 --- a/test/unit.c +++ b/test/unit.c @@ -407,6 +407,7 @@ TEST_CASE test_case[] = { #ifdef WP_HAVE_EC_P256 #ifdef WP_HAVE_ECKEYGEN TEST_DECL(test_eckeygen_p256, NULL), + TEST_DECL(test_ecc_p256_get_params_stale_ret, NULL), #endif #ifdef WP_HAVE_ECDH #ifdef WP_HAVE_ECKEYGEN @@ -515,6 +516,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_ecx_null_init, NULL), #ifdef WP_HAVE_X25519 TEST_DECL(test_ecx_x25519_raw_priv_roundtrip, NULL), + TEST_DECL(test_ecx_x25519_get_params_stale_ret, NULL), TEST_DECL(test_ecx_import_zero_priv, NULL), #endif TEST_DECL(test_ecx_dup, NULL), diff --git a/test/unit.h b/test/unit.h index 6b617944..e003fadd 100644 --- a/test/unit.h +++ b/test/unit.h @@ -380,6 +380,7 @@ int test_eckeygen_p224(void *data); #ifdef WP_HAVE_EC_P256 int test_eckeygen_p256(void *data); +int test_ecc_p256_get_params_stale_ret(void *data); #endif /* WP_HAVE_EC_P256 */ #ifdef WP_HAVE_EC_P384 @@ -522,6 +523,7 @@ int test_ecx_misc(void *data); int test_ecx_null_init(void *data); #ifdef WP_HAVE_X25519 int test_ecx_x25519_raw_priv_roundtrip(void *data); +int test_ecx_x25519_get_params_stale_ret(void *data); int test_ecx_import_zero_priv(void *data); #endif /* WP_HAVE_X25519 */ int test_ecx_dup(void *data);