@@ -4171,42 +4171,57 @@ PHP_FUNCTION(openssl_verify)
41714171/* {{{ Seals data */
41724172PHP_FUNCTION (openssl_seal )
41734173{
4174- zval * pubkeys , * pubkey , * sealdata , * ekeys , * iv = NULL ;
4174+ zval * pubkeys , * pubkey , * sealdata , * ekeys , * iv = NULL , * tag = NULL ;
41754175 HashTable * pubkeysht ;
4176- EVP_PKEY * * pkeys ;
4177- int i , len1 , len2 , * eksl , nkeys , iv_len ;
4178- unsigned char iv_buf [EVP_MAX_IV_LENGTH + 1 ], * buf = NULL , * * eks ;
4176+ EVP_PKEY * * pkeys = NULL ;
4177+ int i , len1 , len2 , * eksl = NULL , nkeys = 0 , iv_len ;
4178+ unsigned char iv_buf [EVP_MAX_IV_LENGTH + 1 ], * buf = NULL , * * eks = NULL ;
41794179 char * data ;
41804180 size_t data_len ;
41814181 char * method ;
41824182 size_t method_len ;
41834183 const EVP_CIPHER * cipher ;
4184- EVP_CIPHER_CTX * ctx ;
4184+ EVP_CIPHER_CTX * ctx = NULL ;
4185+ size_t tag_len ;
41854186
4186- if (zend_parse_parameters (ZEND_NUM_ARGS (), "szzas|z" , & data , & data_len ,
4187- & sealdata , & ekeys , & pubkeys , & method , & method_len , & iv ) == FAILURE ) {
4187+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "szzas|z!z! " , & data , & data_len ,
4188+ & sealdata , & ekeys , & pubkeys , & method , & method_len , & iv , & tag ) == FAILURE ) {
41884189 RETURN_THROWS ();
41894190 }
4191+ RETVAL_FALSE ;
41904192
41914193 PHP_OPENSSL_CHECK_SIZE_T_TO_INT (data_len , data , 1 );
41924194
41934195 pubkeysht = Z_ARRVAL_P (pubkeys );
41944196 nkeys = pubkeysht ? zend_hash_num_elements (pubkeysht ) : 0 ;
41954197 if (!nkeys ) {
41964198 zend_argument_must_not_be_empty_error (4 );
4197- RETURN_THROWS () ;
4199+ goto clean_exit ;
41984200 }
41994201
42004202 cipher = php_openssl_get_evp_cipher_by_name (method );
42014203 if (!cipher ) {
42024204 php_error_docref (NULL , E_WARNING , "Unknown cipher algorithm" );
4203- RETURN_FALSE ;
4205+ goto clean_exit ;
42044206 }
42054207
42064208 iv_len = EVP_CIPHER_iv_length (cipher );
42074209 if (!iv && iv_len > 0 ) {
42084210 zend_argument_value_error (6 , "cannot be null for the chosen cipher algorithm" );
4209- RETURN_THROWS ();
4211+ goto clean_exit ;
4212+ }
4213+
4214+ ctx = EVP_CIPHER_CTX_new ();
4215+ if (ctx == NULL || !EVP_EncryptInit (ctx ,cipher ,NULL ,NULL )) {
4216+ php_openssl_store_errors ();
4217+ goto clean_exit ;
4218+ }
4219+
4220+ tag_len = EVP_CIPHER_CTX_get_tag_length (ctx );
4221+ if ((tag != NULL ) != (tag_len > 0 )) {
4222+ const char * imp = tag ? "cannot" : "must" ;
4223+ zend_argument_value_error (7 , "%s be specified for the chosen cipher algorithm" , imp );
4224+ goto clean_exit ;
42104225 }
42114226
42124227 pkeys = safe_emalloc (nkeys , sizeof (* pkeys ), 0 );
@@ -4223,21 +4238,12 @@ PHP_FUNCTION(openssl_seal)
42234238 if (!EG (exception )) {
42244239 php_error_docref (NULL , E_WARNING , "Not a public key (%dth member of pubkeys)" , i + 1 );
42254240 }
4226- RETVAL_FALSE ;
42274241 goto clean_exit ;
42284242 }
42294243 eks [i ] = emalloc (EVP_PKEY_size (pkeys [i ]) + 1 );
42304244 i ++ ;
42314245 } ZEND_HASH_FOREACH_END ();
42324246
4233- ctx = EVP_CIPHER_CTX_new ();
4234- if (ctx == NULL || !EVP_EncryptInit (ctx ,cipher ,NULL ,NULL )) {
4235- EVP_CIPHER_CTX_free (ctx );
4236- php_openssl_store_errors ();
4237- RETVAL_FALSE ;
4238- goto clean_exit ;
4239- }
4240-
42414247 /* allocate one byte extra to make room for \0 */
42424248 buf = emalloc (data_len + EVP_CIPHER_CTX_block_size (ctx ));
42434249 EVP_CIPHER_CTX_reset (ctx );
@@ -4246,19 +4252,23 @@ PHP_FUNCTION(openssl_seal)
42464252 !EVP_SealUpdate (ctx , buf , & len1 , (unsigned char * )data , (int )data_len ) ||
42474253 !EVP_SealFinal (ctx , buf + len1 , & len2 )) {
42484254 efree (buf );
4249- EVP_CIPHER_CTX_free (ctx );
42504255 php_openssl_store_errors ();
4251- RETVAL_FALSE ;
42524256 goto clean_exit ;
42534257 }
42544258
4259+ if (tag ) {
4260+ zend_string * tag_str = zend_string_alloc (tag_len , 0 );
4261+ EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_GET_TAG , ZSTR_LEN (tag_str ), ZSTR_VAL (tag_str ));
4262+ ZSTR_VAL (tag_str )[ZSTR_LEN (tag_str )] = 0 ;
4263+ ZEND_TRY_ASSIGN_REF_NEW_STR (tag , tag_str );
4264+ }
4265+
42554266 if (len1 + len2 > 0 ) {
42564267 ZEND_TRY_ASSIGN_REF_NEW_STR (sealdata , zend_string_init ((char * )buf , len1 + len2 , 0 ));
42574268 efree (buf );
42584269
42594270 ekeys = zend_try_array_init (ekeys );
42604271 if (!ekeys ) {
4261- EVP_CIPHER_CTX_free (ctx );
42624272 goto clean_exit ;
42634273 }
42644274
@@ -4276,44 +4286,61 @@ PHP_FUNCTION(openssl_seal)
42764286 } else {
42774287 efree (buf );
42784288 }
4289+
42794290 RETVAL_LONG (len1 + len2 );
4280- EVP_CIPHER_CTX_free (ctx );
42814291
42824292clean_exit :
4283- for (i = 0 ; i < nkeys ; i ++ ) {
4284- if (pkeys [i ] != NULL ) {
4285- EVP_PKEY_free (pkeys [i ]);
4293+ if (ctx ) {
4294+ EVP_CIPHER_CTX_free (ctx );
4295+ }
4296+
4297+ if (pkeys ) {
4298+ for (i = 0 ; i < nkeys ; i ++ ) {
4299+ if (pkeys [i ] != NULL ) {
4300+ EVP_PKEY_free (pkeys [i ]);
4301+ }
42864302 }
4287- if (eks [i ]) {
4288- efree (eks [i ]);
4303+ efree (pkeys );
4304+ }
4305+
4306+ if (eks ) {
4307+ for (i = 0 ; i < nkeys ; i ++ ) {
4308+ if (eks [i ]) {
4309+ efree (eks [i ]);
4310+ }
42894311 }
4312+ efree (eks );
4313+ }
4314+
4315+ if (eksl ) {
4316+ efree (eksl );
42904317 }
4291- efree (eks );
4292- efree (eksl );
4293- efree (pkeys );
42944318}
42954319/* }}} */
42964320
42974321/* {{{ Opens data */
42984322PHP_FUNCTION (openssl_open )
42994323{
43004324 zval * privkey , * opendata ;
4301- EVP_PKEY * pkey ;
4325+ EVP_PKEY * pkey = NULL ;
43024326 int len1 , len2 , cipher_iv_len ;
4303- unsigned char * buf , * iv_buf ;
4304- EVP_CIPHER_CTX * ctx ;
4327+ unsigned char * buf = NULL , * iv_buf ;
4328+ EVP_CIPHER_CTX * ctx = NULL ;
43054329 char * data ;
43064330 size_t data_len ;
43074331 char * ekey ;
43084332 size_t ekey_len ;
43094333 char * method , * iv = NULL ;
43104334 size_t method_len , iv_len = 0 ;
4335+ zend_string * tag = NULL ;
43114336 const EVP_CIPHER * cipher ;
4337+ int tag_len ;
43124338
4313- if (zend_parse_parameters (ZEND_NUM_ARGS (), "szszs|s!" , & data , & data_len , & opendata ,
4314- & ekey , & ekey_len , & privkey , & method , & method_len , & iv , & iv_len ) == FAILURE ) {
4339+ if (zend_parse_parameters (ZEND_NUM_ARGS (), "szszs|s!S! " , & data , & data_len , & opendata ,
4340+ & ekey , & ekey_len , & privkey , & method , & method_len , & iv , & iv_len , & tag ) == FAILURE ) {
43154341 RETURN_THROWS ();
43164342 }
4343+ RETVAL_FALSE ;
43174344
43184345 PHP_OPENSSL_CHECK_SIZE_T_TO_INT (data_len , data , 1 );
43194346 PHP_OPENSSL_CHECK_SIZE_T_TO_INT (ekey_len , ekey , 3 );
@@ -4323,24 +4350,24 @@ PHP_FUNCTION(openssl_open)
43234350 if (!EG (exception )) {
43244351 php_error_docref (NULL , E_WARNING , "Unable to coerce parameter 4 into a private key" );
43254352 }
4326- RETURN_FALSE ;
4353+ goto clean_exit ;
43274354 }
43284355
43294356 cipher = php_openssl_get_evp_cipher_by_name (method );
43304357 if (!cipher ) {
43314358 php_error_docref (NULL , E_WARNING , "Unknown cipher algorithm" );
4332- RETURN_FALSE ;
4359+ goto clean_exit ;
43334360 }
43344361
43354362 cipher_iv_len = EVP_CIPHER_iv_length (cipher );
43364363 if (cipher_iv_len > 0 ) {
43374364 if (!iv ) {
43384365 zend_argument_value_error (6 , "cannot be null for the chosen cipher algorithm" );
4339- RETURN_THROWS () ;
4366+ goto clean_exit ;
43404367 }
43414368 if ((size_t )cipher_iv_len != iv_len ) {
43424369 php_error_docref (NULL , E_WARNING , "IV length is invalid" );
4343- RETURN_FALSE ;
4370+ goto clean_exit ;
43444371 }
43454372 iv_buf = (unsigned char * )iv ;
43464373 } else {
@@ -4350,20 +4377,48 @@ PHP_FUNCTION(openssl_open)
43504377 buf = emalloc (data_len + 1 );
43514378
43524379 ctx = EVP_CIPHER_CTX_new ();
4353- if (ctx != NULL && EVP_OpenInit (ctx , cipher , (unsigned char * )ekey , (int )ekey_len , iv_buf , pkey ) &&
4354- EVP_OpenUpdate (ctx , buf , & len1 , (unsigned char * )data , (int )data_len ) &&
4355- EVP_OpenFinal (ctx , buf + len1 , & len2 ) && (len1 + len2 > 0 )) {
4380+ if (ctx == NULL || !EVP_OpenInit (ctx , cipher , (unsigned char * )ekey , (int )ekey_len , iv_buf , pkey )) {
4381+ php_openssl_store_errors ();
4382+ goto clean_exit ;
4383+ }
4384+
4385+ tag_len = EVP_CIPHER_CTX_get_tag_length (ctx );
4386+ if ((tag != NULL ) != (tag_len > 0 )) {
4387+ const char * imp = tag ? "cannot" : "must" ;
4388+ zend_argument_value_error (7 , "%s be specified for the chosen cipher algorithm" , imp );
4389+ goto clean_exit ;
4390+ }
4391+ if (tag ) {
4392+ if (ZSTR_LEN (tag ) != tag_len ) {
4393+ zend_argument_value_error (7 , "must be %d bytes long" , tag_len );
4394+ goto clean_exit ;
4395+ }
4396+
4397+ if (!EVP_CIPHER_CTX_ctrl (ctx , EVP_CTRL_AEAD_SET_TAG , ZSTR_LEN (tag ), ZSTR_VAL (tag ))) {
4398+ php_openssl_store_errors ();
4399+ goto clean_exit ;
4400+ }
4401+ }
4402+
4403+ if (EVP_OpenUpdate (ctx , buf , & len1 , (unsigned char * )data , (int )data_len ) &&
4404+ EVP_OpenFinal (ctx , buf + len1 , & len2 ) && (len1 + len2 > 0 )) {
43564405 buf [len1 + len2 ] = '\0' ;
43574406 ZEND_TRY_ASSIGN_REF_NEW_STR (opendata , zend_string_init ((char * )buf , len1 + len2 , 0 ));
43584407 RETVAL_TRUE ;
43594408 } else {
43604409 php_openssl_store_errors ();
4361- RETVAL_FALSE ;
43624410 }
43634411
4364- efree (buf );
4365- EVP_PKEY_free (pkey );
4366- EVP_CIPHER_CTX_free (ctx );
4412+ clean_exit :
4413+ if (buf ) {
4414+ efree (buf );
4415+ }
4416+ if (pkey ) {
4417+ EVP_PKEY_free (pkey );
4418+ }
4419+ if (ctx ) {
4420+ EVP_CIPHER_CTX_free (ctx );
4421+ }
43674422}
43684423/* }}} */
43694424
0 commit comments