summaryrefslogtreecommitdiffstats
path: root/mysys_ssl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
commit06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /mysys_ssl
parentInitial commit. (diff)
downloadmariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.tar.xz
mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.zip
Adding upstream version 1:10.11.6.upstream/1%10.11.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mysys_ssl')
-rw-r--r--mysys_ssl/CMakeLists.txt49
-rw-r--r--mysys_ssl/my_crypt.cc369
-rw-r--r--mysys_ssl/my_md5.cc152
-rw-r--r--mysys_ssl/my_sha.inl203
-rw-r--r--mysys_ssl/my_sha1.cc18
-rw-r--r--mysys_ssl/my_sha224.cc18
-rw-r--r--mysys_ssl/my_sha256.cc18
-rw-r--r--mysys_ssl/my_sha384.cc18
-rw-r--r--mysys_ssl/my_sha512.cc18
-rw-r--r--mysys_ssl/openssl.c74
10 files changed, 937 insertions, 0 deletions
diff --git a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt
new file mode 100644
index 00000000..1c3f60b5
--- /dev/null
+++ b/mysys_ssl/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/mysys_ssl
+ ${SSL_INCLUDE_DIRS})
+
+IF(SSL_DEFINES)
+ADD_DEFINITIONS(${SSL_DEFINES})
+ENDIF()
+
+SET(MYSYS_SSL_HIDDEN_SOURCES
+ my_sha1.cc
+ my_sha224.cc
+ my_sha256.cc
+ my_sha384.cc
+ my_sha512.cc
+ my_md5.cc
+ openssl.c
+ )
+
+SET(MYSYS_SSL_SOURCES
+ ${MYSYS_SSL_HIDDEN_SOURCES}
+ my_crypt.cc
+ )
+
+# In order to get correct symbol visibility, these files
+# must be compiled with "-fvisibility=hidden"
+IF(WITH_SSL STREQUAL "bundled" AND HAVE_VISIBILITY_HIDDEN)
+ SET_SOURCE_FILES_PROPERTIES(
+ ${MYSYS_SSL_HIDDEN_SOURCES}
+ PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
+ENDIF()
+
+ADD_CONVENIENCE_LIBRARY(mysys_ssl ${MYSYS_SSL_SOURCES})
+TARGET_LINK_LIBRARIES(mysys_ssl dbug strings ${SSL_LIBRARIES})
+DTRACE_INSTRUMENT(mysys_ssl)
diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
new file mode 100644
index 00000000..00447e73
--- /dev/null
+++ b/mysys_ssl/my_crypt.cc
@@ -0,0 +1,369 @@
+/*
+ Copyright (c) 2014 Google Inc.
+ Copyright (c) 2014, 2019, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <string.h>
+
+#define template _template /* bug in WolfSSL 4.4.0, see also violite.h */
+#include <openssl/evp.h>
+#undef template
+#include <openssl/aes.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+
+#include <my_crypt.h>
+#include <ssl_compat.h>
+#include <cstdint>
+
+#define CTX_ALIGN 16
+
+class MyCTX
+{
+public:
+ char ctx_buf[EVP_CIPHER_CTX_SIZE + CTX_ALIGN];
+ EVP_CIPHER_CTX* ctx;
+ MyCTX()
+ {
+#if CTX_ALIGN > 0
+ uintptr_t p= ((uintptr_t)ctx_buf + (CTX_ALIGN - 1)) & ~(CTX_ALIGN - 1);
+ ctx = reinterpret_cast<EVP_CIPHER_CTX*>(p);
+#else
+ ctx = (EVP_CIPHER_CTX*)ctx_buf;
+#endif
+
+ EVP_CIPHER_CTX_init(ctx);
+ }
+ virtual ~MyCTX()
+ {
+ EVP_CIPHER_CTX_reset(ctx);
+ ERR_remove_state(0);
+ }
+
+ virtual int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key,
+ uint klen, const uchar *iv, uint ivlen)
+ {
+ compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX));
+ if (unlikely(!cipher))
+ return MY_AES_BAD_KEYSIZE;
+
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, encrypt) != 1)
+ return MY_AES_OPENSSL_ERROR;
+
+ DBUG_ASSERT(EVP_CIPHER_CTX_key_length(ctx) == (int)klen);
+ DBUG_ASSERT(EVP_CIPHER_CTX_iv_length(ctx) <= (int)ivlen);
+
+ return MY_AES_OK;
+ }
+ virtual int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
+ {
+#ifdef HAVE_WOLFSSL
+ // WolfSSL checks parameters and does not like NULL pointers to be passed to function below.
+ if (!src)
+ {
+ static uchar dummy[MY_AES_BLOCK_SIZE];
+ DBUG_ASSERT(!slen);
+ src=dummy;
+ }
+#endif
+
+ if (EVP_CipherUpdate(ctx, dst, (int*)dlen, src, slen) != 1)
+ return MY_AES_OPENSSL_ERROR;
+ return MY_AES_OK;
+ }
+ virtual int finish(uchar *dst, uint *dlen)
+ {
+ if (EVP_CipherFinal_ex(ctx, dst, (int*)dlen) != 1)
+ return MY_AES_BAD_DATA;
+ return MY_AES_OK;
+ }
+};
+
+class MyCTX_nopad : public MyCTX
+{
+public:
+ const uchar *key;
+ uint klen, source_tail_len;
+ uchar oiv[MY_AES_BLOCK_SIZE];
+ uchar source_tail[MY_AES_BLOCK_SIZE];
+
+ MyCTX_nopad() : MyCTX() { }
+ ~MyCTX_nopad() = default;
+
+ int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
+ const uchar *iv, uint ivlen)
+ {
+ compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
+ this->key= key;
+ this->klen= klen;
+ this->source_tail_len= 0;
+ if (ivlen)
+ memcpy(oiv, iv, ivlen);
+ DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
+
+ int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
+
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ 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)
+ {
+ update_source_tail(src, slen);
+ return MyCTX::update(src, slen, dst, dlen);
+ }
+
+ int finish(uchar *dst, uint *dlen)
+ {
+ if (source_tail_len)
+ {
+ /*
+ 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.
+ */
+ uchar mask[MY_AES_BLOCK_SIZE];
+ uint mlen;
+
+ int rc= my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
+ oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0);
+ DBUG_ASSERT(rc == MY_AES_OK);
+ if (rc)
+ return rc;
+ DBUG_ASSERT(mlen == sizeof(mask));
+
+ for (uint i=0; i < source_tail_len; i++)
+ dst[i]= source_tail[i] ^ mask[i];
+ }
+ *dlen= source_tail_len;
+ return MY_AES_OK;
+ }
+};
+
+#define make_aes_dispatcher(mode) \
+ static inline const EVP_CIPHER *aes_ ## mode(uint klen) \
+ { \
+ switch (klen) { \
+ case 16: return EVP_aes_128_ ## mode(); \
+ case 24: return EVP_aes_192_ ## mode(); \
+ case 32: return EVP_aes_256_ ## mode(); \
+ default: return 0; \
+ } \
+ }
+
+make_aes_dispatcher(ecb)
+make_aes_dispatcher(cbc)
+#ifdef HAVE_EncryptAes128Ctr
+make_aes_dispatcher(ctr)
+#endif /* HAVE_EncryptAes128Ctr */
+#ifdef HAVE_EncryptAes128Gcm
+make_aes_dispatcher(gcm)
+
+/*
+ special implementation for GCM; to fit OpenSSL AES-GCM into the
+ existing my_aes_* API it does the following:
+ - IV tail (over 12 bytes) goes to AAD
+ - the tag is appended to the ciphertext
+*/
+
+class MyCTX_gcm : public MyCTX
+{
+public:
+ const uchar *aad;
+ int aadlen;
+ MyCTX_gcm() : MyCTX() { }
+ ~MyCTX_gcm() { }
+
+ int init(const EVP_CIPHER *cipher, int encrypt, const uchar *key, uint klen,
+ const uchar *iv, uint ivlen)
+ {
+ compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_gcm));
+ int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
+ int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx);
+ aad= iv + real_ivlen;
+ aadlen= ivlen - real_ivlen;
+ return res;
+ }
+
+ int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
+ {
+ /*
+ note that this GCM class cannot do streaming decryption, because
+ it needs the tag (which is located at the end of encrypted data)
+ before decrypting the data. it can encrypt data piecewise, like, first
+ half, then the second half, but it must decrypt all at once
+ */
+ if (!EVP_CIPHER_CTX_encrypting(ctx))
+ {
+ /* encrypted string must contain authenticaton tag (see MDEV-11174) */
+ if (slen < MY_AES_BLOCK_SIZE)
+ return MY_AES_BAD_DATA;
+ slen-= MY_AES_BLOCK_SIZE;
+ if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, MY_AES_BLOCK_SIZE,
+ (void*)(src + slen)))
+ return MY_AES_OPENSSL_ERROR;
+ }
+ int unused;
+ if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen))
+ return MY_AES_OPENSSL_ERROR;
+ aadlen= 0;
+ return MyCTX::update(src, slen, dst, dlen);
+ }
+
+ int finish(uchar *dst, uint *dlen)
+ {
+ int fin;
+ if (!EVP_CipherFinal_ex(ctx, dst, &fin))
+ return MY_AES_BAD_DATA;
+ DBUG_ASSERT(fin == 0);
+
+ if (EVP_CIPHER_CTX_encrypting(ctx))
+ {
+ if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst))
+ return MY_AES_OPENSSL_ERROR;
+ *dlen= MY_AES_BLOCK_SIZE;
+ }
+ else
+ *dlen= 0;
+ return MY_AES_OK;
+ }
+};
+
+#endif
+
+const EVP_CIPHER *(*ciphers[])(uint)= {
+ aes_ecb, aes_cbc
+#ifdef HAVE_EncryptAes128Ctr
+ , aes_ctr
+#ifdef HAVE_EncryptAes128Gcm
+ , aes_gcm
+#endif
+#endif
+};
+
+extern "C" {
+
+int my_aes_crypt_init(void *ctx, enum my_aes_mode mode, int flags,
+ const unsigned char* key, unsigned int klen,
+ const unsigned char* iv, unsigned int ivlen)
+{
+#ifdef HAVE_EncryptAes128Ctr
+#ifdef HAVE_EncryptAes128Gcm
+ if (mode == MY_AES_GCM)
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ return MY_AES_OPENSSL_ERROR;
+ else
+ new (ctx) MyCTX_gcm();
+ else
+#endif
+ if (mode == MY_AES_CTR)
+ new (ctx) MyCTX();
+ else
+#endif
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ new (ctx) MyCTX_nopad();
+ else
+ new (ctx) MyCTX();
+ return ((MyCTX*)ctx)->init(ciphers[mode](klen), flags & 1,
+ key, klen, iv, ivlen);
+}
+
+int my_aes_crypt_update(void *ctx, const uchar *src, uint slen,
+ uchar *dst, uint *dlen)
+{
+ return ((MyCTX*)ctx)->update(src, slen, dst, dlen);
+}
+
+int my_aes_crypt_finish(void *ctx, uchar *dst, uint *dlen)
+{
+ int res= ((MyCTX*)ctx)->finish(dst, dlen);
+ ((MyCTX*)ctx)->~MyCTX();
+ return res;
+}
+
+int my_aes_crypt(enum my_aes_mode mode, int flags,
+ const uchar *src, uint slen, uchar *dst, uint *dlen,
+ const uchar *key, uint klen, const uchar *iv, uint ivlen)
+{
+ void *ctx= alloca(MY_AES_CTX_SIZE);
+ int res1, res2;
+ uint d1= 0, d2;
+ if ((res1= my_aes_crypt_init(ctx, mode, flags, key, klen, iv, ivlen)))
+ return res1;
+ res1= my_aes_crypt_update(ctx, src, slen, dst, &d1);
+ res2= my_aes_crypt_finish(ctx, dst + d1, &d2);
+ if (res1 || res2)
+ ERR_remove_state(0); /* in case of failure clear error queue */
+ else
+ *dlen= d1 + d2;
+ return res1 ? res1 : res2;
+}
+
+
+/*
+ calculate the length of the cyphertext from the length of the plaintext
+ for different AES encryption modes with padding enabled.
+ Without padding (ENCRYPTION_FLAG_NOPAD) cyphertext has the same length
+ as the plaintext
+*/
+unsigned int my_aes_get_size(enum my_aes_mode mode __attribute__((unused)), unsigned int source_length)
+{
+#ifdef HAVE_EncryptAes128Ctr
+ if (mode == MY_AES_CTR)
+ return source_length;
+#ifdef HAVE_EncryptAes128Gcm
+ if (mode == MY_AES_GCM)
+ return source_length + MY_AES_BLOCK_SIZE;
+#endif
+#endif
+ return (source_length / MY_AES_BLOCK_SIZE + 1) * MY_AES_BLOCK_SIZE;
+}
+
+
+unsigned int my_aes_ctx_size(enum my_aes_mode)
+{
+ return MY_AES_CTX_SIZE;
+}
+
+int my_random_bytes(uchar *buf, int num)
+{
+ if (RAND_bytes(buf, num) != 1)
+ return MY_AES_OPENSSL_ERROR;
+ return MY_AES_OK;
+}
+
+}
diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc
new file mode 100644
index 00000000..75995bcc
--- /dev/null
+++ b/mysys_ssl/my_md5.cc
@@ -0,0 +1,152 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates.
+ Copyright (c) 2017, MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+/**
+ @file
+
+ @brief
+ Wrapper functions for OpenSSL and YaSSL. Also provides a Compatibility layer
+ to make available YaSSL's MD5 implementation.
+*/
+
+#include <my_global.h>
+#include <my_md5.h>
+#include <stdarg.h>
+
+#if defined(HAVE_WOLFSSL)
+#include <wolfssl/wolfcrypt/md5.h>
+#include <ssl_compat.h>
+typedef wc_Md5 EVP_MD_CTX;
+static void md5_init(EVP_MD_CTX *context)
+{
+ wc_InitMd5(context);;
+}
+
+static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len)
+{
+ wc_Md5Update(context, buf, len);
+}
+
+static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE])
+{
+ wc_Md5Final(context,digest);
+}
+
+#elif defined(HAVE_OPENSSL)
+#include <openssl/evp.h>
+#include <ssl_compat.h>
+
+static void md5_init(EVP_MD_CTX *context)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_MD *md5;
+ EVP_MD_CTX_init(context);
+ /* Ok to ignore FIPS: MD5 is not used for crypto here */
+ /* In OpenSSL 3.0.0+ it is a different EVP_MD provider */
+ md5 = EVP_MD_fetch(NULL, "MD5", "fips=no");
+ EVP_DigestInit_ex(context, md5, NULL);
+ EVP_MD_free(md5);
+#else
+ EVP_MD_CTX_init(context);
+#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ /* Ok to ignore FIPS: MD5 is not used for crypto here */
+ /* In OpenSSL 1.1.1 the non FIPS allowed flag is context specific */
+ EVP_MD_CTX_set_flags(context, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+#endif
+ EVP_DigestInit_ex(context, EVP_md5(), NULL);
+#endif
+}
+
+static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len)
+{
+ EVP_DigestUpdate(context, buf, len);
+}
+
+static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE])
+{
+ EVP_DigestFinal_ex(context, digest, NULL);
+ EVP_MD_CTX_reset(context);
+}
+
+#endif /* HAVE_WOLFSSL */
+
+/**
+ Wrapper function to compute MD5 message digest.
+
+ @param digest [out] Computed MD5 digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
+
+ @return void
+*/
+void my_md5(uchar *digest, const char *buf, size_t len)
+{
+ char ctx_buf[EVP_MD_CTX_SIZE];
+ EVP_MD_CTX * const ctx= (EVP_MD_CTX*)ctx_buf;
+ md5_init(ctx);
+ md5_input(ctx, (const uchar *)buf, (uint) len);
+ md5_result(ctx, digest);
+}
+
+
+/**
+ Wrapper function to compute MD5 message digest for
+ many messages, concatenated.
+
+ @param digest [out] Computed MD5 digest
+ @param buf1 [in] First message
+ @param len1 [in] Length of first message
+ ...
+ @param bufN [in] NULL terminates the list of buf,len pairs.
+
+ @return void
+*/
+void my_md5_multi(uchar *digest, ...)
+{
+ va_list args;
+ const uchar *str;
+ char ctx_buf[EVP_MD_CTX_SIZE];
+ EVP_MD_CTX * const ctx= (EVP_MD_CTX*)ctx_buf;
+ va_start(args, digest);
+
+ md5_init(ctx);
+ for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
+ md5_input(ctx, str, (uint) va_arg(args, size_t));
+
+ md5_result(ctx, digest);
+ va_end(args);
+}
+
+size_t my_md5_context_size()
+{
+ return EVP_MD_CTX_SIZE;
+}
+
+void my_md5_init(void *context)
+{
+ md5_init((EVP_MD_CTX *)context);
+}
+
+void my_md5_input(void *context, const uchar *buf, size_t len)
+{
+ md5_input((EVP_MD_CTX *)context, buf, (uint) len);
+}
+
+void my_md5_result(void *context, uchar *digest)
+{
+ md5_result((EVP_MD_CTX *)context, digest);
+}
diff --git a/mysys_ssl/my_sha.inl b/mysys_ssl/my_sha.inl
new file mode 100644
index 00000000..6bba6147
--- /dev/null
+++ b/mysys_ssl/my_sha.inl
@@ -0,0 +1,203 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates.
+ Copyright (c) 2014, 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+/**
+ @file
+
+ @brief
+ Wrapper functions for OpenSSL, YaSSL implementations. Also provides a
+ Compatibility layer to make available YaSSL's SHAn implementation.
+*/
+
+#include <my_global.h>
+#include <stdarg.h>
+
+#define HASH_SIZE (NUM > 1 ? NUM/8 : 20)
+
+#if defined(HAVE_WOLFSSL)
+#define WOLFSSL_SHA512
+#define WOLFSSL_SHA384
+#define WOLFSSL_SHA224
+#include <wolfcrypt/sha.h>
+#include <wolfcrypt/sha256.h>
+#include <wolfcrypt/sha512.h>
+#define xCONTEXT(x) wc_Sha ## x
+#define yCONTEXT(y) xCONTEXT(y)
+#define CONTEXT yCONTEXT(NUM)
+#define wc_InitSha1 wc_InitSha
+#define wc_Sha1Final wc_ShaFinal
+#define wc_Sha1Update wc_ShaUpdate
+#define wc_Sha1 wc_Sha
+#define SHA224_CTX SHA256_CTX
+#define SHA384_CTX SHA512_CTX
+
+#define xSHA_Init(x) wc_InitSha ## x
+#define xSHA_Update(x) wc_Sha ## x ## Update
+#define xSHA_Final(x) wc_Sha ## x ## Final
+#define ySHA_Init(y) xSHA_Init(y)
+#define ySHA_Update(y) xSHA_Update(y)
+#define ySHA_Final(y) xSHA_Final(y)
+#define SHA_Init ySHA_Init(NUM)
+#define SHA_Update ySHA_Update(NUM)
+#define SHA_Final ySHA_Final(NUM)
+static void sha_init(CONTEXT *context)
+{
+ SHA_Init(context);
+}
+
+static void sha_init_fast(CONTEXT *context)
+{
+ sha_init(context);
+}
+
+static void sha_input(CONTEXT *context, const uchar *buf, unsigned len)
+{
+ SHA_Update(context, buf, len);
+}
+
+static void sha_result(CONTEXT *context, uchar digest[HASH_SIZE])
+{
+ SHA_Final(context, digest);
+}
+
+#elif defined(HAVE_OPENSSL)
+#include <openssl/sha.h>
+
+#define xCONTEXT(x) SHA ## x ## _CTX
+#define yCONTEXT(y) xCONTEXT(y)
+#define CONTEXT yCONTEXT(NUM)
+#define SHA1_CTX SHA_CTX
+#define SHA224_CTX SHA256_CTX
+#define SHA384_CTX SHA512_CTX
+
+#define xSHA_Init(x) SHA ## x ## _Init
+#define xSHA_Update(x) SHA ## x ## _Update
+#define xSHA_Final(x) SHA ## x ## _Final
+#define ySHA_Init(y) xSHA_Init(y)
+#define ySHA_Update(y) xSHA_Update(y)
+#define ySHA_Final(y) xSHA_Final(y)
+#define SHA_Init ySHA_Init(NUM)
+#define SHA_Update ySHA_Update(NUM)
+#define SHA_Final ySHA_Final(NUM)
+
+static void sha_init(CONTEXT *context)
+{
+ SHA_Init(context);
+}
+
+static void sha_init_fast(CONTEXT *context)
+{
+ sha_init(context);
+}
+
+static void sha_input(CONTEXT *context, const uchar *buf, unsigned len)
+{
+ SHA_Update(context, buf, len);
+}
+
+static void sha_result(CONTEXT *context, uchar digest[HASH_SIZE])
+{
+ SHA_Final(digest, context);
+}
+
+#endif /* HAVE_WOLFSSL */
+
+#define xmy_sha_multi(x) my_sha ## x ## _multi
+#define xmy_sha_context_size(x) my_sha ## x ## _context_size
+#define xmy_sha_init(x) my_sha ## x ## _init
+#define xmy_sha_input(x) my_sha ## x ## _input
+#define xmy_sha_result(x) my_sha ## x ## _result
+#define xmy_sha(x) my_sha ## x
+#define ymy_sha_multi(y) xmy_sha_multi(y)
+#define ymy_sha_context_size(y) xmy_sha_context_size(y)
+#define ymy_sha_init(y) xmy_sha_init(y)
+#define ymy_sha_input(y) xmy_sha_input(y)
+#define ymy_sha_result(y) xmy_sha_result(y)
+#define ymy_sha(y) xmy_sha(y)
+#define my_sha_multi ymy_sha_multi(NUM)
+#define my_sha_context_size ymy_sha_context_size(NUM)
+#define my_sha_init ymy_sha_init(NUM)
+#define my_sha_input ymy_sha_input(NUM)
+#define my_sha_result ymy_sha_result(NUM)
+#define my_sha ymy_sha(NUM)
+
+/**
+ Wrapper function to compute SHAn message digest.
+
+ @param digest [out] Computed SHAn digest
+ @param buf [in] Message to be computed
+ @param len [in] Length of the message
+
+ @return void
+*/
+void my_sha(uchar *digest, const char *buf, size_t len)
+{
+ CONTEXT context;
+
+ sha_init_fast(&context);
+ sha_input(&context, (const uchar *)buf, (unsigned int)len);
+ sha_result(&context, digest);
+}
+
+
+/**
+ Wrapper function to compute SHAn message digest for
+ two messages in order to emulate shaN(msg1, msg2).
+
+ @param digest [out] Computed SHAn digest
+ @param buf1 [in] First message
+ @param len1 [in] Length of first message
+ @param buf2 [in] Second message
+ @param len2 [in] Length of second message
+
+ @return void
+*/
+void my_sha_multi(uchar *digest, ...)
+{
+ va_list args;
+ va_start(args, digest);
+
+ CONTEXT context;
+ const uchar *str;
+
+ sha_init_fast(&context);
+ for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
+ sha_input(&context, str, (uint) va_arg(args, size_t));
+
+ sha_result(&context, digest);
+ va_end(args);
+}
+
+size_t my_sha_context_size()
+{
+ return sizeof(CONTEXT);
+}
+
+void my_sha_init(void *context)
+{
+ sha_init((CONTEXT *)context);
+}
+
+void my_sha_input(void *context, const uchar *buf, size_t len)
+{
+ sha_input((CONTEXT *)context, buf, (uint) len);
+}
+
+void my_sha_result(void *context, uchar *digest)
+{
+ sha_result((CONTEXT *)context, digest);
+}
diff --git a/mysys_ssl/my_sha1.cc b/mysys_ssl/my_sha1.cc
new file mode 100644
index 00000000..29563742
--- /dev/null
+++ b/mysys_ssl/my_sha1.cc
@@ -0,0 +1,18 @@
+/* Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define NUM 1
+
+#include "my_sha.inl"
diff --git a/mysys_ssl/my_sha224.cc b/mysys_ssl/my_sha224.cc
new file mode 100644
index 00000000..5fffdce7
--- /dev/null
+++ b/mysys_ssl/my_sha224.cc
@@ -0,0 +1,18 @@
+/* Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define NUM 224
+
+#include "my_sha.inl"
diff --git a/mysys_ssl/my_sha256.cc b/mysys_ssl/my_sha256.cc
new file mode 100644
index 00000000..59e871de
--- /dev/null
+++ b/mysys_ssl/my_sha256.cc
@@ -0,0 +1,18 @@
+/* Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define NUM 256
+
+#include "my_sha.inl"
diff --git a/mysys_ssl/my_sha384.cc b/mysys_ssl/my_sha384.cc
new file mode 100644
index 00000000..40707de0
--- /dev/null
+++ b/mysys_ssl/my_sha384.cc
@@ -0,0 +1,18 @@
+/* Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define NUM 384
+
+#include "my_sha.inl"
diff --git a/mysys_ssl/my_sha512.cc b/mysys_ssl/my_sha512.cc
new file mode 100644
index 00000000..6a5a04d7
--- /dev/null
+++ b/mysys_ssl/my_sha512.cc
@@ -0,0 +1,18 @@
+/* Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define NUM 512
+
+#include "my_sha.inl"
diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c
new file mode 100644
index 00000000..8adaeae4
--- /dev/null
+++ b/mysys_ssl/openssl.c
@@ -0,0 +1,74 @@
+/*
+ Copyright (c) 2017, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include <my_global.h>
+#include <openssl/evp.h>
+#include <ssl_compat.h>
+
+/*
+ The check is only done for OpenSSL 1.1.x.
+ It could run for OpenSSL 1.0.x but it doesn't make much sense
+ and it hits this bug:
+ https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/1594748
+*/
+
+#ifndef HAVE_OPENSSL11
+int check_openssl_compatibility()
+{
+ return 0;
+}
+#else
+#include <openssl/evp.h>
+
+static uint testing;
+static size_t alloc_size, alloc_count;
+
+static void *coc_malloc(size_t size, const char *f __attribute__((unused)),
+ int l __attribute__((unused)))
+{
+ if (unlikely(testing))
+ {
+ alloc_size+= size;
+ alloc_count++;
+ }
+ return malloc(size);
+}
+
+int check_openssl_compatibility()
+{
+ EVP_CIPHER_CTX *evp_ctx;
+ EVP_MD_CTX *md5_ctx;
+
+ if (!CRYPTO_set_mem_functions(coc_malloc, NULL, NULL))
+ return 0;
+
+ testing= 1;
+ alloc_size= alloc_count= 0;
+ evp_ctx= EVP_CIPHER_CTX_new();
+ EVP_CIPHER_CTX_free(evp_ctx);
+ if (alloc_count != 1 || !alloc_size || alloc_size > EVP_CIPHER_CTX_SIZE)
+ return 1;
+
+ alloc_size= alloc_count= 0;
+ md5_ctx= EVP_MD_CTX_new();
+ EVP_MD_CTX_free(md5_ctx);
+ if (alloc_count != 1 || !alloc_size || alloc_size > EVP_MD_CTX_SIZE)
+ return 1;
+
+ testing= 0;
+ return 0;
+}
+#endif