blob: db123e4a10032111c522c3b010d37f590284bdf0 [file] [log] [blame]
Andrew Geissler9aee5002022-03-30 16:27:02 +00001From c80991c79f701dac42c630af4bd39593b0c7efb4 Mon Sep 17 00:00:00 2001
2From: 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
32Upstream-Status: Pending
33Signed-off-by: Khem Raj <raj.khem@gmail.com>
34---
35 cmake/ssl.cmake | 19 ++++-
36 include/ssl_compat.h | 3 +-
37 mysql-test/lib/openssl.cnf | 2 +-
38 mysql-test/main/ssl_cipher.result | 6 +-
39 mysql-test/main/ssl_cipher.test | 2 +-
40 mysys_ssl/my_crypt.cc | 46 +++++++-----
41 unittest/mysys/aes-t.c | 121 ++++++++++++++++++++++--------
42 7 files changed, 141 insertions(+), 58 deletions(-)
43
44
45--- a/cmake/ssl.cmake
46+++ b/cmake/ssl.cmake
47@@ -118,7 +118,7 @@ MACRO (MYSQL_CHECK_SSL)
48 ENDIF()
49 FIND_PACKAGE(OpenSSL)
50 SET_PACKAGE_PROPERTIES(OpenSSL PROPERTIES TYPE RECOMMENDED)
51- IF(OPENSSL_FOUND AND OPENSSL_VERSION AND OPENSSL_VERSION VERSION_LESS "3.0.0")
52+ IF(OPENSSL_FOUND)
53 SET(OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY})
54 INCLUDE(CheckSymbolExists)
55 SET(SSL_SOURCES "")
56@@ -139,9 +139,20 @@ MACRO (MYSQL_CHECK_SSL)
57 SET(SSL_INTERNAL_INCLUDE_DIRS "")
58 SET(SSL_DEFINES "-DHAVE_OPENSSL")
59
60+ FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
61+ SET(SAVE_CMAKE_REQUIRED_${x} ${CMAKE_REQUIRED_${x}})
62+ ENDFOREACH()
63+
64+ # Silence "deprecated in OpenSSL 3.0"
65+ IF((NOT OPENSSL_VERSION) # 3.0 not determined by older cmake
66+ OR NOT(OPENSSL_VERSION VERSION_LESS "3.0.0"))
67+ SET(SSL_DEFINES "${SSL_DEFINES} -DOPENSSL_API_COMPAT=0x10100000L")
68+ SET(CMAKE_REQUIRED_DEFINITIONS -DOPENSSL_API_COMPAT=0x10100000L)
69+ ENDIF()
70+
71 SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
72 SET(CMAKE_REQUIRED_LIBRARIES ${SSL_LIBRARIES})
73- SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
74+
75 CHECK_SYMBOL_EXISTS(ERR_remove_thread_state "openssl/err.h"
76 HAVE_ERR_remove_thread_state)
77 CHECK_SYMBOL_EXISTS(EVP_aes_128_ctr "openssl/evp.h"
78@@ -150,8 +161,10 @@ MACRO (MYSQL_CHECK_SSL)
79 HAVE_EncryptAes128Gcm)
80 CHECK_SYMBOL_EXISTS(X509_check_host "openssl/x509v3.h"
81 HAVE_X509_check_host)
82- SET(CMAKE_REQUIRED_INCLUDES)
83- SET(CMAKE_REQUIRED_LIBRARIES)
84+
85+ FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
86+ SET(CMAKE_REQUIRED_${x} ${SAVE_CMAKE_REQUIRED_${x}})
87+ ENDFOREACH()
88 ELSE()
89 IF(WITH_SSL STREQUAL "system")
90 MESSAGE(FATAL_ERROR "Cannot find appropriate system libraries for SSL. Use WITH_SSL=bundled to enable SSL support")
91--- a/include/ssl_compat.h
92+++ b/include/ssl_compat.h
93@@ -24,7 +24,7 @@
94 #define SSL_LIBRARY OpenSSL_version(OPENSSL_VERSION)
95 #define ERR_remove_state(X) ERR_clear_error()
96 #define EVP_CIPHER_CTX_SIZE 176
97-#define EVP_MD_CTX_SIZE 48
98+#define EVP_MD_CTX_SIZE 72
99 #undef EVP_MD_CTX_init
100 #define EVP_MD_CTX_init(X) do { memset((X), 0, EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0)
101 #undef EVP_CIPHER_CTX_init
102@@ -77,7 +77,6 @@
103 #define DH_set0_pqg(D,P,Q,G) ((D)->p= (P), (D)->g= (G))
104 #endif
105
106-#define EVP_CIPHER_CTX_buf_noconst(ctx) ((ctx)->buf)
107 #define EVP_CIPHER_CTX_encrypting(ctx) ((ctx)->encrypt)
108 #define EVP_CIPHER_CTX_SIZE sizeof(EVP_CIPHER_CTX)
109
110--- a/mysql-test/lib/openssl.cnf
111+++ b/mysql-test/lib/openssl.cnf
112@@ -9,4 +9,4 @@ ssl_conf = ssl_section
113 system_default = system_default_section
114
115 [system_default_section]
116-CipherString = ALL:@SECLEVEL=1
117+CipherString = ALL:@SECLEVEL=0
118--- a/mysql-test/main/ssl_cipher.result
119+++ b/mysql-test/main/ssl_cipher.result
120@@ -61,8 +61,8 @@ connect ssl_con,localhost,root,,,,,SSL;
121 SHOW STATUS LIKE 'Ssl_cipher';
122 Variable_name Value
123 Ssl_cipher AES128-SHA
124-SHOW STATUS LIKE 'Ssl_cipher_list';
125-Variable_name Value
126-Ssl_cipher_list AES128-SHA
127+SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
128+VARIABLE_VALUE like '%AES128-SHA%'
129+1
130 disconnect ssl_con;
131 connection default;
132--- a/mysql-test/main/ssl_cipher.test
133+++ b/mysql-test/main/ssl_cipher.test
134@@ -98,6 +98,6 @@ let $restart_parameters=--ssl-cipher=AES
135 source include/restart_mysqld.inc;
136 connect (ssl_con,localhost,root,,,,,SSL);
137 SHOW STATUS LIKE 'Ssl_cipher';
138-SHOW STATUS LIKE 'Ssl_cipher_list';
139+SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
140 disconnect ssl_con;
141 connection default;
142--- a/mysys_ssl/my_crypt.cc
143+++ b/mysys_ssl/my_crypt.cc
144@@ -29,11 +29,7 @@
145 #include <ssl_compat.h>
146 #include <cstdint>
147
148-#ifdef HAVE_WOLFSSL
149 #define CTX_ALIGN 16
150-#else
151-#define CTX_ALIGN 0
152-#endif
153
154 class MyCTX
155 {
156@@ -100,8 +96,9 @@ class MyCTX_nopad : public MyCTX
157 {
158 public:
159 const uchar *key;
160- uint klen, buf_len;
161+ uint klen, source_tail_len;
162 uchar oiv[MY_AES_BLOCK_SIZE];
163+ uchar source_tail[MY_AES_BLOCK_SIZE];
164
165 MyCTX_nopad() : MyCTX() { }
166 ~MyCTX_nopad() { }
167@@ -112,7 +109,7 @@ public:
168 compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
169 this->key= key;
170 this->klen= klen;
171- this->buf_len= 0;
172+ this->source_tail_len= 0;
173 if (ivlen)
174 memcpy(oiv, iv, ivlen);
175 DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
176@@ -123,26 +120,41 @@ public:
177 return res;
178 }
179
180+ /** Update last partial source block, stored in source_tail array. */
181+ void update_source_tail(const uchar* src, uint slen)
182+ {
183+ if (!slen)
184+ return;
185+ uint new_tail_len= (source_tail_len + slen) % MY_AES_BLOCK_SIZE;
186+ if (new_tail_len)
187+ {
188+ if (slen + source_tail_len < MY_AES_BLOCK_SIZE)
189+ {
190+ memcpy(source_tail + source_tail_len, src, slen);
191+ }
192+ else
193+ {
194+ DBUG_ASSERT(slen > new_tail_len);
195+ memcpy(source_tail, src + slen - new_tail_len, new_tail_len);
196+ }
197+ }
198+ source_tail_len= new_tail_len;
199+ }
200+
201 int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
202 {
203- buf_len+= slen;
204+ update_source_tail(src, slen);
205 return MyCTX::update(src, slen, dst, dlen);
206 }
207
208 int finish(uchar *dst, uint *dlen)
209 {
210- buf_len %= MY_AES_BLOCK_SIZE;
211- if (buf_len)
212+ if (source_tail_len)
213 {
214- uchar *buf= EVP_CIPHER_CTX_buf_noconst(ctx);
215 /*
216 Not much we can do, block ciphers cannot encrypt data that aren't
217 a multiple of the block length. At least not without padding.
218 Let's do something CTR-like for the last partial block.
219-
220- NOTE this assumes that there are only buf_len bytes in the buf.
221- If OpenSSL will change that, we'll need to change the implementation
222- of this class too.
223 */
224 uchar mask[MY_AES_BLOCK_SIZE];
225 uint mlen;
226@@ -154,10 +166,10 @@ public:
227 return rc;
228 DBUG_ASSERT(mlen == sizeof(mask));
229
230- for (uint i=0; i < buf_len; i++)
231- dst[i]= buf[i] ^ mask[i];
232+ for (uint i=0; i < source_tail_len; i++)
233+ dst[i]= source_tail[i] ^ mask[i];
234 }
235- *dlen= buf_len;
236+ *dlen= source_tail_len;
237 return MY_AES_OK;
238 }
239 };
240--- a/unittest/mysys/aes-t.c
241+++ b/unittest/mysys/aes-t.c
242@@ -21,27 +21,96 @@
243 #include <string.h>
244 #include <ctype.h>
245
246-#define DO_TEST(mode, nopad, slen, fill, dlen, hash) \
247- SKIP_BLOCK_IF(mode == 0xDEADBEAF, nopad ? 4 : 5, #mode " not supported") \
248- { \
249- memset(src, fill, src_len= slen); \
250- ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, \
251- src, src_len, dst, &dst_len, \
252- key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
253- "encrypt " #mode " %u %s", src_len, nopad ? "nopad" : "pad"); \
254- if (!nopad) \
255- ok (dst_len == my_aes_get_size(mode, src_len), "my_aes_get_size");\
256- my_md5(md5, (char*)dst, dst_len); \
257- ok(dst_len == dlen && memcmp(md5, hash, sizeof(md5)) == 0, "md5"); \
258- ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT, \
259- dst, dst_len, ddst, &ddst_len, \
260- key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
261- "decrypt " #mode " %u", dst_len); \
262- ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp"); \
263+
264+/** Test streaming encryption, bytewise update.*/
265+static int aes_crypt_bytewise(enum my_aes_mode mode, int flags, const unsigned char *src,
266+ unsigned int slen, unsigned char *dst, unsigned int *dlen,
267+ const unsigned char *key, unsigned int klen,
268+ const unsigned char *iv, unsigned int ivlen)
269+{
270+ /* Allocate context on odd address on stack, in order to
271+ catch misalignment errors.*/
272+ void *ctx= (char *)alloca(MY_AES_CTX_SIZE+1)+1;
273+
274+ int res1, res2;
275+ uint d1= 0, d2;
276+ uint i;
277+
278+ if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
279+ return res1;
280+ for (i= 0; i < slen; i++)
281+ {
282+ uint tmp_d1=0;
283+ res1= my_aes_crypt_update(ctx, src+i,1, dst, &tmp_d1);
284+ if (res1)
285+ return res1;
286+ d1+= tmp_d1;
287+ dst+= tmp_d1;
288+ }
289+ res2= my_aes_crypt_finish(ctx, dst, &d2);
290+ *dlen= d1 + d2;
291+ return res1 ? res1 : res2;
292+}
293+
294+
295+#ifndef HAVE_EncryptAes128Ctr
296+const uint MY_AES_CTR=0xDEADBEAF;
297+#endif
298+#ifndef HAVE_EncryptAes128Gcm
299+const uint MY_AES_GCM=0xDEADBEAF;
300+#endif
301+
302+#define MY_AES_UNSUPPORTED(x) (x == 0xDEADBEAF)
303+
304+static void do_test(uint mode, const char *mode_str, int nopad, uint slen,
305+ char fill, size_t dlen, const char *hash)
306+{
307+ uchar key[16]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
308+ uchar iv[16]= {2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7};
309+ uchar src[1000], dst[1100], dst2[1100], ddst[1000];
310+ uchar md5[MY_MD5_HASH_SIZE];
311+ uint src_len, dst_len, dst_len2, ddst_len;
312+ int result;
313+
314+ if (MY_AES_UNSUPPORTED(mode))
315+ {
316+ skip(nopad?7:6, "%s not supported", mode_str);
317+ return;
318+ }
319+ memset(src, fill, src_len= slen);
320+ result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src, src_len,
321+ dst, &dst_len, key, sizeof(key), iv, sizeof(iv));
322+ ok(result == MY_AES_OK, "encrypt %s %u %s", mode_str, src_len,
323+ nopad ? "nopad" : "pad");
324+
325+ if (nopad)
326+ {
327+ result= aes_crypt_bytewise(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src,
328+ src_len, dst2, &dst_len2, key, sizeof(key),
329+ iv, sizeof(iv));
330+ ok(result == MY_AES_OK, "encrypt bytewise %s %u", mode_str, src_len);
331+ /* Compare with non-bytewise encryption result*/
332+ ok(dst_len == dst_len2 && memcmp(dst, dst2, dst_len) == 0,
333+ "memcmp bytewise %s %u", mode_str, src_len);
334 }
335+ else
336+ {
337+ int dst_len_real= my_aes_get_size(mode, src_len);
338+ ok(dst_len_real= dst_len, "my_aes_get_size");
339+ }
340+ my_md5(md5, (char *) dst, dst_len);
341+ ok(dst_len == dlen, "md5 len");
342+ ok(memcmp(md5, hash, sizeof(md5)) == 0, "md5");
343+ result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT,
344+ dst, dst_len, ddst, &ddst_len, key, sizeof(key), iv,
345+ sizeof(iv));
346+
347+ ok(result == MY_AES_OK, "decrypt %s %u", mode_str, dst_len);
348+ ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp");
349+}
350
351-#define DO_TEST_P(M,S,F,D,H) DO_TEST(M,0,S,F,D,H)
352-#define DO_TEST_N(M,S,F,D,H) DO_TEST(M,ENCRYPTION_FLAG_NOPAD,S,F,D,H)
353+#define DO_TEST_P(M, S, F, D, H) do_test(M, #M, 0, S, F, D, H)
354+#define DO_TEST_N(M, S, F, D, H) do_test(M, #M, ENCRYPTION_FLAG_NOPAD, S, F, D, H)
355
356 /* useful macro for debugging */
357 #define PRINT_MD5() \
358@@ -53,25 +122,15 @@
359 printf("\"\n"); \
360 } while(0);
361
362-#ifndef HAVE_EncryptAes128Ctr
363-const uint MY_AES_CTR=0xDEADBEAF;
364-#endif
365-#ifndef HAVE_EncryptAes128Gcm
366-const uint MY_AES_GCM=0xDEADBEAF;
367-#endif
368
369 int
370 main(int argc __attribute__((unused)),char *argv[])
371 {
372- uchar key[16]= {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
373- uchar iv[16]= {2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7};
374- uchar src[1000], dst[1100], ddst[1000];
375- uchar md5[MY_MD5_HASH_SIZE];
376- uint src_len, dst_len, ddst_len;
377
378 MY_INIT(argv[0]);
379
380- plan(87);
381+ plan(122);
382+
383 DO_TEST_P(MY_AES_ECB, 200, '.', 208, "\xd8\x73\x8e\x3a\xbc\x66\x99\x13\x7f\x90\x23\x52\xee\x97\x6f\x9a");
384 DO_TEST_P(MY_AES_ECB, 128, '?', 144, "\x19\x58\x33\x85\x4c\xaa\x7f\x06\xd1\xb2\xec\xd7\xb7\x6a\xa9\x5b");
385 DO_TEST_P(MY_AES_CBC, 159, '%', 160, "\x4b\x03\x18\x3d\xf1\xa7\xcd\xa1\x46\xb3\xc6\x8a\x92\xc0\x0f\xc9");