From 6e4ff62df789b55b80c14b2e7b15c25154fbf9fe Mon Sep 17 00:00:00 2001
From: Bob Copeland <copeland@lastpass.com>
Date: Mon, 5 Dec 2016 09:55:19 -0500
Subject: [PATCH 1/3] cipher: support opaque EVP_CIPHER_CTX

In OpenSSL 1.1+, EVP_CIPHER_CTX can no longer be declared on
the stack; instead you have to declare a pointer and then
use _new()/_free() to allocate or free it.  These functions
continue to work on older OpenSSL, so switch to the new
method.

Signed-off-by: Bob Copeland <copeland@lastpass.com>
---
 cipher.c | 36 +++++++++++++++++++++---------------
 config.c | 33 +++++++++++++++++++--------------
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/cipher.c b/cipher.c
index 71487787af5a..ebae92e0431c 100644
--- a/cipher.c
+++ b/cipher.c
@@ -147,36 +147,39 @@ int cipher_rsa_encrypt(const char *plaintext,
 
 char *cipher_aes_decrypt(const unsigned char *ciphertext, size_t len, const unsigned char key[KDF_HASH_LEN])
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	char *plaintext;
 	int out_len;
 
 	if (!len)
 		return NULL;
 
-	EVP_CIPHER_CTX_init(&ctx);
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
+		return NULL;
+
 	plaintext = xcalloc(len + AES_BLOCK_SIZE + 1, 1);
 	if (len >= 33 && len % 16 == 1 && ciphertext[0] == '!') {
-		if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, (unsigned char *)(ciphertext + 1)))
+		if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, (unsigned char *)(ciphertext + 1)))
 			goto error;
 		ciphertext += 17;
 		len -= 17;
 	} else {
-		if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_ecb(), NULL, key, NULL))
+		if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL))
 			goto error;
 	}
-	if (!EVP_DecryptUpdate(&ctx, (unsigned char *)plaintext, &out_len, (unsigned char *)ciphertext, len))
+	if (!EVP_DecryptUpdate(ctx, (unsigned char *)plaintext, &out_len, (unsigned char *)ciphertext, len))
 		goto error;
 	len = out_len;
-	if (!EVP_DecryptFinal_ex(&ctx, (unsigned char *)(plaintext + out_len), &out_len))
+	if (!EVP_DecryptFinal_ex(ctx, (unsigned char *)(plaintext + out_len), &out_len))
 		goto error;
 	len += out_len;
 	plaintext[len] = '\0';
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	return plaintext;
 
 error:
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	secure_clear(plaintext, len + AES_BLOCK_SIZE + 1);
 	free(plaintext);
 	return NULL;
@@ -188,7 +191,7 @@ size_t cipher_aes_encrypt_bytes(const unsigned char *bytes, size_t len,
 				const unsigned char *iv,
 				unsigned char **out)
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	int out_len;
 	size_t ret_len = 0;
 	unsigned char *ctext;
@@ -197,24 +200,27 @@ size_t cipher_aes_encrypt_bytes(const unsigned char *bytes, size_t len,
 	if (!ctext)
 		ctext = xcalloc(len + AES_BLOCK_SIZE * 2 + 1, 1);
 
-	EVP_CIPHER_CTX_init(&ctx);
-	if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv))
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
 		goto error;
 
-	if (!EVP_EncryptUpdate(&ctx, ctext, &out_len, bytes, len))
+	if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
+		goto error;
+
+	if (!EVP_EncryptUpdate(ctx, ctext, &out_len, bytes, len))
 		goto error;
 
 	ret_len += out_len;
-	if (!EVP_EncryptFinal_ex(&ctx, ctext + ret_len, &out_len))
+	if (!EVP_EncryptFinal_ex(ctx, ctext + ret_len, &out_len))
 		goto error;
 	ret_len += out_len;
 
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	*out = ctext;
 	return ret_len;
 
 error:
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	if (!*out)
 		free(ctext);
 	die("Failed to encrypt data.");
diff --git a/config.c b/config.c
index bd68cfe8b21b..976202c5d6ad 100644
--- a/config.c
+++ b/config.c
@@ -319,7 +319,7 @@ size_t config_read_buffer(const char *name, unsigned char **out)
 
 static size_t encrypt_buffer(const char *buffer, size_t in_len, unsigned const char key[KDF_HASH_LEN], char **out)
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	char *ciphertext;
 	unsigned char iv[AES_BLOCK_SIZE];
 	int out_len;
@@ -329,31 +329,34 @@ static size_t encrypt_buffer(const char *buffer, size_t in_len, unsigned const c
 	if (!RAND_bytes(iv, AES_BLOCK_SIZE))
 		die("Could not generate random bytes for CBC IV.");
 
-	EVP_CIPHER_CTX_init(&ctx);
 	ciphertext = xcalloc(in_len + AES_BLOCK_SIZE * 2 + SHA256_DIGEST_LENGTH, 1);
 
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
+		goto error;
+
 	len = SHA256_DIGEST_LENGTH;
 	memcpy(ciphertext + len, iv, AES_BLOCK_SIZE);
 	len += AES_BLOCK_SIZE;
 
-	if (!EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv))
+	if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
 		goto error;
-	if (!EVP_EncryptUpdate(&ctx, (unsigned char *)(ciphertext + len), &out_len, (unsigned char *)buffer, in_len))
+	if (!EVP_EncryptUpdate(ctx, (unsigned char *)(ciphertext + len), &out_len, (unsigned char *)buffer, in_len))
 		goto error;
 	len += out_len;
-	if (!EVP_EncryptFinal_ex(&ctx, (unsigned char *)(ciphertext + len), &out_len))
+	if (!EVP_EncryptFinal_ex(ctx, (unsigned char *)(ciphertext + len), &out_len))
 		goto error;
 	len += out_len;
-	EVP_CIPHER_CTX_cleanup(&ctx);
 
 	if (!HMAC(EVP_sha256(), key, KDF_HASH_LEN, (unsigned char *)(ciphertext + SHA256_DIGEST_LENGTH), len - SHA256_DIGEST_LENGTH, (unsigned char *)ciphertext, &hmac_len))
 		goto error;
 
+	EVP_CIPHER_CTX_free(ctx);
 	*out = ciphertext;
 	return len;
 
 error:
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	free(ciphertext);
 	die("Failed to encrypt data.");
 
@@ -361,14 +364,16 @@ static size_t encrypt_buffer(const char *buffer, size_t in_len, unsigned const c
 
 static size_t decrypt_buffer(const unsigned char *buffer, size_t in_len, unsigned const char key[KDF_HASH_LEN], unsigned char **out)
 {
-	EVP_CIPHER_CTX ctx;
+	EVP_CIPHER_CTX *ctx;
 	unsigned char *plaintext = NULL;
 	int out_len;
 	unsigned int hmac_len;
 	size_t len;
 	unsigned char hmac[SHA256_DIGEST_LENGTH];
 
-	EVP_CIPHER_CTX_init(&ctx);
+	ctx = EVP_CIPHER_CTX_new();
+	if (!ctx)
+		goto error;
 
 	if (in_len < (SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE * 2))
 		goto error;
@@ -379,20 +384,20 @@ static size_t decrypt_buffer(const unsigned char *buffer, size_t in_len, unsigne
 		goto error;
 
 	plaintext = xcalloc(in_len + AES_BLOCK_SIZE, 1);
-	if (!EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, (unsigned char *)(buffer + SHA256_DIGEST_LENGTH)))
+	if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, (unsigned char *)(buffer + SHA256_DIGEST_LENGTH)))
 		goto error;
-	if (!EVP_DecryptUpdate(&ctx, (unsigned char *)plaintext, &out_len, (unsigned char *)(buffer + SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE), in_len - SHA256_DIGEST_LENGTH - AES_BLOCK_SIZE))
+	if (!EVP_DecryptUpdate(ctx, (unsigned char *)plaintext, &out_len, (unsigned char *)(buffer + SHA256_DIGEST_LENGTH + AES_BLOCK_SIZE), in_len - SHA256_DIGEST_LENGTH - AES_BLOCK_SIZE))
 		goto error;
 	len = out_len;
-	if (!EVP_DecryptFinal_ex(&ctx, (unsigned char *)(plaintext + out_len), &out_len))
+	if (!EVP_DecryptFinal_ex(ctx, (unsigned char *)(plaintext + out_len), &out_len))
 		goto error;
 	len += out_len;
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	*out = plaintext;
 	return len;
 
 error:
-	EVP_CIPHER_CTX_cleanup(&ctx);
+	EVP_CIPHER_CTX_free(ctx);
 	free(plaintext);
 	*out = NULL;
 	return 0;
-- 
2.11.0

