From 395270ce1d547ba857f704533890c7e915c52cb7 Mon Sep 17 00:00:00 2001
From: Alok Menghrajani <alok@squareup.com>
Date: Mon, 8 Sep 2014 14:40:43 -0700
Subject: [PATCH] Ensures that EVP encryption & decryption operations check the
 encrypt flag on the context.

This change ensures that a user cannot accidentally decrypt data with an encryption context
or vice-versa. Without the check, if an encryption context is used to decrypt
EVP_aes_256_gcm encrypted data, the code will fail to validate the TAG.

Example code availabe at: http://quaxio.com/wtf/openssl_wtf.html
---
 crypto/evp/evp_enc.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index f705967..d690ca1 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -295,7 +295,7 @@ int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *im
 	return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0);
 	}
 
-int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
+int EVP_EncryptOrDecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
 	     const unsigned char *in, int inl)
 	{
 	int i,j,bl;
@@ -368,6 +368,17 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
 	return 1;
 	}
 
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
+	     const unsigned char *in, int inl)
+	{
+
+	if (!ctx->encrypt) {
+		// Disallow using a decryption context for encryption
+		return 0;
+	}
+	return EVP_EncryptOrDecryptUpdate(ctx, out, outl, in, inl);
+	}
+
 int EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
 	{
 	int ret;
@@ -380,6 +391,11 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
 	int n,ret;
 	unsigned int i, b, bl;
 
+	if (!ctx->encrypt) {
+		// Disallow using a decryption context for encryption
+		return 0;
+	}
+
 	if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER)
 		{
 		ret = ctx->cipher->do_cipher(ctx, out, NULL, 0);
@@ -427,6 +443,11 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
 	int fix_len;
 	unsigned int b;
 
+	if (ctx->encrypt) {
+		// Disallow using an encryption context for decryption
+		return 0;
+	}
+
 	if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER)
 		{
 		fix_len = ctx->cipher->do_cipher(ctx, out, in, inl);
@@ -447,7 +468,7 @@ 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);
+		return EVP_EncryptOrDecryptUpdate(ctx, out, outl, in, inl);
 
 	b=ctx->cipher->block_size;
 	OPENSSL_assert(b <= sizeof ctx->final);
@@ -462,7 +483,7 @@ int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
 		fix_len = 0;
 
 
-	if(!EVP_EncryptUpdate(ctx,out,outl,in,inl))
+	if(!EVP_EncryptOrDecryptUpdate(ctx,out,outl,in,inl))
 		return 0;
 
 	/* if we have 'decrypted' a multiple of block size, make sure
@@ -495,6 +516,11 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
 	unsigned int b;
 	*outl=0;
 
+	if (ctx->encrypt) {
+		// Disallow using an encryption context for decryption
+		return 0;
+	}
+
 	if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER)
 		{
 		i = ctx->cipher->do_cipher(ctx, out, NULL, 0);
-- 
2.0.4

