Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDEV-28133: Backport OpenSSL compatibility to 10.6 branch #2036

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions cmake/ssl.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ MACRO (MYSQL_CHECK_SSL)
ENDIF()
FIND_PACKAGE(OpenSSL)
SET_PACKAGE_PROPERTIES(OpenSSL PROPERTIES TYPE RECOMMENDED)
IF(OPENSSL_FOUND AND OPENSSL_VERSION AND OPENSSL_VERSION VERSION_LESS "3.0.0")
IF(OPENSSL_FOUND)
SET(OPENSSL_LIBRARY ${OPENSSL_SSL_LIBRARY})
INCLUDE(CheckSymbolExists)
SET(SSL_SOURCES "")
Expand All @@ -139,9 +139,20 @@ MACRO (MYSQL_CHECK_SSL)
SET(SSL_INTERNAL_INCLUDE_DIRS "")
SET(SSL_DEFINES "-DHAVE_OPENSSL")

FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
SET(SAVE_CMAKE_REQUIRED_${x} ${CMAKE_REQUIRED_${x}})
ENDFOREACH()

# Silence "deprecated in OpenSSL 3.0"
IF((NOT OPENSSL_VERSION) # 3.0 not determined by older cmake
OR NOT(OPENSSL_VERSION VERSION_LESS "3.0.0"))
SET(SSL_DEFINES "${SSL_DEFINES} -DOPENSSL_API_COMPAT=0x10100000L")
SET(CMAKE_REQUIRED_DEFINITIONS -DOPENSSL_API_COMPAT=0x10100000L)
ENDIF()

SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
SET(CMAKE_REQUIRED_LIBRARIES ${SSL_LIBRARIES})
SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})

CHECK_SYMBOL_EXISTS(ERR_remove_thread_state "openssl/err.h"
HAVE_ERR_remove_thread_state)
CHECK_SYMBOL_EXISTS(EVP_aes_128_ctr "openssl/evp.h"
Expand All @@ -150,8 +161,10 @@ MACRO (MYSQL_CHECK_SSL)
HAVE_EncryptAes128Gcm)
CHECK_SYMBOL_EXISTS(X509_check_host "openssl/x509v3.h"
HAVE_X509_check_host)
SET(CMAKE_REQUIRED_INCLUDES)
SET(CMAKE_REQUIRED_LIBRARIES)

FOREACH(x INCLUDES LIBRARIES DEFINITIONS)
SET(CMAKE_REQUIRED_${x} ${SAVE_CMAKE_REQUIRED_${x}})
ENDFOREACH()
ELSE()
IF(WITH_SSL STREQUAL "system")
MESSAGE(FATAL_ERROR "Cannot find appropriate system libraries for SSL. Use WITH_SSL=bundled to enable SSL support")
Expand Down
2 changes: 1 addition & 1 deletion include/ssl_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#define SSL_LIBRARY OpenSSL_version(OPENSSL_VERSION)
#define ERR_remove_state(X) ERR_clear_error()
#define EVP_CIPHER_CTX_SIZE 176
#define EVP_MD_CTX_SIZE 48
#define EVP_MD_CTX_SIZE 72
#undef EVP_MD_CTX_init
#define EVP_MD_CTX_init(X) do { memset((X), 0, EVP_MD_CTX_SIZE); EVP_MD_CTX_reset(X); } while(0)
#undef EVP_CIPHER_CTX_init
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/lib/openssl.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ ssl_conf = ssl_section
system_default = system_default_section

[system_default_section]
CipherString = ALL:@SECLEVEL=1
CipherString = ALL:@SECLEVEL=0
9 changes: 3 additions & 6 deletions mysql-test/main/ssl_cipher.result
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,8 @@ Ssl_cipher AES256-SHA
drop user mysqltest_1@localhost;
# restart: --ssl-cipher=AES128-SHA
connect ssl_con,localhost,root,,,,,SSL;
SHOW STATUS LIKE 'Ssl_cipher';
Variable_name Value
Ssl_cipher AES128-SHA
SHOW STATUS LIKE 'Ssl_cipher_list';
Variable_name Value
Ssl_cipher_list AES128-SHA
SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
VARIABLE_VALUE like '%AES128-SHA%'
1
disconnect ssl_con;
connection default;
3 changes: 1 addition & 2 deletions mysql-test/main/ssl_cipher.test
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ drop user mysqltest_1@localhost;
let $restart_parameters=--ssl-cipher=AES128-SHA;
source include/restart_mysqld.inc;
connect (ssl_con,localhost,root,,,,,SSL);
SHOW STATUS LIKE 'Ssl_cipher';
SHOW STATUS LIKE 'Ssl_cipher_list';
SELECT VARIABLE_VALUE like '%AES128-SHA%' FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME='Ssl_cipher_list';
disconnect ssl_con;
connection default;
46 changes: 29 additions & 17 deletions mysys_ssl/my_crypt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@
#include <ssl_compat.h>
#include <cstdint>

#ifdef HAVE_WOLFSSL
#define CTX_ALIGN 16
#else
#define CTX_ALIGN 0
#endif

class MyCTX
{
Expand Down Expand Up @@ -100,8 +96,9 @@ class MyCTX_nopad : public MyCTX
{
public:
const uchar *key;
uint klen, buf_len;
uint klen, source_tail_len;
uchar oiv[MY_AES_BLOCK_SIZE];
uchar source_tail[MY_AES_BLOCK_SIZE];

MyCTX_nopad() : MyCTX() { }
~MyCTX_nopad() { }
Expand All @@ -112,7 +109,7 @@ class MyCTX_nopad : public MyCTX
compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
this->key= key;
this->klen= klen;
this->buf_len= 0;
this->source_tail_len= 0;
if (ivlen)
memcpy(oiv, iv, ivlen);
DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
Expand All @@ -123,26 +120,41 @@ class MyCTX_nopad : public MyCTX
return res;
}

/** Update last partial source block, stored in source_tail array. */
void update_source_tail(const uchar* src, uint slen)
{
if (!slen)
return;
uint new_tail_len= (source_tail_len + slen) % MY_AES_BLOCK_SIZE;
if (new_tail_len)
{
if (slen + source_tail_len < MY_AES_BLOCK_SIZE)
{
memcpy(source_tail + source_tail_len, src, slen);
}
else
{
DBUG_ASSERT(slen > new_tail_len);
memcpy(source_tail, src + slen - new_tail_len, new_tail_len);
}
}
source_tail_len= new_tail_len;
}

int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
{
buf_len+= slen;
update_source_tail(src, slen);
return MyCTX::update(src, slen, dst, dlen);
}

int finish(uchar *dst, uint *dlen)
{
buf_len %= MY_AES_BLOCK_SIZE;
if (buf_len)
if (source_tail_len)
{
uchar *buf= EVP_CIPHER_CTX_buf_noconst(ctx);
/*
Not much we can do, block ciphers cannot encrypt data that aren't
a multiple of the block length. At least not without padding.
Let's do something CTR-like for the last partial block.

NOTE this assumes that there are only buf_len bytes in the buf.
If OpenSSL will change that, we'll need to change the implementation
of this class too.
*/
uchar mask[MY_AES_BLOCK_SIZE];
uint mlen;
Expand All @@ -154,10 +166,10 @@ class MyCTX_nopad : public MyCTX
return rc;
DBUG_ASSERT(mlen == sizeof(mask));

for (uint i=0; i < buf_len; i++)
dst[i]= buf[i] ^ mask[i];
for (uint i=0; i < source_tail_len; i++)
dst[i]= source_tail[i] ^ mask[i];
}
*dlen= buf_len;
*dlen= source_tail_len;
return MY_AES_OK;
}
};
Expand Down
121 changes: 90 additions & 31 deletions unittest/mysys/aes-t.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,96 @@
#include <string.h>
#include <ctype.h>

#define DO_TEST(mode, nopad, slen, fill, dlen, hash) \
SKIP_BLOCK_IF(mode == 0xDEADBEAF, nopad ? 4 : 5, #mode " not supported") \
{ \
memset(src, fill, src_len= slen); \
ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, \
src, src_len, dst, &dst_len, \
key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
"encrypt " #mode " %u %s", src_len, nopad ? "nopad" : "pad"); \
if (!nopad) \
ok (dst_len == my_aes_get_size(mode, src_len), "my_aes_get_size");\
my_md5(md5, (char*)dst, dst_len); \
ok(dst_len == dlen && memcmp(md5, hash, sizeof(md5)) == 0, "md5"); \
ok(my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT, \
dst, dst_len, ddst, &ddst_len, \
key, sizeof(key), iv, sizeof(iv)) == MY_AES_OK, \
"decrypt " #mode " %u", dst_len); \
ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp"); \

/** Test streaming encryption, bytewise update.*/
static int aes_crypt_bytewise(enum my_aes_mode mode, int flags, const unsigned char *src,
unsigned int slen, unsigned char *dst, unsigned int *dlen,
const unsigned char *key, unsigned int klen,
const unsigned char *iv, unsigned int ivlen)
{
/* Allocate context on odd address on stack, in order to
catch misalignment errors.*/
void *ctx= (char *)alloca(MY_AES_CTX_SIZE+1)+1;

int res1, res2;
uint d1= 0, d2;
uint i;

if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
return res1;
for (i= 0; i < slen; i++)
{
uint tmp_d1=0;
res1= my_aes_crypt_update(ctx, src+i,1, dst, &tmp_d1);
if (res1)
return res1;
d1+= tmp_d1;
dst+= tmp_d1;
}
res2= my_aes_crypt_finish(ctx, dst, &d2);
*dlen= d1 + d2;
return res1 ? res1 : res2;
}


#ifndef HAVE_EncryptAes128Ctr
const uint MY_AES_CTR=0xDEADBEAF;
#endif
#ifndef HAVE_EncryptAes128Gcm
const uint MY_AES_GCM=0xDEADBEAF;
#endif

#define MY_AES_UNSUPPORTED(x) (x == 0xDEADBEAF)

static void do_test(uint mode, const char *mode_str, int nopad, uint slen,
char fill, size_t dlen, const char *hash)
{
uchar key[16]= {1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6};
uchar iv[16]= {2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7};
uchar src[1000], dst[1100], dst2[1100], ddst[1000];
uchar md5[MY_MD5_HASH_SIZE];
uint src_len, dst_len, dst_len2, ddst_len;
int result;

if (MY_AES_UNSUPPORTED(mode))
{
skip(nopad?7:6, "%s not supported", mode_str);
return;
}
memset(src, fill, src_len= slen);
result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src, src_len,
dst, &dst_len, key, sizeof(key), iv, sizeof(iv));
ok(result == MY_AES_OK, "encrypt %s %u %s", mode_str, src_len,
nopad ? "nopad" : "pad");

if (nopad)
{
result= aes_crypt_bytewise(mode, nopad | ENCRYPTION_FLAG_ENCRYPT, src,
src_len, dst2, &dst_len2, key, sizeof(key),
iv, sizeof(iv));
ok(result == MY_AES_OK, "encrypt bytewise %s %u", mode_str, src_len);
/* Compare with non-bytewise encryption result*/
ok(dst_len == dst_len2 && memcmp(dst, dst2, dst_len) == 0,
"memcmp bytewise %s %u", mode_str, src_len);
}
else
{
int dst_len_real= my_aes_get_size(mode, src_len);
ok(dst_len_real= dst_len, "my_aes_get_size");
}
my_md5(md5, (char *) dst, dst_len);
ok(dst_len == dlen, "md5 len");
ok(memcmp(md5, hash, sizeof(md5)) == 0, "md5");
result= my_aes_crypt(mode, nopad | ENCRYPTION_FLAG_DECRYPT,
dst, dst_len, ddst, &ddst_len, key, sizeof(key), iv,
sizeof(iv));

ok(result == MY_AES_OK, "decrypt %s %u", mode_str, dst_len);
ok(ddst_len == src_len && memcmp(src, ddst, src_len) == 0, "memcmp");
}

#define DO_TEST_P(M,S,F,D,H) DO_TEST(M,0,S,F,D,H)
#define DO_TEST_N(M,S,F,D,H) DO_TEST(M,ENCRYPTION_FLAG_NOPAD,S,F,D,H)
#define DO_TEST_P(M, S, F, D, H) do_test(M, #M, 0, S, F, D, H)
#define DO_TEST_N(M, S, F, D, H) do_test(M, #M, ENCRYPTION_FLAG_NOPAD, S, F, D, H)

/* useful macro for debugging */
#define PRINT_MD5() \
Expand All @@ -53,25 +122,15 @@
printf("\"\n"); \
} while(0);

#ifndef HAVE_EncryptAes128Ctr
const uint MY_AES_CTR=0xDEADBEAF;
#endif
#ifndef HAVE_EncryptAes128Gcm
const uint MY_AES_GCM=0xDEADBEAF;
#endif

int
main(int argc __attribute__((unused)),char *argv[])
{
uchar key[16]= {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};
uchar iv[16]= {2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7};
uchar src[1000], dst[1100], ddst[1000];
uchar md5[MY_MD5_HASH_SIZE];
uint src_len, dst_len, ddst_len;

MY_INIT(argv[0]);

plan(87);
plan(122);

DO_TEST_P(MY_AES_ECB, 200, '.', 208, "\xd8\x73\x8e\x3a\xbc\x66\x99\x13\x7f\x90\x23\x52\xee\x97\x6f\x9a");
DO_TEST_P(MY_AES_ECB, 128, '?', 144, "\x19\x58\x33\x85\x4c\xaa\x7f\x06\xd1\xb2\xec\xd7\xb7\x6a\xa9\x5b");
DO_TEST_P(MY_AES_CBC, 159, '%', 160, "\x4b\x03\x18\x3d\xf1\xa7\xcd\xa1\x46\xb3\xc6\x8a\x92\xc0\x0f\xc9");
Expand Down