From 7141ba31969d0b378d08104a51f8f99b9187b9d5 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Tue, 24 Jan 2017 12:57:34 +0000 Subject: [PATCH] Fix the overlapping check for fragmented "Update" operations When doing in place encryption the overlapping buffer check can fail incorrectly where we have done a partial block "Update" operation. This fixes things to take account of any pending partial blocks. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2275) --- crypto/evp/e_aes.c | 10 ++++++++++ crypto/evp/e_des3.c | 7 +++++++ crypto/evp/evp_enc.c | 20 +++++++++----------- crypto/evp/evp_err.c | 3 +++ crypto/evp/evp_locl.h | 2 ++ include/openssl/evp.h | 3 +++ test/evp_test.c | 3 --- 7 files changed, 34 insertions(+), 14 deletions(-) diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index d3be6a086a..c0b0a1ebaf 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -17,6 +17,7 @@ #include "internal/evp_int.h" #include "modes_lcl.h" #include +#include "evp_locl.h" typedef struct { union { @@ -2233,6 +2234,10 @@ static int aes_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, /* If not padding input must be multiple of 8 */ if (!pad && inlen & 0x7) return -1; + if (is_partially_overlapping(out, in, inlen)) { + EVPerr(EVP_F_AES_WRAP_CIPHER, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } if (!out) { if (EVP_CIPHER_CTX_encrypting(ctx)) { /* If padding round up to multiple of 8 */ @@ -2551,6 +2556,11 @@ static int aes_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } else { buf = octx->data_buf; buf_len = &(octx->data_buf_len); + + if (is_partially_overlapping(out + *buf_len, in, len)) { + EVPerr(EVP_F_AES_OCB_CIPHER, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } } /* diff --git a/crypto/evp/e_des3.c b/crypto/evp/e_des3.c index a842913658..da77936c96 100644 --- a/crypto/evp/e_des3.c +++ b/crypto/evp/e_des3.c @@ -15,6 +15,7 @@ # include "internal/evp_int.h" # include # include +# include "evp_locl.h" typedef struct { union { @@ -392,6 +393,12 @@ static int des_ede3_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, */ if (inl >= EVP_MAXCHUNK || inl % 8) return -1; + + if (is_partially_overlapping(out, in, inl)) { + EVPerr(EVP_F_DES_EDE3_WRAP_CIPHER, EVP_R_PARTIALLY_OVERLAPPING); + return 0; + } + if (EVP_CIPHER_CTX_encrypting(ctx)) return des_ede3_wrap(ctx, out, in, inl); else diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index bedc964361..ef66cb1de5 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -276,8 +276,7 @@ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, # define PTRDIFF_T size_t #endif -static int is_partially_overlapping(const void *ptr1, const void *ptr2, - int len) +int is_partially_overlapping(const void *ptr1, const void *ptr2, int len) { PTRDIFF_T diff = (PTRDIFF_T)ptr1-(PTRDIFF_T)ptr2; /* @@ -296,8 +295,11 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, { int i, j, bl; + bl = ctx->cipher->block_size; + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { - if (is_partially_overlapping(out, in, inl)) { + /* If block size > 1 then the cipher will have to do this check */ + if (bl == 1 && is_partially_overlapping(out, in, inl)) { EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); return 0; } @@ -314,7 +316,7 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, *outl = 0; return inl == 0; } - if (is_partially_overlapping(out, in, inl)) { + if (is_partially_overlapping(out + ctx->buf_len, in, inl)) { EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); return 0; } @@ -329,7 +331,6 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, } } i = ctx->buf_len; - bl = ctx->cipher->block_size; OPENSSL_assert(bl <= (int)sizeof(ctx->buf)); if (i != 0) { if (bl - i > inl) { @@ -342,10 +343,6 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, memcpy(&(ctx->buf[i]), in, j); inl -= j; in += j; - if (is_partially_overlapping(out, in, bl)) { - EVPerr(EVP_F_EVP_ENCRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); - return 0; - } if (!ctx->cipher->do_cipher(ctx, out, ctx->buf, bl)) return 0; out += bl; @@ -422,8 +419,10 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, int fix_len; unsigned int b; + b = ctx->cipher->block_size; + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { - if (is_partially_overlapping(out, in, inl)) { + if (b == 1 && is_partially_overlapping(out, in, inl)) { EVPerr(EVP_F_EVP_DECRYPTUPDATE, EVP_R_PARTIALLY_OVERLAPPING); return 0; } @@ -445,7 +444,6 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, if (ctx->flags & EVP_CIPH_NO_PADDING) return EVP_EncryptUpdate(ctx, out, outl, in, inl); - b = ctx->cipher->block_size; OPENSSL_assert(b <= sizeof ctx->final); if (ctx->final_used) { diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 2527df60dd..bf09052809 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -21,11 +21,14 @@ static ERR_STRING_DATA EVP_str_functs[] = { {ERR_FUNC(EVP_F_AESNI_INIT_KEY), "aesni_init_key"}, {ERR_FUNC(EVP_F_AES_INIT_KEY), "aes_init_key"}, + {ERR_FUNC(EVP_F_AES_OCB_CIPHER), "aes_ocb_cipher"}, {ERR_FUNC(EVP_F_AES_T4_INIT_KEY), "aes_t4_init_key"}, + {ERR_FUNC(EVP_F_AES_WRAP_CIPHER), "aes_wrap_cipher"}, {ERR_FUNC(EVP_F_ALG_MODULE_INIT), "alg_module_init"}, {ERR_FUNC(EVP_F_CAMELLIA_INIT_KEY), "camellia_init_key"}, {ERR_FUNC(EVP_F_CHACHA20_POLY1305_CTRL), "chacha20_poly1305_ctrl"}, {ERR_FUNC(EVP_F_CMLL_T4_INIT_KEY), "cmll_t4_init_key"}, + {ERR_FUNC(EVP_F_DES_EDE3_WRAP_CIPHER), "des_ede3_wrap_cipher"}, {ERR_FUNC(EVP_F_DO_SIGVER_INIT), "do_sigver_init"}, {ERR_FUNC(EVP_F_EVP_CIPHERINIT_EX), "EVP_CipherInit_ex"}, {ERR_FUNC(EVP_F_EVP_CIPHER_CTX_COPY), "EVP_CIPHER_CTX_copy"}, diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index 7f3526f1ba..209577b7c2 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -64,3 +64,5 @@ struct evp_Encode_Ctx_st { typedef struct evp_pbe_st EVP_PBE_CTL; DEFINE_STACK_OF(EVP_PBE_CTL) + +int is_partially_overlapping(const void *ptr1, const void *ptr2, int len); diff --git a/include/openssl/evp.h b/include/openssl/evp.h index fda0713ce4..8252e25780 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -1467,11 +1467,14 @@ int ERR_load_EVP_strings(void); /* Function codes. */ # define EVP_F_AESNI_INIT_KEY 165 # define EVP_F_AES_INIT_KEY 133 +# define EVP_F_AES_OCB_CIPHER 169 # define EVP_F_AES_T4_INIT_KEY 178 +# define EVP_F_AES_WRAP_CIPHER 170 # define EVP_F_ALG_MODULE_INIT 177 # define EVP_F_CAMELLIA_INIT_KEY 159 # define EVP_F_CHACHA20_POLY1305_CTRL 182 # define EVP_F_CMLL_T4_INIT_KEY 179 +# define EVP_F_DES_EDE3_WRAP_CIPHER 171 # define EVP_F_DO_SIGVER_INIT 161 # define EVP_F_EVP_CIPHERINIT_EX 123 # define EVP_F_EVP_CIPHER_CTX_COPY 163 diff --git a/test/evp_test.c b/test/evp_test.c index cc0a5bd420..f0e8ca35c0 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -1101,9 +1101,6 @@ static int cipher_test_run(struct evp_test *t) static char aux_err[64]; t->aux_err = aux_err; for (inp_misalign = (size_t)-1; inp_misalign != 2; inp_misalign++) { - if (frag && inp_misalign == (size_t)-1) - continue; - if (inp_misalign == (size_t)-1) { /* kludge: inp_misalign == -1 means "exercise in-place" */ BIO_snprintf(aux_err, sizeof(aux_err), -- 2.25.1