120 lines
3.9 KiB
Diff
120 lines
3.9 KiB
Diff
From 2a73e91a9f9136fbbfcc9177573b6af71e3d5dce Mon Sep 17 00:00:00 2001
|
|
From: David Carlier <devnexen@gmail.com>
|
|
Date: Fri, 29 May 2026 21:44:14 +0100
|
|
Subject: [PATCH] ext/openssl: openssl_encrypt() zend mm heap overflow on
|
|
AES-WRAP-PAD mode.
|
|
|
|
Fix #22186
|
|
|
|
close GH-22187
|
|
|
|
(cherry picked from commit cbc0489126a7682796aad1e5fb4e51de74af162c)
|
|
(cherry picked from commit 95e9851111d249e43948b76663cff1baeb5e758d)
|
|
---
|
|
NEWS | 6 ++++++
|
|
ext/openssl/openssl.c | 17 +++++++++++++++--
|
|
ext/openssl/tests/gh22186.phpt | 32 ++++++++++++++++++++++++++++++++
|
|
3 files changed, 53 insertions(+), 2 deletions(-)
|
|
create mode 100644 ext/openssl/tests/gh22186.phpt
|
|
|
|
diff --git a/NEWS b/NEWS
|
|
index eb31a08afd..e3cb991135 100644
|
|
--- a/NEWS
|
|
+++ b/NEWS
|
|
@@ -1,6 +1,12 @@
|
|
PHP NEWS
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
+Backported from 8.2.32
|
|
+
|
|
+- OpenSSL:
|
|
+ . Fixed bug GH-22187 (Memory corruption (zend_mm_heap corrupted) in
|
|
+ openssl_encrypt with AES-WRAP-PAD). (David Carlier)
|
|
+
|
|
Backported from 8.2.31
|
|
|
|
- FPM:
|
|
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
|
|
index 45a7e79440..73d4f6f699 100644
|
|
--- a/ext/openssl/openssl.c
|
|
+++ b/ext/openssl/openssl.c
|
|
@@ -7155,6 +7155,7 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
|
|
const char *aad, size_t aad_len, int enc) /* {{{ */
|
|
{
|
|
int i = 0;
|
|
+ size_t outlen = data_len + EVP_CIPHER_block_size(cipher_type);
|
|
|
|
if (mode->is_single_run_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) {
|
|
php_openssl_store_errors();
|
|
@@ -7168,7 +7169,19 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
|
|
return FAILURE;
|
|
}
|
|
|
|
- *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0);
|
|
+#ifdef EVP_CIPH_WRAP_MODE
|
|
+ if ((EVP_CIPHER_mode(cipher_type)) == EVP_CIPH_WRAP_MODE) {
|
|
+ /*
|
|
+ * RFC 5649 wrap-with-padding rounds the input up to the block size
|
|
+ * and prepends an integrity block, we reserve one extra block.
|
|
+ * See EVP_EncryptUpdate(3): wrap mode may write up to
|
|
+ * inl + cipher_block_size bytes.
|
|
+ */
|
|
+ outlen += EVP_CIPHER_block_size(cipher_type);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ *poutbuf = zend_string_alloc(outlen, false);
|
|
|
|
if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf),
|
|
&i, (const unsigned char *)data, (int)data_len)) {
|
|
@@ -7180,7 +7193,7 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
|
|
}
|
|
*/
|
|
php_openssl_store_errors();
|
|
- zend_string_release_ex(*poutbuf, 0);
|
|
+ zend_string_release_ex(*poutbuf, false);
|
|
return FAILURE;
|
|
}
|
|
|
|
diff --git a/ext/openssl/tests/gh22186.phpt b/ext/openssl/tests/gh22186.phpt
|
|
new file mode 100644
|
|
index 0000000000..8f28e6c45b
|
|
--- /dev/null
|
|
+++ b/ext/openssl/tests/gh22186.phpt
|
|
@@ -0,0 +1,32 @@
|
|
+--TEST--
|
|
+GH-22186 (Heap buffer overflow in openssl_encrypt with AES-WRAP-PAD)
|
|
+--EXTENSIONS--
|
|
+openssl
|
|
+--SKIPIF--
|
|
+<?php
|
|
+/* openssl_get_cipher_methods() enumerates provider ciphers, but openssl_encrypt()
|
|
+ * resolves names via the legacy EVP_get_cipherbyname(), so on some builds the
|
|
+ * cipher is listed yet not usable. Probe the actual call path instead. */
|
|
+if (!@openssl_encrypt("test", "aes-128-wrap-pad", str_repeat("k", 16),
|
|
+ OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, str_repeat("\0", 4))) {
|
|
+ die('skip aes-128-wrap-pad not usable on this OpenSSL build');
|
|
+}
|
|
+?>
|
|
+--FILE--
|
|
+<?php
|
|
+$pass = str_repeat("k", 16);
|
|
+$iv = str_repeat("\0", 4);
|
|
+
|
|
+for ($i = 1; $i < 258; $i++) {
|
|
+ $data = str_repeat("a", $i);
|
|
+ $enc = openssl_encrypt($data, 'aes-128-wrap-pad', $pass, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
|
|
+ $dec = openssl_decrypt($enc, 'aes-128-wrap-pad', $pass, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
|
|
+ if ($dec !== $data) {
|
|
+ die("mismatch at $i\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+echo "done\n";
|
|
+?>
|
|
+--EXPECT--
|
|
+done
|
|
--
|
|
2.54.0
|
|
|