Blame SOURCES/cryptsetup-2.4.1-Adapt-crypto-backend-to-openssl3-lib-context.patch

79c0bd
From 6c9d3863031d5809cee6e157a0e53e7c4ef56940 Mon Sep 17 00:00:00 2001
79c0bd
From: Ondrej Kozina <okozina@redhat.com>
79c0bd
Date: Thu, 2 Sep 2021 15:36:15 +0200
79c0bd
Subject: [PATCH 01/11] Adapt crypto backend to openssl3 lib context.
79c0bd
79c0bd
Fully leverage openssl custom library context for various
79c0bd
providers (default, legacy). It can be used to properly
79c0bd
free all openssl resources used by libcryptsetup when
79c0bd
libcryptsetup is unloaded (and destructor is triggered).
79c0bd
---
79c0bd
 lib/crypto_backend/crypto_openssl.c | 188 +++++++++++++++++++++++-----
79c0bd
 1 file changed, 155 insertions(+), 33 deletions(-)
79c0bd
79c0bd
diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c
79c0bd
index 19960a07..a5ec4048 100644
79c0bd
--- a/lib/crypto_backend/crypto_openssl.c
79c0bd
+++ b/lib/crypto_backend/crypto_openssl.c
79c0bd
@@ -41,8 +41,10 @@
79c0bd
 #include "crypto_backend_internal.h"
79c0bd
 #if OPENSSL_VERSION_MAJOR >= 3
79c0bd
 #include <openssl/provider.h>
79c0bd
+#include <openssl/kdf.h>
79c0bd
 static OSSL_PROVIDER *ossl_legacy = NULL;
79c0bd
 static OSSL_PROVIDER *ossl_default = NULL;
79c0bd
+static OSSL_LIB_CTX  *ossl_ctx = NULL;
79c0bd
 #endif
79c0bd
 
79c0bd
 #define CONST_CAST(x) (x)(uintptr_t)
79c0bd
@@ -68,6 +70,7 @@ struct crypt_cipher {
79c0bd
 	struct {
79c0bd
 		EVP_CIPHER_CTX *hd_enc;
79c0bd
 		EVP_CIPHER_CTX *hd_dec;
79c0bd
+		const EVP_CIPHER *cipher_type;
79c0bd
 		size_t iv_length;
79c0bd
 	} lib;
79c0bd
 	} u;
79c0bd
@@ -130,31 +133,41 @@ static void HMAC_CTX_free(HMAC_CTX *md)
79c0bd
 	free(md);
79c0bd
 }
79c0bd
 #else
79c0bd
-static void openssl_backend_init(void)
79c0bd
+static int openssl_backend_init(void)
79c0bd
 {
79c0bd
 /*
79c0bd
  * OpenSSL >= 3.0.0 provides some algorithms in legacy provider
79c0bd
  */
79c0bd
 #if OPENSSL_VERSION_MAJOR >= 3
79c0bd
-	OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
79c0bd
-	ossl_legacy  = OSSL_PROVIDER_try_load(NULL, "legacy", 0);
79c0bd
-	ossl_default = OSSL_PROVIDER_try_load(NULL, "default", 0);
79c0bd
+	ossl_ctx = OSSL_LIB_CTX_new();
79c0bd
+	if (!ossl_ctx)
79c0bd
+		return -EINVAL;
79c0bd
+
79c0bd
+	ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
79c0bd
+	if (!ossl_default) {
79c0bd
+		OSSL_LIB_CTX_free(ossl_ctx);
79c0bd
+		return -EINVAL;
79c0bd
+	}
79c0bd
+
79c0bd
+	/* Optional */
79c0bd
+	ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
79c0bd
 #endif
79c0bd
+	return 0;
79c0bd
 }
79c0bd
 
79c0bd
 static void openssl_backend_exit(void)
79c0bd
 {
79c0bd
 #if OPENSSL_VERSION_MAJOR >= 3
79c0bd
-	/*
79c0bd
-	 * If Destructor was already called, we must not call it again
79c0bd
-	 */
79c0bd
-	if (OPENSSL_init_crypto(0, NULL) != 0) {
79c0bd
+	if (ossl_legacy)
79c0bd
 		OSSL_PROVIDER_unload(ossl_legacy);
79c0bd
+	if (ossl_default)
79c0bd
 		OSSL_PROVIDER_unload(ossl_default);
79c0bd
-		OPENSSL_cleanup();
79c0bd
-	}
79c0bd
+	if (ossl_ctx)
79c0bd
+		OSSL_LIB_CTX_free(ossl_ctx);
79c0bd
+
79c0bd
 	ossl_legacy = NULL;
79c0bd
 	ossl_default = NULL;
79c0bd
+	ossl_ctx = NULL;
79c0bd
 #endif
79c0bd
 }
79c0bd
 
79c0bd
@@ -169,7 +182,8 @@ int crypt_backend_init(void)
79c0bd
 	if (crypto_backend_initialised)
79c0bd
 		return 0;
79c0bd
 
79c0bd
-	openssl_backend_init();
79c0bd
+	if (openssl_backend_init())
79c0bd
+		return -EINVAL;
79c0bd
 
79c0bd
 	crypto_backend_initialised = 1;
79c0bd
 	return 0;
79c0bd
@@ -177,7 +191,14 @@ int crypt_backend_init(void)
79c0bd
 
79c0bd
 void crypt_backend_destroy(void)
79c0bd
 {
79c0bd
+	/*
79c0bd
+	 * If Destructor was already called, we must not call it again
79c0bd
+	 */
79c0bd
+	if (!crypto_backend_initialised)
79c0bd
+		return;
79c0bd
+
79c0bd
 	crypto_backend_initialised = 0;
79c0bd
+
79c0bd
 	openssl_backend_exit();
79c0bd
 }
79c0bd
 
79c0bd
@@ -215,16 +236,51 @@ static const char *crypt_hash_compat_name(const char *name)
79c0bd
 	return hash_name;
79c0bd
 }
79c0bd
 
79c0bd
+static const EVP_MD *hash_id_get(const char *name)
79c0bd
+{
79c0bd
+#if OPENSSL_VERSION_MAJOR >= 3
79c0bd
+	return EVP_MD_fetch(ossl_ctx, crypt_hash_compat_name(name), NULL);
79c0bd
+#else
79c0bd
+	return EVP_get_digestbyname(crypt_hash_compat_name(name));
79c0bd
+#endif
79c0bd
+}
79c0bd
+
79c0bd
+static void hash_id_free(const EVP_MD *hash_id)
79c0bd
+{
79c0bd
+#if OPENSSL_VERSION_MAJOR >= 3
79c0bd
+	EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
79c0bd
+#endif
79c0bd
+}
79c0bd
+
79c0bd
+static const EVP_CIPHER *cipher_type_get(const char *name)
79c0bd
+{
79c0bd
+#if OPENSSL_VERSION_MAJOR >= 3
79c0bd
+	return EVP_CIPHER_fetch(ossl_ctx, name, NULL);
79c0bd
+#else
79c0bd
+	return EVP_get_cipherbyname(name);
79c0bd
+#endif
79c0bd
+}
79c0bd
+
79c0bd
+static void cipher_type_free(const EVP_CIPHER *cipher_type)
79c0bd
+{
79c0bd
+#if OPENSSL_VERSION_MAJOR >= 3
79c0bd
+	EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
79c0bd
+#endif
79c0bd
+}
79c0bd
+
79c0bd
 /* HASH */
79c0bd
 int crypt_hash_size(const char *name)
79c0bd
 {
79c0bd
+	int size;
79c0bd
 	const EVP_MD *hash_id;
79c0bd
 
79c0bd
-	hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
79c0bd
+	hash_id = hash_id_get(name);
79c0bd
 	if (!hash_id)
79c0bd
 		return -EINVAL;
79c0bd
 
79c0bd
-	return EVP_MD_size(hash_id);
79c0bd
+	size = EVP_MD_size(hash_id);
79c0bd
+	hash_id_free(hash_id);
79c0bd
+	return size;
79c0bd
 }
79c0bd
 
79c0bd
 int crypt_hash_init(struct crypt_hash **ctx, const char *name)
79c0bd
@@ -241,7 +297,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
79c0bd
 		return -ENOMEM;
79c0bd
 	}
79c0bd
 
79c0bd
-	h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
79c0bd
+	h->hash_id = hash_id_get(name);
79c0bd
 	if (!h->hash_id) {
79c0bd
 		EVP_MD_CTX_free(h->md);
79c0bd
 		free(h);
79c0bd
@@ -249,6 +305,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
79c0bd
 	}
79c0bd
 
79c0bd
 	if (EVP_DigestInit_ex(h->md, h->hash_id, NULL) != 1) {
79c0bd
+		hash_id_free(h->hash_id);
79c0bd
 		EVP_MD_CTX_free(h->md);
79c0bd
 		free(h);
79c0bd
 		return -EINVAL;
79c0bd
@@ -300,6 +357,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
79c0bd
 
79c0bd
 void crypt_hash_destroy(struct crypt_hash *ctx)
79c0bd
 {
79c0bd
+	hash_id_free(ctx->hash_id);
79c0bd
 	EVP_MD_CTX_free(ctx->md);
79c0bd
 	memset(ctx, 0, sizeof(*ctx));
79c0bd
 	free(ctx);
79c0bd
@@ -326,7 +384,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
79c0bd
 		return -ENOMEM;
79c0bd
 	}
79c0bd
 
79c0bd
-	h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
79c0bd
+	h->hash_id = hash_id_get(name);
79c0bd
 	if (!h->hash_id) {
79c0bd
 		HMAC_CTX_free(h->md);
79c0bd
 		free(h);
79c0bd
@@ -374,6 +432,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
79c0bd
 
79c0bd
 void crypt_hmac_destroy(struct crypt_hmac *ctx)
79c0bd
 {
79c0bd
+	hash_id_free(ctx->hash_id);
79c0bd
 	HMAC_CTX_free(ctx->md);
79c0bd
 	memset(ctx, 0, sizeof(*ctx));
79c0bd
 	free(ctx);
79c0bd
@@ -389,6 +448,67 @@ int crypt_backend_rng(char *buffer, size_t length,
79c0bd
 	return 0;
79c0bd
 }
79c0bd
 
79c0bd
+static int pbkdf2(const char *password, size_t password_length,
79c0bd
+		const char *salt, size_t salt_length,
79c0bd
+		uint32_t iterations, const char *hash, size_t key_length,
79c0bd
+		unsigned char *key)
79c0bd
+{
79c0bd
+#if OPENSSL_VERSION_MAJOR >= 3
79c0bd
+	EVP_KDF_CTX *ctx;
79c0bd
+	EVP_KDF *pbkdf2;
79c0bd
+	int r;
79c0bd
+	OSSL_PARAM params[] = {
79c0bd
+		{ .key = "pass",
79c0bd
+		  .data_type = OSSL_PARAM_OCTET_STRING,
79c0bd
+		  .data = CONST_CAST(void*)password,
79c0bd
+		  .data_size = password_length
79c0bd
+		},
79c0bd
+		{ .key = "salt",
79c0bd
+		  .data_type = OSSL_PARAM_OCTET_STRING,
79c0bd
+		  .data = CONST_CAST(void*)salt,
79c0bd
+		  .data_size = salt_length
79c0bd
+		},
79c0bd
+		{ .key = "iter",
79c0bd
+		  .data_type = OSSL_PARAM_UNSIGNED_INTEGER,
79c0bd
+		  .data = &iterations,
79c0bd
+		  .data_size = sizeof(iterations)
79c0bd
+		},
79c0bd
+		{ .key = "digest",
79c0bd
+		  .data_type = OSSL_PARAM_UTF8_STRING,
79c0bd
+		  .data = CONST_CAST(void*)hash,
79c0bd
+		  .data_size = strlen(hash)
79c0bd
+		},
79c0bd
+		{ NULL, 0, NULL, 0, 0 }
79c0bd
+	};
79c0bd
+
79c0bd
+	pbkdf2 = EVP_KDF_fetch(ossl_ctx, "pbkdf2", NULL);
79c0bd
+	if (!pbkdf2)
79c0bd
+		return 0;
79c0bd
+
79c0bd
+	ctx = EVP_KDF_CTX_new(pbkdf2);
79c0bd
+	if (!ctx) {
79c0bd
+		EVP_KDF_free(pbkdf2);
79c0bd
+		return 0;
79c0bd
+	}
79c0bd
+
79c0bd
+	r = EVP_KDF_derive(ctx, key, key_length, params);
79c0bd
+
79c0bd
+	EVP_KDF_CTX_free(ctx);
79c0bd
+	EVP_KDF_free(pbkdf2);
79c0bd
+
79c0bd
+	/* _derive() returns 0 or negative value on error, 1 on success */
79c0bd
+	return r <= 0 ? 0 : 1;
79c0bd
+#else
79c0bd
+	const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
79c0bd
+	if (!hash_id)
79c0bd
+		return 0;
79c0bd
+
79c0bd
+	return PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt,
79c0bd
+				 (int)salt_length, iterations, hash_id,
79c0bd
+				 (int)key_length, key);
79c0bd
+#endif
79c0bd
+}
79c0bd
+
79c0bd
 /* PBKDF */
79c0bd
 int crypt_pbkdf(const char *kdf, const char *hash,
79c0bd
 		const char *password, size_t password_length,
79c0bd
@@ -397,19 +517,12 @@ int crypt_pbkdf(const char *kdf, const char *hash,
79c0bd
 		uint32_t iterations, uint32_t memory, uint32_t parallel)
79c0bd
 
79c0bd
 {
79c0bd
-	const EVP_MD *hash_id;
79c0bd
-
79c0bd
 	if (!kdf)
79c0bd
 		return -EINVAL;
79c0bd
 
79c0bd
 	if (!strcmp(kdf, "pbkdf2")) {
79c0bd
-		hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
79c0bd
-		if (!hash_id)
79c0bd
-			return -EINVAL;
79c0bd
-
79c0bd
-		if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
79c0bd
-		    (const unsigned char *)salt, (int)salt_length,
79c0bd
-	            (int)iterations, hash_id, (int)key_length, (unsigned char *)key))
79c0bd
+		if (!pbkdf2(password, password_length,
79c0bd
+		    salt, salt_length, iterations, hash, key_length, (unsigned char *)key))
79c0bd
 			return -EINVAL;
79c0bd
 		return 0;
79c0bd
 	} else if (!strncmp(kdf, "argon2", 6)) {
79c0bd
@@ -421,16 +534,19 @@ int crypt_pbkdf(const char *kdf, const char *hash,
79c0bd
 }
79c0bd
 
79c0bd
 /* Block ciphers */
79c0bd
-static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
79c0bd
+static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type)
79c0bd
 {
79c0bd
 	EVP_CIPHER_CTX_free(*hd_enc);
79c0bd
 	*hd_enc = NULL;
79c0bd
 
79c0bd
 	EVP_CIPHER_CTX_free(*hd_dec);
79c0bd
 	*hd_dec = NULL;
79c0bd
+
79c0bd
+	cipher_type_free(*cipher_type);
79c0bd
+	*cipher_type = NULL;
79c0bd
 }
79c0bd
 
79c0bd
-static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
79c0bd
+static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type, const char *name,
79c0bd
 			const char *mode, const void *key, size_t key_length, size_t *iv_length)
79c0bd
 {
79c0bd
 	char cipher_name[256];
79c0bd
@@ -445,32 +561,38 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
79c0bd
 	if (r < 0 || (size_t)r >= sizeof(cipher_name))
79c0bd
 		return -EINVAL;
79c0bd
 
79c0bd
-	type = EVP_get_cipherbyname(cipher_name);
79c0bd
+	type = cipher_type_get(cipher_name);
79c0bd
 	if (!type)
79c0bd
 		return -ENOENT;
79c0bd
 
79c0bd
-	if (EVP_CIPHER_key_length(type) != (int)key_length)
79c0bd
+	if (EVP_CIPHER_key_length(type) != (int)key_length) {
79c0bd
+		cipher_type_free(type);
79c0bd
 		return -EINVAL;
79c0bd
+	}
79c0bd
 
79c0bd
 	*hd_enc = EVP_CIPHER_CTX_new();
79c0bd
 	*hd_dec = EVP_CIPHER_CTX_new();
79c0bd
 	*iv_length = EVP_CIPHER_iv_length(type);
79c0bd
 
79c0bd
-	if (!*hd_enc || !*hd_dec)
79c0bd
+	if (!*hd_enc || !*hd_dec) {
79c0bd
+		cipher_type_free(type);
79c0bd
 		return -EINVAL;
79c0bd
+	}
79c0bd
 
79c0bd
 	if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
79c0bd
 	    EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
79c0bd
-		_cipher_destroy(hd_enc, hd_dec);
79c0bd
+		_cipher_destroy(hd_enc, hd_dec, &type);
79c0bd
 		return -EINVAL;
79c0bd
 	}
79c0bd
 
79c0bd
 	if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
79c0bd
 	    EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
79c0bd
-		_cipher_destroy(hd_enc, hd_dec);
79c0bd
+		_cipher_destroy(hd_enc, hd_dec, &type);
79c0bd
 		return -EINVAL;
79c0bd
 	}
79c0bd
 
79c0bd
+	*cipher_type = type;
79c0bd
+
79c0bd
 	return 0;
79c0bd
 }
79c0bd
 
79c0bd
@@ -484,7 +606,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
79c0bd
 	if (!h)
79c0bd
 		return -ENOMEM;
79c0bd
 
79c0bd
-	if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
79c0bd
+	if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, &h->u.lib.cipher_type, name, mode, key,
79c0bd
 			  key_length, &h->u.lib.iv_length)) {
79c0bd
 		h->use_kernel = false;
79c0bd
 		*ctx = h;
79c0bd
@@ -507,7 +629,7 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
79c0bd
 	if (ctx->use_kernel)
79c0bd
 		crypt_cipher_destroy_kernel(&ctx->u.kernel);
79c0bd
 	else
79c0bd
-		_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
79c0bd
+		_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec, &ctx->u.lib.cipher_type);
79c0bd
 	free(ctx);
79c0bd
 }
79c0bd
 
79c0bd
-- 
79c0bd
2.27.0
79c0bd