diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index f770dc6deac8b..2c09b89e31200 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -4171,24 +4171,22 @@ PHP_FUNCTION(openssl_verify) /* {{{ Seals data */ PHP_FUNCTION(openssl_seal) { - zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL, *tag = NULL; + zval *pubkeys, *pubkey, *sealdata, *ekeys, *iv = NULL; HashTable *pubkeysht; - EVP_PKEY **pkeys = NULL; - int i, len1, len2, *eksl = NULL, nkeys = 0, iv_len; - unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks = NULL; + EVP_PKEY **pkeys; + int i, len1, len2, *eksl, nkeys, iv_len; + unsigned char iv_buf[EVP_MAX_IV_LENGTH + 1], *buf = NULL, **eks; char * data; size_t data_len; char *method; size_t method_len; const EVP_CIPHER *cipher; - EVP_CIPHER_CTX *ctx = NULL; - size_t tag_len; + EVP_CIPHER_CTX *ctx; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "szzas|z!z!", &data, &data_len, - &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv, &tag) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szzas|z", &data, &data_len, + &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) { RETURN_THROWS(); } - RETVAL_FALSE; PHP_OPENSSL_CHECK_SIZE_T_TO_INT(data_len, data, 1); @@ -4196,32 +4194,19 @@ PHP_FUNCTION(openssl_seal) nkeys = pubkeysht ? zend_hash_num_elements(pubkeysht) : 0; if (!nkeys) { zend_argument_must_not_be_empty_error(4); - goto clean_exit; + RETURN_THROWS(); } cipher = php_openssl_get_evp_cipher_by_name(method); if (!cipher) { php_error_docref(NULL, E_WARNING, "Unknown cipher algorithm"); - goto clean_exit; + RETURN_FALSE; } iv_len = EVP_CIPHER_iv_length(cipher); if (!iv && iv_len > 0) { zend_argument_value_error(6, "cannot be null for the chosen cipher algorithm"); - goto clean_exit; - } - - ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) { - php_openssl_store_errors(); - goto clean_exit; - } - - tag_len = EVP_CIPHER_CTX_get_tag_length(ctx); - if ((tag != NULL) != (tag_len > 0)) { - const char *imp = tag ? "cannot" : "must"; - zend_argument_value_error(7, "%s be specified for the chosen cipher algorithm", imp); - goto clean_exit; + RETURN_THROWS(); } pkeys = safe_emalloc(nkeys, sizeof(*pkeys), 0); @@ -4238,12 +4223,21 @@ PHP_FUNCTION(openssl_seal) if (!EG(exception)) { php_error_docref(NULL, E_WARNING, "Not a public key (%dth member of pubkeys)", i+1); } + RETVAL_FALSE; goto clean_exit; } eks[i] = emalloc(EVP_PKEY_size(pkeys[i]) + 1); i++; } ZEND_HASH_FOREACH_END(); + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL || !EVP_EncryptInit(ctx,cipher,NULL,NULL)) { + EVP_CIPHER_CTX_free(ctx); + php_openssl_store_errors(); + RETVAL_FALSE; + goto clean_exit; + } + /* allocate one byte extra to make room for \0 */ buf = emalloc(data_len + EVP_CIPHER_CTX_block_size(ctx)); EVP_CIPHER_CTX_reset(ctx); @@ -4252,23 +4246,19 @@ PHP_FUNCTION(openssl_seal) !EVP_SealUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) || !EVP_SealFinal(ctx, buf + len1, &len2)) { efree(buf); + EVP_CIPHER_CTX_free(ctx); php_openssl_store_errors(); + RETVAL_FALSE; goto clean_exit; } - if (tag) { - zend_string *tag_str = zend_string_alloc(tag_len, 0); - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, ZSTR_LEN(tag_str), ZSTR_VAL(tag_str)); - ZSTR_VAL(tag_str)[ZSTR_LEN(tag_str)] = 0; - ZEND_TRY_ASSIGN_REF_NEW_STR(tag, tag_str); - } - if (len1 + len2 > 0) { ZEND_TRY_ASSIGN_REF_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0)); efree(buf); ekeys = zend_try_array_init(ekeys); if (!ekeys) { + EVP_CIPHER_CTX_free(ctx); goto clean_exit; } @@ -4286,35 +4276,21 @@ PHP_FUNCTION(openssl_seal) } else { efree(buf); } - RETVAL_LONG(len1 + len2); + EVP_CIPHER_CTX_free(ctx); clean_exit: - if (ctx) { - EVP_CIPHER_CTX_free(ctx); - } - - if (pkeys) { - for (i=0; i 0) { if (!iv) { zend_argument_value_error(6, "cannot be null for the chosen cipher algorithm"); - goto clean_exit; + RETURN_THROWS(); } if ((size_t)cipher_iv_len != iv_len) { php_error_docref(NULL, E_WARNING, "IV length is invalid"); - goto clean_exit; + RETURN_FALSE; } iv_buf = (unsigned char *)iv; } else { @@ -4377,48 +4350,20 @@ PHP_FUNCTION(openssl_open) buf = emalloc(data_len + 1); ctx = EVP_CIPHER_CTX_new(); - if (ctx == NULL || !EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey)) { - php_openssl_store_errors(); - goto clean_exit; - } - - tag_len = EVP_CIPHER_CTX_get_tag_length(ctx); - if ((tag != NULL) != (tag_len > 0)) { - const char *imp = tag ? "cannot" : "must"; - zend_argument_value_error(7, "%s be specified for the chosen cipher algorithm", imp); - goto clean_exit; - } - if (tag) { - if (ZSTR_LEN(tag) != tag_len) { - zend_argument_value_error(7, "must be %d bytes long", tag_len); - goto clean_exit; - } - - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ZSTR_LEN(tag), ZSTR_VAL(tag))) { - php_openssl_store_errors(); - goto clean_exit; - } - } - - if (EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) && - EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) { + if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) && + EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) && + EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) { buf[len1 + len2] = '\0'; ZEND_TRY_ASSIGN_REF_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0)); RETVAL_TRUE; } else { php_openssl_store_errors(); + RETVAL_FALSE; } -clean_exit: - if (buf) { - efree(buf); - } - if (pkey) { - EVP_PKEY_free(pkey); - } - if (ctx) { - EVP_CIPHER_CTX_free(ctx); - } + efree(buf); + EVP_PKEY_free(pkey); + EVP_CIPHER_CTX_free(ctx); } /* }}} */ diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index 56e96a27a6ab2..94902a4acf0da 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -628,15 +628,14 @@ function openssl_verify(string $data, string $signature, $public_key, string|int * @param string $sealed_data * @param array $encrypted_keys * @param string $iv - * @param string $tag */ -function openssl_seal(#[\SensitiveParameter] string $data, &$sealed_data, &$encrypted_keys, array $public_key, string $cipher_algo, &$iv = null, &$tag = null): int|false {} +function openssl_seal(#[\SensitiveParameter] string $data, &$sealed_data, &$encrypted_keys, array $public_key, string $cipher_algo, &$iv = null): int|false {} /** * @param string $output * @param OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $private_key */ -function openssl_open(string $data, #[\SensitiveParameter] &$output, string $encrypted_key, #[\SensitiveParameter] $private_key, string $cipher_algo, ?string $iv = null, ?string $tag = null): bool {} +function openssl_open(string $data, #[\SensitiveParameter] &$output, string $encrypted_key, #[\SensitiveParameter] $private_key, string $cipher_algo, ?string $iv = null): bool {} /** * @return array diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index 5ab604828e5cb..796582c185bb6 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 91d576073b79bf4b441e44eccb0deaa2b79a6949 */ + * Stub hash: 8233a8abc8ab7145d905d0fa51478edfe1e55a06 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) @@ -302,7 +302,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_openssl_seal, 0, 5, MAY_BE_LONG| ZEND_ARG_TYPE_INFO(0, public_key, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, cipher_algo, IS_STRING, 0) ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, iv, "null") - ZEND_ARG_INFO_WITH_DEFAULT_VALUE(1, tag, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_open, 0, 5, _IS_BOOL, 0) @@ -312,7 +311,6 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_open, 0, 5, _IS_BOOL, 0) ZEND_ARG_INFO(0, private_key) ZEND_ARG_TYPE_INFO(0, cipher_algo, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, iv, IS_STRING, 1, "null") - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, tag, IS_STRING, 1, "null") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_get_md_methods, 0, 0, IS_ARRAY, 0) diff --git a/ext/openssl/tests/gh7737.phpt b/ext/openssl/tests/gh7737.phpt deleted file mode 100644 index 5136e3e295c1d..0000000000000 --- a/ext/openssl/tests/gh7737.phpt +++ /dev/null @@ -1,57 +0,0 @@ ---TEST-- -GitHub Bug#7737 - openssl_seal/open() does not handle ciphers with Tags (e.g. AES-256-CGM) ---EXTENSIONS-- -openssl ---SKIPIF-- - ---FILE-- - KEY_TYPE]); - define('KEY_PUBLIC', openssl_pkey_get_details($key)['key']); - define('KEY_PRIVATE', openssl_pkey_get_private($key)); -})(); - -echo 'Plaintext: '; var_dump(PLAINTEXT); - -$sealResult = openssl_seal(PLAINTEXT, - $sealedData, /* out */ - $sealedKeys, /* out */ - [KEY_PUBLIC], - CIPHER_ALGO, - $iv, /* out */ - $tag); /* out */ - -echo 'Seal Result: '; var_dump($sealResult); -echo 'Sealed Data: '; var_dump(strlen($sealedData)); -echo 'IV Length: '; var_dump(strlen($iv)); -echo 'Tag Length: '; var_dump(strlen($tag)); - -$unsealResult = openssl_open($sealedData, - $unsealedData, /* out */ - $sealedKeys[0], - KEY_PRIVATE, - CIPHER_ALGO, - $iv, - $tag); - -echo 'Unseal Result: '; var_dump($unsealResult); -echo 'Unsealed Data: '; var_dump($unsealedData); - -?> ---EXPECT-- -Plaintext: string(16) "Test Data String" -Seal Result: int(16) -Sealed Data: int(16) -IV Length: int(12) -Tag Length: int(16) -Unseal Result: bool(true) -Unsealed Data: string(16) "Test Data String"