diff options
Diffstat (limited to 'mysys_ssl')
-rw-r--r-- | mysys_ssl/CMakeLists.txt | 1 | ||||
-rw-r--r-- | mysys_ssl/my_crypt.cc | 94 | ||||
-rw-r--r-- | mysys_ssl/my_md5.cc | 72 | ||||
-rw-r--r-- | mysys_ssl/my_sha.ic | 6 | ||||
-rw-r--r-- | mysys_ssl/openssl.c | 72 | ||||
-rw-r--r-- | mysys_ssl/yassl.cc | 12 |
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; |