blob: 878675f30d77a89b218d25e560e103b0cf42891c [file] [log] [blame]
Patrick Williams45852732022-04-02 08:58:32 -05001From 1626955f3a2107ec4c7fd927ebfa3c6c1d2b09b8 Mon Sep 17 00:00:00 2001
Andrew Geissler9aee5002022-03-30 16:27:02 +00002From: Vladislav Vaintroub <wlad@mariadb.com>
3Date: Mon, 8 Nov 2021 18:48:19 +0100
4Subject: [PATCH] MDEV-25785 Add support for OpenSSL 3.0
5
6Summary of changes
7
8- MD_CTX_SIZE is increased
9
10- EVP_CIPHER_CTX_buf_noconst(ctx) does not work anymore, points
11 to nobody knows where. The assumption made previously was that
12 (since the function does not seem to be documented)
13 was that it points to the last partial source block.
14 Add own partial block buffer for NOPAD encryption instead
15
16- SECLEVEL in CipherString in openssl.cnf
17 had been downgraded to 0, from 1, to make TLSv1.0 and TLSv1.1 possible
18
19- Workaround Ssl_cipher_list issue, it now returns TLSv1.3 ciphers,
20 in addition to what was set in --ssl-cipher
21
22- ctx_buf buffer now must be aligned to 16 bytes with openssl(
23 previously with WolfSSL only), ot crashes will happen
24
25- updated aes-t , to be better debuggable
26 using function, rather than a huge multiline macro
27 added test that does "nopad" encryption piece-wise, to test
28 replacement of EVP_CIPHER_CTX_buf_noconst
29
30Patch from Fedora https://src.fedoraproject.org/rpms/mariadb/raw/rawhide/f/mariadb-openssl3.patch
31
Patrick Williams45852732022-04-02 08:58:32 -050032Upstream-Status: Backport [https://github.com/MariaDB/server/commit/d42c2efbaa06a0307c2f0fd8fa87819ff50bbd7e]
Andrew Geissler9aee5002022-03-30 16:27:02 +000033Signed-off-by: Khem Raj <raj.khem@gmail.com>
Patrick Williams45852732022-04-02 08:58:32 -050034Signed-off-by: Mingli Yu <mingli.yu@windriver.com>
Andrew Geissler9aee5002022-03-30 16:27:02 +000035---
Patrick Williams45852732022-04-02 08:58:32 -050036 cmake/ssl.cmake | 21 +++++-
37 include/mysql/service_my_crypt.h | 2 +-
Andrew Geissler9aee5002022-03-30 16:27:02 +000038 include/ssl_compat.h | 3 +-
39 mysql-test/lib/openssl.cnf | 2 +-
40 mysql-test/main/ssl_cipher.result | 6 +-
41 mysql-test/main/ssl_cipher.test | 2 +-
42 mysys_ssl/my_crypt.cc | 46 +++++++-----
43 unittest/mysys/aes-t.c | 121 ++++++++++++++++++++++--------
Patrick Williams45852732022-04-02 08:58:32 -050044 8 files changed, 143 insertions(+), 60 deletions(-)
Andrew Geissler9aee5002022-03-30 16:27:02 +000045
Patrick Williams45852732022-04-02 08:58:32 -050046diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake
47index a6793cf3..64c93ff9 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +000048--- a/cmake/ssl.cmake
49+++ b/cmake/ssl.cmake
50@@ -118,7 +118,7 @@ MACRO (MYSQL_CHECK_SSL)
51 ENDIF()
52 FIND_PACKAGE(OpenSSL)
53 SET_PACKAGE_PROPERTIES(OpenSSL PROPERTIES TYPE RECOMMENDED)
54- IF(OPENSSL_FOUND AND OPENSSL_VERSION AND OPENSSL_VERSION VERSION_LESS "3.0.0")
55+ IF(OPENSSL_FOUND)
56 SET(OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY})
57 INCLUDE(CheckSymbolExists)
58 SET(SSL_SOURCES "")
59@@ -139,9 +139,20 @@ MACRO (MYSQL_CHECK_SSL)
60 SET(SSL_INTERNAL_INCLUDE_DIRS "")
61 SET(SSL_DEFINES "-DHAVE_OPENSSL")
62
63+ FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
64+ SET(SAVE_CMAKE_REQUIRED_${x} ${CMAKE_REQUIRED_${x}})
65+ ENDFOREACH()
66+
67+ # Silence "deprecated in OpenSSL 3.0"
68+ IF((NOT OPENSSL_VERSION) # 3.0 not determined by older cmake
69+ OR NOT(OPENSSL_VERSION VERSION_LESS "3.0.0"))
70+ SET(SSL_DEFINES "${SSL_DEFINES} -DOPENSSL_API_COMPAT=0x10100000L")
71+ SET(CMAKE_REQUIRED_DEFINITIONS -DOPENSSL_API_COMPAT=0x10100000L)
72+ ENDIF()
73+
74 SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
75 SET(CMAKE_REQUIRED_LIBRARIES ${SSL_LIBRARIES})
76- SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
77+
78 CHECK_SYMBOL_EXISTS(ERR_remove_thread_state "openssl/err.h"
79 HAVE_ERR_remove_thread_state)
80 CHECK_SYMBOL_EXISTS(EVP_aes_128_ctr "openssl/evp.h"
81@@ -150,8 +161,10 @@ MACRO (MYSQL_CHECK_SSL)
82 HAVE_EncryptAes128Gcm)
83 CHECK_SYMBOL_EXISTS(X509_check_host "openssl/x509v3.h"
84 HAVE_X509_check_host)
85- SET(CMAKE_REQUIRED_INCLUDES)
86- SET(CMAKE_REQUIRED_LIBRARIES)
87+
88+ FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
89+ SET(CMAKE_REQUIRED_${x} ${SAVE_CMAKE_REQUIRED_${x}})
90+ ENDFOREACH()
91 ELSE()
92 IF(WITH_SSL STREQUAL "system")
93 MESSAGE(FATAL_ERROR "Cannot find appropriate system libraries for SSL. Use WITH_SSL=bundled to enable SSL support")
Patrick Williams45852732022-04-02 08:58:32 -050094diff --git a/include/mysql/service_my_crypt.h b/include/mysql/service_my_crypt.h
95index 2a232117..bb038aaa 100644
96--- a/include/mysql/service_my_crypt.h
97+++ b/include/mysql/service_my_crypt.h
98@@ -45,7 +45,7 @@ extern "C" {
99 /* The max key length of all supported algorithms */
100 #define MY_AES_MAX_KEY_LENGTH 32
101
102-#define MY_AES_CTX_SIZE 656
103+#define MY_AES_CTX_SIZE 672
104
105 enum my_aes_mode {
106 MY_AES_ECB, MY_AES_CBC
107diff --git a/include/ssl_compat.h b/include/ssl_compat.h
108index 8dc12254..6db1baab 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000109--- a/include/ssl_compat.h
110+++ b/include/ssl_compat.h
111@@ -24,7 +24,7 @@
112 #define SSL_LIBRARY OpenSSL_version(OPENSSL_VERSION)
113 #define ERR_remove_state(X) ERR_clear_error()
114 #define EVP_CIPHER_CTX_SIZE 176
115-#define EVP_MD_CTX_SIZE 48
116+#define EVP_MD_CTX_SIZE 72
117 #undef EVP_MD_CTX_init
118 #define EVP_MD_CTX_init(X) do { memset((X), 0, EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0)
119 #undef EVP_CIPHER_CTX_init
120@@ -77,7 +77,6 @@
121 #define DH_set0_pqg(D,P,Q,G) ((D)->p= (P), (D)->g= (G))
122 #endif
123
124-#define EVP_CIPHER_CTX_buf_noconst(ctx) ((ctx)->buf)
125 #define EVP_CIPHER_CTX_encrypting(ctx) ((ctx)->encrypt)
126 #define EVP_CIPHER_CTX_SIZE sizeof(EVP_CIPHER_CTX)
127
Patrick Williams45852732022-04-02 08:58:32 -0500128diff --git a/mysql-test/lib/openssl.cnf b/mysql-test/lib/openssl.cnf
129index b9ab37ac..7cd6f748 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000130--- a/mysql-test/lib/openssl.cnf
131+++ b/mysql-test/lib/openssl.cnf
132@@ -9,4 +9,4 @@ ssl_conf = ssl_section
133 system_default = system_default_section
134
135 [system_default_section]
136-CipherString = ALL:@SECLEVEL=1
137+CipherString = ALL:@SECLEVEL=0
Patrick Williams45852732022-04-02 08:58:32 -0500138diff --git a/mysql-test/main/ssl_cipher.result b/mysql-test/main/ssl_cipher.result
139index 930d384e..66d817b7 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000140--- a/mysql-test/main/ssl_cipher.result
141+++ b/mysql-test/main/ssl_cipher.result
142@@ -61,8 +61,8 @@ connect ssl_con,localhost,root,,,,,SSL;
143 SHOW STATUS LIKE 'Ssl_cipher';
144 Variable_name Value
145 Ssl_cipher AES128-SHA
146-SHOW STATUS LIKE 'Ssl_cipher_list';
147-Variable_name Value
148-Ssl_cipher_list AES128-SHA
149+SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
150+VARIABLE_VALUE like '%AES128-SHA%'
151+1
152 disconnect ssl_con;
153 connection default;
Patrick Williams45852732022-04-02 08:58:32 -0500154diff --git a/mysql-test/main/ssl_cipher.test b/mysql-test/main/ssl_cipher.test
155index 36549d76..d4cdcffb 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000156--- a/mysql-test/main/ssl_cipher.test
157+++ b/mysql-test/main/ssl_cipher.test
Patrick Williams45852732022-04-02 08:58:32 -0500158@@ -98,6 +98,6 @@ let $restart_parameters=--ssl-cipher=AES128-SHA;
Andrew Geissler9aee5002022-03-30 16:27:02 +0000159 source include/restart_mysqld.inc;
160 connect (ssl_con,localhost,root,,,,,SSL);
161 SHOW STATUS LIKE 'Ssl_cipher';
162-SHOW STATUS LIKE 'Ssl_cipher_list';
163+SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
164 disconnect ssl_con;
165 connection default;
Patrick Williams45852732022-04-02 08:58:32 -0500166diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
167index e512eee9..4d7ebc7b 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000168--- a/mysys_ssl/my_crypt.cc
169+++ b/mysys_ssl/my_crypt.cc
170@@ -29,11 +29,7 @@
171 #include <ssl_compat.h>
172 #include <cstdint>
173
174-#ifdef HAVE_WOLFSSL
175 #define CTX_ALIGN 16
176-#else
177-#define CTX_ALIGN 0
178-#endif
179
180 class MyCTX
181 {
182@@ -100,8 +96,9 @@ class MyCTX_nopad : public MyCTX
183 {
184 public:
185 const uchar *key;
186- uint klen, buf_len;
187+ uint klen, source_tail_len;
188 uchar oiv[MY_AES_BLOCK_SIZE];
189+ uchar source_tail[MY_AES_BLOCK_SIZE];
190
191 MyCTX_nopad() : MyCTX() { }
192 ~MyCTX_nopad() { }
Patrick Williams45852732022-04-02 08:58:32 -0500193@@ -112,7 +109,7 @@ class MyCTX_nopad : public MyCTX
Andrew Geissler9aee5002022-03-30 16:27:02 +0000194 compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
195 this->key= key;
196 this->klen= klen;
197- this->buf_len= 0;
198+ this->source_tail_len= 0;
199 if (ivlen)
200 memcpy(oiv, iv, ivlen);
201 DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
Patrick Williams45852732022-04-02 08:58:32 -0500202@@ -123,26 +120,41 @@ class MyCTX_nopad : public MyCTX
Andrew Geissler9aee5002022-03-30 16:27:02 +0000203 return res;
204 }
205
206+ /** Update last partial source block, stored in source_tail array. */
207+ void update_source_tail(const uchar* src, uint slen)
208+ {
209+ if (!slen)
210+ return;
211+ uint new_tail_len= (source_tail_len + slen) % MY_AES_BLOCK_SIZE;
212+ if (new_tail_len)
213+ {
214+ if (slen + source_tail_len < MY_AES_BLOCK_SIZE)
215+ {
216+ memcpy(source_tail + source_tail_len, src, slen);
217+ }
218+ else
219+ {
220+ DBUG_ASSERT(slen > new_tail_len);
221+ memcpy(source_tail, src + slen - new_tail_len, new_tail_len);
222+ }
223+ }
224+ source_tail_len= new_tail_len;
225+ }
226+
227 int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
228 {
229- buf_len+= slen;
230+ update_source_tail(src, slen);
231 return MyCTX::update(src, slen, dst, dlen);
232 }
233
234 int finish(uchar *dst, uint *dlen)
235 {
236- buf_len %= MY_AES_BLOCK_SIZE;
237- if (buf_len)
238+ if (source_tail_len)
239 {
240- uchar *buf= EVP_CIPHER_CTX_buf_noconst(ctx);
241 /*
242 Not much we can do, block ciphers cannot encrypt data that aren't
243 a multiple of the block length. At least not without padding.
244 Let's do something CTR-like for the last partial block.
245-
246- NOTE this assumes that there are only buf_len bytes in the buf.
247- If OpenSSL will change that, we'll need to change the implementation
248- of this class too.
249 */
250 uchar mask[MY_AES_BLOCK_SIZE];
251 uint mlen;
Patrick Williams45852732022-04-02 08:58:32 -0500252@@ -154,10 +166,10 @@ class MyCTX_nopad : public MyCTX
Andrew Geissler9aee5002022-03-30 16:27:02 +0000253 return rc;
254 DBUG_ASSERT(mlen == sizeof(mask));
255
256- for (uint i=0; i < buf_len; i++)
257- dst[i]= buf[i] ^ mask[i];
258+ for (uint i=0; i < source_tail_len; i++)
259+ dst[i]= source_tail[i] ^ mask[i];
260 }
261- *dlen= buf_len;
262+ *dlen= source_tail_len;
263 return MY_AES_OK;
264 }
265 };
Patrick Williams45852732022-04-02 08:58:32 -0500266diff --git a/unittest/mysys/aes-t.c b/unittest/mysys/aes-t.c
267index 34704e06..cbec2760 100644
Andrew Geissler9aee5002022-03-30 16:27:02 +0000268--- a/unittest/mysys/aes-t.c
269+++ b/unittest/mysys/aes-t.c
270@@ -21,27 +21,96 @@
271 #include <string.h>
272 #include <ctype.h>
273
274-#define DO_TEST(mode, nopad, slen, fill, dlen, hash) \
275- SKIP_BLOCK_IF(mode == 0xDEADBEAF, nopad ? 4 : 5, #mode " not supported") \
276- { \
277- memset(src, fill, src_len= slen); \
278- ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, \
279- src, src_len, dst, &dst_len, \
280- key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
281- "encrypt " #mode " %u %s", src_len, nopad ? "nopad" : "pad"); \
282- if (!nopad) \
283- ok (dst_len == my_aes_get_size(mode, src_len), "my_aes_get_size");\
284- my_md5(md5, (char*)dst, dst_len); \
285- ok(dst_len == dlen && memcmp(md5, hash, sizeof(md5)) == 0, "md5"); \
286- ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT, \
287- dst, dst_len, ddst, &ddst_len, \
288- key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
289- "decrypt " #mode " %u", dst_len); \
290- ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp"); \
291+
292+/** Test streaming encryption, bytewise update.*/
293+static int aes_crypt_bytewise(enum my_aes_mode mode, int flags, const unsigned char *src,
294+ unsigned int slen, unsigned char *dst, unsigned int *dlen,
295+ const unsigned char *key, unsigned int klen,
296+ const unsigned char *iv, unsigned int ivlen)
297+{
298+ /* Allocate context on odd address on stack, in order to
299+ catch misalignment errors.*/
300+ void *ctx= (char *)alloca(MY_AES_CTX_SIZE+1)+1;
301+
302+ int res1, res2;
303+ uint d1= 0, d2;
304+ uint i;
305+
306+ if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
307+ return res1;
308+ for (i= 0; i < slen; i++)
309+ {
310+ uint tmp_d1=0;
311+ res1= my_aes_crypt_update(ctx, src+i,1, dst, &tmp_d1);
312+ if (res1)
313+ return res1;
314+ d1+= tmp_d1;
315+ dst+= tmp_d1;
316+ }
317+ res2= my_aes_crypt_finish(ctx, dst, &d2);
318+ *dlen= d1 + d2;
319+ return res1 ? res1 : res2;
320+}
321+
322+
323+#ifndef HAVE_EncryptAes128Ctr
324+const uint MY_AES_CTR=0xDEADBEAF;
325+#endif
326+#ifndef HAVE_EncryptAes128Gcm
327+const uint MY_AES_GCM=0xDEADBEAF;
328+#endif
329+
330+#define MY_AES_UNSUPPORTED(x) (x == 0xDEADBEAF)
331+
332+static void do_test(uint mode, const char *mode_str, int nopad, uint slen,
333+ char fill, size_t dlen, const char *hash)
334+{
335+ uchar key[16]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
336+ uchar iv[16]= {2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7};
337+ uchar src[1000], dst[1100], dst2[1100], ddst[1000];
338+ uchar md5[MY_MD5_HASH_SIZE];
339+ uint src_len, dst_len, dst_len2, ddst_len;
340+ int result;
341+
342+ if (MY_AES_UNSUPPORTED(mode))
343+ {
344+ skip(nopad?7:6, "%s not supported", mode_str);
345+ return;
346+ }
347+ memset(src, fill, src_len= slen);
348+ result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src, src_len,
349+ dst, &dst_len, key, sizeof(key), iv, sizeof(iv));
350+ ok(result == MY_AES_OK, "encrypt %s %u %s", mode_str, src_len,
351+ nopad ? "nopad" : "pad");
352+
353+ if (nopad)
354+ {
355+ result= aes_crypt_bytewise(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src,
356+ src_len, dst2, &dst_len2, key, sizeof(key),
357+ iv, sizeof(iv));
358+ ok(result == MY_AES_OK, "encrypt bytewise %s %u", mode_str, src_len);
359+ /* Compare with non-bytewise encryption result*/
360+ ok(dst_len == dst_len2 && memcmp(dst, dst2, dst_len) == 0,
361+ "memcmp bytewise %s %u", mode_str, src_len);
Patrick Williams45852732022-04-02 08:58:32 -0500362+ }
Andrew Geissler9aee5002022-03-30 16:27:02 +0000363+ else
364+ {
365+ int dst_len_real= my_aes_get_size(mode, src_len);
366+ ok(dst_len_real= dst_len, "my_aes_get_size");
Patrick Williams45852732022-04-02 08:58:32 -0500367 }
Andrew Geissler9aee5002022-03-30 16:27:02 +0000368+ my_md5(md5, (char *) dst, dst_len);
369+ ok(dst_len == dlen, "md5 len");
370+ ok(memcmp(md5, hash, sizeof(md5)) == 0, "md5");
371+ result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT,
372+ dst, dst_len, ddst, &ddst_len, key, sizeof(key), iv,
373+ sizeof(iv));
374+
375+ ok(result == MY_AES_OK, "decrypt %s %u", mode_str, dst_len);
376+ ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp");
377+}
378
379-#define DO_TEST_P(M,S,F,D,H) DO_TEST(M,0,S,F,D,H)
380-#define DO_TEST_N(M,S,F,D,H) DO_TEST(M,ENCRYPTION_FLAG_NOPAD,S,F,D,H)
381+#define DO_TEST_P(M, S, F, D, H) do_test(M, #M, 0, S, F, D, H)
382+#define DO_TEST_N(M, S, F, D, H) do_test(M, #M, ENCRYPTION_FLAG_NOPAD, S, F, D, H)
383
384 /* useful macro for debugging */
385 #define PRINT_MD5() \
386@@ -53,25 +122,15 @@
387 printf("\"\n"); \
388 } while(0);
389
390-#ifndef HAVE_EncryptAes128Ctr
391-const uint MY_AES_CTR=0xDEADBEAF;
392-#endif
393-#ifndef HAVE_EncryptAes128Gcm
394-const uint MY_AES_GCM=0xDEADBEAF;
395-#endif
396
397 int
398 main(int argc __attribute__((unused)),char *argv[])
399 {
400- uchar key[16]= {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
401- uchar iv[16]= {2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7};
402- uchar src[1000], dst[1100], ddst[1000];
403- uchar md5[MY_MD5_HASH_SIZE];
404- uint src_len, dst_len, ddst_len;
405
406 MY_INIT(argv[0]);
407
408- plan(87);
409+ plan(122);
410+
411 DO_TEST_P(MY_AES_ECB, 200, '.', 208, "\xd8\x73\x8e\x3a\xbc\x66\x99\x13\x7f\x90\x23\x52\xee\x97\x6f\x9a");
412 DO_TEST_P(MY_AES_ECB, 128, '?', 144, "\x19\x58\x33\x85\x4c\xaa\x7f\x06\xd1\xb2\xec\xd7\xb7\x6a\xa9\x5b");
413 DO_TEST_P(MY_AES_CBC, 159, '%', 160, "\x4b\x03\x18\x3d\xf1\xa7\xcd\xa1\x46\xb3\xc6\x8a\x92\xc0\x0f\xc9");
Patrick Williams45852732022-04-02 08:58:32 -0500414--
4152.25.1
416