mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Improve openssl ext to generate EC keys with custom EC parameters
This change extends supported parameter when generating EC keys. Specifically following parameters are now supported: p, a, b, order, generator, seed, cofactory, g_x, g_y, x, y and d. Those parameters can be passed to ec field in openssl_pkey_new options. It also fixes some issues openssl_pkey_get_details related to SM2 support. Closes GH-9991
This commit is contained in:
3
NEWS
3
NEWS
@@ -10,6 +10,9 @@ PHP NEWS
|
||||
. Fixed line number of JMP instruction over else block. (ilutov)
|
||||
. Fixed use-of-uninitialized-value with ??= on assert. (ilutov)
|
||||
|
||||
- OpenSSL
|
||||
. Added support for additional EC parameters in openssl_pkey_new. (Eno-CN)
|
||||
|
||||
06 Jul 2023, PHP 8.3.0alpha3
|
||||
|
||||
- Core:
|
||||
|
||||
@@ -97,6 +97,14 @@
|
||||
|
||||
#if !defined(OPENSSL_NO_EC) && defined(EVP_PKEY_EC)
|
||||
#define HAVE_EVP_PKEY_EC 1
|
||||
|
||||
/* the OPENSSL_EC_EXPLICIT_CURVE value was added
|
||||
* in OpenSSL 1.1.0; previous versions should
|
||||
* use 0 instead.
|
||||
*/
|
||||
#ifndef OPENSSL_EC_EXPLICIT_CURVE
|
||||
#define OPENSSL_EC_EXPLICIT_CURVE 0x000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(openssl)
|
||||
@@ -4264,158 +4272,290 @@ cleanup:
|
||||
#ifdef HAVE_EVP_PKEY_EC
|
||||
#if PHP_OPENSSL_API_VERSION < 0x30000
|
||||
static bool php_openssl_pkey_init_legacy_ec(EC_KEY *eckey, zval *data, bool *is_private) {
|
||||
BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL, *g_x = NULL, *g_y = NULL , *cofactor = NULL;
|
||||
BIGNUM *x = NULL, *y = NULL, *d = NULL;
|
||||
EC_POINT *point_g = NULL;
|
||||
EC_POINT *point_q = NULL;
|
||||
EC_GROUP *group = NULL;
|
||||
EC_POINT *pnt = NULL;
|
||||
BIGNUM *d = NULL;
|
||||
zval *bn;
|
||||
zval *x;
|
||||
zval *y;
|
||||
BN_CTX *bctx = BN_CTX_new();
|
||||
|
||||
*is_private = false;
|
||||
|
||||
if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1)) != NULL &&
|
||||
Z_TYPE_P(bn) == IS_STRING) {
|
||||
int nid = OBJ_sn2nid(Z_STRVAL_P(bn));
|
||||
if (nid != NID_undef) {
|
||||
group = EC_GROUP_new_by_curve_name(nid);
|
||||
if (!group) {
|
||||
php_openssl_store_errors();
|
||||
zval *curve_name_zv = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1);
|
||||
if (curve_name_zv && Z_TYPE_P(curve_name_zv) == IS_STRING && Z_STRLEN_P(curve_name_zv) > 0) {
|
||||
int nid = OBJ_sn2nid(Z_STRVAL_P(curve_name_zv));
|
||||
if (nid == NID_undef) {
|
||||
php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(curve_name_zv));
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!(group = EC_GROUP_new_by_curve_name(nid))) {
|
||||
goto clean_exit;
|
||||
}
|
||||
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
|
||||
} else {
|
||||
OPENSSL_PKEY_SET_BN(data, p);
|
||||
OPENSSL_PKEY_SET_BN(data, a);
|
||||
OPENSSL_PKEY_SET_BN(data, b);
|
||||
OPENSSL_PKEY_SET_BN(data, order);
|
||||
|
||||
if (!(p && a && b && order)) {
|
||||
if (!p && !a && !b && !order) {
|
||||
php_error_docref(NULL, E_WARNING, "Missing params: curve_name");
|
||||
} else {
|
||||
php_error_docref(
|
||||
NULL, E_WARNING, "Missing params: curve_name or p, a, b, order");
|
||||
}
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!(group = EC_GROUP_new_curve_GFp(p, a, b, bctx))) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!(point_g = EC_POINT_new(group))) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
zval *generator_zv = zend_hash_str_find(Z_ARRVAL_P(data), "generator", sizeof("generator") - 1);
|
||||
if (generator_zv && Z_TYPE_P(generator_zv) == IS_STRING && Z_STRLEN_P(generator_zv) > 0) {
|
||||
if (!(EC_POINT_oct2point(group, point_g, (unsigned char *)Z_STRVAL_P(generator_zv), Z_STRLEN_P(generator_zv), bctx))) {
|
||||
goto clean_exit;
|
||||
}
|
||||
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
|
||||
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
|
||||
if (!EC_KEY_set_group(eckey, group)) {
|
||||
php_openssl_store_errors();
|
||||
} else {
|
||||
OPENSSL_PKEY_SET_BN(data, g_x);
|
||||
OPENSSL_PKEY_SET_BN(data, g_y);
|
||||
|
||||
if (!g_x || !g_y) {
|
||||
php_error_docref(
|
||||
NULL, E_WARNING, "Missing params: generator or g_x and g_y");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(group, point_g, g_x, g_y, bctx)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
zval *seed_zv = zend_hash_str_find(Z_ARRVAL_P(data), "seed", sizeof("seed") - 1);
|
||||
if (seed_zv && Z_TYPE_P(seed_zv) == IS_STRING && Z_STRLEN_P(seed_zv) > 0) {
|
||||
if (!EC_GROUP_set_seed(group, (unsigned char *)Z_STRVAL_P(seed_zv), Z_STRLEN_P(seed_zv))) {
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OpenSSL uses 0 cofactor as a marker for "unknown cofactor".
|
||||
* So accept cofactor == NULL or cofactor >= 0.
|
||||
* Internally, the lib will check the cofactor value.
|
||||
*/
|
||||
OPENSSL_PKEY_SET_BN(data, cofactor);
|
||||
if (!EC_GROUP_set_generator(group, point_g, order, cofactor)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_EXPLICIT_CURVE);
|
||||
}
|
||||
|
||||
if (group == NULL) {
|
||||
php_error_docref(NULL, E_WARNING, "Unknown curve name");
|
||||
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
|
||||
|
||||
if (!EC_KEY_set_group(eckey, group)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// The public key 'pnt' can be calculated from 'd' or is defined by 'x' and 'y'
|
||||
if ((bn = zend_hash_str_find(Z_ARRVAL_P(data), "d", sizeof("d") - 1)) != NULL &&
|
||||
Z_TYPE_P(bn) == IS_STRING) {
|
||||
OPENSSL_PKEY_SET_BN(data, d);
|
||||
OPENSSL_PKEY_SET_BN(data, x);
|
||||
OPENSSL_PKEY_SET_BN(data, y);
|
||||
|
||||
if (d) {
|
||||
*is_private = true;
|
||||
d = BN_bin2bn((unsigned char*) Z_STRVAL_P(bn), Z_STRLEN_P(bn), NULL);
|
||||
if (!EC_KEY_set_private_key(eckey, d)) {
|
||||
php_openssl_store_errors();
|
||||
goto clean_exit;
|
||||
}
|
||||
// Calculate the public key by multiplying the Point Q with the public key
|
||||
// P = d * Q
|
||||
pnt = EC_POINT_new(group);
|
||||
if (!pnt || !EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) {
|
||||
php_openssl_store_errors();
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
BN_free(d);
|
||||
} else if ((x = zend_hash_str_find(Z_ARRVAL_P(data), "x", sizeof("x") - 1)) != NULL &&
|
||||
Z_TYPE_P(x) == IS_STRING &&
|
||||
(y = zend_hash_str_find(Z_ARRVAL_P(data), "y", sizeof("y") - 1)) != NULL &&
|
||||
Z_TYPE_P(y) == IS_STRING) {
|
||||
pnt = EC_POINT_new(group);
|
||||
if (pnt == NULL) {
|
||||
php_openssl_store_errors();
|
||||
point_q = EC_POINT_new(group);
|
||||
if (!point_q || !EC_POINT_mul(group, point_q, d, NULL, NULL, bctx)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(
|
||||
group, pnt, BN_bin2bn((unsigned char*) Z_STRVAL_P(x), Z_STRLEN_P(x), NULL),
|
||||
BN_bin2bn((unsigned char*) Z_STRVAL_P(y), Z_STRLEN_P(y), NULL), NULL)) {
|
||||
php_openssl_store_errors();
|
||||
} else if (x && y) {
|
||||
/* OpenSSL does not allow setting EC_PUB_X/EC_PUB_Y, so convert to encoded format. */
|
||||
point_q = EC_POINT_new(group);
|
||||
if (!point_q || !EC_POINT_set_affine_coordinates_GFp(group, point_q, x, y, bctx)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (pnt != NULL) {
|
||||
if (!EC_KEY_set_public_key(eckey, pnt)) {
|
||||
php_openssl_store_errors();
|
||||
if (point_q != NULL) {
|
||||
if (!EC_KEY_set_public_key(eckey, point_q)) {
|
||||
goto clean_exit;
|
||||
}
|
||||
EC_POINT_free(pnt);
|
||||
pnt = NULL;
|
||||
}
|
||||
|
||||
if (!EC_KEY_check_key(eckey)) {
|
||||
*is_private = true;
|
||||
PHP_OPENSSL_RAND_ADD_TIME();
|
||||
EC_KEY_generate_key(eckey);
|
||||
php_openssl_store_errors();
|
||||
}
|
||||
if (EC_KEY_check_key(eckey)) {
|
||||
EC_GROUP_free(group);
|
||||
return true;
|
||||
} else {
|
||||
php_openssl_store_errors();
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
BN_free(d);
|
||||
EC_POINT_free(pnt);
|
||||
php_openssl_store_errors();
|
||||
BN_CTX_free(bctx);
|
||||
EC_GROUP_free(group);
|
||||
return false;
|
||||
EC_POINT_free(point_g);
|
||||
EC_POINT_free(point_q);
|
||||
BN_free(p);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(order);
|
||||
BN_free(g_x);
|
||||
BN_free(g_y);
|
||||
BN_free(cofactor);
|
||||
BN_free(d);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
return EC_KEY_check_key(eckey);
|
||||
}
|
||||
#endif
|
||||
|
||||
static EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
|
||||
#if PHP_OPENSSL_API_VERSION >= 0x30000
|
||||
BIGNUM *d = NULL, *x = NULL, *y = NULL;
|
||||
int nid = NID_undef;
|
||||
BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL, *g_x = NULL, *g_y = NULL, *cofactor = NULL;
|
||||
BIGNUM *x = NULL, *y = NULL, *d = NULL;
|
||||
EC_POINT *point_g = NULL;
|
||||
EC_POINT *point_q = NULL;
|
||||
unsigned char *point_g_buf = NULL;
|
||||
unsigned char *point_q_buf = NULL;
|
||||
EC_GROUP *group = NULL;
|
||||
EC_POINT *pnt = NULL;
|
||||
unsigned char *pnt_oct = NULL;
|
||||
EVP_PKEY *param_key = NULL, *pkey = NULL;
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||
BN_CTX *bctx = BN_CTX_new();
|
||||
OSSL_PARAM *params = NULL;
|
||||
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
|
||||
zval *curve_name_zv = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1);
|
||||
|
||||
OPENSSL_PKEY_SET_BN(data, d);
|
||||
OPENSSL_PKEY_SET_BN(data, x);
|
||||
OPENSSL_PKEY_SET_BN(data, y);
|
||||
|
||||
*is_private = false;
|
||||
|
||||
if (!ctx || !bld || !curve_name_zv || Z_TYPE_P(curve_name_zv) != IS_STRING) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
int nid = OBJ_sn2nid(Z_STRVAL_P(curve_name_zv));
|
||||
group = EC_GROUP_new_by_curve_name(nid);
|
||||
if (!group) {
|
||||
php_error_docref(NULL, E_WARNING, "Unknown curve name");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
OSSL_PARAM_BLD_push_utf8_string(
|
||||
bld, OSSL_PKEY_PARAM_GROUP_NAME, Z_STRVAL_P(curve_name_zv), Z_STRLEN_P(curve_name_zv));
|
||||
|
||||
if (d) {
|
||||
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, d);
|
||||
|
||||
pnt = EC_POINT_new(group);
|
||||
if (!pnt || !EC_POINT_mul(group, pnt, d, NULL, NULL, NULL)) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (x && y) {
|
||||
/* OpenSSL does not allow setting EC_PUB_X/EC_PUB_Y, so convert to encoded format. */
|
||||
pnt = EC_POINT_new(group);
|
||||
if (!pnt || !EC_POINT_set_affine_coordinates(group, pnt, x, y, NULL)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (pnt) {
|
||||
size_t pnt_oct_len =
|
||||
EC_POINT_point2buf(group, pnt, POINT_CONVERSION_COMPRESSED, &pnt_oct, NULL);
|
||||
if (!pnt_oct_len) {
|
||||
zval *curve_name_zv = zend_hash_str_find(Z_ARRVAL_P(data), "curve_name", sizeof("curve_name") - 1);
|
||||
if (curve_name_zv && Z_TYPE_P(curve_name_zv) == IS_STRING && Z_STRLEN_P(curve_name_zv) > 0) {
|
||||
nid = OBJ_sn2nid(Z_STRVAL_P(curve_name_zv));
|
||||
if (nid == NID_undef) {
|
||||
php_error_docref(NULL, E_WARNING, "Unknown elliptic curve (short) name %s", Z_STRVAL_P(curve_name_zv));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pnt_oct, pnt_oct_len);
|
||||
if (!(group = EC_GROUP_new_by_curve_name(nid))) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, Z_STRVAL_P(curve_name_zv), Z_STRLEN_P(curve_name_zv))) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
OPENSSL_PKEY_SET_BN(data, p);
|
||||
OPENSSL_PKEY_SET_BN(data, a);
|
||||
OPENSSL_PKEY_SET_BN(data, b);
|
||||
OPENSSL_PKEY_SET_BN(data, order);
|
||||
|
||||
if (!(p && a && b && order)) {
|
||||
if (!p && !a && !b && !order) {
|
||||
php_error_docref(NULL, E_WARNING, "Missing params: curve_name");
|
||||
} else {
|
||||
php_error_docref(NULL, E_WARNING, "Missing params: curve_name or p, a, b, order");
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_P, p) ||
|
||||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_A, a) ||
|
||||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_B, b) ||
|
||||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_ORDER, order) ||
|
||||
!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_FIELD_TYPE, SN_X9_62_prime_field, 0)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(group = EC_GROUP_new_curve_GFp(p, a, b, bctx))) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(point_g = EC_POINT_new(group))) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
zval *generator_zv = zend_hash_str_find(Z_ARRVAL_P(data), "generator", sizeof("generator") - 1);
|
||||
if (generator_zv && Z_TYPE_P(generator_zv) == IS_STRING && Z_STRLEN_P(generator_zv) > 0) {
|
||||
if (!EC_POINT_oct2point(group, point_g, (unsigned char *)Z_STRVAL_P(generator_zv), Z_STRLEN_P(generator_zv), bctx) ||
|
||||
!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_GENERATOR, Z_STRVAL_P(generator_zv), Z_STRLEN_P(generator_zv))) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
OPENSSL_PKEY_SET_BN(data, g_x);
|
||||
OPENSSL_PKEY_SET_BN(data, g_y);
|
||||
|
||||
if (!g_x || !g_y) {
|
||||
php_error_docref(
|
||||
NULL, E_WARNING, "Missing params: generator or g_x and g_y");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!EC_POINT_set_affine_coordinates(group, point_g, g_x, g_y, bctx)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
size_t point_g_buf_len =
|
||||
EC_POINT_point2buf(group, point_g, POINT_CONVERSION_COMPRESSED, &point_g_buf, bctx);
|
||||
if (!point_g_buf_len) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_GENERATOR, point_g_buf, point_g_buf_len)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
zval *seed_zv = zend_hash_str_find(Z_ARRVAL_P(data), "seed", sizeof("seed") - 1);
|
||||
if (seed_zv && Z_TYPE_P(seed_zv) == IS_STRING && Z_STRLEN_P(seed_zv) > 0) {
|
||||
if (!EC_GROUP_set_seed(group, (unsigned char *)Z_STRVAL_P(seed_zv), Z_STRLEN_P(seed_zv)) ||
|
||||
!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_SEED, Z_STRVAL_P(seed_zv), Z_STRLEN_P(seed_zv))) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
OPENSSL_PKEY_SET_BN(data, cofactor);
|
||||
if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor) ||
|
||||
!EC_GROUP_set_generator(group, point_g, order, cofactor)) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
nid = EC_GROUP_check_named_curve(group, 0, bctx);
|
||||
}
|
||||
|
||||
/* custom params not supported with SM2, SKIP */
|
||||
if (nid != NID_sm2) {
|
||||
OPENSSL_PKEY_SET_BN(data, d);
|
||||
OPENSSL_PKEY_SET_BN(data, x);
|
||||
OPENSSL_PKEY_SET_BN(data, y);
|
||||
|
||||
if (d) {
|
||||
point_q = EC_POINT_new(group);
|
||||
if (!point_q || !EC_POINT_mul(group, point_q, d, NULL, NULL, bctx) ||
|
||||
!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, d)) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (x && y) {
|
||||
/* OpenSSL does not allow setting EC_PUB_X/EC_PUB_Y, so convert to encoded format. */
|
||||
point_q = EC_POINT_new(group);
|
||||
if (!point_q || !EC_POINT_set_affine_coordinates(group, point_q, x, y, bctx)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (point_q) {
|
||||
size_t point_q_buf_len =
|
||||
EC_POINT_point2buf(group, point_q, POINT_CONVERSION_COMPRESSED, &point_q_buf, bctx);
|
||||
if (!point_q_buf_len ||
|
||||
!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, point_q_buf, point_q_buf_len)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params = OSSL_PARAM_BLD_to_param(bld);
|
||||
@@ -4423,21 +4563,25 @@ static EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
|
||||
if (d || (x && y)) {
|
||||
if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
|
||||
EVP_PKEY_fromdata(ctx, ¶m_key, EVP_PKEY_KEYPAIR, params) <= 0) {
|
||||
goto cleanup;
|
||||
goto cleanup;
|
||||
}
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
ctx = EVP_PKEY_CTX_new(param_key, NULL);
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
ctx = EVP_PKEY_CTX_new(param_key, NULL);
|
||||
if (EVP_PKEY_check(ctx)) {
|
||||
|
||||
if (EVP_PKEY_check(ctx) || EVP_PKEY_public_check_quick(ctx)) {
|
||||
*is_private = d != NULL;
|
||||
EVP_PKEY_up_ref(param_key);
|
||||
pkey = param_key;
|
||||
} else {
|
||||
*is_private = true;
|
||||
PHP_OPENSSL_RAND_ADD_TIME();
|
||||
if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) {
|
||||
if (EVP_PKEY_keygen_init(ctx) != 1 ||
|
||||
EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
|
||||
EVP_PKEY_generate(ctx, &pkey) != 1) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@@ -4446,11 +4590,21 @@ cleanup:
|
||||
php_openssl_store_errors();
|
||||
EVP_PKEY_free(param_key);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
BN_CTX_free(bctx);
|
||||
OSSL_PARAM_free(params);
|
||||
OSSL_PARAM_BLD_free(bld);
|
||||
EC_POINT_free(pnt);
|
||||
EC_GROUP_free(group);
|
||||
OPENSSL_free(pnt_oct);
|
||||
EC_POINT_free(point_g);
|
||||
EC_POINT_free(point_q);
|
||||
OPENSSL_free(point_g_buf);
|
||||
OPENSSL_free(point_q_buf);
|
||||
BN_free(p);
|
||||
BN_free(a);
|
||||
BN_free(b);
|
||||
BN_free(order);
|
||||
BN_free(g_x);
|
||||
BN_free(g_y);
|
||||
BN_free(cofactor);
|
||||
BN_free(d);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
@@ -4796,7 +4950,21 @@ PHP_FUNCTION(openssl_pkey_get_details)
|
||||
*/
|
||||
#if PHP_OPENSSL_API_VERSION >= 0x30000
|
||||
zval ary;
|
||||
switch (EVP_PKEY_base_id(pkey)) {
|
||||
int base_id = 0;
|
||||
|
||||
if (EVP_PKEY_id(pkey) != EVP_PKEY_KEYMGMT) {
|
||||
base_id = EVP_PKEY_base_id(pkey);
|
||||
} else {
|
||||
const char *type_name = EVP_PKEY_get0_type_name(pkey);
|
||||
if (type_name) {
|
||||
int nid = OBJ_txt2nid(type_name);
|
||||
if (nid != NID_undef) {
|
||||
base_id = EVP_PKEY_type(nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (base_id) {
|
||||
case EVP_PKEY_RSA:
|
||||
ktype = OPENSSL_KEYTYPE_RSA;
|
||||
array_init(&ary);
|
||||
@@ -4859,7 +5027,9 @@ PHP_FUNCTION(openssl_pkey_get_details)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
EMPTY_SWITCH_DEFAULT_CASE();
|
||||
default:
|
||||
ktype = -1;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (EVP_PKEY_base_id(pkey)) {
|
||||
@@ -4955,24 +5125,22 @@ PHP_FUNCTION(openssl_pkey_get_details)
|
||||
|
||||
ec_group = EC_KEY_get0_group(ec_key);
|
||||
|
||||
// Curve nid (numerical identifier) used for ASN1 mapping
|
||||
nid = EC_GROUP_get_curve_name(ec_group);
|
||||
if (nid == NID_undef) {
|
||||
break;
|
||||
}
|
||||
array_init(&ec);
|
||||
|
||||
// Short object name
|
||||
crv_sn = (char*) OBJ_nid2sn(nid);
|
||||
if (crv_sn != NULL) {
|
||||
add_assoc_string(&ec, "curve_name", crv_sn);
|
||||
}
|
||||
/** Curve nid (numerical identifier) used for ASN1 mapping */
|
||||
nid = EC_GROUP_get_curve_name(ec_group);
|
||||
if (nid != NID_undef) {
|
||||
crv_sn = (char*) OBJ_nid2sn(nid);
|
||||
if (crv_sn != NULL) {
|
||||
add_assoc_string(&ec, "curve_name", crv_sn);
|
||||
}
|
||||
|
||||
obj = OBJ_nid2obj(nid);
|
||||
if (obj != NULL) {
|
||||
int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
|
||||
add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len);
|
||||
ASN1_OBJECT_free(obj);
|
||||
obj = OBJ_nid2obj(nid);
|
||||
if (obj != NULL) {
|
||||
int oir_len = OBJ_obj2txt(oir_buf, sizeof(oir_buf), obj, 1);
|
||||
add_assoc_stringl(&ec, "curve_oid", (char*) oir_buf, oir_len);
|
||||
ASN1_OBJECT_free(obj);
|
||||
}
|
||||
}
|
||||
|
||||
pub = EC_KEY_get0_public_key(ec_key);
|
||||
|
||||
@@ -74,7 +74,8 @@ var_dump($csr);
|
||||
$pubkey1 = openssl_pkey_get_details(openssl_csr_get_public_key($csr));
|
||||
var_dump(isset($pubkey1["ec"]["priv_key"]));
|
||||
unset($d1["ec"]["priv_key"]);
|
||||
var_dump(array_diff($d1["ec"], $pubkey1["ec"]));
|
||||
$diff = array_diff($d1["ec"], $pubkey1["ec"]);
|
||||
var_dump(isset($diff["d"]) && is_string($diff["d"]) && strlen($diff["d"]) > 0);
|
||||
|
||||
$x509 = openssl_csr_sign($csr, null, $key1, 365, $args);
|
||||
var_dump($x509);
|
||||
@@ -121,10 +122,7 @@ Testing openssl_csr_new with existing ecc key
|
||||
object(OpenSSLCertificateSigningRequest)#%d (0) {
|
||||
}
|
||||
bool(false)
|
||||
array(1) {
|
||||
["d"]=>
|
||||
string(%d) "%a"
|
||||
}
|
||||
bool(true)
|
||||
object(OpenSSLCertificate)#%d (0) {
|
||||
}
|
||||
Testing openssl_x509_check_private_key
|
||||
|
||||
113
ext/openssl/tests/ecc_custom_params.phpt
Normal file
113
ext/openssl/tests/ecc_custom_params.phpt
Normal file
@@ -0,0 +1,113 @@
|
||||
--TEST--
|
||||
openssl_*() with OPENSSL_KEYTYPE_EC for ec custom params
|
||||
--EXTENSIONS--
|
||||
openssl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!defined("OPENSSL_KEYTYPE_EC")) die("skip EC disabled");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
// EC - generate keypair with curve_name
|
||||
echo "Testing openssl_pkey_new with ec curve_name\n";
|
||||
$curve_name = openssl_get_curve_names()[0];
|
||||
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'curve_name' => $curve_name,
|
||||
)
|
||||
));
|
||||
|
||||
var_dump($ec);
|
||||
$details = openssl_pkey_get_details($ec);
|
||||
$ec_details = $details['ec'];
|
||||
var_dump($ec_details['curve_name'] === $curve_name);
|
||||
|
||||
// EC - generate keypair from priv_key "d" with explicit parameters (OSCCA WAPIP192v1 Elliptic curve)
|
||||
echo "Testing openssl_pkey_new with ec explicit parameters\n";
|
||||
$d = hex2bin('8D0AC65AAEA0D6B96254C65817D4A143A9E7A03876F1A37D');
|
||||
$x = hex2bin('98E07AAD50C31F9189EBE6B8B5C70E5DEE59D7A8BC344CC6');
|
||||
$y = hex2bin('6109D3D96E52D0867B9D05D72D07BE5876A3D973E0E96792');
|
||||
$p = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F');
|
||||
$a = hex2bin('BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985');
|
||||
$b = hex2bin('1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1');
|
||||
$g_x = hex2bin('4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640');
|
||||
$g_y = hex2bin('02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2');
|
||||
$order = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677');
|
||||
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'p' => $p,
|
||||
'a' => $a,
|
||||
'b' => $b,
|
||||
'order' => $order,
|
||||
'g_x' => $g_x,
|
||||
'g_y' => $g_y,
|
||||
'd' => $d,
|
||||
)
|
||||
));
|
||||
|
||||
$details = openssl_pkey_get_details($ec);
|
||||
$ec_details = $details['ec'];
|
||||
var_dump($ec_details['x'] === $x);
|
||||
var_dump($ec_details['y'] === $y);
|
||||
var_dump($ec_details['d'] === $d);
|
||||
|
||||
echo "Testing openssl_pkey_new with ec missing params \n";
|
||||
// EC - invalid curve_name
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'curve_name' => 'invalid_curve_name',
|
||||
)
|
||||
));
|
||||
var_dump($ec);
|
||||
|
||||
// EC - missing all params
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array()
|
||||
));
|
||||
var_dump($ec);
|
||||
|
||||
// EC - missing "p" param
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'a' => $a,
|
||||
'b' => $b,
|
||||
'order' => $order
|
||||
)
|
||||
));
|
||||
var_dump($ec);
|
||||
|
||||
// EC - missing "generator" or "g_x" and "g_y" param
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'p' => $p,
|
||||
'a' => $a,
|
||||
'b' => $b,
|
||||
'order' => $order
|
||||
)
|
||||
));
|
||||
var_dump($ec);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Testing openssl_pkey_new with ec curve_name
|
||||
object(OpenSSLAsymmetricKey)#%d (0) {
|
||||
}
|
||||
bool(true)
|
||||
Testing openssl_pkey_new with ec explicit parameters
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
Testing openssl_pkey_new with ec missing params
|
||||
|
||||
Warning: openssl_pkey_new(): Unknown elliptic curve (short) name invalid_curve_name in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: openssl_pkey_new(): Missing params: curve_name in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: openssl_pkey_new(): Missing params: curve_name or p, a, b, order in %s on line %d
|
||||
bool(false)
|
||||
|
||||
Warning: openssl_pkey_new(): Missing params: generator or g_x and g_y in %s on line %d
|
||||
bool(false)
|
||||
92
ext/openssl/tests/ecc_sm2.phpt
Normal file
92
ext/openssl/tests/ecc_sm2.phpt
Normal file
@@ -0,0 +1,92 @@
|
||||
--TEST--
|
||||
openssl_*() with OPENSSL_KEYTYPE_EC for SM2
|
||||
--EXTENSIONS--
|
||||
openssl
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!defined("OPENSSL_KEYTYPE_EC")) die("skip EC disabled");
|
||||
if (!in_array('SM2', openssl_get_curve_names())) die("skip SM2 disabled");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
// EC - generate SM2 keypair with curve_name
|
||||
echo "Testing openssl_pkey_new with ec curve_name SM2\n";
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'curve_name' => 'SM2',
|
||||
)
|
||||
));
|
||||
|
||||
var_dump($ec);
|
||||
$details = openssl_pkey_get_details($ec);
|
||||
var_dump($details["bits"]);
|
||||
var_dump(strlen($details["key"]));
|
||||
var_dump($details["ec"]["curve_name"]);
|
||||
var_dump($details["type"] == OPENSSL_KEYTYPE_EC);
|
||||
|
||||
// EC - generate SM2 keypair with curve_name
|
||||
echo "Testing openssl_pkey_get_public from SM2 pem pubkey\n";
|
||||
$public_key = openssl_pkey_get_public($details["key"]);
|
||||
var_dump($public_key);
|
||||
$details_public_key = openssl_pkey_get_details($public_key);
|
||||
var_dump(strlen($details["key"]));
|
||||
var_dump($details_public_key["ec"]["curve_name"]);
|
||||
var_dump($details["type"] == OPENSSL_KEYTYPE_EC);
|
||||
var_dump($details_public_key["ec"]["x"] === $details["ec"]["x"]);
|
||||
var_dump($details_public_key["ec"]["y"] === $details["ec"]["y"]);
|
||||
|
||||
// EC - generate keypair with explicit parameters (SM2 curve)
|
||||
echo "Testing openssl_pkey_new with ec explicit parameters (SM2 curve)\n";
|
||||
$p = hex2bin('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF');
|
||||
$a = hex2bin('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC');
|
||||
$b = hex2bin('28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93');
|
||||
$g_x = hex2bin('32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7');
|
||||
$g_y = hex2bin('BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0');
|
||||
$order = hex2bin('FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123');
|
||||
|
||||
$ec = openssl_pkey_new(array(
|
||||
'ec'=> array(
|
||||
'p' => $p,
|
||||
'a' => $a,
|
||||
'b' => $b,
|
||||
'order' => $order,
|
||||
'g_x' => $g_x,
|
||||
'g_y' => $g_y
|
||||
)
|
||||
));
|
||||
|
||||
$details = openssl_pkey_get_details($ec);
|
||||
var_dump($details['bits']);
|
||||
var_dump(strlen($details['key']));
|
||||
var_dump($details['type'] == OPENSSL_KEYTYPE_EC);
|
||||
$public_key = openssl_pkey_get_public($details["key"]);
|
||||
$details_public_key = openssl_pkey_get_details($public_key);
|
||||
var_dump(strlen($details["key"]));
|
||||
var_dump($details["type"] == OPENSSL_KEYTYPE_EC);
|
||||
var_dump($details_public_key["ec"]["x"] === $details["ec"]["x"]);
|
||||
var_dump($details_public_key["ec"]["y"] === $details["ec"]["y"]);
|
||||
?>
|
||||
--EXPECTF--
|
||||
Testing openssl_pkey_new with ec curve_name SM2
|
||||
object(OpenSSLAsymmetricKey)#%d (0) {
|
||||
}
|
||||
int(256)
|
||||
int(178)
|
||||
string(3) "SM2"
|
||||
bool(true)
|
||||
Testing openssl_pkey_get_public from SM2 pem pubkey
|
||||
object(OpenSSLAsymmetricKey)#%d (0) {
|
||||
}
|
||||
int(178)
|
||||
string(3) "SM2"
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
Testing openssl_pkey_new with ec explicit parameters (SM2 curve)
|
||||
int(256)
|
||||
int(475)
|
||||
bool(true)
|
||||
int(475)
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(true)
|
||||
Reference in New Issue
Block a user