File 0009-strongswan-openssl-aead-add-ccm-support.patch of Package strongswan.22506

From 546f61d3c820d0289f79cbe3228e97f75c73dd0b Mon Sep 17 00:00:00 2001
From: Tobias Brunner <tobias@strongswan.org>
Date: Tue, 4 May 2021 18:19:57 +0200
References: bsc#1185363
Upstream: https://github.com/strongswan/strongswan/pull/353
Subject: [PATCH] openssl: Add support for AES in CCM mode

While CCM is available in earlier versions, we only use it with
OpenSSL 1.1.0 and newer because the generic control variables are not
available before and we default to GCM for them.

Closes strongswan/strongswan#353.

diff --git a/src/libstrongswan/plugins/openssl/openssl_aead.c b/src/libstrongswan/plugins/openssl/openssl_aead.c
index 52c5ac3f8..9262cfb23 100644
--- a/src/libstrongswan/plugins/openssl/openssl_aead.c
+++ b/src/libstrongswan/plugins/openssl/openssl_aead.c
@@ -29,10 +29,17 @@
 #define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
 #endif
 
+/* not defined for older versions of BoringSSL */
+#ifndef EVP_CIPH_CCM_MODE
+#define EVP_CIPH_CCM_MODE 0xffff
+#endif
+
 /** as defined in RFC 4106 */
-#define IV_LEN		8
-#define SALT_LEN	4
-#define NONCE_LEN	(IV_LEN + SALT_LEN)
+#define IV_LEN			8
+#define SALT_LEN		4
+#define NONCE_LEN		(IV_LEN + SALT_LEN)
+/** as defined in RFC 4309 */
+#define CCM_SALT_LEN	3
 
 typedef struct private_aead_t private_aead_t;
 
@@ -56,6 +63,11 @@ struct private_aead_t {
 	 */
 	char salt[SALT_LEN];
 
+	/**
+	 * Size of the salt
+	 */
+	size_t salt_size;
+
 	/**
 	 * Size of the integrity check value
 	 */
@@ -83,27 +95,39 @@ static bool crypt(private_aead_t *this, chunk_t data, chunk_t assoc, chunk_t iv,
 	bool success = FALSE;
 	int len;
 
-	memcpy(nonce, this->salt, SALT_LEN);
-	memcpy(nonce + SALT_LEN, iv.ptr, IV_LEN);
+	memcpy(nonce, this->salt, this->salt_size);
+	memcpy(nonce + this->salt_size, iv.ptr, IV_LEN);
 
 	ctx = EVP_CIPHER_CTX_new();
 	EVP_CIPHER_CTX_set_padding(ctx, 0);
 	if (!EVP_CipherInit_ex(ctx, this->cipher, NULL, NULL, NULL, enc) ||
-		!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, NONCE_LEN, NULL) ||
-		!EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, nonce, enc))
+		!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
+							 this->salt_size + IV_LEN, NULL))
 	{
 		goto done;
 	}
-	if (!enc && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, this->icv_size,
-									 data.ptr + data.len))
-	{	/* set ICV for verification on decryption */
+	if ((!enc || EVP_CIPHER_mode(this->cipher) == EVP_CIPH_CCM_MODE) &&
+		!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, this->icv_size,
+							 enc ? NULL : data.ptr + data.len))
+	{	/* set ICV for verification on decryption, CCM requires the ICV length
+		 * when encrypting */
+		goto done;
+	}
+	if (!EVP_CipherInit_ex(ctx, NULL, NULL, this->key.ptr, nonce, enc))
+	{	/* set key and nonce */
+		goto done;
+	}
+	if (EVP_CIPHER_mode(this->cipher) == EVP_CIPH_CCM_MODE &&
+		!EVP_CipherUpdate(ctx, NULL, &len, NULL, data.len))
+	{	/* CCM requires setting the total input length (plain or cipher+ICV) */
 		goto done;
 	}
 	if (assoc.len && !EVP_CipherUpdate(ctx, NULL, &len, assoc.ptr, assoc.len))
 	{	/* set AAD if specified */
 		goto done;
 	}
-	if (!EVP_CipherUpdate(ctx, out, &len, data.ptr, data.len) ||
+	/* CCM doesn't like NULL pointers as input, make sure we don't pass one */
+	if (!EVP_CipherUpdate(ctx, out, &len, data.ptr ?: out, data.len) ||
 		!EVP_CipherFinal_ex(ctx, out + len, &len))
 	{	/* EVP_CipherFinal_ex fails if ICV is incorrect on decryption */
 		goto done;
@@ -183,7 +207,7 @@ METHOD(aead_t, get_iv_gen, iv_gen_t*,
 METHOD(aead_t, get_key_size, size_t,
 	private_aead_t *this)
 {
-	return this->key.len + SALT_LEN;
+	return this->key.len + this->salt_size;
 }
 
 METHOD(aead_t, set_key, bool,
@@ -193,7 +217,7 @@ METHOD(aead_t, set_key, bool,
 	{
 		return FALSE;
 	}
-	memcpy(this->salt, key.ptr + key.len - SALT_LEN, SALT_LEN);
+	memcpy(this->salt, key.ptr + key.len - this->salt_size, this->salt_size);
 	memcpy(this->key.ptr, key.ptr, this->key.len);
 	return TRUE;
 }
@@ -226,17 +250,21 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo,
 			.set_key = _set_key,
 			.destroy = _destroy,
 		},
+		.salt_size = SALT_LEN,
 	);
 
 	switch (algo)
 	{
 		case ENCR_AES_GCM_ICV8:
+		case ENCR_AES_CCM_ICV8:
 			this->icv_size = 8;
 			break;
 		case ENCR_AES_GCM_ICV12:
+		case ENCR_AES_CCM_ICV12:
 			this->icv_size = 12;
 			break;
 		case ENCR_AES_GCM_ICV16:
+		case ENCR_AES_CCM_ICV16:
 			this->icv_size = 16;
 			break;
 		case ENCR_CHACHA20_POLY1305:
@@ -247,13 +275,6 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo,
 			return NULL;
 	}
 
-	if (salt_size && salt_size != SALT_LEN)
-	{
-		/* currently not supported */
-		free(this);
-		return NULL;
-	}
-
 	switch (algo)
 	{
 		case ENCR_AES_GCM_ICV8:
@@ -278,6 +299,31 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo,
 					return NULL;
 			}
 			break;
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+		case ENCR_AES_CCM_ICV8:
+		case ENCR_AES_CCM_ICV12:
+		case ENCR_AES_CCM_ICV16:
+			switch (key_size)
+			{
+				case 0:
+					key_size = 16;
+					/* FALL */
+				case 16:
+					this->cipher = EVP_aes_128_ccm();
+					break;
+				case 24:
+					this->cipher = EVP_aes_192_ccm();
+					break;
+				case 32:
+					this->cipher = EVP_aes_256_ccm();
+					break;
+				default:
+					free(this);
+					return NULL;
+			}
+			this->salt_size = CCM_SALT_LEN;
+			break;
+#endif /* OPENSSL_VERSION_NUMBER */
 #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)
 		case ENCR_CHACHA20_POLY1305:
 			switch (key_size)
@@ -299,6 +345,13 @@ aead_t *openssl_aead_create(encryption_algorithm_t algo,
 			return NULL;
 	}
 
+	if (salt_size && salt_size != this->salt_size)
+	{
+		/* currently not supported */
+		free(this);
+		return NULL;
+	}
+
 	if (!this->cipher)
 	{
 		free(this);
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c
index 851d029dd..edc5ddab1 100644
--- a/src/libstrongswan/plugins/openssl/openssl_plugin.c
+++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c
@@ -615,6 +615,18 @@ METHOD(plugin_t, get_features, int,
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  16),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  24),
 			PLUGIN_PROVIDE(AEAD, ENCR_AES_GCM_ICV8,  32),
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+			/* CCM is available before 1.1.0 but not via generic controls */
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV16, 32),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV12, 32),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  16),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  24),
+			PLUGIN_PROVIDE(AEAD, ENCR_AES_CCM_ICV8,  32),
+#endif /* OPENSSL_VERSION_NUMBER */
 #endif /* OPENSSL_NO_AES */
 #if OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)
 			PLUGIN_PROVIDE(AEAD, ENCR_CHACHA20_POLY1305, 32),
-- 
2.26.2

openSUSE Build Service is sponsored by