summaryrefslogtreecommitdiffstats
path: root/crypto/evp/evp_enc.c
diff options
context:
space:
mode:
authorAndy Polyakov <appro@openssl.org>2016-06-17 13:55:01 +0200
committerAndy Polyakov <appro@openssl.org>2016-06-27 10:08:01 +0200
commitc3a73daf0acc1272905db954b92a23146aad82f0 (patch)
tree8f026610033563c6185e2f1644234f591ca67c45 /crypto/evp/evp_enc.c
parentdca5eeb4d06262b5e48f21af5e5d4dd672a8c5af (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.c41
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) {