summaryrefslogtreecommitdiff
path: root/mysys_ssl
diff options
context:
space:
mode:
Diffstat (limited to 'mysys_ssl')
-rw-r--r--mysys_ssl/CMakeLists.txt1
-rw-r--r--mysys_ssl/my_crypt.cc94
-rw-r--r--mysys_ssl/my_md5.cc72
-rw-r--r--mysys_ssl/my_sha.ic6
-rw-r--r--mysys_ssl/openssl.c72
-rw-r--r--mysys_ssl/yassl.cc12
6 files changed, 172 insertions, 85 deletions
diff --git a/mysys_ssl/CMakeLists.txt b/mysys_ssl/CMakeLists.txt
index 4f6f7458c5b..f8a767ed6f3 100644
--- a/mysys_ssl/CMakeLists.txt
+++ b/mysys_ssl/CMakeLists.txt
@@ -28,6 +28,7 @@ SET(MYSYS_SSL_HIDDEN_SOURCES
my_sha384.cc
my_sha512.cc
my_md5.cc
+ openssl.c
)
SET(MYSYS_SSL_SOURCES
diff --git a/mysys_ssl/my_crypt.cc b/mysys_ssl/my_crypt.cc
index 439339423cd..db303f37b0e 100644
--- a/mysys_ssl/my_crypt.cc
+++ b/mysys_ssl/my_crypt.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2014 Google Inc.
- Copyright (c) 2014, 2015 MariaDB Corporation
+ Copyright (c) 2014, 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
@@ -17,53 +17,60 @@
#include <my_global.h>
#include <string.h>
-#include <my_crypt.h>
#ifdef HAVE_YASSL
#include "yassl.cc"
#else
-
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
-
-#ifdef HAVE_ERR_remove_thread_state
-#define ERR_remove_state(X) ERR_remove_thread_state(NULL)
#endif
-#endif
+#include <my_crypt.h>
+#include <ssl_compat.h>
class MyCTX
{
public:
- EVP_CIPHER_CTX ctx;
- MyCTX() { EVP_CIPHER_CTX_init(&ctx); }
- virtual ~MyCTX() { EVP_CIPHER_CTX_cleanup(&ctx); ERR_remove_state(0); }
+ char ctx_buf[EVP_CIPHER_CTX_SIZE];
+ EVP_CIPHER_CTX *ctx;
+
+ MyCTX()
+ {
+ ctx= (EVP_CIPHER_CTX *)ctx_buf;
+ 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))
+ if (!EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, encrypt))
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);
+ 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)
{
- if (!EVP_CipherUpdate(&ctx, dst, (int*)dlen, src, slen))
+ if (!EVP_CipherUpdate(ctx, dst, (int*)dlen, src, slen))
return MY_AES_OPENSSL_ERROR;
return MY_AES_OK;
}
virtual int finish(uchar *dst, uint *dlen)
{
- if (!EVP_CipherFinal_ex(&ctx, dst, (int*)dlen))
+ if (!EVP_CipherFinal_ex(ctx, dst, (int*)dlen))
return MY_AES_BAD_DATA;
return MY_AES_OK;
}
@@ -73,7 +80,8 @@ class MyCTX_nopad : public MyCTX
{
public:
const uchar *key;
- int klen;
+ uint klen, buf_len;
+ uchar oiv[MY_AES_BLOCK_SIZE];
MyCTX_nopad() : MyCTX() { }
~MyCTX_nopad() { }
@@ -84,32 +92,48 @@ public:
compile_time_assert(MY_AES_CTX_SIZE >= sizeof(MyCTX_nopad));
this->key= key;
this->klen= klen;
+ this->buf_len= 0;
+ memcpy(oiv, iv, ivlen);
+ DBUG_ASSERT(ivlen == 0 || ivlen == sizeof(oiv));
+
int res= MyCTX::init(cipher, encrypt, key, klen, iv, ivlen);
- memcpy(ctx.oiv, iv, ivlen); // in ECB mode OpenSSL doesn't do that itself
- EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
return res;
}
+ int update(const uchar *src, uint slen, uchar *dst, uint *dlen)
+ {
+ buf_len+= slen;
+ return MyCTX::update(src, slen, dst, dlen);
+ }
+
int finish(uchar *dst, uint *dlen)
{
- if (ctx.buf_len)
+ buf_len %= MY_AES_BLOCK_SIZE;
+ if (buf_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;
my_aes_crypt(MY_AES_ECB, ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
- ctx.oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0);
+ oiv, sizeof(mask), mask, &mlen, key, klen, 0, 0);
DBUG_ASSERT(mlen == sizeof(mask));
- for (int i=0; i < ctx.buf_len; i++)
- dst[i]= ctx.buf[i] ^ mask[i];
+ for (uint i=0; i < buf_len; i++)
+ dst[i]= buf[i] ^ mask[i];
}
- *dlen= ctx.buf_len;
+ *dlen= buf_len;
return MY_AES_OK;
}
};
@@ -153,7 +177,7 @@ public:
{
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);
+ int real_ivlen= EVP_CIPHER_CTX_iv_length(ctx);
aad= iv + real_ivlen;
aadlen= ivlen - real_ivlen;
return res;
@@ -167,15 +191,18 @@ public:
before decrypting the data. it can encrypt data piecewise, like, first
half, then the second half, but it must decrypt all at once
*/
- if (!ctx.encrypt)
+ 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,
+ 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))
+ if (aadlen && !EVP_CipherUpdate(ctx, NULL, &unused, aad, aadlen))
return MY_AES_OPENSSL_ERROR;
aadlen= 0;
return MyCTX::update(src, slen, dst, dlen);
@@ -184,13 +211,13 @@ public:
int finish(uchar *dst, uint *dlen)
{
int fin;
- if (!EVP_CipherFinal_ex(&ctx, dst, &fin))
+ if (!EVP_CipherFinal_ex(ctx, dst, &fin))
return MY_AES_BAD_DATA;
DBUG_ASSERT(fin == 0);
- if (ctx.encrypt)
+ if (EVP_CIPHER_CTX_encrypting(ctx))
{
- if(!EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, MY_AES_BLOCK_SIZE, dst))
+ 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;
}
@@ -258,12 +285,15 @@ int my_aes_crypt(enum my_aes_mode mode, int flags,
{
void *ctx= alloca(MY_AES_CTX_SIZE);
int res1, res2;
- uint d1, d2;
+ 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);
- *dlen= d1 + d2;
+ if (res1 || res2)
+ ERR_remove_state(0); /* in case of failure clear error queue */
+ else
+ *dlen= d1 + d2;
return res1 ? res1 : res2;
}
diff --git a/mysys_ssl/my_md5.cc b/mysys_ssl/my_md5.cc
index 7139ea9b6ff..359bcd49ec6 100644
--- a/mysys_ssl/my_md5.cc
+++ b/mysys_ssl/my_md5.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2012, Oracle and/or its affiliates.
- Copyright (c) 2014, SkySQL Ab.
+ 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
@@ -29,38 +29,31 @@
#if defined(HAVE_YASSL)
#include "md5.hpp"
+#include <ssl_compat.h>
-typedef TaoCrypt::MD5 MD5_CONTEXT;
+typedef TaoCrypt::MD5 EVP_MD_CTX;
-static void md5_init(MD5_CONTEXT *context)
+static void md5_init(EVP_MD_CTX *context)
{
- context= new(context) MD5_CONTEXT;
+ context= new(context) EVP_MD_CTX;
context->Init();
}
-/*
- this is a variant of md5_init to be used in this file only.
- does nothing for yassl, because the context's constructor was called automatically.
-*/
-static void md5_init_fast(MD5_CONTEXT *context)
-{
-}
-
-static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len)
+static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len)
{
context->Update((const TaoCrypt::byte *) buf, len);
}
-static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE])
+static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE])
{
context->Final((TaoCrypt::byte *) digest);
}
#elif defined(HAVE_OPENSSL)
#include <openssl/evp.h>
-typedef EVP_MD_CTX MD5_CONTEXT;
+#include <ssl_compat.h>
-static void md5_init(MD5_CONTEXT *context)
+static void md5_init(EVP_MD_CTX *context)
{
EVP_MD_CTX_init(context);
#ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
@@ -70,20 +63,15 @@ static void md5_init(MD5_CONTEXT *context)
EVP_DigestInit_ex(context, EVP_md5(), NULL);
}
-static void md5_init_fast(MD5_CONTEXT *context)
-{
- md5_init(context);
-}
-
-static void md5_input(MD5_CONTEXT *context, const uchar *buf, unsigned len)
+static void md5_input(EVP_MD_CTX *context, const uchar *buf, unsigned len)
{
EVP_DigestUpdate(context, buf, len);
}
-static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE])
+static void md5_result(EVP_MD_CTX *context, uchar digest[MD5_HASH_SIZE])
{
EVP_DigestFinal_ex(context, digest, NULL);
- EVP_MD_CTX_cleanup(context);
+ EVP_MD_CTX_reset(context);
}
#endif /* HAVE_YASSL */
@@ -99,58 +87,58 @@ static void md5_result(MD5_CONTEXT *context, uchar digest[MD5_HASH_SIZE])
*/
void my_md5(uchar *digest, const char *buf, size_t len)
{
- MD5_CONTEXT md5_context;
-
- md5_init_fast(&md5_context);
- md5_input(&md5_context, (const uchar *)buf, len);
- md5_result(&md5_context, digest);
+ 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
- two messages in order to emulate md5(msg1, msg2).
+ many messages, concatenated.
@param digest [out] Computed MD5 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
+ ...
+ @param bufN [in] NULL terminates the list of buf,len pairs.
@return void
*/
void my_md5_multi(uchar *digest, ...)
{
va_list args;
- va_start(args, digest);
-
- MD5_CONTEXT md5_context;
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_fast(&md5_context);
+ md5_init(ctx);
for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
- md5_input(&md5_context, str, va_arg(args, size_t));
+ md5_input(ctx, str, (uint) va_arg(args, size_t));
- md5_result(&md5_context, digest);
+ md5_result(ctx, digest);
va_end(args);
}
size_t my_md5_context_size()
{
- return sizeof(MD5_CONTEXT);
+ return EVP_MD_CTX_SIZE;
}
void my_md5_init(void *context)
{
- md5_init((MD5_CONTEXT *)context);
+ md5_init((EVP_MD_CTX *)context);
}
void my_md5_input(void *context, const uchar *buf, size_t len)
{
- md5_input((MD5_CONTEXT *)context, buf, len);
+ md5_input((EVP_MD_CTX *)context, buf, (uint) len);
}
void my_md5_result(void *context, uchar *digest)
{
- md5_result((MD5_CONTEXT *)context, digest);
+ md5_result((EVP_MD_CTX *)context, digest);
}
diff --git a/mysys_ssl/my_sha.ic b/mysys_ssl/my_sha.ic
index a7ec8bad593..e4433b49a0f 100644
--- a/mysys_ssl/my_sha.ic
+++ b/mysys_ssl/my_sha.ic
@@ -134,7 +134,7 @@ void my_sha(uchar *digest, const char *buf, size_t len)
CONTEXT context;
sha_init_fast(&context);
- sha_input(&context, (const uchar *)buf, len);
+ sha_input(&context, (const uchar *)buf, (unsigned int)len);
sha_result(&context, digest);
}
@@ -161,7 +161,7 @@ void my_sha_multi(uchar *digest, ...)
sha_init_fast(&context);
for (str= va_arg(args, const uchar*); str; str= va_arg(args, const uchar*))
- sha_input(&context, str, va_arg(args, size_t));
+ sha_input(&context, str, (uint) va_arg(args, size_t));
sha_result(&context, digest);
va_end(args);
@@ -179,7 +179,7 @@ void my_sha_init(void *context)
void my_sha_input(void *context, const uchar *buf, size_t len)
{
- sha_input((CONTEXT *)context, buf, len);
+ sha_input((CONTEXT *)context, buf, (uint) len);
}
void my_sha_result(void *context, uchar *digest)
diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c
new file mode 100644
index 00000000000..3f841eec92f
--- /dev/null
+++ b/mysys_ssl/openssl.c
@@ -0,0 +1,72 @@
+/*
+ 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 <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, 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 1;
+
+ 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_create();
+ EVP_MD_CTX_destroy(md5_ctx);
+ if (alloc_count != 1 || !alloc_size || alloc_size > EVP_MD_CTX_SIZE)
+ return 1;
+
+ testing= 0;
+ return 0;
+}
+#endif
diff --git a/mysys_ssl/yassl.cc b/mysys_ssl/yassl.cc
index e9f8e650347..4e9c21ebfd1 100644
--- a/mysys_ssl/yassl.cc
+++ b/mysys_ssl/yassl.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2015 MariaDB Corporation
+ Copyright (c) 2015, 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
@@ -28,9 +28,9 @@
using yaSSL::yaERR_remove_state;
using yaSSL::yaRAND_bytes;
-#define EVP_CIPH_ECB_MODE 0x1
-#define EVP_CIPH_CBC_MODE 0x2
-#define EVP_CIPH_NO_PADDING 0x100
+#define EVP_CIPH_ECB_MODE 0x1U
+#define EVP_CIPH_CBC_MODE 0x2U
+#define EVP_CIPH_NO_PADDING 0x100U
/*
note that TaoCrypt::AES object is not explicitly put into EVP_CIPHER_CTX.
@@ -45,7 +45,6 @@ typedef struct
int buf_len;
int final_used;
uchar tao_buf[sizeof(TaoCrypt::AES)]; // TaoCrypt::AES object
- uchar oiv[TaoCrypt::AES::BLOCK_SIZE]; // original IV
uchar buf[TaoCrypt::AES::BLOCK_SIZE]; // last partial input block
uchar final[TaoCrypt::AES::BLOCK_SIZE]; // last decrypted (output) block
} EVP_CIPHER_CTX;
@@ -98,10 +97,7 @@ static int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
: TaoCrypt::DECRYPTION, cipher->mode);
TAO(ctx)->SetKey(key, cipher->key_len);
if (iv)
- {
TAO(ctx)->SetIV(iv);
- memcpy(ctx->oiv, iv, TaoCrypt::AES::BLOCK_SIZE);
- }
ctx->encrypt= enc;
ctx->key_len= cipher->key_len;
ctx->flags|= cipher->mode == TaoCrypt::CBC ? EVP_CIPH_CBC_MODE : EVP_CIPH_ECB_MODE;