diff --git a/.cryptsetup.metadata b/.cryptsetup.metadata
new file mode 100644
index 0000000..0274ab2
--- /dev/null
+++ b/.cryptsetup.metadata
@@ -0,0 +1 @@
+7aae3037a6eba63df19fd89310e325ac9b75aebd SOURCES/cryptsetup-2.4.0.tar.xz
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f4e3f7f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/cryptsetup-2.4.0.tar.xz
diff --git a/SOURCES/cryptsetup-2.4.1-Adapt-crypto-backend-to-openssl3-lib-context.patch b/SOURCES/cryptsetup-2.4.1-Adapt-crypto-backend-to-openssl3-lib-context.patch
new file mode 100644
index 0000000..0178126
--- /dev/null
+++ b/SOURCES/cryptsetup-2.4.1-Adapt-crypto-backend-to-openssl3-lib-context.patch
@@ -0,0 +1,386 @@
+From 6c9d3863031d5809cee6e157a0e53e7c4ef56940 Mon Sep 17 00:00:00 2001
+From: Ondrej Kozina <okozina@redhat.com>
+Date: Thu, 2 Sep 2021 15:36:15 +0200
+Subject: [PATCH 01/11] Adapt crypto backend to openssl3 lib context.
+
+Fully leverage openssl custom library context for various
+providers (default, legacy). It can be used to properly
+free all openssl resources used by libcryptsetup when
+libcryptsetup is unloaded (and destructor is triggered).
+---
+ lib/crypto_backend/crypto_openssl.c | 188 +++++++++++++++++++++++-----
+ 1 file changed, 155 insertions(+), 33 deletions(-)
+
+diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c
+index 19960a07..a5ec4048 100644
+--- a/lib/crypto_backend/crypto_openssl.c
++++ b/lib/crypto_backend/crypto_openssl.c
+@@ -41,8 +41,10 @@
+ #include "crypto_backend_internal.h"
+ #if OPENSSL_VERSION_MAJOR >= 3
+ #include <openssl/provider.h>
++#include <openssl/kdf.h>
+ static OSSL_PROVIDER *ossl_legacy = NULL;
+ static OSSL_PROVIDER *ossl_default = NULL;
++static OSSL_LIB_CTX  *ossl_ctx = NULL;
+ #endif
+ 
+ #define CONST_CAST(x) (x)(uintptr_t)
+@@ -68,6 +70,7 @@ struct crypt_cipher {
+ 	struct {
+ 		EVP_CIPHER_CTX *hd_enc;
+ 		EVP_CIPHER_CTX *hd_dec;
++		const EVP_CIPHER *cipher_type;
+ 		size_t iv_length;
+ 	} lib;
+ 	} u;
+@@ -130,31 +133,41 @@ static void HMAC_CTX_free(HMAC_CTX *md)
+ 	free(md);
+ }
+ #else
+-static void openssl_backend_init(void)
++static int openssl_backend_init(void)
+ {
+ /*
+  * OpenSSL >= 3.0.0 provides some algorithms in legacy provider
+  */
+ #if OPENSSL_VERSION_MAJOR >= 3
+-	OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL);
+-	ossl_legacy  = OSSL_PROVIDER_try_load(NULL, "legacy", 0);
+-	ossl_default = OSSL_PROVIDER_try_load(NULL, "default", 0);
++	ossl_ctx = OSSL_LIB_CTX_new();
++	if (!ossl_ctx)
++		return -EINVAL;
++
++	ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
++	if (!ossl_default) {
++		OSSL_LIB_CTX_free(ossl_ctx);
++		return -EINVAL;
++	}
++
++	/* Optional */
++	ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
+ #endif
++	return 0;
+ }
+ 
+ static void openssl_backend_exit(void)
+ {
+ #if OPENSSL_VERSION_MAJOR >= 3
+-	/*
+-	 * If Destructor was already called, we must not call it again
+-	 */
+-	if (OPENSSL_init_crypto(0, NULL) != 0) {
++	if (ossl_legacy)
+ 		OSSL_PROVIDER_unload(ossl_legacy);
++	if (ossl_default)
+ 		OSSL_PROVIDER_unload(ossl_default);
+-		OPENSSL_cleanup();
+-	}
++	if (ossl_ctx)
++		OSSL_LIB_CTX_free(ossl_ctx);
++
+ 	ossl_legacy = NULL;
+ 	ossl_default = NULL;
++	ossl_ctx = NULL;
+ #endif
+ }
+ 
+@@ -169,7 +182,8 @@ int crypt_backend_init(void)
+ 	if (crypto_backend_initialised)
+ 		return 0;
+ 
+-	openssl_backend_init();
++	if (openssl_backend_init())
++		return -EINVAL;
+ 
+ 	crypto_backend_initialised = 1;
+ 	return 0;
+@@ -177,7 +191,14 @@ int crypt_backend_init(void)
+ 
+ void crypt_backend_destroy(void)
+ {
++	/*
++	 * If Destructor was already called, we must not call it again
++	 */
++	if (!crypto_backend_initialised)
++		return;
++
+ 	crypto_backend_initialised = 0;
++
+ 	openssl_backend_exit();
+ }
+ 
+@@ -215,16 +236,51 @@ static const char *crypt_hash_compat_name(const char *name)
+ 	return hash_name;
+ }
+ 
++static const EVP_MD *hash_id_get(const char *name)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	return EVP_MD_fetch(ossl_ctx, crypt_hash_compat_name(name), NULL);
++#else
++	return EVP_get_digestbyname(crypt_hash_compat_name(name));
++#endif
++}
++
++static void hash_id_free(const EVP_MD *hash_id)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	EVP_MD_free(CONST_CAST(EVP_MD*)hash_id);
++#endif
++}
++
++static const EVP_CIPHER *cipher_type_get(const char *name)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	return EVP_CIPHER_fetch(ossl_ctx, name, NULL);
++#else
++	return EVP_get_cipherbyname(name);
++#endif
++}
++
++static void cipher_type_free(const EVP_CIPHER *cipher_type)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	EVP_CIPHER_free(CONST_CAST(EVP_CIPHER*)cipher_type);
++#endif
++}
++
+ /* HASH */
+ int crypt_hash_size(const char *name)
+ {
++	int size;
+ 	const EVP_MD *hash_id;
+ 
+-	hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
++	hash_id = hash_id_get(name);
+ 	if (!hash_id)
+ 		return -EINVAL;
+ 
+-	return EVP_MD_size(hash_id);
++	size = EVP_MD_size(hash_id);
++	hash_id_free(hash_id);
++	return size;
+ }
+ 
+ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
+@@ -241,7 +297,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
+ 		return -ENOMEM;
+ 	}
+ 
+-	h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
++	h->hash_id = hash_id_get(name);
+ 	if (!h->hash_id) {
+ 		EVP_MD_CTX_free(h->md);
+ 		free(h);
+@@ -249,6 +305,7 @@ int crypt_hash_init(struct crypt_hash **ctx, const char *name)
+ 	}
+ 
+ 	if (EVP_DigestInit_ex(h->md, h->hash_id, NULL) != 1) {
++		hash_id_free(h->hash_id);
+ 		EVP_MD_CTX_free(h->md);
+ 		free(h);
+ 		return -EINVAL;
+@@ -300,6 +357,7 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length)
+ 
+ void crypt_hash_destroy(struct crypt_hash *ctx)
+ {
++	hash_id_free(ctx->hash_id);
+ 	EVP_MD_CTX_free(ctx->md);
+ 	memset(ctx, 0, sizeof(*ctx));
+ 	free(ctx);
+@@ -326,7 +384,7 @@ int crypt_hmac_init(struct crypt_hmac **ctx, const char *name,
+ 		return -ENOMEM;
+ 	}
+ 
+-	h->hash_id = EVP_get_digestbyname(crypt_hash_compat_name(name));
++	h->hash_id = hash_id_get(name);
+ 	if (!h->hash_id) {
+ 		HMAC_CTX_free(h->md);
+ 		free(h);
+@@ -374,6 +432,7 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length)
+ 
+ void crypt_hmac_destroy(struct crypt_hmac *ctx)
+ {
++	hash_id_free(ctx->hash_id);
+ 	HMAC_CTX_free(ctx->md);
+ 	memset(ctx, 0, sizeof(*ctx));
+ 	free(ctx);
+@@ -389,6 +448,67 @@ int crypt_backend_rng(char *buffer, size_t length,
+ 	return 0;
+ }
+ 
++static int pbkdf2(const char *password, size_t password_length,
++		const char *salt, size_t salt_length,
++		uint32_t iterations, const char *hash, size_t key_length,
++		unsigned char *key)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	EVP_KDF_CTX *ctx;
++	EVP_KDF *pbkdf2;
++	int r;
++	OSSL_PARAM params[] = {
++		{ .key = "pass",
++		  .data_type = OSSL_PARAM_OCTET_STRING,
++		  .data = CONST_CAST(void*)password,
++		  .data_size = password_length
++		},
++		{ .key = "salt",
++		  .data_type = OSSL_PARAM_OCTET_STRING,
++		  .data = CONST_CAST(void*)salt,
++		  .data_size = salt_length
++		},
++		{ .key = "iter",
++		  .data_type = OSSL_PARAM_UNSIGNED_INTEGER,
++		  .data = &iterations,
++		  .data_size = sizeof(iterations)
++		},
++		{ .key = "digest",
++		  .data_type = OSSL_PARAM_UTF8_STRING,
++		  .data = CONST_CAST(void*)hash,
++		  .data_size = strlen(hash)
++		},
++		{ NULL, 0, NULL, 0, 0 }
++	};
++
++	pbkdf2 = EVP_KDF_fetch(ossl_ctx, "pbkdf2", NULL);
++	if (!pbkdf2)
++		return 0;
++
++	ctx = EVP_KDF_CTX_new(pbkdf2);
++	if (!ctx) {
++		EVP_KDF_free(pbkdf2);
++		return 0;
++	}
++
++	r = EVP_KDF_derive(ctx, key, key_length, params);
++
++	EVP_KDF_CTX_free(ctx);
++	EVP_KDF_free(pbkdf2);
++
++	/* _derive() returns 0 or negative value on error, 1 on success */
++	return r <= 0 ? 0 : 1;
++#else
++	const EVP_MD *hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
++	if (!hash_id)
++		return 0;
++
++	return PKCS5_PBKDF2_HMAC(password, (int)password_length, (const unsigned char *)salt,
++				 (int)salt_length, iterations, hash_id,
++				 (int)key_length, key);
++#endif
++}
++
+ /* PBKDF */
+ int crypt_pbkdf(const char *kdf, const char *hash,
+ 		const char *password, size_t password_length,
+@@ -397,19 +517,12 @@ int crypt_pbkdf(const char *kdf, const char *hash,
+ 		uint32_t iterations, uint32_t memory, uint32_t parallel)
+ 
+ {
+-	const EVP_MD *hash_id;
+-
+ 	if (!kdf)
+ 		return -EINVAL;
+ 
+ 	if (!strcmp(kdf, "pbkdf2")) {
+-		hash_id = EVP_get_digestbyname(crypt_hash_compat_name(hash));
+-		if (!hash_id)
+-			return -EINVAL;
+-
+-		if (!PKCS5_PBKDF2_HMAC(password, (int)password_length,
+-		    (const unsigned char *)salt, (int)salt_length,
+-	            (int)iterations, hash_id, (int)key_length, (unsigned char *)key))
++		if (!pbkdf2(password, password_length,
++		    salt, salt_length, iterations, hash, key_length, (unsigned char *)key))
+ 			return -EINVAL;
+ 		return 0;
+ 	} else if (!strncmp(kdf, "argon2", 6)) {
+@@ -421,16 +534,19 @@ int crypt_pbkdf(const char *kdf, const char *hash,
+ }
+ 
+ /* Block ciphers */
+-static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec)
++static void _cipher_destroy(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type)
+ {
+ 	EVP_CIPHER_CTX_free(*hd_enc);
+ 	*hd_enc = NULL;
+ 
+ 	EVP_CIPHER_CTX_free(*hd_dec);
+ 	*hd_dec = NULL;
++
++	cipher_type_free(*cipher_type);
++	*cipher_type = NULL;
+ }
+ 
+-static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const char *name,
++static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const EVP_CIPHER **cipher_type, const char *name,
+ 			const char *mode, const void *key, size_t key_length, size_t *iv_length)
+ {
+ 	char cipher_name[256];
+@@ -445,32 +561,38 @@ static int _cipher_init(EVP_CIPHER_CTX **hd_enc, EVP_CIPHER_CTX **hd_dec, const
+ 	if (r < 0 || (size_t)r >= sizeof(cipher_name))
+ 		return -EINVAL;
+ 
+-	type = EVP_get_cipherbyname(cipher_name);
++	type = cipher_type_get(cipher_name);
+ 	if (!type)
+ 		return -ENOENT;
+ 
+-	if (EVP_CIPHER_key_length(type) != (int)key_length)
++	if (EVP_CIPHER_key_length(type) != (int)key_length) {
++		cipher_type_free(type);
+ 		return -EINVAL;
++	}
+ 
+ 	*hd_enc = EVP_CIPHER_CTX_new();
+ 	*hd_dec = EVP_CIPHER_CTX_new();
+ 	*iv_length = EVP_CIPHER_iv_length(type);
+ 
+-	if (!*hd_enc || !*hd_dec)
++	if (!*hd_enc || !*hd_dec) {
++		cipher_type_free(type);
+ 		return -EINVAL;
++	}
+ 
+ 	if (EVP_EncryptInit_ex(*hd_enc, type, NULL, key, NULL) != 1 ||
+ 	    EVP_DecryptInit_ex(*hd_dec, type, NULL, key, NULL) != 1) {
+-		_cipher_destroy(hd_enc, hd_dec);
++		_cipher_destroy(hd_enc, hd_dec, &type);
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (EVP_CIPHER_CTX_set_padding(*hd_enc, 0) != 1 ||
+ 	    EVP_CIPHER_CTX_set_padding(*hd_dec, 0) != 1) {
+-		_cipher_destroy(hd_enc, hd_dec);
++		_cipher_destroy(hd_enc, hd_dec, &type);
+ 		return -EINVAL;
+ 	}
+ 
++	*cipher_type = type;
++
+ 	return 0;
+ }
+ 
+@@ -484,7 +606,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
+ 	if (!h)
+ 		return -ENOMEM;
+ 
+-	if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, name, mode, key,
++	if (!_cipher_init(&h->u.lib.hd_enc, &h->u.lib.hd_dec, &h->u.lib.cipher_type, name, mode, key,
+ 			  key_length, &h->u.lib.iv_length)) {
+ 		h->use_kernel = false;
+ 		*ctx = h;
+@@ -507,7 +629,7 @@ void crypt_cipher_destroy(struct crypt_cipher *ctx)
+ 	if (ctx->use_kernel)
+ 		crypt_cipher_destroy_kernel(&ctx->u.kernel);
+ 	else
+-		_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec);
++		_cipher_destroy(&ctx->u.lib.hd_enc, &ctx->u.lib.hd_dec, &ctx->u.lib.cipher_type);
+ 	free(ctx);
+ }
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/cryptsetup-2.4.1-Cache-FIPS-mode-check.patch b/SOURCES/cryptsetup-2.4.1-Cache-FIPS-mode-check.patch
new file mode 100644
index 0000000..d64cbee
--- /dev/null
+++ b/SOURCES/cryptsetup-2.4.1-Cache-FIPS-mode-check.patch
@@ -0,0 +1,42 @@
+From 75e45462f097a9a75747b3f44d7672f2547e63e9 Mon Sep 17 00:00:00 2001
+From: Milan Broz <gmazyland@gmail.com>
+Date: Tue, 14 Sep 2021 09:56:05 +0200
+Subject: [PATCH 04/11] Cache FIPS mode check.
+
+We do not support switch while the crypto backend is already initialized,
+so it does not make sense to check repeatedly for the FIPS mode status.
+---
+ lib/utils_fips.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/lib/utils_fips.c b/lib/utils_fips.c
+index 0c2b6434..640ff0e3 100644
+--- a/lib/utils_fips.c
++++ b/lib/utils_fips.c
+@@ -26,6 +26,9 @@
+ #if !ENABLE_FIPS
+ bool crypt_fips_mode(void) { return false; }
+ #else
++static bool fips_checked = false;
++static bool fips_mode = false;
++
+ static bool kernel_fips_mode(void)
+ {
+ 	int fd;
+@@ -41,6 +44,12 @@ static bool kernel_fips_mode(void)
+ 
+ bool crypt_fips_mode(void)
+ {
+-	return kernel_fips_mode() && !access("/etc/system-fips", F_OK);
++	if (fips_checked)
++		return fips_mode;
++
++	fips_mode = kernel_fips_mode() && !access("/etc/system-fips", F_OK);
++	fips_checked = true;
++
++	return fips_mode;
+ }
+ #endif /* ENABLE_FIPS */
+-- 
+2.27.0
+
diff --git a/SOURCES/cryptsetup-2.4.1-Do-not-load-own-OpenSSL-backend-context-in-FIPS-mode.patch b/SOURCES/cryptsetup-2.4.1-Do-not-load-own-OpenSSL-backend-context-in-FIPS-mode.patch
new file mode 100644
index 0000000..928e65e
--- /dev/null
+++ b/SOURCES/cryptsetup-2.4.1-Do-not-load-own-OpenSSL-backend-context-in-FIPS-mode.patch
@@ -0,0 +1,236 @@
+From f8eb7b225affe8b6b9f02ab6a90fd2e73181a526 Mon Sep 17 00:00:00 2001
+From: Milan Broz <gmazyland@gmail.com>
+Date: Mon, 13 Sep 2021 19:45:05 +0200
+Subject: [PATCH 03/11] Do not load own OpenSSL backend context in FIPS mode.
+
+In the FIPS mode keep configuration up to the system wide config.
+---
+ lib/crypto_backend/crypto_backend.h |  2 +-
+ lib/crypto_backend/crypto_gcrypt.c  |  2 +-
+ lib/crypto_backend/crypto_kernel.c  |  2 +-
+ lib/crypto_backend/crypto_nettle.c  |  2 +-
+ lib/crypto_backend/crypto_nss.c     |  2 +-
+ lib/crypto_backend/crypto_openssl.c | 39 +++++++++++++++++------------
+ lib/setup.c                         |  2 +-
+ lib/utils_fips.c                    |  8 +++---
+ lib/utils_fips.h                    |  4 ++-
+ tests/crypto-vectors.c              |  2 +-
+ 10 files changed, 37 insertions(+), 28 deletions(-)
+
+diff --git a/lib/crypto_backend/crypto_backend.h b/lib/crypto_backend/crypto_backend.h
+index 5278c345..88cc2d59 100644
+--- a/lib/crypto_backend/crypto_backend.h
++++ b/lib/crypto_backend/crypto_backend.h
+@@ -31,7 +31,7 @@ struct crypt_hmac;
+ struct crypt_cipher;
+ struct crypt_storage;
+ 
+-int crypt_backend_init(void);
++int crypt_backend_init(bool fips);
+ void crypt_backend_destroy(void);
+ 
+ #define CRYPT_BACKEND_KERNEL (1 << 0)	/* Crypto uses kernel part, for benchmark */
+diff --git a/lib/crypto_backend/crypto_gcrypt.c b/lib/crypto_backend/crypto_gcrypt.c
+index 2845382e..67f26067 100644
+--- a/lib/crypto_backend/crypto_gcrypt.c
++++ b/lib/crypto_backend/crypto_gcrypt.c
+@@ -94,7 +94,7 @@ static void crypt_hash_test_whirlpool_bug(void)
+ 		crypto_backend_whirlpool_bug = 1;
+ }
+ 
+-int crypt_backend_init(void)
++int crypt_backend_init(bool fips __attribute__((unused)))
+ {
+ 	int r;
+ 
+diff --git a/lib/crypto_backend/crypto_kernel.c b/lib/crypto_backend/crypto_kernel.c
+index 2e3d65b2..ce84cfac 100644
+--- a/lib/crypto_backend/crypto_kernel.c
++++ b/lib/crypto_backend/crypto_kernel.c
+@@ -117,7 +117,7 @@ static int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *op
+ 	return 0;
+ }
+ 
+-int crypt_backend_init(void)
++int crypt_backend_init(bool fips __attribute__((unused)))
+ {
+ 	struct utsname uts;
+ 	struct sockaddr_alg sa = {
+diff --git a/lib/crypto_backend/crypto_nettle.c b/lib/crypto_backend/crypto_nettle.c
+index 0860a52d..c9b9f5f8 100644
+--- a/lib/crypto_backend/crypto_nettle.c
++++ b/lib/crypto_backend/crypto_nettle.c
+@@ -213,7 +213,7 @@ static struct hash_alg *_get_alg(const char *name)
+ 	return NULL;
+ }
+ 
+-int crypt_backend_init(void)
++int crypt_backend_init(bool fips __attribute__((unused)))
+ {
+ 	return 0;
+ }
+diff --git a/lib/crypto_backend/crypto_nss.c b/lib/crypto_backend/crypto_nss.c
+index ebe9de0e..a84d3d65 100644
+--- a/lib/crypto_backend/crypto_nss.c
++++ b/lib/crypto_backend/crypto_nss.c
+@@ -75,7 +75,7 @@ static struct hash_alg *_get_alg(const char *name)
+ 	return NULL;
+ }
+ 
+-int crypt_backend_init(void)
++int crypt_backend_init(bool fips __attribute__((unused)))
+ {
+ 	int r;
+ 
+diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c
+index 92eeb33c..2a490ce5 100644
+--- a/lib/crypto_backend/crypto_openssl.c
++++ b/lib/crypto_backend/crypto_openssl.c
+@@ -88,7 +88,7 @@ struct hash_alg {
+ #if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+     (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+ 
+-static void openssl_backend_init(void)
++static void openssl_backend_init(bool fips __attribute__((unused)))
+ {
+ 	OpenSSL_add_all_algorithms();
+ }
+@@ -150,7 +150,7 @@ static void openssl_backend_exit(void)
+ #endif
+ }
+ 
+-static int openssl_backend_init(void)
++static int openssl_backend_init(bool fips)
+ {
+ /*
+  * OpenSSL >= 3.0.0 provides some algorithms in legacy provider
+@@ -158,23 +158,30 @@ static int openssl_backend_init(void)
+ #if OPENSSL_VERSION_MAJOR >= 3
+ 	int r;
+ 
+-	ossl_ctx = OSSL_LIB_CTX_new();
+-	if (!ossl_ctx)
+-		return -EINVAL;
++	/*
++	 * In FIPS mode we keep default OpenSSL context & global config
++	 */
++	if (!fips) {
++		ossl_ctx = OSSL_LIB_CTX_new();
++		if (!ossl_ctx)
++			return -EINVAL;
+ 
+-	ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
+-	if (!ossl_default) {
+-		OSSL_LIB_CTX_free(ossl_ctx);
+-		return -EINVAL;
+-	}
++		ossl_default = OSSL_PROVIDER_try_load(ossl_ctx, "default", 0);
++		if (!ossl_default) {
++			OSSL_LIB_CTX_free(ossl_ctx);
++			return -EINVAL;
++		}
+ 
+-	/* Optional */
+-	ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
++		/* Optional */
++		ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
++	}
+ 
+-	r = snprintf(backend_version, sizeof(backend_version), "%s %s%s",
++	r = snprintf(backend_version, sizeof(backend_version), "%s %s%s%s",
+ 		OpenSSL_version(OPENSSL_VERSION),
+ 		ossl_default ? "[default]" : "",
+-		ossl_legacy  ? "[legacy]" : "");
++		ossl_legacy  ? "[legacy]" : "",
++		fips  ? "[fips]" : "");
++
+ 	if (r < 0 || (size_t)r >= sizeof(backend_version)) {
+ 		openssl_backend_exit();
+ 		return -EINVAL;
+@@ -193,12 +200,12 @@ static const char *openssl_backend_version(void)
+ }
+ #endif
+ 
+-int crypt_backend_init(void)
++int crypt_backend_init(bool fips)
+ {
+ 	if (crypto_backend_initialised)
+ 		return 0;
+ 
+-	if (openssl_backend_init())
++	if (openssl_backend_init(fips))
+ 		return -EINVAL;
+ 
+ 	crypto_backend_initialised = 1;
+diff --git a/lib/setup.c b/lib/setup.c
+index dc5459f5..a5dfd843 100644
+--- a/lib/setup.c
++++ b/lib/setup.c
+@@ -227,7 +227,7 @@ int init_crypto(struct crypt_device *ctx)
+ 		return r;
+ 	}
+ 
+-	r = crypt_backend_init();
++	r = crypt_backend_init(crypt_fips_mode());
+ 	if (r < 0)
+ 		log_err(ctx, _("Cannot initialize crypto backend."));
+ 
+diff --git a/lib/utils_fips.c b/lib/utils_fips.c
+index 4fa22fb9..0c2b6434 100644
+--- a/lib/utils_fips.c
++++ b/lib/utils_fips.c
+@@ -24,9 +24,9 @@
+ #include "utils_fips.h"
+ 
+ #if !ENABLE_FIPS
+-int crypt_fips_mode(void) { return 0; }
++bool crypt_fips_mode(void) { return false; }
+ #else
+-static int kernel_fips_mode(void)
++static bool kernel_fips_mode(void)
+ {
+ 	int fd;
+ 	char buf[1] = "";
+@@ -36,10 +36,10 @@ static int kernel_fips_mode(void)
+ 		close(fd);
+ 	}
+ 
+-	return (buf[0] == '1') ? 1 : 0;
++	return (buf[0] == '1');
+ }
+ 
+-int crypt_fips_mode(void)
++bool crypt_fips_mode(void)
+ {
+ 	return kernel_fips_mode() && !access("/etc/system-fips", F_OK);
+ }
+diff --git a/lib/utils_fips.h b/lib/utils_fips.h
+index 51b110b5..13cfc9fb 100644
+--- a/lib/utils_fips.h
++++ b/lib/utils_fips.h
+@@ -21,6 +21,8 @@
+ #ifndef _UTILS_FIPS_H
+ #define _UTILS_FIPS_H
+ 
+-int crypt_fips_mode(void);
++#include <stdbool.h>
++
++bool crypt_fips_mode(void);
+ 
+ #endif /* _UTILS_FIPS_H */
+diff --git a/tests/crypto-vectors.c b/tests/crypto-vectors.c
+index 025585de..6484e97a 100644
+--- a/tests/crypto-vectors.c
++++ b/tests/crypto-vectors.c
+@@ -1301,7 +1301,7 @@ int main(__attribute__ ((unused)) int argc, __attribute__ ((unused))char *argv[]
+ 		exit(77);
+ 	}
+ 
+-	if (crypt_backend_init())
++	if (crypt_backend_init(fips_mode()))
+ 		exit_test("Crypto backend init error.", EXIT_FAILURE);
+ 
+ 	printf("Test vectors using %s crypto backend.\n", crypt_backend_version());
+-- 
+2.27.0
+
diff --git a/SOURCES/cryptsetup-2.4.1-OpenSSL-backend-make-legacy-for-OpenSSL3-optional-an.patch b/SOURCES/cryptsetup-2.4.1-OpenSSL-backend-make-legacy-for-OpenSSL3-optional-an.patch
new file mode 100644
index 0000000..060b1ef
--- /dev/null
+++ b/SOURCES/cryptsetup-2.4.1-OpenSSL-backend-make-legacy-for-OpenSSL3-optional-an.patch
@@ -0,0 +1,100 @@
+From 29ea07ef66be59c8ab62058b2ce3e92765e2be10 Mon Sep 17 00:00:00 2001
+From: Milan Broz <gmazyland@gmail.com>
+Date: Mon, 13 Sep 2021 14:48:15 +0200
+Subject: [PATCH 02/11] OpenSSL backend: make legacy for OpenSSL3 optional and
+ report loaded providers
+
+---
+ lib/crypto_backend/crypto_openssl.c | 48 +++++++++++++++++++----------
+ 1 file changed, 32 insertions(+), 16 deletions(-)
+
+diff --git a/lib/crypto_backend/crypto_openssl.c b/lib/crypto_backend/crypto_openssl.c
+index a5ec4048..92eeb33c 100644
+--- a/lib/crypto_backend/crypto_openssl.c
++++ b/lib/crypto_backend/crypto_openssl.c
+@@ -45,6 +45,7 @@
+ static OSSL_PROVIDER *ossl_legacy = NULL;
+ static OSSL_PROVIDER *ossl_default = NULL;
+ static OSSL_LIB_CTX  *ossl_ctx = NULL;
++static char backend_version[256] = "OpenSSL";
+ #endif
+ 
+ #define CONST_CAST(x) (x)(uintptr_t)
+@@ -133,12 +134,30 @@ static void HMAC_CTX_free(HMAC_CTX *md)
+ 	free(md);
+ }
+ #else
++static void openssl_backend_exit(void)
++{
++#if OPENSSL_VERSION_MAJOR >= 3
++	if (ossl_legacy)
++		OSSL_PROVIDER_unload(ossl_legacy);
++	if (ossl_default)
++		OSSL_PROVIDER_unload(ossl_default);
++	if (ossl_ctx)
++		OSSL_LIB_CTX_free(ossl_ctx);
++
++	ossl_legacy = NULL;
++	ossl_default = NULL;
++	ossl_ctx = NULL;
++#endif
++}
++
+ static int openssl_backend_init(void)
+ {
+ /*
+  * OpenSSL >= 3.0.0 provides some algorithms in legacy provider
+  */
+ #if OPENSSL_VERSION_MAJOR >= 3
++	int r;
++
+ 	ossl_ctx = OSSL_LIB_CTX_new();
+ 	if (!ossl_ctx)
+ 		return -EINVAL;
+@@ -151,30 +170,27 @@ static int openssl_backend_init(void)
+ 
+ 	/* Optional */
+ 	ossl_legacy = OSSL_PROVIDER_try_load(ossl_ctx, "legacy", 0);
++
++	r = snprintf(backend_version, sizeof(backend_version), "%s %s%s",
++		OpenSSL_version(OPENSSL_VERSION),
++		ossl_default ? "[default]" : "",
++		ossl_legacy  ? "[legacy]" : "");
++	if (r < 0 || (size_t)r >= sizeof(backend_version)) {
++		openssl_backend_exit();
++		return -EINVAL;
++	}
+ #endif
+ 	return 0;
+ }
+ 
+-static void openssl_backend_exit(void)
++static const char *openssl_backend_version(void)
+ {
+ #if OPENSSL_VERSION_MAJOR >= 3
+-	if (ossl_legacy)
+-		OSSL_PROVIDER_unload(ossl_legacy);
+-	if (ossl_default)
+-		OSSL_PROVIDER_unload(ossl_default);
+-	if (ossl_ctx)
+-		OSSL_LIB_CTX_free(ossl_ctx);
+-
+-	ossl_legacy = NULL;
+-	ossl_default = NULL;
+-	ossl_ctx = NULL;
++	return backend_version;
++#else
++	return OpenSSL_version(OPENSSL_VERSION);
+ #endif
+ }
+-
+-static const char *openssl_backend_version(void)
+-{
+-    return OpenSSL_version(OPENSSL_VERSION);
+-}
+ #endif
+ 
+ int crypt_backend_init(void)
+-- 
+2.27.0
+
diff --git a/SOURCES/cryptsetup-add-system-library-paths.patch b/SOURCES/cryptsetup-add-system-library-paths.patch
new file mode 100644
index 0000000..0a5d753
--- /dev/null
+++ b/SOURCES/cryptsetup-add-system-library-paths.patch
@@ -0,0 +1,22 @@
+diff -rupN cryptsetup-2.2.0.old/configure cryptsetup-2.2.0/configure
+--- cryptsetup-2.2.0.old/configure	2019-08-14 20:45:07.000000000 +0200
++++ cryptsetup-2.2.0/configure	2019-08-15 09:11:14.775184005 +0200
+@@ -12294,6 +12294,9 @@ fi
+   # before this can be enabled.
+   hardcode_into_libs=yes
+ 
++  # Add ABI-specific directories to the system library path.
++  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
++
+   # Ideally, we could use ldconfig to report *all* directores which are
+   # searched for libraries, however this is still not possible.  Aside from not
+   # being certain /sbin/ldconfig is available, command
+@@ -12302,7 +12305,7 @@ fi
+   # appending ld.so.conf contents (and includes) to the search path.
+   if test -f /etc/ld.so.conf; then
+     lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+-    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
++    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+   fi
+ 
+   # We used to test for /lib/ld.so.1 and disable shared libraries on
diff --git a/SPECS/cryptsetup.spec b/SPECS/cryptsetup.spec
new file mode 100644
index 0000000..3d879b5
--- /dev/null
+++ b/SPECS/cryptsetup.spec
@@ -0,0 +1,158 @@
+Summary: Utility for setting up encrypted disks
+Name: cryptsetup
+Version: 2.4.0
+Release: 2%{?dist}
+License: GPLv2+ and LGPLv2+
+URL: https://gitlab.com/cryptsetup/cryptsetup
+BuildRequires: openssl-devel, popt-devel, device-mapper-devel
+BuildRequires: libuuid-devel, gcc, json-c-devel
+BuildRequires: libpwquality-devel, libblkid-devel
+BuildRequires: make
+Requires: cryptsetup-libs = %{version}-%{release}
+Requires: libpwquality >= 1.2.0
+
+%global upstream_version %{version}
+Source0: https://www.kernel.org/pub/linux/utils/cryptsetup/v2.4/cryptsetup-%{upstream_version}.tar.xz
+# Following patch has to applied last
+Patch0000: %{name}-2.4.1-Adapt-crypto-backend-to-openssl3-lib-context.patch
+Patch0001: %{name}-2.4.1-OpenSSL-backend-make-legacy-for-OpenSSL3-optional-an.patch
+Patch0002: %{name}-2.4.1-Do-not-load-own-OpenSSL-backend-context-in-FIPS-mode.patch
+Patch0003: %{name}-2.4.1-Cache-FIPS-mode-check.patch
+Patch9999: %{name}-add-system-library-paths.patch
+
+%description
+The cryptsetup package contains a utility for setting up
+disk encryption using dm-crypt kernel module.
+
+%package devel
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Requires: pkgconfig
+Summary: Headers and libraries for using encrypted file systems
+
+%description devel
+The cryptsetup-devel package contains libraries and header files
+used for writing code that makes use of disk encryption.
+
+%package libs
+Summary: Cryptsetup shared library
+
+%description libs
+This package contains the cryptsetup shared library, libcryptsetup.
+
+%package -n veritysetup
+Summary: A utility for setting up dm-verity volumes
+Requires: cryptsetup-libs = %{version}-%{release}
+
+%description -n veritysetup
+The veritysetup package contains a utility for setting up
+disk verification using dm-verity kernel module.
+
+%package -n integritysetup
+Summary: A utility for setting up dm-integrity volumes
+Requires: cryptsetup-libs = %{version}-%{release}
+
+%description -n integritysetup
+The integritysetup package contains a utility for setting up
+disk integrity protection using dm-integrity kernel module.
+
+%package reencrypt
+Summary: A utility for offline reencryption of LUKS encrypted disks
+Requires: cryptsetup-libs = %{version}-%{release}
+
+%description reencrypt
+This package contains cryptsetup-reencrypt utility which
+can be used for offline reencryption of disk in situ.
+
+%prep
+%autosetup -n cryptsetup-%{upstream_version} -p 1
+chmod -x misc/dracut_90reencrypt/*
+
+%build
+%configure --enable-fips --enable-pwquality --enable-internal-sse-argon2 --disable-ssh-token
+%make_build
+
+%install
+%make_install
+rm -rf %{buildroot}%{_libdir}/*.la
+
+%find_lang cryptsetup
+
+%ldconfig_scriptlets -n cryptsetup-libs
+
+%files
+%license COPYING
+%doc AUTHORS FAQ docs/*ReleaseNotes
+%{_mandir}/man8/cryptsetup.8.gz
+%{_sbindir}/cryptsetup
+
+%files -n veritysetup
+%license COPYING
+%{_mandir}/man8/veritysetup.8.gz
+%{_sbindir}/veritysetup
+
+%files -n integritysetup
+%license COPYING
+%{_mandir}/man8/integritysetup.8.gz
+%{_sbindir}/integritysetup
+
+%files reencrypt
+%license COPYING
+%doc misc/dracut_90reencrypt
+%{_mandir}/man8/cryptsetup-reencrypt.8.gz
+%{_sbindir}/cryptsetup-reencrypt
+
+%files devel
+%doc docs/examples/*
+%{_includedir}/libcryptsetup.h
+%{_libdir}/libcryptsetup.so
+%{_libdir}/pkgconfig/libcryptsetup.pc
+
+%files libs -f cryptsetup.lang
+%license COPYING COPYING.LGPL
+%{_libdir}/libcryptsetup.so.*
+%dir %{_libdir}/%{name}/
+%{_tmpfilesdir}/cryptsetup.conf
+%ghost %attr(700, -, -) %dir /run/cryptsetup
+
+%changelog
+* Thu Sep 09 2021 Ondrej Kozina <okozina@redhat.com> - 2.4.0-2
+- Fix openssl crypto backend teardown in library destructor
+  Resolves: #1998921
+
+* Thu Aug 19 2021 Ondrej Kozina <okozina@redhat.com> - 2.4.0-1
+- Update to cryptsetup 2.4.0.
+  Resolves: #1869553 #1972722 #1974271 #1975799
+
+* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.3.6-3
+- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
+  Related: rhbz#1991688
+
+* Thu Jun 17 2021 Mohan Boddu <mboddu@redhat.com> - 2.3.6-2
+- Specbump for openssl 3.0
+  Related: rhbz#1971065
+
+* Wed Jun 16 2021 Ondrej Kozina <okozina@redhat.com> - 2.3.6-1
+- Update to cryptsetup 2.3.6.
+- Resolves: #1961291 #1970932
+
+* Tue Jun 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.3.5-5
+- Rebuilt for RHEL 9 BETA for openssl 3.0
+
+Related: rhbz#1971065
+
+* Tue Apr 27 2021 Ondrej Kozina <okozina@redhat.com> - 2.3.5-4
+- Drop dependency on libargon2
+- Resolves: #1936959
+
+* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.3.5-3
+- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
+
+* Thu Mar 11 2021 Milan Broz <gmazyland@gmail.com> - 2.3.5-1
+- Update to cryptsetup 2.3.5.
+
+* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.3.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
+
+* Thu Sep 03 2020 Milan Broz <gmazyland@gmail.com> - 2.3.4-1
+- Update to cryptsetup 2.3.4.
+- Fix for CVE-2020-14382 (#1874712)