projects/aports·blob master · refs

97 lines · 3.4 KiB

1Patch-Source: https://github.com/php/php-src/commit/cbc0489126a7682796aad1e5fb4e51de74af162c
2From cbc0489126a7682796aad1e5fb4e51de74af162c Mon Sep 17 00:00:00 2001
3From: David Carlier <[email protected]>
4Date: Fri, 29 May 2026 21:44:14 +0100
5Subject: [PATCH] ext/openssl: openssl_encrypt() zend mm heap overflow on
6 AES-WRAP-PAD mode.
7
8Fix #22186
9
10close GH-22187
11---
12 NEWS | 3 +++
13 ext/openssl/openssl.c | 17 +++++++++++++++--
14 ext/openssl/tests/gh22186.phpt | 32 ++++++++++++++++++++++++++++++++
15 3 files changed, 50 insertions(+), 2 deletions(-)
16 create mode 100644 ext/openssl/tests/gh22186.phpt
17
18diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
19index 1d467f5b50af..c3e2ba2438e4 100644
20--- a/ext/openssl/openssl.c
21+++ b/ext/openssl/openssl.c
22@@ -7472,6 +7472,7 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
23 const char *aad, size_t aad_len, int enc) /* {{{ */
24 {
25 int i = 0;
26+ size_t outlen = data_len + EVP_CIPHER_block_size(cipher_type);
27
28 if (mode->is_single_run_aead && !EVP_CipherUpdate(cipher_ctx, NULL, &i, NULL, (int)data_len)) {
29 php_openssl_store_errors();
30@@ -7485,7 +7486,19 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
31 return FAILURE;
32 }
33
34- *poutbuf = zend_string_alloc((int)data_len + EVP_CIPHER_block_size(cipher_type), 0);
35+#ifdef EVP_CIPH_WRAP_MODE
36+ if ((EVP_CIPHER_mode(cipher_type)) == EVP_CIPH_WRAP_MODE) {
37+ /*
38+ * RFC 5649 wrap-with-padding rounds the input up to the block size
39+ * and prepends an integrity block, we reserve one extra block.
40+ * See EVP_EncryptUpdate(3): wrap mode may write up to
41+ * inl + cipher_block_size bytes.
42+ */
43+ outlen += EVP_CIPHER_block_size(cipher_type);
44+ }
45+#endif
46+
47+ *poutbuf = zend_string_alloc(outlen, false);
48
49 if (!EVP_CipherUpdate(cipher_ctx, (unsigned char*)ZSTR_VAL(*poutbuf),
50 &i, (const unsigned char *)data, (int)data_len)) {
51@@ -7497,7 +7510,7 @@ static int php_openssl_cipher_update(const EVP_CIPHER *cipher_type,
52 }
53 */
54 php_openssl_store_errors();
55- zend_string_release_ex(*poutbuf, 0);
56+ zend_string_release_ex(*poutbuf, false);
57 return FAILURE;
58 }
59
60diff --git a/ext/openssl/tests/gh22186.phpt b/ext/openssl/tests/gh22186.phpt
61new file mode 100644
62index 000000000000..8f28e6c45b58
63--- /dev/null
64+++ b/ext/openssl/tests/gh22186.phpt
65@@ -0,0 +1,32 @@
66+--TEST--
67+GH-22186 (Heap buffer overflow in openssl_encrypt with AES-WRAP-PAD)
68+--EXTENSIONS--
69+openssl
70+--SKIPIF--
71+<?php
72+/* openssl_get_cipher_methods() enumerates provider ciphers, but openssl_encrypt()
73+ * resolves names via the legacy EVP_get_cipherbyname(), so on some builds the
74+ * cipher is listed yet not usable. Probe the actual call path instead. */
75+if (!@openssl_encrypt("test", "aes-128-wrap-pad", str_repeat("k", 16),
76+ OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, str_repeat("\0", 4))) {
77+ die('skip aes-128-wrap-pad not usable on this OpenSSL build');
78+}
79+?>
80+--FILE--
81+<?php
82+$pass = str_repeat("k", 16);
83+$iv = str_repeat("\0", 4);
84+
85+for ($i = 1; $i < 258; $i++) {
86+ $data = str_repeat("a", $i);
87+ $enc = openssl_encrypt($data, 'aes-128-wrap-pad', $pass, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
88+ $dec = openssl_decrypt($enc, 'aes-128-wrap-pad', $pass, OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY, $iv);
89+ if ($dec !== $data) {
90+ die("mismatch at $i\n");
91+ }
92+}
93+
94+echo "done\n";
95+?>
96+--EXPECT--
97+done