diff options
author | Andy Polyakov <appro@openssl.org> | 2016-06-17 13:55:01 +0200 |
---|---|---|
committer | Andy Polyakov <appro@openssl.org> | 2016-06-27 10:08:01 +0200 |
commit | c3a73daf0acc1272905db954b92a23146aad82f0 (patch) | |
tree | 8f026610033563c6185e2f1644234f591ca67c45 /crypto/evp/evp_enc.c | |
parent | dca5eeb4d06262b5e48f21af5e5d4dd672a8c5af (diff) |
evp/evp_enc.c: check for partially[!] overlapping buffers
in EVP_EncryptUpdate and EVP_DecryptUpdate. It is argued that in
general case it's impossible to provide guarantee that partially[!]
overlapping buffers can be tolerated.
Reviewed-by: Matt Caswell <matt@openssl.org>
Diffstat (limited to 'crypto/evp/evp_enc.c')
-rw-r--r-- | crypto/evp/evp_enc.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index acb6b8bead..92319e5ab7 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -8,6 +8,7 @@ */ #include <stdio.h> +#include <assert.h> #include "internal/cryptlib.h" #include <openssl/evp.h> #include <openssl/err.h> @@ -252,11 +253,48 @@ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0); } +/* + * According to the letter of standard difference between pointers + * is specified to be valid only within same object. This makes + * it formally challenging to determine if input and output buffers + * are not partially overlapping with standard pointer arithmetic. + */ +#ifdef PTRDIFF_T +# undef PTRDIFF_T +#endif +#if defined(OPENSSL_SYS_VMS) && __INITIAL_POINTER_SIZE==64 +/* + * Then we have VMS that distinguishes itself by adhering to + * sizeof(size_t)==4 even in 64-bit builds... + */ +# define PTRDIFF_T uint64_t +#else +# define PTRDIFF_T size_t +#endif + +static int is_partially_overlapping(const void *ptr1, const void *ptr2, + int len) +{ + PTRDIFF_T diff = (PTRDIFF_T)ptr1-(PTRDIFF_T)ptr2; + /* + * Check for partially overlapping buffers. [Binary logical + * operations are used instead of boolean to minimize number + * of conditional branches.] + */ + int condition = (len > 0) & (diff != 0) & ((diff < (PTRDIFF_T)len) | + (diff > (0 - (PTRDIFF_T)len))); + assert(!condition); + return condition; +} + int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) { int i, j, bl; + if (is_partially_overlapping(out, in, inl)) + return 0; + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { i = ctx->cipher->do_cipher(ctx, out, in, inl); if (i < 0) @@ -370,6 +408,9 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, int fix_len; unsigned int b; + if (is_partially_overlapping(out, in, inl)) + return 0; + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { fix_len = ctx->cipher->do_cipher(ctx, out, in, inl); if (fix_len < 0) { |