Skip to content

Commit 2bf316f

Browse files
committed
Switch manual DSA key generation to param API
This is very similar to the DH case, with the primary difference that priv_key is ignored if pub_key is not given, rather than generating pub_key from priv_key. Would be nice if these worked the same (in which case we should probably also unify the keygen for FFC algorithms, as it's very similar).
1 parent a7740a0 commit 2bf316f

File tree

1 file changed

+102
-24
lines changed

1 file changed

+102
-24
lines changed

ext/openssl/openssl.c

Lines changed: 102 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3819,8 +3819,8 @@ static bool php_openssl_pkey_init_and_assign_rsa(EVP_PKEY *pkey, RSA *rsa, zval
38193819
return 1;
38203820
}
38213821

3822-
/* {{{ php_openssl_pkey_init_dsa */
3823-
static bool php_openssl_pkey_init_dsa(DSA *dsa, zval *data, bool *is_private)
3822+
#if PHP_OPENSSL_API_VERSION < 0x30000
3823+
static bool php_openssl_pkey_init_legacy_dsa(DSA *dsa, zval *data, bool *is_private)
38243824
{
38253825
BIGNUM *p, *q, *g, *priv_key, *pub_key;
38263826
const BIGNUM *priv_key_const, *pub_key_const;
@@ -3853,9 +3853,102 @@ static bool php_openssl_pkey_init_dsa(DSA *dsa, zval *data, bool *is_private)
38533853
return 0;
38543854
}
38553855
/* all good */
3856+
*is_private = true;
38563857
return 1;
38573858
}
3858-
/* }}} */
3859+
#endif
3860+
3861+
static EVP_PKEY *php_openssl_pkey_init_dsa(zval *data, bool *is_private)
3862+
{
3863+
#if PHP_OPENSSL_API_VERSION >= 0x30000
3864+
BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
3865+
EVP_PKEY *param_key = NULL, *pkey = NULL;
3866+
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
3867+
OSSL_PARAM *params = NULL;
3868+
OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
3869+
3870+
OPENSSL_PKEY_SET_BN(data, p);
3871+
OPENSSL_PKEY_SET_BN(data, q);
3872+
OPENSSL_PKEY_SET_BN(data, g);
3873+
OPENSSL_PKEY_SET_BN(data, priv_key);
3874+
OPENSSL_PKEY_SET_BN(data, pub_key);
3875+
3876+
if (!ctx || !bld || !p || !q || !g) {
3877+
goto cleanup;
3878+
}
3879+
3880+
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_P, p);
3881+
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_Q, q);
3882+
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_FFC_G, g);
3883+
// TODO: We silently ignore priv_key if pub_key is not given, unlike in the DH case.
3884+
if (pub_key) {
3885+
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_key);
3886+
if (priv_key) {
3887+
OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_key);
3888+
}
3889+
}
3890+
3891+
params = OSSL_PARAM_BLD_to_param(bld);
3892+
if (!params) {
3893+
goto cleanup;
3894+
}
3895+
3896+
if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
3897+
EVP_PKEY_fromdata(ctx, &param_key, EVP_PKEY_KEYPAIR, params) <= 0) {
3898+
goto cleanup;
3899+
}
3900+
3901+
if (pub_key) {
3902+
*is_private = priv_key != NULL;
3903+
EVP_PKEY_up_ref(param_key);
3904+
pkey = param_key;
3905+
} else {
3906+
*is_private = true;
3907+
PHP_OPENSSL_RAND_ADD_TIME();
3908+
EVP_PKEY_CTX_free(ctx);
3909+
ctx = EVP_PKEY_CTX_new(param_key, NULL);
3910+
if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_keygen(ctx, &pkey) <= 0) {
3911+
goto cleanup;
3912+
}
3913+
}
3914+
3915+
cleanup:
3916+
php_openssl_store_errors();
3917+
EVP_PKEY_free(param_key);
3918+
EVP_PKEY_CTX_free(ctx);
3919+
OSSL_PARAM_free(params);
3920+
OSSL_PARAM_BLD_free(bld);
3921+
BN_free(p);
3922+
BN_free(q);
3923+
BN_free(g);
3924+
BN_free(priv_key);
3925+
BN_free(pub_key);
3926+
return pkey;
3927+
#else
3928+
EVP_PKEY *pkey = EVP_PKEY_new();
3929+
if (!pkey) {
3930+
php_openssl_store_errors();
3931+
return NULL;
3932+
}
3933+
3934+
DSA *dsa = DSA_new();
3935+
if (!dsa) {
3936+
php_openssl_store_errors();
3937+
EVP_PKEY_free(pkey);
3938+
return NULL;
3939+
}
3940+
3941+
if (!php_openssl_pkey_init_legacy_dsa(dsa, data, is_private)
3942+
|| !EVP_PKEY_assign_DSA(pkey, dsa)) {
3943+
php_openssl_store_errors();
3944+
EVP_PKEY_free(pkey);
3945+
DSA_free(dsa);
3946+
return NULL;
3947+
}
3948+
3949+
return pkey;
3950+
#endif
3951+
}
38593952

38603953
/* {{{ php_openssl_dh_pub_from_priv */
38613954
static BIGNUM *php_openssl_dh_pub_from_priv(BIGNUM *priv_key, BIGNUM *g, BIGNUM *p)
@@ -4070,28 +4163,13 @@ PHP_FUNCTION(openssl_pkey_new)
40704163
RETURN_FALSE;
40714164
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dsa", sizeof("dsa") - 1)) != NULL &&
40724165
Z_TYPE_P(data) == IS_ARRAY) {
4073-
pkey = EVP_PKEY_new();
4074-
if (pkey) {
4075-
DSA *dsa = DSA_new();
4076-
if (dsa) {
4077-
bool is_private;
4078-
if (php_openssl_pkey_init_dsa(dsa, data, &is_private)) {
4079-
if (EVP_PKEY_assign_DSA(pkey, dsa)) {
4080-
php_openssl_pkey_object_init(return_value, pkey, is_private);
4081-
return;
4082-
} else {
4083-
php_openssl_store_errors();
4084-
}
4085-
}
4086-
DSA_free(dsa);
4087-
} else {
4088-
php_openssl_store_errors();
4089-
}
4090-
EVP_PKEY_free(pkey);
4091-
} else {
4092-
php_openssl_store_errors();
4166+
bool is_private;
4167+
pkey = php_openssl_pkey_init_dsa(data, &is_private);
4168+
if (!pkey) {
4169+
RETURN_FALSE;
40934170
}
4094-
RETURN_FALSE;
4171+
php_openssl_pkey_object_init(return_value, pkey, is_private);
4172+
return;
40954173
} else if ((data = zend_hash_str_find(Z_ARRVAL_P(args), "dh", sizeof("dh") - 1)) != NULL &&
40964174
Z_TYPE_P(data) == IS_ARRAY) {
40974175
bool is_private;

0 commit comments

Comments
 (0)