@@ -120,7 +120,13 @@ enum php_openssl_key_type {
120
120
OPENSSL_KEYTYPE_DH ,
121
121
OPENSSL_KEYTYPE_DEFAULT = OPENSSL_KEYTYPE_RSA ,
122
122
#ifdef HAVE_EVP_PKEY_EC
123
- OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH + 1
123
+ OPENSSL_KEYTYPE_EC = OPENSSL_KEYTYPE_DH + 1 ,
124
+ #endif
125
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
126
+ OPENSSL_KEYTYPE_X25519 = OPENSSL_KEYTYPE_DH + 2 ,
127
+ OPENSSL_KEYTYPE_ED25519 = OPENSSL_KEYTYPE_DH + 3 ,
128
+ OPENSSL_KEYTYPE_X448 = OPENSSL_KEYTYPE_DH + 4 ,
129
+ OPENSSL_KEYTYPE_ED448 = OPENSSL_KEYTYPE_DH + 5 ,
124
130
#endif
125
131
};
126
132
@@ -1011,7 +1017,11 @@ static int php_openssl_parse_config(struct php_x509_request * req, zval * option
1011
1017
req -> digest_name = php_openssl_conf_get_string (req -> req_config , req -> section_name , "default_md" );
1012
1018
}
1013
1019
if (req -> digest_name != NULL ) {
1014
- req -> digest = req -> md_alg = EVP_get_digestbyname (req -> digest_name );
1020
+ if (strcmp (req -> digest_name , "null" ) == 0 ) {
1021
+ req -> digest = req -> md_alg = EVP_md_null ();
1022
+ } else {
1023
+ req -> digest = req -> md_alg = EVP_get_digestbyname (req -> digest_name );
1024
+ }
1015
1025
}
1016
1026
if (req -> md_alg == NULL ) {
1017
1027
req -> md_alg = req -> digest = EVP_sha1 ();
@@ -3732,6 +3742,16 @@ static int php_openssl_get_evp_pkey_type(int key_type) {
3732
3742
#ifdef HAVE_EVP_PKEY_EC
3733
3743
case OPENSSL_KEYTYPE_EC :
3734
3744
return EVP_PKEY_EC ;
3745
+ #endif
3746
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
3747
+ case OPENSSL_KEYTYPE_X25519 :
3748
+ return EVP_PKEY_X25519 ;
3749
+ case OPENSSL_KEYTYPE_ED25519 :
3750
+ return EVP_PKEY_ED25519 ;
3751
+ case OPENSSL_KEYTYPE_X448 :
3752
+ return EVP_PKEY_X448 ;
3753
+ case OPENSSL_KEYTYPE_ED448 :
3754
+ return EVP_PKEY_ED448 ;
3735
3755
#endif
3736
3756
default :
3737
3757
return -1 ;
@@ -3802,6 +3822,16 @@ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req
3802
3822
goto cleanup ;
3803
3823
}
3804
3824
break ;
3825
+ #endif
3826
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
3827
+ case EVP_PKEY_X25519 :
3828
+ break ;
3829
+ case EVP_PKEY_ED25519 :
3830
+ break ;
3831
+ case EVP_PKEY_X448 :
3832
+ break ;
3833
+ case EVP_PKEY_ED448 :
3834
+ break ;
3805
3835
#endif
3806
3836
EMPTY_SWITCH_DEFAULT_CASE ()
3807
3837
}
@@ -4669,6 +4699,62 @@ static EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) {
4669
4699
}
4670
4700
#endif
4671
4701
4702
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
4703
+ static void php_openssl_pkey_object_curve_25519_448 (zval * return_value , int key_type , zval * data ) {
4704
+ EVP_PKEY * pkey = NULL ;
4705
+ EVP_PKEY_CTX * ctx = NULL ;
4706
+ OSSL_PARAM * params = NULL ;
4707
+ OSSL_PARAM_BLD * bld = OSSL_PARAM_BLD_new ();
4708
+ bool is_private ;
4709
+
4710
+ RETVAL_FALSE ;
4711
+
4712
+ zval * priv_key = zend_hash_str_find (Z_ARRVAL_P (data ), "priv_key" , sizeof ("priv_key" ) - 1 );
4713
+ if (priv_key && Z_TYPE_P (priv_key ) == IS_STRING && Z_STRLEN_P (priv_key ) > 0 ) {
4714
+ if (!OSSL_PARAM_BLD_push_octet_string (bld , OSSL_PKEY_PARAM_PRIV_KEY , Z_STRVAL_P (priv_key ), Z_STRLEN_P (priv_key ))) {
4715
+ goto cleanup ;
4716
+ }
4717
+ }
4718
+
4719
+ zval * pub_key = zend_hash_str_find (Z_ARRVAL_P (data ), "pub_key" , sizeof ("pub_key" ) - 1 );
4720
+ if (pub_key && Z_TYPE_P (pub_key ) == IS_STRING && Z_STRLEN_P (pub_key ) > 0 ) {
4721
+ if (!OSSL_PARAM_BLD_push_octet_string (bld , OSSL_PKEY_PARAM_PUB_KEY , Z_STRVAL_P (pub_key ), Z_STRLEN_P (pub_key ))) {
4722
+ goto cleanup ;
4723
+ }
4724
+ }
4725
+
4726
+ params = OSSL_PARAM_BLD_to_param (bld );
4727
+ if (!params ) {
4728
+ goto cleanup ;
4729
+ }
4730
+
4731
+ ctx = EVP_PKEY_CTX_new_id (key_type , NULL );
4732
+ if (pub_key || priv_key ) {
4733
+ if (EVP_PKEY_fromdata_init (ctx ) <= 0 ||
4734
+ EVP_PKEY_fromdata (ctx , & pkey , EVP_PKEY_KEYPAIR , params ) <= 0 ) {
4735
+ goto cleanup ;
4736
+ }
4737
+ is_private = priv_key != NULL ;
4738
+ } else {
4739
+ is_private = true;
4740
+ PHP_OPENSSL_RAND_ADD_TIME ();
4741
+ if (EVP_PKEY_keygen_init (ctx ) <= 0 || EVP_PKEY_keygen (ctx , & pkey ) <= 0 ) {
4742
+ goto cleanup ;
4743
+ }
4744
+ }
4745
+
4746
+ if (pkey ) {
4747
+ php_openssl_pkey_object_init (return_value , pkey , is_private );
4748
+ }
4749
+
4750
+ cleanup :
4751
+ php_openssl_store_errors ();
4752
+ EVP_PKEY_CTX_free (ctx );
4753
+ OSSL_PARAM_free (params );
4754
+ OSSL_PARAM_BLD_free (bld );
4755
+ }
4756
+ #endif
4757
+
4672
4758
/* {{{ Generates a new private key */
4673
4759
PHP_FUNCTION (openssl_pkey_new )
4674
4760
{
@@ -4720,6 +4806,24 @@ PHP_FUNCTION(openssl_pkey_new)
4720
4806
}
4721
4807
php_openssl_pkey_object_init (return_value , pkey , is_private );
4722
4808
return ;
4809
+ #endif
4810
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
4811
+ } else if ((data = zend_hash_str_find (Z_ARRVAL_P (args ), "x25519" , sizeof ("x25519" ) - 1 )) != NULL &&
4812
+ Z_TYPE_P (data ) == IS_ARRAY ) {
4813
+ php_openssl_pkey_object_curve_25519_448 (return_value , EVP_PKEY_X25519 , data );
4814
+ return ;
4815
+ } else if ((data = zend_hash_str_find (Z_ARRVAL_P (args ), "ed25519" , sizeof ("ed25519" ) - 1 )) != NULL &&
4816
+ Z_TYPE_P (data ) == IS_ARRAY ) {
4817
+ php_openssl_pkey_object_curve_25519_448 (return_value , EVP_PKEY_ED25519 , data );
4818
+ return ;
4819
+ } else if ((data = zend_hash_str_find (Z_ARRVAL_P (args ), "x448" , sizeof ("x448" ) - 1 )) != NULL &&
4820
+ Z_TYPE_P (data ) == IS_ARRAY ) {
4821
+ php_openssl_pkey_object_curve_25519_448 (return_value , EVP_PKEY_X448 , data );
4822
+ return ;
4823
+ } else if ((data = zend_hash_str_find (Z_ARRVAL_P (args ), "ed448" , sizeof ("ed448" ) - 1 )) != NULL &&
4824
+ Z_TYPE_P (data ) == IS_ARRAY ) {
4825
+ php_openssl_pkey_object_curve_25519_448 (return_value , EVP_PKEY_ED448 , data );
4826
+ return ;
4723
4827
#endif
4724
4828
}
4725
4829
}
@@ -4952,6 +5056,27 @@ static zend_string *php_openssl_get_utf8_param(
4952
5056
return NULL ;
4953
5057
}
4954
5058
#endif
5059
+
5060
+ static void php_openssl_copy_octet_string_param (
5061
+ zval * ary , EVP_PKEY * pkey , const char * param , const char * name ) {
5062
+ unsigned char buf [64 ];
5063
+ size_t len ;
5064
+ if (EVP_PKEY_get_octet_string_param (pkey , param , buf , sizeof (buf ), & len ) > 0 ) {
5065
+ zend_string * str = zend_string_alloc (len , 0 );
5066
+ memcpy (ZSTR_VAL (str ), buf , len );
5067
+ ZSTR_VAL (str )[len ] = '\0' ;
5068
+ add_assoc_str (ary , name , str );
5069
+ }
5070
+ }
5071
+
5072
+ static void php_openssl_copy_curve_25519_448_params (
5073
+ zval * return_value , const char * assoc_name , EVP_PKEY * pkey ) {
5074
+ zval ary ;
5075
+ array_init (& ary );
5076
+ add_assoc_zval (return_value , assoc_name , & ary );
5077
+ php_openssl_copy_octet_string_param (& ary , pkey , OSSL_PKEY_PARAM_PRIV_KEY , "priv_key" );
5078
+ php_openssl_copy_octet_string_param (& ary , pkey , OSSL_PKEY_PARAM_PUB_KEY , "pub_key" );
5079
+ }
4955
5080
#endif
4956
5081
4957
5082
/* {{{ returns an array with the key details (bits, pkey, type)*/
@@ -5060,6 +5185,28 @@ PHP_FUNCTION(openssl_pkey_get_details)
5060
5185
php_openssl_copy_bn_param (& ary , pkey , OSSL_PKEY_PARAM_PRIV_KEY , "d" );
5061
5186
break ;
5062
5187
}
5188
+ #endif
5189
+ #if PHP_OPENSSL_API_VERSION >= 0x30000
5190
+ case EVP_PKEY_X25519 : {
5191
+ ktype = OPENSSL_KEYTYPE_X25519 ;
5192
+ php_openssl_copy_curve_25519_448_params (return_value , "x25519" , pkey );
5193
+ break ;
5194
+ }
5195
+ case EVP_PKEY_ED25519 : {
5196
+ ktype = OPENSSL_KEYTYPE_ED25519 ;
5197
+ php_openssl_copy_curve_25519_448_params (return_value , "ed25519" , pkey );
5198
+ break ;
5199
+ }
5200
+ case EVP_PKEY_X448 : {
5201
+ ktype = OPENSSL_KEYTYPE_X448 ;
5202
+ php_openssl_copy_curve_25519_448_params (return_value , "x448" , pkey );
5203
+ break ;
5204
+ }
5205
+ case EVP_PKEY_ED448 : {
5206
+ ktype = OPENSSL_KEYTYPE_ED448 ;
5207
+ php_openssl_copy_curve_25519_448_params (return_value , "ed448" , pkey );
5208
+ break ;
5209
+ }
5063
5210
#endif
5064
5211
default :
5065
5212
ktype = -1 ;
@@ -6937,14 +7084,14 @@ PHP_FUNCTION(openssl_sign)
6937
7084
{
6938
7085
zval * key , * signature ;
6939
7086
EVP_PKEY * pkey ;
6940
- unsigned int siglen ;
6941
- zend_string * sigbuf ;
7087
+ zend_string * sigbuf = NULL ;
6942
7088
char * data ;
6943
7089
size_t data_len ;
6944
7090
EVP_MD_CTX * md_ctx ;
6945
7091
zend_string * method_str = NULL ;
6946
7092
zend_long method_long = OPENSSL_ALGO_SHA1 ;
6947
7093
const EVP_MD * mdtype ;
7094
+ bool can_default_digest = ZEND_THREEWAY_COMPARE (PHP_OPENSSL_API_VERSION , 0x30000 ) >= 0 ;
6948
7095
6949
7096
ZEND_PARSE_PARAMETERS_START (3 , 4 )
6950
7097
Z_PARAM_STRING (data , data_len )
@@ -6967,19 +7114,27 @@ PHP_FUNCTION(openssl_sign)
6967
7114
} else {
6968
7115
mdtype = php_openssl_get_evp_md_from_algo (method_long );
6969
7116
}
6970
- if (!mdtype ) {
7117
+ if (!mdtype && (! can_default_digest || method_long != 0 ) ) {
6971
7118
php_error_docref (NULL , E_WARNING , "Unknown digest algorithm" );
6972
7119
RETURN_FALSE ;
6973
7120
}
6974
7121
6975
- siglen = EVP_PKEY_size (pkey );
6976
- sigbuf = zend_string_alloc (siglen , 0 );
6977
-
6978
7122
md_ctx = EVP_MD_CTX_create ();
7123
+ size_t siglen ;
7124
+ #if PHP_OPENSSL_API_VERSION >= 0x10100
7125
+ if (md_ctx != NULL &&
7126
+ EVP_DigestSignInit (md_ctx , NULL , mdtype , NULL , pkey ) &&
7127
+ EVP_DigestSign (md_ctx , NULL , & siglen , (unsigned char * )data , data_len ) &&
7128
+ (sigbuf = zend_string_alloc (siglen , 0 )) != NULL &&
7129
+ EVP_DigestSign (md_ctx , (unsigned char * )ZSTR_VAL (sigbuf ), & siglen , (unsigned char * )data , data_len )) {
7130
+ #else
6979
7131
if (md_ctx != NULL &&
6980
7132
EVP_SignInit (md_ctx , mdtype ) &&
6981
7133
EVP_SignUpdate (md_ctx , data , data_len ) &&
6982
- EVP_SignFinal (md_ctx , (unsigned char * )ZSTR_VAL (sigbuf ), & siglen , pkey )) {
7134
+ (siglen = EVP_PKEY_size (pkey )) &&
7135
+ (sigbuf = zend_string_alloc (siglen , 0 )) != NULL &&
7136
+ EVP_SignFinal (md_ctx , (unsigned char * )ZSTR_VAL (sigbuf ), (unsigned int * )& siglen , pkey )) {
7137
+ #endif
6983
7138
ZSTR_VAL (sigbuf )[siglen ] = '\0' ;
6984
7139
ZSTR_LEN (sigbuf ) = siglen ;
6985
7140
ZEND_TRY_ASSIGN_REF_NEW_STR (signature , sigbuf );
@@ -7008,6 +7163,7 @@ PHP_FUNCTION(openssl_verify)
7008
7163
size_t signature_len ;
7009
7164
zend_string * method_str = NULL ;
7010
7165
zend_long method_long = OPENSSL_ALGO_SHA1 ;
7166
+ bool can_default_digest = ZEND_THREEWAY_COMPARE (PHP_OPENSSL_API_VERSION , 0x30000 ) >= 0 ;
7011
7167
7012
7168
ZEND_PARSE_PARAMETERS_START (3 , 4 )
7013
7169
Z_PARAM_STRING (data , data_len )
@@ -7024,7 +7180,7 @@ PHP_FUNCTION(openssl_verify)
7024
7180
} else {
7025
7181
mdtype = php_openssl_get_evp_md_from_algo (method_long );
7026
7182
}
7027
- if (!mdtype ) {
7183
+ if (!mdtype && (! can_default_digest || method_long != 0 ) ) {
7028
7184
php_error_docref (NULL , E_WARNING , "Unknown digest algorithm" );
7029
7185
RETURN_FALSE ;
7030
7186
}
@@ -7039,9 +7195,14 @@ PHP_FUNCTION(openssl_verify)
7039
7195
7040
7196
md_ctx = EVP_MD_CTX_create ();
7041
7197
if (md_ctx == NULL ||
7198
+ #if PHP_OPENSSL_API_VERSION >= 0x10100
7199
+ !EVP_DigestVerifyInit (md_ctx , NULL , mdtype , NULL , pkey ) ||
7200
+ (err = EVP_DigestVerify (md_ctx , (unsigned char * )signature , signature_len , (unsigned char * )data , data_len )) < 0 ) {
7201
+ #else
7042
7202
!EVP_VerifyInit (md_ctx , mdtype ) ||
7043
7203
!EVP_VerifyUpdate (md_ctx , data , data_len ) ||
7044
7204
(err = EVP_VerifyFinal (md_ctx , (unsigned char * )signature , (unsigned int )signature_len , pkey )) < 0 ) {
7205
+ #endif
7045
7206
php_openssl_store_errors ();
7046
7207
}
7047
7208
EVP_MD_CTX_destroy (md_ctx );
0 commit comments