From fb0b540c39c782c9152081c2021f54363e04307c Mon Sep 17 00:00:00 2001
From: tb <>
Date: Sun, 17 Mar 2019 18:07:41 +0000
Subject: Provide EVP_aes_{128,192,256}_wrap(). This is a compatible
 implementation based on the one in OpenSSL 1.0.2r which is still freely
 licensed.

The functions are undocumented in OpenSSL. To use them, one
needs to set the undocumented EVP_CIPHER_CTX_FLAG_WRAP_ALLOW
flag on the EVP_CIPHER_CTX.

resolves #505

ok jsing
---
 src/lib/libcrypto/Symbols.list  |   3 +
 src/lib/libcrypto/evp/c_all.c   |   5 +-
 src/lib/libcrypto/evp/e_aes.c   | 146 +++++++++++++++++++++++++++++++++++++++-
 src/lib/libcrypto/evp/evp.h     |  13 +++-
 src/lib/libcrypto/evp/evp_enc.c |  10 ++-
 src/lib/libcrypto/evp/evp_err.c |   3 +-
 6 files changed, 174 insertions(+), 6 deletions(-)

diff --git a/src/lib/libcrypto/Symbols.list b/src/lib/libcrypto/Symbols.list
index 63e3ee45ac..9fdf723f87 100644
--- a/src/lib/libcrypto/Symbols.list
+++ b/src/lib/libcrypto/Symbols.list
@@ -1515,6 +1515,7 @@ EVP_aes_128_ctr
 EVP_aes_128_ecb
 EVP_aes_128_gcm
 EVP_aes_128_ofb
+EVP_aes_128_wrap
 EVP_aes_128_xts
 EVP_aes_192_cbc
 EVP_aes_192_ccm
@@ -1526,6 +1527,7 @@ EVP_aes_192_ctr
 EVP_aes_192_ecb
 EVP_aes_192_gcm
 EVP_aes_192_ofb
+EVP_aes_192_wrap
 EVP_aes_256_cbc
 EVP_aes_256_cbc_hmac_sha1
 EVP_aes_256_ccm
@@ -1537,6 +1539,7 @@ EVP_aes_256_ctr
 EVP_aes_256_ecb
 EVP_aes_256_gcm
 EVP_aes_256_ofb
+EVP_aes_256_wrap
 EVP_aes_256_xts
 EVP_bf_cbc
 EVP_bf_cfb
diff --git a/src/lib/libcrypto/evp/c_all.c b/src/lib/libcrypto/evp/c_all.c
index cce3640866..9e9d39d5ab 100644
--- a/src/lib/libcrypto/evp/c_all.c
+++ b/src/lib/libcrypto/evp/c_all.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_all.c,v 1.25 2019/03/17 17:42:37 tb Exp $ */
+/* $OpenBSD: c_all.c,v 1.26 2019/03/17 18:07:41 tb Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -159,6 +159,7 @@ OpenSSL_add_all_ciphers_internal(void)
 	EVP_add_cipher(EVP_aes_128_ofb());
 	EVP_add_cipher(EVP_aes_128_ctr());
 	EVP_add_cipher(EVP_aes_128_gcm());
+	EVP_add_cipher(EVP_aes_128_wrap());
 	EVP_add_cipher(EVP_aes_128_xts());
 	EVP_add_cipher_alias(SN_aes_128_cbc, "AES128");
 	EVP_add_cipher_alias(SN_aes_128_cbc, "aes128");
@@ -171,6 +172,7 @@ OpenSSL_add_all_ciphers_internal(void)
 	EVP_add_cipher(EVP_aes_192_ofb());
 	EVP_add_cipher(EVP_aes_192_ctr());
 	EVP_add_cipher(EVP_aes_192_gcm());
+	EVP_add_cipher(EVP_aes_192_wrap());
 	EVP_add_cipher_alias(SN_aes_192_cbc, "AES192");
 	EVP_add_cipher_alias(SN_aes_192_cbc, "aes192");
 	EVP_add_cipher(EVP_aes_256_ecb());
@@ -182,6 +184,7 @@ OpenSSL_add_all_ciphers_internal(void)
 	EVP_add_cipher(EVP_aes_256_ofb());
 	EVP_add_cipher(EVP_aes_256_ctr());
 	EVP_add_cipher(EVP_aes_256_gcm());
+	EVP_add_cipher(EVP_aes_256_wrap());
 	EVP_add_cipher(EVP_aes_256_xts());
 	EVP_add_cipher_alias(SN_aes_256_cbc, "AES256");
 	EVP_add_cipher_alias(SN_aes_256_cbc, "aes256");
diff --git a/src/lib/libcrypto/evp/e_aes.c b/src/lib/libcrypto/evp/e_aes.c
index 7c713db026..6b455dc503 100644
--- a/src/lib/libcrypto/evp/e_aes.c
+++ b/src/lib/libcrypto/evp/e_aes.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: e_aes.c,v 1.34 2017/05/02 03:59:44 deraadt Exp $ */
+/* $OpenBSD: e_aes.c,v 1.35 2019/03/17 18:07:41 tb Exp $ */
 /* ====================================================================
  * Copyright (c) 2001-2011 The OpenSSL Project.  All rights reserved.
  *
@@ -49,6 +49,7 @@
  *
  */
 
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -1549,4 +1550,147 @@ EVP_aead_aes_256_gcm(void)
 	return &aead_aes_256_gcm;
 }
 
+typedef struct {
+	union {
+		double align;
+		AES_KEY ks;
+	} ks;
+	unsigned char *iv;
+} EVP_AES_WRAP_CTX;
+
+static int
+aes_wrap_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+    const unsigned char *iv, int enc)
+{
+	EVP_AES_WRAP_CTX *wctx = (EVP_AES_WRAP_CTX *)ctx->cipher_data;
+
+	if (iv == NULL && key == NULL)
+		return 1;
+
+	if (key != NULL) {
+		if (ctx->encrypt)
+			AES_set_encrypt_key(key, 8 * ctx->key_len,
+			    &wctx->ks.ks);
+		else
+			AES_set_decrypt_key(key, 8 * ctx->key_len,
+			    &wctx->ks.ks);
+
+		if (iv == NULL)
+			wctx->iv = NULL;
+	}
+
+	if (iv != NULL) {
+		memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx));
+		wctx->iv = ctx->iv;
+	}
+
+	return 1;
+}
+
+static int
+aes_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+    const unsigned char *in, size_t inlen)
+{
+	EVP_AES_WRAP_CTX *wctx = ctx->cipher_data;
+	int ret;
+
+	if (in == NULL)
+		return 0;
+
+	if (inlen % 8 != 0)
+		return -1;
+	if (ctx->encrypt && inlen < 8)
+		return -1;
+	if (!ctx->encrypt && inlen < 16)
+		return -1;
+	if (inlen > INT_MAX)
+		return -1;
+
+	if (out == NULL) {
+		if (ctx->encrypt)
+			return inlen + 8;
+		else
+			return inlen - 8;
+	}
+
+	if (ctx->encrypt)
+		ret = AES_wrap_key(&wctx->ks.ks, wctx->iv, out, in,
+		    (unsigned int)inlen);
+	else
+		ret = AES_unwrap_key(&wctx->ks.ks, wctx->iv, out, in,
+		    (unsigned int)inlen);
+
+	return ret != 0 ? ret : -1;
+}
+
+#define WRAP_FLAGS \
+    ( EVP_CIPH_WRAP_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | \
+      EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_FLAG_DEFAULT_ASN1 )
+
+static const EVP_CIPHER aes_128_wrap = {
+	.nid = NID_id_aes128_wrap,
+	.block_size = 8,
+	.key_len = 16,
+	.iv_len = 8,
+	.flags = WRAP_FLAGS,
+	.init = aes_wrap_init_key,
+	.do_cipher = aes_wrap_cipher,
+	.cleanup = NULL,
+	.ctx_size = sizeof(EVP_AES_WRAP_CTX),
+	.set_asn1_parameters = NULL,
+	.get_asn1_parameters = NULL,
+	.ctrl = NULL,
+	.app_data = NULL,
+};
+
+const EVP_CIPHER *
+EVP_aes_128_wrap(void)
+{
+	return &aes_128_wrap;
+}
+
+static const EVP_CIPHER aes_192_wrap = {
+	.nid = NID_id_aes192_wrap,
+	.block_size = 8,
+	.key_len = 24,
+	.iv_len = 8,
+	.flags = WRAP_FLAGS,
+	.init = aes_wrap_init_key,
+	.do_cipher = aes_wrap_cipher,
+	.cleanup = NULL,
+	.ctx_size = sizeof(EVP_AES_WRAP_CTX),
+	.set_asn1_parameters = NULL,
+	.get_asn1_parameters = NULL,
+	.ctrl = NULL,
+	.app_data = NULL,
+};
+
+const EVP_CIPHER *
+EVP_aes_192_wrap(void)
+{
+	return &aes_192_wrap;
+}
+
+static const EVP_CIPHER aes_256_wrap = {
+	.nid = NID_id_aes256_wrap,
+	.block_size = 8,
+	.key_len = 32,
+	.iv_len = 8,
+	.flags = WRAP_FLAGS,
+	.init = aes_wrap_init_key,
+	.do_cipher = aes_wrap_cipher,
+	.cleanup = NULL,
+	.ctx_size = sizeof(EVP_AES_WRAP_CTX),
+	.set_asn1_parameters = NULL,
+	.get_asn1_parameters = NULL,
+	.ctrl = NULL,
+	.app_data = NULL,
+};
+
+const EVP_CIPHER *
+EVP_aes_256_wrap(void)
+{
+	return &aes_256_wrap;
+}
+
 #endif
diff --git a/src/lib/libcrypto/evp/evp.h b/src/lib/libcrypto/evp/evp.h
index cd9b33c9b8..22876f9fe9 100644
--- a/src/lib/libcrypto/evp/evp.h
+++ b/src/lib/libcrypto/evp/evp.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: evp.h,v 1.73 2019/03/17 17:42:37 tb Exp $ */
+/* $OpenBSD: evp.h,v 1.74 2019/03/17 18:07:41 tb Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -325,6 +325,7 @@ struct evp_cipher_st {
 #define		EVP_CIPH_GCM_MODE		0x6
 #define		EVP_CIPH_CCM_MODE		0x7
 #define		EVP_CIPH_XTS_MODE		0x10001
+#define		EVP_CIPH_WRAP_MODE		0x10002
 #define 	EVP_CIPH_MODE			0xF0007
 /* Set if variable length cipher */
 #define 	EVP_CIPH_VARIABLE_LENGTH	0x8
@@ -356,6 +357,12 @@ struct evp_cipher_st {
 #define 	EVP_CIPH_FLAG_CUSTOM_CIPHER	0x100000
 #define		EVP_CIPH_FLAG_AEAD_CIPHER	0x200000
 
+/*
+ * Cipher context flag to indicate that we can handle wrap mode: if allowed in
+ * older applications, it could overflow buffers.
+ */
+#define		EVP_CIPHER_CTX_FLAG_WRAP_ALLOW	0x1
+
 /* ctrl() values */
 
 #define		EVP_CTRL_INIT			0x0
@@ -776,6 +783,7 @@ const EVP_CIPHER *EVP_aes_128_ofb(void);
 const EVP_CIPHER *EVP_aes_128_ctr(void);
 const EVP_CIPHER *EVP_aes_128_ccm(void);
 const EVP_CIPHER *EVP_aes_128_gcm(void);
+const EVP_CIPHER *EVP_aes_128_wrap(void);
 const EVP_CIPHER *EVP_aes_128_xts(void);
 const EVP_CIPHER *EVP_aes_192_ecb(void);
 const EVP_CIPHER *EVP_aes_192_cbc(void);
@@ -787,6 +795,7 @@ const EVP_CIPHER *EVP_aes_192_ofb(void);
 const EVP_CIPHER *EVP_aes_192_ctr(void);
 const EVP_CIPHER *EVP_aes_192_ccm(void);
 const EVP_CIPHER *EVP_aes_192_gcm(void);
+const EVP_CIPHER *EVP_aes_192_wrap(void);
 const EVP_CIPHER *EVP_aes_256_ecb(void);
 const EVP_CIPHER *EVP_aes_256_cbc(void);
 const EVP_CIPHER *EVP_aes_256_cfb1(void);
@@ -797,6 +806,7 @@ const EVP_CIPHER *EVP_aes_256_ofb(void);
 const EVP_CIPHER *EVP_aes_256_ctr(void);
 const EVP_CIPHER *EVP_aes_256_ccm(void);
 const EVP_CIPHER *EVP_aes_256_gcm(void);
+const EVP_CIPHER *EVP_aes_256_wrap(void);
 const EVP_CIPHER *EVP_aes_256_xts(void);
 #if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1)
 const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void);
@@ -1523,6 +1533,7 @@ void ERR_load_EVP_strings(void);
 #define EVP_R_UNSUPPORTED_KEY_SIZE			 108
 #define EVP_R_UNSUPPORTED_PRF				 125
 #define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM		 118
+#define EVP_R_WRAP_MODE_NOT_ALLOWED			 170
 #define EVP_R_UNSUPPORTED_SALT_TYPE			 126
 #define EVP_R_WRONG_FINAL_BLOCK_LENGTH			 109
 #define EVP_R_WRONG_PUBLIC_KEY_TYPE			 110
diff --git a/src/lib/libcrypto/evp/evp_enc.c b/src/lib/libcrypto/evp/evp_enc.c
index db2deb6905..a229901956 100644
--- a/src/lib/libcrypto/evp/evp_enc.c
+++ b/src/lib/libcrypto/evp/evp_enc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: evp_enc.c,v 1.39 2018/04/14 07:09:21 tb Exp $ */
+/* $OpenBSD: evp_enc.c,v 1.40 2019/03/17 18:07:41 tb Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -153,7 +153,7 @@ EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl,
 			ctx->cipher_data = NULL;
 		}
 		ctx->key_len = cipher->key_len;
-		ctx->flags = 0;
+		ctx->flags &= EVP_CIPHER_CTX_FLAG_WRAP_ALLOW;
 		if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) {
 			if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) {
 				EVPerror(EVP_R_INITIALIZATION_ERROR);
@@ -175,6 +175,12 @@ skip_to_init:
 		return 0;
 	}
 
+	if (!(ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) &&
+	    EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) {
+		EVPerror(EVP_R_WRAP_MODE_NOT_ALLOWED);
+		return 0;
+	}
+
 	if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) {
 		switch (EVP_CIPHER_CTX_mode(ctx)) {
 
diff --git a/src/lib/libcrypto/evp/evp_err.c b/src/lib/libcrypto/evp/evp_err.c
index 1e1cc8350b..814637c739 100644
--- a/src/lib/libcrypto/evp/evp_err.c
+++ b/src/lib/libcrypto/evp/evp_err.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: evp_err.c,v 1.22 2017/01/29 17:49:23 beck Exp $ */
+/* $OpenBSD: evp_err.c,v 1.23 2019/03/17 18:07:41 tb Exp $ */
 /* ====================================================================
  * Copyright (c) 1999-2011 The OpenSSL Project.  All rights reserved.
  *
@@ -147,6 +147,7 @@ static ERR_STRING_DATA EVP_str_reasons[] = {
 	{ERR_REASON(EVP_R_UNSUPPORTED_PRF)       , "unsupported prf"},
 	{ERR_REASON(EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM), "unsupported private key algorithm"},
 	{ERR_REASON(EVP_R_UNSUPPORTED_SALT_TYPE) , "unsupported salt type"},
+	{ERR_REASON(EVP_R_WRAP_MODE_NOT_ALLOWED), "wrap mode not allowed"},
 	{ERR_REASON(EVP_R_WRONG_FINAL_BLOCK_LENGTH), "wrong final block length"},
 	{ERR_REASON(EVP_R_WRONG_PUBLIC_KEY_TYPE) , "wrong public key type"},
 	{0, NULL}
-- 
cgit v1.2.3-55-g6feb