Fix the overlapping check for fragmented "Update" operations
authorMatt Caswell <matt@openssl.org>
Tue, 24 Jan 2017 12:57:34 +0000 (12:57 +0000)
committerMatt Caswell <matt@openssl.org>
Wed, 25 Jan 2017 15:02:44 +0000 (15:02 +0000)
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 <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2275)

crypto/evp/e_aes.c
crypto/evp/e_des3.c
crypto/evp/evp_enc.c
crypto/evp/evp_err.c
crypto/evp/evp_locl.h
include/openssl/evp.h
test/evp_test.c

index d3be6a0..c0b0a1e 100644 (file)
@@ -17,6 +17,7 @@
 #include "internal/evp_int.h"
 #include "modes_lcl.h"
 #include <openssl/rand.h>
+#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;
+            }
         }
 
         /*
index a842913..da77936 100644 (file)
@@ -15,6 +15,7 @@
 # include "internal/evp_int.h"
 # include <openssl/des.h>
 # include <openssl/rand.h>
+# 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
index bedc964..ef66cb1 100644 (file)
@@ -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) {
index 2527df6..bf09052 100644 (file)
 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"},
index 7f3526f..209577b 100644 (file)
@@ -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);
index fda0713..8252e25 100644 (file)
@@ -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
index cc0a5bd..f0e8ca3 100644 (file)
@@ -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),