summaryrefslogtreecommitdiffstats
path: root/php-gh22187.patch
blob: 181708c248416b4503f3b0ed792531de31f1d273 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
From 58c39c2f8402261fd4e8ffd327c37adc53a9c861 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)
(cherry picked from commit 2a73e91a9f9136fbbfcc9177573b6af71e3d5dce)
(cherry picked from commit e058b01e1bd23421a425cffae9f458b0fa8db222)
(cherry picked from commit 09cccab30d53614bb826e4390ad23ad7451b6d6c)
(cherry picked from commit f15d1e26160a8175474160907eb6ab7e10090fa0)
---
 NEWS                           |  6 ++++++
 ext/openssl/openssl.c          | 15 ++++++++++++++-
 ext/openssl/tests/gh22186.phpt | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 52 insertions(+), 1 deletion(-)
 create mode 100644 ext/openssl/tests/gh22186.phpt

diff --git a/NEWS b/NEWS
index 7afe0597de9..ca517e5c959 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 72db9941d4f..5ab6f4e1924 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -6341,6 +6341,7 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
 		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();
@@ -6354,7 +6355,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, 0);
 
 	if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf),
 					&i, (unsigned char *)data, (int)data_len)) {
diff --git a/ext/openssl/tests/gh22186.phpt b/ext/openssl/tests/gh22186.phpt
new file mode 100644
index 00000000000..8f28e6c45b5
--- /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