Commit 3258e29a authored by Matt Caswell's avatar Matt Caswell
Browse files

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: default avatarRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2275)
(cherry picked from commit 7141ba31)
parent fd18736a
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
            }
        }

        /*
+7 −0
Original line number Diff line number Diff line
@@ -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
+9 −11
Original line number Diff line number Diff line
@@ -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) {
+3 −0
Original line number Diff line number Diff line
@@ -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"},
+2 −0
Original line number Diff line number Diff line
@@ -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);
Loading