summaryrefslogtreecommitdiffstats
path: root/php-gh22187.patch
blob: 7a41072e69f6dd637aa2128015fbe03c076fb4dd (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
115
116
117
118
119
120
121
122
From 4eeb25a7ae8f91e517b760423b50a5a5ef9e98fb 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)
(cherry picked from commit 58c39c2f8402261fd4e8ffd327c37adc53a9c861)
---
 NEWS                           |  6 ++++++
 ext/openssl/openssl.c          | 22 ++++++++++++++++++++++
 ext/openssl/tests/gh22186.phpt | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 60 insertions(+)
 create mode 100644 ext/openssl/tests/gh22186.phpt

diff --git a/NEWS b/NEWS
index b5014af12e..a6fcc89ccd 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 5fbb55b5df..151fddd9ff 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -5728,6 +5728,17 @@ PHP_FUNCTION(openssl_encrypt)
 	free_iv = php_openssl_validate_iv(&iv, &iv_len, max_iv_len);
 
 	outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+#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
 	outbuf = zend_string_alloc(outlen, 0);
 
 	EVP_EncryptInit(cipher_ctx, cipher_type, NULL, NULL);
@@ -5832,6 +5843,17 @@ PHP_FUNCTION(openssl_decrypt)
 	free_iv = php_openssl_validate_iv(&iv, &iv_len, EVP_CIPHER_iv_length(cipher_type));
 
 	outlen = data_len + EVP_CIPHER_block_size(cipher_type);
+#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
 	outbuf = zend_string_alloc(outlen, 0);
 
 	EVP_DecryptInit(cipher_ctx, cipher_type, NULL, NULL);
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