diff --git a/SOURCES/0002-Don-t-assume-end-of-argv-is-NULL.patch b/SOURCES/0002-Don-t-assume-end-of-argv-is-NULL.patch
new file mode 100644
index 0000000..4bc3186
--- /dev/null
+++ b/SOURCES/0002-Don-t-assume-end-of-argv-is-NULL.patch
@@ -0,0 +1,46 @@
+From 3520df21494727e5dcde19e079d06d8d9899c7f1 Mon Sep 17 00:00:00 2001
+From: Erik Larsson <who+github@cnackers.org>
+Date: Sat, 21 Nov 2020 10:59:13 +0100
+Subject: [PATCH 01/17] Don't assume end of argv is NULL
+
+On a musl based system argv[optind] && strcmp(...) where optind > argc might read random memory and segfault.
+
+Signed-off-by: Erik Larsson <who+github@cnackers.org>
+---
+ lib/tpm2_options.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/lib/tpm2_options.c b/lib/tpm2_options.c
+index e9aaa036..9fa583c6 100644
+--- a/lib/tpm2_options.c
++++ b/lib/tpm2_options.c
+@@ -300,7 +300,7 @@ tpm2_option_code tpm2_handle_options(int argc, char **argv,
+             if (argv[optind - 1]) {
+                 if (!strcmp(argv[optind - 1], "--help=no-man") ||
+                     !strcmp(argv[optind - 1], "-h=no-man") ||
+-                    (argv[optind] && !strcmp(argv[optind], "no-man"))) {
++                    (argc < optind && !strcmp(argv[optind], "no-man"))) {
+                     manpager = false;
+                     optind++;
+                 /*
+@@ -309,7 +309,7 @@ tpm2_option_code tpm2_handle_options(int argc, char **argv,
+                  */
+                 } else if (!strcmp(argv[optind - 1], "--help=man") ||
+                            !strcmp(argv[optind - 1], "-h=man") ||
+-                           (argv[optind] && !strcmp(argv[optind], "man"))) {
++                           (argc < optind && !strcmp(argv[optind], "man"))) {
+                     manpager = true;
+                     explicit_manpager = true;
+                     optind++;
+@@ -318,7 +318,7 @@ tpm2_option_code tpm2_handle_options(int argc, char **argv,
+                      * argv[0] = "tool name"
+                      * argv[1] = "--help" argv[2] = 0
+                      */
+-                    if (!argv[optind] && argc == 2) {
++                    if (optind >= argc && argc == 2) {
+                         manpager = false;
+                     } else {
+                         /*
+-- 
+2.31.1
+
diff --git a/SOURCES/0003-tpm2_options-fix-possible-null-ptr-passed-to-strdup.patch b/SOURCES/0003-tpm2_options-fix-possible-null-ptr-passed-to-strdup.patch
new file mode 100644
index 0000000..b3deac9
--- /dev/null
+++ b/SOURCES/0003-tpm2_options-fix-possible-null-ptr-passed-to-strdup.patch
@@ -0,0 +1,31 @@
+From 2a064f4c91a90ab95fe354a42e1166a4c64452fb Mon Sep 17 00:00:00 2001
+From: William Roberts <william.c.roberts@intel.com>
+Date: Wed, 25 Nov 2020 07:48:44 -0600
+Subject: [PATCH 02/17] tpm2_options: fix possible null ptr passed to strdup
+
+Fixes:
+../lib/tpm2_options.c:201:20: warning: Null pointer passed as an argument to a 'nonnull' parameter
+    command_copy = strdup(command);
+
+Signed-off-by: William Roberts <william.c.roberts@intel.com>
+---
+ lib/tpm2_options.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/lib/tpm2_options.c b/lib/tpm2_options.c
+index 9fa583c6..c2e18bad 100644
+--- a/lib/tpm2_options.c
++++ b/lib/tpm2_options.c
+@@ -193,8 +193,7 @@ void tpm2_print_usage(const char *command, struct tpm2_options *tool_opts) {
+     unsigned int i;
+     bool indent = true;
+     char *command_copy;
+-
+-    if (!tool_opts) {
++    if (!tool_opts || !command) {
+         return;
+     }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0004-tpm2_identity_util-move-create_name-into-utility-lib.patch b/SOURCES/0004-tpm2_identity_util-move-create_name-into-utility-lib.patch
new file mode 100644
index 0000000..ae72fb7
--- /dev/null
+++ b/SOURCES/0004-tpm2_identity_util-move-create_name-into-utility-lib.patch
@@ -0,0 +1,143 @@
+From 6a3100ad060934228a1bec06ae43b41f5ea8a51b Mon Sep 17 00:00:00 2001
+From: Trammell hudson <hudson@trmm.net>
+Date: Fri, 26 Mar 2021 17:23:07 +0000
+Subject: [PATCH 03/17] tpm2_identity_util: move create_name() into utility
+ library
+
+Signed-off-by: Trammell Hudson <hudson@trmm.net>
+---
+ lib/tpm2_identity_util.c | 40 ++++++++++++++++++++++++++++++++++++++
+ lib/tpm2_identity_util.h | 10 ++++++++++
+ tools/tpm2_import.c      | 42 +---------------------------------------
+ 3 files changed, 51 insertions(+), 41 deletions(-)
+
+diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
+index a3b0e387..e11137ab 100644
+--- a/lib/tpm2_identity_util.c
++++ b/lib/tpm2_identity_util.c
+@@ -423,3 +423,43 @@ void tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+             encrypted_duplicate_sensitive->size, pubname->name, pubname->size,
+             protection_hmac_key->buffer, outer_hmac);
+ }
++
++bool tpm2_identity_create_name(TPM2B_PUBLIC *public, TPM2B_NAME *pubname) {
++
++    /*
++     * A TPM2B_NAME is the name of the algorithm, followed by the hash.
++     * Calculate the name by:
++     * 1. Marshaling the name algorithm
++     * 2. Marshaling the TPMT_PUBLIC past the name algorithm from step 1.
++     * 3. Hash the TPMT_PUBLIC portion in marshaled data.
++     */
++
++    TPMI_ALG_HASH name_alg = public->publicArea.nameAlg;
++
++    // Step 1 - set beginning of name to hash alg
++    size_t hash_offset = 0;
++    Tss2_MU_UINT16_Marshal(name_alg, pubname->name, pubname->size,
++            &hash_offset);
++
++    // Step 2 - marshal TPMTP
++    TPMT_PUBLIC marshaled_tpmt;
++    size_t tpmt_marshalled_size = 0;
++    Tss2_MU_TPMT_PUBLIC_Marshal(&public->publicArea,
++            (uint8_t *) &marshaled_tpmt, sizeof(public->publicArea),
++            &tpmt_marshalled_size);
++
++    // Step 3 - Hash the data into name just past the alg type.
++    digester d = tpm2_openssl_halg_to_digester(name_alg);
++    if (!d) {
++        return false;
++    }
++
++    d((const unsigned char *) &marshaled_tpmt, tpmt_marshalled_size,
++            pubname->name + hash_offset);
++
++    //Set the name size, UINT16 followed by HASH
++    UINT16 hash_size = tpm2_alg_util_get_hash_size(name_alg);
++    pubname->size = hash_size + hash_offset;
++
++    return true;
++}
+diff --git a/lib/tpm2_identity_util.h b/lib/tpm2_identity_util.h
+index 0ac55793..61e10376 100644
+--- a/lib/tpm2_identity_util.h
++++ b/lib/tpm2_identity_util.h
+@@ -102,4 +102,14 @@ void tpm2_identity_util_calculate_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+         TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive,
+         TPM2B_DIGEST *outer_hmac);
+ 
++/**
++ * Computes the name of a TPM key.
++ *
++ * @param public
++ *  Public key structure
++ * @param pubname
++ *  The name structure to populate.
++ */
++bool tpm2_identity_create_name(TPM2B_PUBLIC *public, TPM2B_NAME *pubname);
++
+ #endif /* LIB_TPM2_IDENTITY_UTIL_H_ */
+diff --git a/tools/tpm2_import.c b/tools/tpm2_import.c
+index eb8dd9a7..a5d1b4e6 100644
+--- a/tools/tpm2_import.c
++++ b/tools/tpm2_import.c
+@@ -74,46 +74,6 @@ static tool_rc readpublic(ESYS_CONTEXT *ectx, ESYS_TR handle,
+     return tpm2_readpublic(ectx, handle, public, NULL, NULL);
+ }
+ 
+-static bool create_name(TPM2B_PUBLIC *public, TPM2B_NAME *pubname) {
+-
+-    /*
+-     * A TPM2B_NAME is the name of the algorithm, followed by the hash.
+-     * Calculate the name by:
+-     * 1. Marshaling the name algorithm
+-     * 2. Marshaling the TPMT_PUBLIC past the name algorithm from step 1.
+-     * 3. Hash the TPMT_PUBLIC portion in marshaled data.
+-     */
+-
+-    TPMI_ALG_HASH name_alg = public->publicArea.nameAlg;
+-
+-    // Step 1 - set beginning of name to hash alg
+-    size_t hash_offset = 0;
+-    Tss2_MU_UINT16_Marshal(name_alg, pubname->name, pubname->size,
+-            &hash_offset);
+-
+-    // Step 2 - marshal TPMTP
+-    TPMT_PUBLIC marshaled_tpmt;
+-    size_t tpmt_marshalled_size = 0;
+-    Tss2_MU_TPMT_PUBLIC_Marshal(&public->publicArea,
+-            (uint8_t *) &marshaled_tpmt, sizeof(public->publicArea),
+-            &tpmt_marshalled_size);
+-
+-    // Step 3 - Hash the data into name just past the alg type.
+-    digester d = tpm2_openssl_halg_to_digester(name_alg);
+-    if (!d) {
+-        return false;
+-    }
+-
+-    d((const unsigned char *) &marshaled_tpmt, tpmt_marshalled_size,
+-            pubname->name + 2);
+-
+-    //Set the name size, UINT16 followed by HASH
+-    UINT16 hash_size = tpm2_alg_util_get_hash_size(name_alg);
+-    pubname->size = hash_size + 2;
+-
+-    return true;
+-}
+-
+ static void create_import_key_private_data(TPM2B_PRIVATE *private,
+         TPMI_ALG_HASH parent_name_alg,
+         TPM2B_MAX_BUFFER *encrypted_duplicate_sensitive,
+@@ -155,7 +115,7 @@ static tool_rc key_import(ESYS_CONTEXT *ectx, TPM2B_PUBLIC *parent_pub,
+      * Calculate the object name.
+      */
+     TPM2B_NAME pubname = TPM2B_TYPE_INIT(TPM2B_NAME, name);
+-    bool res = create_name(pubkey, &pubname);
++    bool res = tpm2_identity_create_name(pubkey, &pubname);
+     if (!res) {
+         return false;
+     }
+-- 
+2.31.1
+
diff --git a/SOURCES/0005-openssl-Remove-support-for-OpenSSL-1.1.0.patch b/SOURCES/0005-openssl-Remove-support-for-OpenSSL-1.1.0.patch
new file mode 100644
index 0000000..d7721ed
--- /dev/null
+++ b/SOURCES/0005-openssl-Remove-support-for-OpenSSL-1.1.0.patch
@@ -0,0 +1,254 @@
+From 61989b4c0a2da337a5c8df56e68c83e73259ed75 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 11:39:52 +0200
+Subject: [PATCH 04/17] openssl: Remove support for OpenSSL < 1.1.0
+
+The OpenSSL 1.0.2 is no longer maintained. Supporting an EOL crypto
+library is not a good idea.
+
+ - Compared to the upstream commit 1e439d85 changes related to functions
+   and features not previously backported were ommited.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ configure.ac       |  2 +-
+ doc/CHANGELOG.md   |  5 +++
+ doc/INSTALL.md     |  2 +-
+ doc/RELEASE.md     |  7 ----
+ lib/tpm2_openssl.c | 87 ----------------------------------------------
+ lib/tpm2_openssl.h | 10 ------
+ 6 files changed, 7 insertions(+), 106 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index a3988e15..9561fa86 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -58,7 +58,7 @@ PKG_CHECK_MODULES([TSS2_TCTILDR], [tss2-tctildr])
+ PKG_CHECK_MODULES([TSS2_MU], [tss2-mu])
+ PKG_CHECK_MODULES([TSS2_RC], [tss2-rc])
+ PKG_CHECK_MODULES([TSS2_SYS], [tss2-sys])
+-PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.0.2g])
++PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.1.0])
+ PKG_CHECK_MODULES([CURL], [libcurl])
+ PKG_CHECK_MODULES([UUID], [uuid])
+ 
+diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md
+index 87573fd7..b244dfee 100644
+--- a/doc/CHANGELOG.md
++++ b/doc/CHANGELOG.md
+@@ -1,5 +1,10 @@
+ ## Changelog
+ 
++### next
++
++  * openssl:
++      - Dropped support for OpenSSL < 1.1.0
++
+ ### 5.0 - 2020-11-16
+ 
+ #### Non Backwards Compatible Changes
+diff --git a/doc/INSTALL.md b/doc/INSTALL.md
+index b23b8d61..ab160581 100644
+--- a/doc/INSTALL.md
++++ b/doc/INSTALL.md
+@@ -19,7 +19,7 @@ To build and install the tpm2-tools software the following software is required:
+   * C compiler
+   * C Library Development Libraries and Header Files (for pthreads headers)
+   * ESAPI - TPM2.0 TSS ESAPI library (tss2-esys) and header files
+-  * OpenSSL libcrypto library and header files
++  * OpenSSL libcrypto library and header files (version >= 1.1.0)
+   * Curl library and header files
+   * Universally Unique ID library (UUID)
+ 
+diff --git a/doc/RELEASE.md b/doc/RELEASE.md
+index e2c72a67..8769b57d 100644
+--- a/doc/RELEASE.md
++++ b/doc/RELEASE.md
+@@ -23,13 +23,6 @@ the next release.
+ - [3.0.X](https://github.com/tpm2-software/tpm2-tools/tree/3.0.X): EOL after
+ 3.2.1 release.
+ 
+-## OpenSSL
+-
+-tpm2-tools relies heavily on OpenSSL. OpenSSL will be EOL'ing 1.0.2 at the end
+-of 2019, see: https://www.openssl.org/blog/blog/2018/05/18/new-lts/. When this
+-occurs, we will remove OSSL 1.0.2 support from the tpm2-tools repository as
+-supporting an EOL crypto library is not a good idea.
+-
+ # Release Information
+ 
+ Releases shall be tagged following semantic version guidelines found at:
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index e769d6df..877d2764 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -72,58 +72,6 @@ const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm) {
+     /* no return, not possible */
+ }
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) {
+-
+-    if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL)) {
+-        return 0;
+-    }
+-
+-    if (n != NULL) {
+-        BN_free(r->n);
+-        r->n = n;
+-    }
+-
+-    if (e != NULL) {
+-        BN_free(r->e);
+-        r->e = e;
+-    }
+-
+-    if (d != NULL) {
+-        BN_free(r->d);
+-        r->d = d;
+-    }
+-
+-    return 1;
+-}
+-
+-void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) {
+-    if(p) {
+-        *p = r->p;
+-    }
+-
+-    if (q) {
+-        *q = r->q;
+-    }
+-}
+-
+-int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
+-
+-    if (!r || !s) {
+-        return 0;
+-    }
+-
+-    BN_clear_free(sig->r);
+-    BN_clear_free(sig->s);
+-
+-    sig->r = r;
+-    sig->s = s;
+-
+-    return 1;
+-}
+-
+-#endif
+-
+ bool tpm2_openssl_hash_compute_data(TPMI_ALG_HASH halg, BYTE *buffer,
+         UINT16 length, TPM2B_DIGEST *digest) {
+ 
+@@ -422,54 +370,28 @@ out:
+ 
+ HMAC_CTX *tpm2_openssl_hmac_new() {
+     HMAC_CTX *ctx;
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    ctx = malloc(sizeof(*ctx));
+-#else
+     ctx = HMAC_CTX_new();
+-#endif
+     if (!ctx)
+         return NULL;
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    HMAC_CTX_init(ctx);
+-#endif
+-
+     return ctx;
+ }
+ 
+ void tpm2_openssl_hmac_free(HMAC_CTX *ctx) {
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    HMAC_CTX_cleanup(ctx);
+-    free(ctx);
+-#else
+     HMAC_CTX_free(ctx);
+-#endif
+ }
+ 
+ EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void) {
+     EVP_CIPHER_CTX *ctx;
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    ctx = malloc(sizeof(*ctx));
+-#else
+     ctx = EVP_CIPHER_CTX_new();
+-#endif
+     if (!ctx)
+         return NULL;
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    EVP_CIPHER_CTX_init(ctx);
+-#endif
+-
+     return ctx;
+ }
+ 
+ void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx) {
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    EVP_CIPHER_CTX_cleanup(ctx);
+-    free(ctx);
+-#else
+     EVP_CIPHER_CTX_free(ctx);
+-#endif
+ }
+ 
+ digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) {
+@@ -680,12 +602,7 @@ static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {
+     const BIGNUM *n; /* modulus */
+     const BIGNUM *e; /* public key exponent */
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    n = k->n;
+-    e = k->e;
+-#else
+     RSA_get0_key(k, &n, &e, NULL);
+-#endif
+ 
+     /*
+      * The size of the modulus is the key size in RSA, store this as the
+@@ -1006,11 +923,7 @@ static bool load_private_RSA_from_key(RSA *k, TPM2B_SENSITIVE *priv) {
+ 
+     const BIGNUM *p; /* the private key exponent */
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-    p = k->p;
+-#else
+     RSA_get0_factors(k, &p, NULL);
+-#endif
+ 
+     TPMT_SENSITIVE *sa = &priv->sensitiveArea;
+ 
+diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h
+index 46c8f9c0..8e3e0c17 100644
+--- a/lib/tpm2_openssl.h
++++ b/lib/tpm2_openssl.h
+@@ -13,10 +13,6 @@
+ 
+ #include "pcr.h"
+ 
+-#if (OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(LIBRESSL_VERSION_NUMBER)) || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L) /* OpenSSL 1.1.0 */
+-#define LIB_TPM2_OPENSSL_OPENSSL_PRE11
+-#endif
+-
+ #if OPENSSL_VERSION_NUMBER >= 0x10101000L
+ #define EC_POINT_set_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \
+         EC_POINT_set_affine_coordinates(group, tpm_pub_key, bn_x, bn_y, dmy)
+@@ -32,12 +28,6 @@
+         EC_POINT_get_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy)
+ #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */
+ 
+-#if defined(LIB_TPM2_OPENSSL_OPENSSL_PRE11)
+-int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+-void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+-int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+-#endif
+-
+ /**
+  * Function prototype for a hashing routine.
+  *
+-- 
+2.31.1
+
diff --git a/SOURCES/0006-openssl-Remove-functions-that-have-no-effect-in-Open.patch b/SOURCES/0006-openssl-Remove-functions-that-have-no-effect-in-Open.patch
new file mode 100644
index 0000000..41c0216
--- /dev/null
+++ b/SOURCES/0006-openssl-Remove-functions-that-have-no-effect-in-Open.patch
@@ -0,0 +1,48 @@
+From 8c1968a1e52c3d45a96509e9eba753357ad377c9 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 11:45:14 +0200
+Subject: [PATCH 05/17] openssl: Remove functions that have no effect in
+ OpenSSL >= 1.1.0
+
+This will work with OpenSSL 1.1.0 through 3.0.0.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_convert.c | 1 -
+ tools/tpm2_tool.c  | 8 --------
+ 2 files changed, 9 deletions(-)
+
+diff --git a/lib/tpm2_convert.c b/lib/tpm2_convert.c
+index 27a0effe..cc1c18ab 100644
+--- a/lib/tpm2_convert.c
++++ b/lib/tpm2_convert.c
+@@ -262,7 +262,6 @@ static bool tpm2_convert_pubkey_bio(TPMT_PUBLIC *public,
+                 "Unsupported key type for requested output format. Only RSA is supported.");
+     }
+ 
+-    ERR_free_strings();
+     return result;
+ }
+ 
+diff --git a/tools/tpm2_tool.c b/tools/tpm2_tool.c
+index f4865266..edd04c83 100644
+--- a/tools/tpm2_tool.c
++++ b/tools/tpm2_tool.c
+@@ -230,14 +230,6 @@ int main(int argc, char **argv) {
+         tpm2_errata_init(ctx.ectx);
+     }
+ 
+-    /*
+-     * Load the openssl error strings and algorithms
+-     * so library routines work as expected.
+-     */
+-    OpenSSL_add_all_algorithms();
+-    OpenSSL_add_all_ciphers();
+-    ERR_load_crypto_strings();
+-
+     /*
+      * Call the specific tool, all tools implement this function instead of
+      * 'main'.
+-- 
+2.31.1
+
diff --git a/SOURCES/0007-openssl-Remove-unnecesary-EVP_CIPHER_CTX-and-HMAC_CT.patch b/SOURCES/0007-openssl-Remove-unnecesary-EVP_CIPHER_CTX-and-HMAC_CT.patch
new file mode 100644
index 0000000..6a2d105
--- /dev/null
+++ b/SOURCES/0007-openssl-Remove-unnecesary-EVP_CIPHER_CTX-and-HMAC_CT.patch
@@ -0,0 +1,150 @@
+From 43ad483907069798920a949a3cc9615cb3156975 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 11:56:22 +0200
+Subject: [PATCH 06/17] openssl: Remove unnecesary EVP_CIPHER_CTX and HMAC_CTX
+ wrappers
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_identity_util.c |  7 +++++--
+ lib/tpm2_kdfa.c          |  4 ++--
+ lib/tpm2_openssl.c       | 26 --------------------------
+ lib/tpm2_openssl.h       | 31 -------------------------------
+ 4 files changed, 7 insertions(+), 61 deletions(-)
+
+diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
+index e11137ab..a268295f 100644
+--- a/lib/tpm2_identity_util.c
++++ b/lib/tpm2_identity_util.c
+@@ -289,7 +289,10 @@ static bool aes_encrypt_buffers(TPMT_SYM_DEF_OBJECT *sym,
+         return false;
+     }
+ 
+-    EVP_CIPHER_CTX *ctx = tpm2_openssl_cipher_new();
++    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
++    if (!ctx) {
++        return false;
++    }
+ 
+     int rc = EVP_EncryptInit_ex(ctx, cipher, NULL, encryption_key, iv);
+     if (!rc) {
+@@ -336,7 +339,7 @@ static bool aes_encrypt_buffers(TPMT_SYM_DEF_OBJECT *sym,
+     result = true;
+ 
+ out:
+-    tpm2_openssl_cipher_free(ctx);
++    EVP_CIPHER_CTX_free(ctx);
+ 
+     return result;
+ }
+diff --git a/lib/tpm2_kdfa.c b/lib/tpm2_kdfa.c
+index 354516e8..5747b3ca 100644
+--- a/lib/tpm2_kdfa.c
++++ b/lib/tpm2_kdfa.c
+@@ -40,7 +40,7 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+         return TPM2_RC_HASH;
+     }
+ 
+-    HMAC_CTX *ctx = tpm2_openssl_hmac_new();
++    HMAC_CTX *ctx = HMAC_CTX_new();
+     if (!ctx) {
+         LOG_ERR("HMAC context allocation failed");
+         return TPM2_RC_MEMORY;
+@@ -100,7 +100,7 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+     result_key->size = bytes;
+ 
+ err:
+-    tpm2_openssl_hmac_free(ctx);
++    HMAC_CTX_free(ctx);
+ 
+     return rval;
+ }
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index 877d2764..1752525e 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -368,32 +368,6 @@ out:
+     return result;
+ }
+ 
+-HMAC_CTX *tpm2_openssl_hmac_new() {
+-    HMAC_CTX *ctx;
+-    ctx = HMAC_CTX_new();
+-    if (!ctx)
+-        return NULL;
+-
+-    return ctx;
+-}
+-
+-void tpm2_openssl_hmac_free(HMAC_CTX *ctx) {
+-    HMAC_CTX_free(ctx);
+-}
+-
+-EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void) {
+-    EVP_CIPHER_CTX *ctx;
+-    ctx = EVP_CIPHER_CTX_new();
+-    if (!ctx)
+-        return NULL;
+-
+-    return ctx;
+-}
+-
+-void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx) {
+-    EVP_CIPHER_CTX_free(ctx);
+-}
+-
+ digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) {
+ 
+     switch (halg) {
+diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h
+index 8e3e0c17..642e4635 100644
+--- a/lib/tpm2_openssl.h
++++ b/lib/tpm2_openssl.h
+@@ -67,20 +67,6 @@ int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm);
+  */
+ const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm);
+ 
+-/**
+- * Start an openssl hmac session.
+- * @return
+- *  A valid session pointer or NULL on error.
+- */
+-HMAC_CTX *tpm2_openssl_hmac_new();
+-
+-/**
+- * Free an hmac context created via tpm2_openssl_hmac_new().
+- * @param ctx
+- *  The context to release resources of.
+- */
+-void tpm2_openssl_hmac_free(HMAC_CTX *ctx);
+-
+ /**
+  * Hash a byte buffer.
+  * @param halg
+@@ -161,23 +147,6 @@ bool tpm2_openssl_hash_pcr_banks_le(TPMI_ALG_HASH hashAlg,
+ bool tpm2_openssl_pcr_extend(TPMI_ALG_HASH halg, BYTE *pcr,
+         const BYTE *data, UINT16 length);
+ 
+-/**
+- * Obtains an OpenSSL EVP_CIPHER_CTX dealing with version
+- * API changes in OSSL.
+- *
+- * @return
+- *  An Initialized OpenSSL EVP_CIPHER_CTX.
+- */
+-EVP_CIPHER_CTX *tpm2_openssl_cipher_new(void);
+-
+-/**
+- * Free's an EVP_CIPHER_CTX obtained via tpm2_openssl_cipher_new()
+- * dealing with OSSL API version changes.
+- * @param ctx
+- *  The EVP_CIPHER_CTX to free.
+- */
+-void tpm2_openssl_cipher_free(EVP_CIPHER_CTX *ctx);
+-
+ /**
+  * Returns a function pointer capable of performing the
+  * given digest from a TPMI_HASH_ALG.
+-- 
+2.31.1
+
diff --git a/SOURCES/0008-openssl-Replace-SHA256_CTX-by-EVP_MD_CTX.patch b/SOURCES/0008-openssl-Replace-SHA256_CTX-by-EVP_MD_CTX.patch
new file mode 100644
index 0000000..c78be34
--- /dev/null
+++ b/SOURCES/0008-openssl-Replace-SHA256_CTX-by-EVP_MD_CTX.patch
@@ -0,0 +1,104 @@
+From 59f35567cf810d9eafdeedced5dc5571d9b33dfd Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 12:26:15 +0200
+Subject: [PATCH 07/17] openssl: Replace SHA256_CTX by EVP_MD_CTX
+
+The EVP_MD_CTX_new() was introduced in OpenSSL 1.1.0 and
+the SHA256_CTX was deprecated in OpenSSL 3.0.0.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ tools/tpm2_getekcertificate.c | 28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/tools/tpm2_getekcertificate.c b/tools/tpm2_getekcertificate.c
+index b480dbc3..81600b61 100644
+--- a/tools/tpm2_getekcertificate.c
++++ b/tools/tpm2_getekcertificate.c
+@@ -63,20 +63,20 @@ static unsigned char *hash_ek_public(void) {
+         return NULL;
+     }
+ 
+-    SHA256_CTX sha256;
+-    int is_success = SHA256_Init(&sha256);
++    EVP_MD_CTX *sha256 = EVP_MD_CTX_new();
++    int is_success = EVP_DigestInit(sha256, EVP_sha256());
+     if (!is_success) {
+-        LOG_ERR("SHA256_Init failed");
++        LOG_ERR("EVP_DigestInit failed");
+         goto err;
+     }
+ 
+     switch (ctx.out_public->publicArea.type) {
+     case TPM2_ALG_RSA:
+-        is_success = SHA256_Update(&sha256,
++        is_success = EVP_DigestUpdate(sha256,
+                 ctx.out_public->publicArea.unique.rsa.buffer,
+                 ctx.out_public->publicArea.unique.rsa.size);
+         if (!is_success) {
+-            LOG_ERR("SHA256_Update failed");
++            LOG_ERR("EVP_DigestUpdate failed");
+             goto err;
+         }
+ 
+@@ -85,27 +85,27 @@ static unsigned char *hash_ek_public(void) {
+             goto err;
+         }
+         BYTE buf[3] = { 0x1, 0x00, 0x01 }; // Exponent
+-        is_success = SHA256_Update(&sha256, buf, sizeof(buf));
++        is_success = EVP_DigestUpdate(sha256, buf, sizeof(buf));
+         if (!is_success) {
+-            LOG_ERR("SHA256_Update failed");
++            LOG_ERR("EVP_DigestUpdate failed");
+             goto err;
+         }
+         break;
+ 
+     case TPM2_ALG_ECC:
+-        is_success = SHA256_Update(&sha256,
++        is_success = EVP_DigestUpdate(sha256,
+                 ctx.out_public->publicArea.unique.ecc.x.buffer,
+                 ctx.out_public->publicArea.unique.ecc.x.size);
+         if (!is_success) {
+-            LOG_ERR("SHA256_Update failed");
++            LOG_ERR("EVP_DigestUpdate failed");
+             goto err;
+         }
+ 
+-        is_success = SHA256_Update(&sha256,
++        is_success = EVP_DigestUpdate(sha256,
+                 ctx.out_public->publicArea.unique.ecc.y.buffer,
+                 ctx.out_public->publicArea.unique.ecc.y.size);
+         if (!is_success) {
+-            LOG_ERR("SHA256_Update failed");
++            LOG_ERR("EVP_DigestUpdate failed");
+             goto err;
+         }
+         break;
+@@ -115,12 +115,13 @@ static unsigned char *hash_ek_public(void) {
+         goto err;
+     }
+ 
+-    is_success = SHA256_Final(hash, &sha256);
++    is_success = EVP_DigestFinal_ex(sha256, hash, NULL);
+     if (!is_success) {
+-        LOG_ERR("SHA256_Final failed");
++        LOG_ERR("EVP_DigestFinal failed");
+         goto err;
+     }
+ 
++    EVP_MD_CTX_free(sha256);
+     if (ctx.verbose) {
+         tpm2_tool_output("public-key-hash:\n");
+         tpm2_tool_output("  sha256: ");
+@@ -134,6 +135,7 @@ static unsigned char *hash_ek_public(void) {
+     return hash;
+ err:
+     free(hash);
++    EVP_MD_CTX_free(sha256);
+     return NULL;
+ }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0009-openssl-Replace-deprecated-X509_get_-by-X509_getm_.patch b/SOURCES/0009-openssl-Replace-deprecated-X509_get_-by-X509_getm_.patch
new file mode 100644
index 0000000..5ccfe2b
--- /dev/null
+++ b/SOURCES/0009-openssl-Replace-deprecated-X509_get_-by-X509_getm_.patch
@@ -0,0 +1,31 @@
+From 0dfb7b70f77ddcb8a82ca45f04e028c5fcfc350e Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 12:29:28 +0200
+Subject: [PATCH 08/17] openssl: Replace deprecated X509_get_ by X509_getm_
+
+The X509_get_notBefore() and X509_get_notAfter() were deprecated already
+in OpenSSL 1.1.0.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ tools/misc/tpm2_certifyX509certutil.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/tools/misc/tpm2_certifyX509certutil.c b/tools/misc/tpm2_certifyX509certutil.c
+index e56da2d3..62ed644a 100644
+--- a/tools/misc/tpm2_certifyX509certutil.c
++++ b/tools/misc/tpm2_certifyX509certutil.c
+@@ -260,8 +260,8 @@ static tool_rc generate_partial_X509() {
+         goto out_err;
+     }
+ 
+-    X509_gmtime_adj(X509_get_notBefore(cert), 0); // add valid not before
+-    X509_gmtime_adj(X509_get_notAfter(cert), valid_days * 86400); // add valid not after
++    X509_gmtime_adj(X509_getm_notBefore(cert), 0); // add valid not before
++    X509_gmtime_adj(X509_getm_notAfter(cert), valid_days * 86400); // add valid not after
+ 
+     X509_NAME *subject = X509_get_subject_name(cert);
+     if (!subject) {
+-- 
+2.31.1
+
diff --git a/SOURCES/0010-openssl-Convert-deprecated-SHA256-384-digesters-to-E.patch b/SOURCES/0010-openssl-Convert-deprecated-SHA256-384-digesters-to-E.patch
new file mode 100644
index 0000000..4f760b9
--- /dev/null
+++ b/SOURCES/0010-openssl-Convert-deprecated-SHA256-384-digesters-to-E.patch
@@ -0,0 +1,209 @@
+From 220b7e0afa943693a4fdafd9a5b8d9e38ea4e785 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sat, 7 Aug 2021 15:54:51 +0200
+Subject: [PATCH 09/17] openssl: Convert deprecated SHA256|384 digesters to
+ EVP_Digest
+
+The EVP_Digest function is available since OpenSSL 1.1.0
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_identity_util.c | 34 ++++++++++++++++++++++++----------
+ lib/tpm2_kdfe.c          | 13 +++++++++++--
+ lib/tpm2_openssl.c       | 17 -----------------
+ lib/tpm2_openssl.h       | 28 ----------------------------
+ lib/tpm2_util.c          | 15 +++++++++++----
+ 5 files changed, 46 insertions(+), 61 deletions(-)
+
+diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
+index a268295f..e0c3f404 100644
+--- a/lib/tpm2_identity_util.c
++++ b/lib/tpm2_identity_util.c
+@@ -391,11 +391,20 @@ bool tpm2_identity_util_calculate_inner_integrity(TPMI_ALG_HASH name_alg,
+     Tss2_MU_UINT16_Marshal(hash_size, marshalled_sensitive_and_name_digest,
+             sizeof(uint16_t), &digest_size_info);
+ 
+-    digester d = tpm2_openssl_halg_to_digester(name_alg);
+-    d(buffer_marshalled_sensitiveArea,
+-            marshalled_sensitive_size_info + marshalled_sensitive_size
+-                    + pubname->size,
+-            marshalled_sensitive_and_name_digest + digest_size_info);
++    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    if (!md) {
++        LOG_ERR("Algorithm not supported: %x", name_alg);
++        return false;
++    }
++    int rc = EVP_Digest(buffer_marshalled_sensitiveArea,
++                        marshalled_sensitive_size_info + marshalled_sensitive_size
++                            + pubname->size,
++                        marshalled_sensitive_and_name_digest + digest_size_info,
++                        NULL, md, NULL);
++    if (!rc) {
++        LOG_ERR("Hash calculation failed");
++        return false;
++    }
+ 
+     //Inner integrity
+     encrypted_inner_integrity->size = marshalled_sensitive_size_info
+@@ -452,16 +461,21 @@ bool tpm2_identity_create_name(TPM2B_PUBLIC *public, TPM2B_NAME *pubname) {
+             &tpmt_marshalled_size);
+ 
+     // Step 3 - Hash the data into name just past the alg type.
+-    digester d = tpm2_openssl_halg_to_digester(name_alg);
+-    if (!d) {
++    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    if (!md) {
++        LOG_ERR("Algorithm not supported: %x", name_alg);
+         return false;
+     }
+ 
+-    d((const unsigned char *) &marshaled_tpmt, tpmt_marshalled_size,
+-            pubname->name + hash_offset);
++    unsigned int hash_size;
++    int rc = EVP_Digest(&marshaled_tpmt, tpmt_marshalled_size,
++                        pubname->name + hash_offset, &hash_size, md, NULL);
++    if (!rc) {
++        LOG_ERR("Hash calculation failed");
++        return false;
++    }
+ 
+     //Set the name size, UINT16 followed by HASH
+-    UINT16 hash_size = tpm2_alg_util_get_hash_size(name_alg);
+     pubname->size = hash_size + hash_offset;
+ 
+     return true;
+diff --git a/lib/tpm2_kdfe.c b/lib/tpm2_kdfe.c
+index e8aeb04c..aa4d3e0b 100644
+--- a/lib/tpm2_kdfe.c
++++ b/lib/tpm2_kdfe.c
+@@ -42,13 +42,22 @@ TSS2_RC tpm2_kdfe(
+     tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_u);
+     tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_v);
+ 
+-    digester d = tpm2_openssl_halg_to_digester(hash_alg);
++    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hash_alg);
++    if (!md) {
++        LOG_ERR("Algorithm not supported: %x", hash_alg);
++        return TPM2_RC_HASH;
++    }
+ 
+     for (done = 0, counter = 1; done < bytes; done += hash_size, counter++) {
+         counter_be = tpm2_util_hton_32(counter);
+         memcpy(hash_input.buffer, &counter_be, 4);
+ 
+-        d(hash_input.buffer, hash_input.size, result_key->buffer + done);
++        int rc = EVP_Digest(hash_input.buffer, hash_input.size,
++                            result_key->buffer + done, NULL, md, NULL);
++        if (!rc) {
++            LOG_ERR("Hash calculation failed");
++            return TPM2_RC_MEMORY;
++        }
+     }
+     // truncate the result to the desired size
+     result_key->size = bytes;
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index 1752525e..cdce92f8 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -368,23 +368,6 @@ out:
+     return result;
+ }
+ 
+-digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg) {
+-
+-    switch (halg) {
+-    case TPM2_ALG_SHA1:
+-        return SHA1;
+-    case TPM2_ALG_SHA256:
+-        return SHA256;
+-    case TPM2_ALG_SHA384:
+-        return SHA384;
+-    case TPM2_ALG_SHA512:
+-        return SHA512;
+-        /* no default */
+-    }
+-
+-    return NULL;
+-}
+-
+ /*
+  * Per man openssl(1), handle the following --passin formats:
+  *     pass:password
+diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h
+index 642e4635..78cb826a 100644
+--- a/lib/tpm2_openssl.h
++++ b/lib/tpm2_openssl.h
+@@ -28,23 +28,6 @@
+         EC_POINT_get_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy)
+ #endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */
+ 
+-/**
+- * Function prototype for a hashing routine.
+- *
+- * This is a wrapper around OSSL SHA256|384 and etc digesters.
+- *
+- * @param d
+- *  The data to digest.
+- * @param n
+- *  The length of the data to digest.
+- * @param md
+- *  The output message digest.
+- * @return
+- * A pointer to the digest or NULL on error.
+- */
+-typedef unsigned char *(*digester)(const unsigned char *d, size_t n,
+-        unsigned char *md);
+-
+ static inline const char *tpm2_openssl_get_err(void) {
+     return ERR_error_string(ERR_get_error(), NULL);
+ }
+@@ -147,17 +130,6 @@ bool tpm2_openssl_hash_pcr_banks_le(TPMI_ALG_HASH hashAlg,
+ bool tpm2_openssl_pcr_extend(TPMI_ALG_HASH halg, BYTE *pcr,
+         const BYTE *data, UINT16 length);
+ 
+-/**
+- * Returns a function pointer capable of performing the
+- * given digest from a TPMI_HASH_ALG.
+- *
+- * @param halg
+- *  The hashing algorithm to use.
+- * @return
+- *  NULL on failure or a valid digester on success.
+- */
+-digester tpm2_openssl_halg_to_digester(TPMI_ALG_HASH halg);
+-
+ typedef enum tpm2_openssl_load_rc tpm2_openssl_load_rc;
+ enum tpm2_openssl_load_rc {
+     lprc_error = 0, /* an error has occurred */
+diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
+index 4125a4b9..d2c654db 100644
+--- a/lib/tpm2_util.c
++++ b/lib/tpm2_util.c
+@@ -579,13 +579,20 @@ bool tpm2_util_calc_unique(TPMI_ALG_HASH name_alg,
+     memcpy(buf.buffer, seed->buffer, seed->size);
+     memcpy(&buf.buffer[seed->size], key->buffer, key->size);
+ 
+-    digester d = tpm2_openssl_halg_to_digester(name_alg);
+-    if (!d) {
++    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    if (!md) {
++        LOG_ERR("Algorithm not supported: %x", name_alg);
+         return false;
+     }
+ 
+-    unique_data->size = tpm2_alg_util_get_hash_size(name_alg);
+-    d(buf.buffer, buf.size, unique_data->buffer);
++    unsigned int hash_size;
++    int rc = EVP_Digest(buf.buffer, buf.size, unique_data->buffer, &hash_size,
++                        md, NULL);
++    if (!rc) {
++        LOG_ERR("Hash calculation failed");
++        return false;
++    }
++    unique_data->size = hash_size;
+ 
+     return true;
+ }
+-- 
+2.31.1
+
diff --git a/SOURCES/0011-openssl-Rename-tpm2_openssl_halg_from_tpmhalg.patch b/SOURCES/0011-openssl-Rename-tpm2_openssl_halg_from_tpmhalg.patch
new file mode 100644
index 0000000..9eeaedf
--- /dev/null
+++ b/SOURCES/0011-openssl-Rename-tpm2_openssl_halg_from_tpmhalg.patch
@@ -0,0 +1,194 @@
+From b32168af24708f42a0ee28252912e3155505e983 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Tue, 10 Aug 2021 11:49:00 +0200
+Subject: [PATCH 10/17] openssl: Rename tpm2_openssl_halg_from_tpmhalg
+
+Change its name to tpm2_openssl_md_from_tpmhalg for better naming
+consistency with the openssl.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_identity_util.c     |  8 ++++----
+ lib/tpm2_kdfa.c              |  2 +-
+ lib/tpm2_kdfe.c              |  2 +-
+ lib/tpm2_openssl.c           | 12 ++++++------
+ lib/tpm2_openssl.h           |  2 +-
+ lib/tpm2_util.c              |  4 ++--
+ tools/misc/tpm2_checkquote.c |  2 +-
+ 7 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
+index e0c3f404..ba0c0e1c 100644
+--- a/lib/tpm2_identity_util.c
++++ b/lib/tpm2_identity_util.c
+@@ -134,7 +134,7 @@ static bool share_secret_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed,
+     unsigned char encoded[TPM2_MAX_DIGEST_BUFFER];
+     return_code = RSA_padding_add_PKCS1_OAEP_mgf1(encoded, mod_size,
+             protection_seed->buffer, protection_seed->size, label, label_len,
+-            tpm2_openssl_halg_from_tpmhalg(parent_name_alg), NULL);
++            tpm2_openssl_md_from_tpmhalg(parent_name_alg), NULL);
+     if (return_code != 1) {
+         LOG_ERR("Failed RSA_padding_add_PKCS1_OAEP_mgf1\n");
+         goto error;
+@@ -356,7 +356,7 @@ static void hmac_outer_integrity(TPMI_ALG_HASH parent_name_alg,
+ 
+     UINT16 hash_size = tpm2_alg_util_get_hash_size(parent_name_alg);
+ 
+-    HMAC(tpm2_openssl_halg_from_tpmhalg(parent_name_alg), hmac_key, hash_size,
++    HMAC(tpm2_openssl_md_from_tpmhalg(parent_name_alg), hmac_key, hash_size,
+             to_hmac_buffer, buffer1_size + buffer2_size,
+             outer_integrity_hmac->buffer, &size);
+     outer_integrity_hmac->size = size;
+@@ -391,7 +391,7 @@ bool tpm2_identity_util_calculate_inner_integrity(TPMI_ALG_HASH name_alg,
+     Tss2_MU_UINT16_Marshal(hash_size, marshalled_sensitive_and_name_digest,
+             sizeof(uint16_t), &digest_size_info);
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(name_alg);
+     if (!md) {
+         LOG_ERR("Algorithm not supported: %x", name_alg);
+         return false;
+@@ -461,7 +461,7 @@ bool tpm2_identity_create_name(TPM2B_PUBLIC *public, TPM2B_NAME *pubname) {
+             &tpmt_marshalled_size);
+ 
+     // Step 3 - Hash the data into name just past the alg type.
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(name_alg);
+     if (!md) {
+         LOG_ERR("Algorithm not supported: %x", name_alg);
+         return false;
+diff --git a/lib/tpm2_kdfa.c b/lib/tpm2_kdfa.c
+index 5747b3ca..c8d0a2e1 100644
+--- a/lib/tpm2_kdfa.c
++++ b/lib/tpm2_kdfa.c
+@@ -34,7 +34,7 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+ 
+     i = 1;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hash_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(hash_alg);
+     if (!md) {
+         LOG_ERR("Algorithm not supported for hmac: %x", hash_alg);
+         return TPM2_RC_HASH;
+diff --git a/lib/tpm2_kdfe.c b/lib/tpm2_kdfe.c
+index aa4d3e0b..84718b9f 100644
+--- a/lib/tpm2_kdfe.c
++++ b/lib/tpm2_kdfe.c
+@@ -42,7 +42,7 @@ TSS2_RC tpm2_kdfe(
+     tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_u);
+     tpm2_util_concat_buffer(&hash_input, (TPM2B *) party_v);
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hash_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(hash_alg);
+     if (!md) {
+         LOG_ERR("Algorithm not supported: %x", hash_alg);
+         return TPM2_RC_HASH;
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index cdce92f8..9cc362af 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -55,7 +55,7 @@ int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm) {
+     /* no return, not possible */
+ }
+ 
+-const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm) {
++const EVP_MD *tpm2_openssl_md_from_tpmhalg(TPMI_ALG_HASH algorithm) {
+ 
+     switch (algorithm) {
+     case TPM2_ALG_SHA1:
+@@ -77,7 +77,7 @@ bool tpm2_openssl_hash_compute_data(TPMI_ALG_HASH halg, BYTE *buffer,
+ 
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(halg);
+     if (!md) {
+         return false;
+     }
+@@ -121,7 +121,7 @@ bool tpm2_openssl_pcr_extend(TPMI_ALG_HASH halg, BYTE *pcr,
+ 
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(halg);
+     if (!md) {
+         return false;
+     }
+@@ -170,7 +170,7 @@ bool tpm2_openssl_hash_pcr_values(TPMI_ALG_HASH halg, TPML_DIGEST *digests,
+ 
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(halg);
+     if (!md) {
+         return false;
+     }
+@@ -222,7 +222,7 @@ bool tpm2_openssl_hash_pcr_banks(TPMI_ALG_HASH hash_alg,
+     UINT32 vi = 0, di = 0, i;
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hash_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(hash_alg);
+     if (!md) {
+         return false;
+     }
+@@ -299,7 +299,7 @@ bool tpm2_openssl_hash_pcr_banks_le(TPMI_ALG_HASH hash_alg,
+     UINT32 vi = 0, di = 0, i;
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(hash_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(hash_alg);
+     if (!md) {
+         return false;
+     }
+diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h
+index 78cb826a..b757baa5 100644
+--- a/lib/tpm2_openssl.h
++++ b/lib/tpm2_openssl.h
+@@ -48,7 +48,7 @@ int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm);
+  * @return
+  *  A pointer to a message digester or NULL on failure.
+  */
+-const EVP_MD *tpm2_openssl_halg_from_tpmhalg(TPMI_ALG_HASH algorithm);
++const EVP_MD *tpm2_openssl_md_from_tpmhalg(TPMI_ALG_HASH algorithm);
+ 
+ /**
+  * Hash a byte buffer.
+diff --git a/lib/tpm2_util.c b/lib/tpm2_util.c
+index d2c654db..c4dc68e4 100644
+--- a/lib/tpm2_util.c
++++ b/lib/tpm2_util.c
+@@ -579,7 +579,7 @@ bool tpm2_util_calc_unique(TPMI_ALG_HASH name_alg,
+     memcpy(buf.buffer, seed->buffer, seed->size);
+     memcpy(&buf.buffer[seed->size], key->buffer, key->size);
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(name_alg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(name_alg);
+     if (!md) {
+         LOG_ERR("Algorithm not supported: %x", name_alg);
+         return false;
+@@ -951,7 +951,7 @@ bool tpm2_calq_qname(TPM2B_NAME *pqname,
+     // QNB ≔ HB (QNA || NAMEB)
+     bool result = false;
+ 
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(halg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(halg);
+ 
+     EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
+     if (!mdctx) {
+diff --git a/tools/misc/tpm2_checkquote.c b/tools/misc/tpm2_checkquote.c
+index ca78238e..5e0c42a5 100644
+--- a/tools/misc/tpm2_checkquote.c
++++ b/tools/misc/tpm2_checkquote.c
+@@ -74,7 +74,7 @@ static bool verify(void) {
+     /* get the digest alg */
+     /* TODO SPlit loading on plain vs tss format to detect the hash alg */
+     /* If its a plain sig we need -g */
+-    const EVP_MD *md = tpm2_openssl_halg_from_tpmhalg(ctx.halg);
++    const EVP_MD *md = tpm2_openssl_md_from_tpmhalg(ctx.halg);
+     // TODO error handling
+ 
+     int rc = EVP_PKEY_verify_init(pkey_ctx);
+-- 
+2.31.1
+
diff --git a/SOURCES/0012-openssl-Use-EVP_MAC_update-instead-HMAC_Update-on-Op.patch b/SOURCES/0012-openssl-Use-EVP_MAC_update-instead-HMAC_Update-on-Op.patch
new file mode 100644
index 0000000..beaab9f
--- /dev/null
+++ b/SOURCES/0012-openssl-Use-EVP_MAC_update-instead-HMAC_Update-on-Op.patch
@@ -0,0 +1,103 @@
+From d67cbd4e6dc7ac83fd0c06a382a89d12f921628a Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 11:54:00 +0200
+Subject: [PATCH 11/17] openssl: Use EVP_MAC_update instead HMAC_Update on
+ OpenSSL >= 3.0.0
+
+The HMAC_Update is deprecated in OpenSSL 3.0, but the replacement
+EVP_MAC_update was added in OpenSSL 3.0, so version specific code is
+needed.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_kdfa.c | 35 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 35 insertions(+)
+
+diff --git a/lib/tpm2_kdfa.c b/lib/tpm2_kdfa.c
+index c8d0a2e1..5eb8d558 100644
+--- a/lib/tpm2_kdfa.c
++++ b/lib/tpm2_kdfa.c
+@@ -2,6 +2,13 @@
+ 
+ #include <string.h>
+ 
++#include <openssl/evp.h>
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++#include <openssl/hmac.h>
++#else
++#include <openssl/core_names.h>
++#endif
++
+ #include "log.h"
+ #include "tpm2_kdfa.h"
+ #include "tpm2_openssl.h"
+@@ -40,13 +47,27 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+         return TPM2_RC_HASH;
+     }
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+     HMAC_CTX *ctx = HMAC_CTX_new();
++#else
++    EVP_MAC *hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
++    EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(hmac);
++#endif
+     if (!ctx) {
+         LOG_ERR("HMAC context allocation failed");
+         return TPM2_RC_MEMORY;
+     }
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+     int rc = HMAC_Init_ex(ctx, key->buffer, key->size, md, NULL);
++#else
++    OSSL_PARAM params[2];
++
++    params[0] = OSSL_PARAM_construct_utf8_string(OSSL_ALG_PARAM_DIGEST,
++                                                 (char *)EVP_MD_get0_name(md), 0);
++    params[1] = OSSL_PARAM_construct_end();
++    int rc = EVP_MAC_init(ctx, key->buffer, key->size, params);
++#endif
+     if (!rc) {
+         LOG_ERR("HMAC Init failed: %s", ERR_error_string(rc, NULL));
+         rval = TPM2_RC_MEMORY;
+@@ -71,7 +92,11 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+         int c;
+         for (c = 0; c < j; c++) {
+             TPM2B_DIGEST *digest = buffer_list[c];
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+             int rc = HMAC_Update(ctx, digest->buffer, digest->size);
++#else
++            int rc = EVP_MAC_update(ctx, digest->buffer, digest->size);
++#endif
+             if (!rc) {
+                 LOG_ERR("HMAC Update failed: %s", ERR_error_string(rc, NULL));
+                 rval = TPM2_RC_MEMORY;
+@@ -79,8 +104,13 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+             }
+         }
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+         unsigned size = sizeof(tmpResult.buffer);
+         int rc = HMAC_Final(ctx, tmpResult.buffer, &size);
++#else
++        size_t size;
++        int rc = EVP_MAC_final(ctx, tmpResult.buffer, &size, sizeof(tmpResult.buffer));
++#endif
+         if (!rc) {
+             LOG_ERR("HMAC Final failed: %s", ERR_error_string(rc, NULL));
+             rval = TPM2_RC_MEMORY;
+@@ -100,7 +130,12 @@ TSS2_RC tpm2_kdfa(TPMI_ALG_HASH hash_alg, TPM2B *key, char *label,
+     result_key->size = bytes;
+ 
+ err:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+     HMAC_CTX_free(ctx);
++#else
++    EVP_MAC_CTX_free(ctx);
++    EVP_MAC_free(hmac);
++#endif
+ 
+     return rval;
+ }
+-- 
+2.31.1
+
diff --git a/SOURCES/0013-openssl-Remove-unnecessary-compatibility-function.patch b/SOURCES/0013-openssl-Remove-unnecessary-compatibility-function.patch
new file mode 100644
index 0000000..c5ca0b9
--- /dev/null
+++ b/SOURCES/0013-openssl-Remove-unnecessary-compatibility-function.patch
@@ -0,0 +1,50 @@
+From d295e6214ec4562b3940ac4a88178a260e656929 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 13:50:36 +0200
+Subject: [PATCH 12/17] openssl: Remove unnecessary compatibility function
+
+This was required for OpenSSL < 1.1.0 only.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_openssl.c | 24 ------------------------
+ 1 file changed, 24 deletions(-)
+
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index 9cc362af..ea1d6c3b 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -14,30 +14,6 @@
+ #include "tpm2_openssl.h"
+ #include "tpm2_systemdeps.h"
+ 
+-/* compatibility function for OpenSSL versions < 1.1.0 */
+-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+-static int BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) {
+-    int r;
+-    int topad;
+-    int islen;
+-
+-    islen = BN_num_bytes(a);
+-
+-    if (tolen < islen)
+-        return -1;
+-
+-    topad = tolen - islen;
+-
+-    memset(to, 0x00, topad);
+-    r = BN_bn2bin(a, to + topad);
+-    if (r == 0) {
+-        return -1;
+-    }
+-
+-    return tolen;
+-}
+-#endif
+-
+ int tpm2_openssl_halgid_from_tpmhalg(TPMI_ALG_HASH algorithm) {
+ 
+     switch (algorithm) {
+-- 
+2.31.1
+
diff --git a/SOURCES/0014-openssl-Implement-EVP_PKEY-based-key-import.patch b/SOURCES/0014-openssl-Implement-EVP_PKEY-based-key-import.patch
new file mode 100644
index 0000000..aa7851d
--- /dev/null
+++ b/SOURCES/0014-openssl-Implement-EVP_PKEY-based-key-import.patch
@@ -0,0 +1,555 @@
+From 7852dfbda959aa326de7dcd341f6e4808d918e15 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 14:01:06 +0200
+Subject: [PATCH 13/17] openssl: Implement EVP_PKEY based key import
+
+The `RSA_KEY` and `EC_KEY` are not publicly available in OpenSSL 3.0 and
+the generic `EVP_PKEY` must be used instead.
+Since import of raw keys still requires access to the internal structures
+the OpenSSL 3.0 introduced a completely new approach to access key internals.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_openssl.c | 297 ++++++++++++++++++++++++++++-----------------
+ lib/tpm2_openssl.h |  12 --
+ 2 files changed, 184 insertions(+), 125 deletions(-)
+
+diff --git a/lib/tpm2_openssl.c b/lib/tpm2_openssl.c
+index ea1d6c3b..036127c3 100644
+--- a/lib/tpm2_openssl.c
++++ b/lib/tpm2_openssl.c
+@@ -6,7 +6,11 @@
+ #include <string.h>
+ 
+ #include <openssl/pem.h>
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ #include <openssl/rand.h>
++#else
++#include <openssl/core_names.h>
++#endif
+ 
+ #include "files.h"
+ #include "log.h"
+@@ -516,8 +520,9 @@ static bool handle_ossl_pass(const char *passin, char **pass) {
+     return pfn(passin, pass);
+ }
+ 
+-static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {
++static bool load_public_RSA_from_key(EVP_PKEY *key, TPM2B_PUBLIC *pub) {
+ 
++    bool result = false;
+     TPMT_PUBLIC *pt = &pub->publicArea;
+     pt->type = TPM2_ALG_RSA;
+ 
+@@ -532,11 +537,33 @@ static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {
+     sym->keyBits.sym = 0;
+     sym->mode.sym = TPM2_ALG_NULL;
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+     const BIGNUM *n; /* modulus */
+     const BIGNUM *e; /* public key exponent */
+ 
++    RSA *k = EVP_PKEY_get0_RSA(key);
++    if (!k) {
++        LOG_ERR("Could not retrieve RSA key");
++        goto out;
++    }
++
+     RSA_get0_key(k, &n, &e, NULL);
++#else
++    BIGNUM *n = NULL; /* modulus */
++    BIGNUM *e = NULL; /* public key exponent */
++
++    int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_N, &n);
++    if (!rc) {
++        LOG_ERR("Could not read public modulus N");
++        goto out;
++    }
+ 
++    rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &e);
++    if (!rc) {
++        LOG_ERR("Could not read public exponent E");
++        goto out;
++    }
++#endif
+     /*
+      * The size of the modulus is the key size in RSA, store this as the
+      * keyBits in the RSA details.
+@@ -549,7 +576,7 @@ static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {
+         break;
+     default:
+         LOG_ERR("RSA key-size %u is not supported", rdetail->keyBits);
+-        return false;
++        goto out;
+     }
+ 
+     /* copy the modulus to the unique RSA field */
+@@ -557,47 +584,25 @@ static bool load_public_RSA_from_key(RSA *k, TPM2B_PUBLIC *pub) {
+     int success = BN_bn2bin(n, pt->unique.rsa.buffer);
+     if (!success) {
+         LOG_ERR("Could not copy public modulus N");
+-        return false;
+-    }
+-
+-    /*Make sure that we can fit the exponent into a UINT32 */
+-    unsigned e_size = BN_num_bytes(e);
+-    if (e_size > sizeof(rdetail->exponent)) {
+-        LOG_ERR(
+-                "Exponent is too big. Got %d expected less than or equal to %zu",
+-                e_size, sizeof(rdetail->exponent));
+-        return false;
+-    }
+-
+-    /*
+-     * Copy the exponent into the field.
+-     * Returns 1 on success false on error.
+-     */
+-    return BN_bn2bin(e, (unsigned char *) &rdetail->exponent);
+-}
+-
+-static RSA *tpm2_openssl_get_public_RSA_from_pem(FILE *f, const char *path) {
+-
+-    /*
+-     * Public PEM files appear in two formats:
+-     * 1. PEM format, read with PEM_read_RSA_PUBKEY
+-     * 2. PKCS#1 format, read with PEM_read_RSAPublicKey
+-     *
+-     * See:
+-     *  - https://stackoverflow.com/questions/7818117/why-i-cant-read-openssl-generated-rsa-pub-key-with-pem-read-rsapublickey
+-     */
+-    RSA *pub = PEM_read_RSA_PUBKEY(f, NULL, NULL, NULL);
+-    if (!pub) {
+-        pub = PEM_read_RSAPublicKey(f, NULL, NULL, NULL);
++        goto out;
+     }
+ 
+-    if (!pub) {
+-        ERR_print_errors_fp(stderr);
+-        LOG_ERR("Reading public PEM file \"%s\" failed", path);
+-        return NULL;
++    unsigned long exp = BN_get_word(e);
++    if (exp == 0xffffffffL) {
++        LOG_ERR("Could not copy public exponent E");
++        goto out;
+     }
++    rdetail->exponent = exp;
+ 
+-    return pub;
++    result = true;
++out:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    /* k,n,e point to internal structrues and must not be freed after use */
++#else
++    BN_free(n);
++    BN_free(e);
++#endif
++    return result;
+ }
+ 
+ static bool load_public_RSA_from_pem(FILE *f, const char *path,
+@@ -611,15 +616,19 @@ static bool load_public_RSA_from_pem(FILE *f, const char *path,
+      * See:
+      *  - https://stackoverflow.com/questions/7818117/why-i-cant-read-openssl-generated-rsa-pub-key-with-pem-read-rsapublickey
+      */
+-    RSA *k = tpm2_openssl_get_public_RSA_from_pem(f, path);
++    EVP_PKEY *k = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+     if (!k) {
+-        /* tpm2_openssl_get_public_RSA_from_pem() should already log errors */
++        ERR_print_errors_fp(stderr);
++        LOG_ERR("Reading public PEM file \"%s\" failed", path);
+         return false;
+     }
+ 
+-    bool result = load_public_RSA_from_key(k, pub);
++    bool result = false;
++    if (EVP_PKEY_base_id(k) == EVP_PKEY_RSA) {
++        result = load_public_RSA_from_key(k, pub);
++    }
+ 
+-    RSA_free(k);
++    EVP_PKEY_free(k);
+ 
+     return result;
+ }
+@@ -682,39 +691,41 @@ int tpm2_ossl_curve_to_nid(TPMI_ECC_CURVE curve) {
+     return -1;
+ }
+ 
+-static bool load_public_ECC_from_key(EC_KEY *k, TPM2B_PUBLIC *pub) {
++static bool load_public_ECC_from_key(EVP_PKEY *key, TPM2B_PUBLIC *pub) {
+ 
++    BIGNUM *y = NULL;
++    BIGNUM *x = NULL;
++    int nid;
++    unsigned keysize;
+     bool result = false;
+ 
+-    BIGNUM *y = BN_new();
+-    BIGNUM *x = BN_new();
+-    if (!x || !y) {
+-        LOG_ERR("oom");
+-        goto out;
+-    }
+-
+     /*
+      * Set the algorithm type
+      */
+     pub->publicArea.type = TPM2_ALG_ECC;
++    TPMS_ECC_PARMS *pp = &pub->publicArea.parameters.eccDetail;
+ 
+     /*
+-     * Get the curve type
++     * Get the curve type and the public key (X and Y)
+      */
+-    const EC_GROUP *group = EC_KEY_get0_group(k);
+-    int nid = EC_GROUP_get_curve_name(group);
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    EC_KEY *k = EVP_PKEY_get0_EC_KEY(key);
++    if (!k) {
++        LOG_ERR("Could not retrieve ECC key");
++        goto out;
++    }
+ 
+-    TPMS_ECC_PARMS *pp = &pub->publicArea.parameters.eccDetail;
+-    TPM2_ECC_CURVE curve_id = ossl_nid_to_curve(nid); // Not sure what lines up with NIST 256...
+-    if (curve_id == TPM2_ALG_ERROR) {
++    y = BN_new();
++    x = BN_new();
++    if (!x || !y) {
++        LOG_ERR("oom");
+         goto out;
+     }
+ 
+-    pp->curveID = curve_id;
++    const EC_GROUP *group = EC_KEY_get0_group(k);
++    nid = EC_GROUP_get_curve_name(group);
++    keysize = (EC_GROUP_get_degree(group) + 7) / 8;
+ 
+-    /*
+-     * Set the unique data to the public key.
+-     */
+     const EC_POINT *point = EC_KEY_get0_public_key(k);
+ 
+     int ret = EC_POINT_get_affine_coordinates_tss(group, point, x, y, NULL);
+@@ -722,6 +733,39 @@ static bool load_public_ECC_from_key(EC_KEY *k, TPM2B_PUBLIC *pub) {
+         LOG_ERR("Could not get X and Y affine coordinates");
+         goto out;
+     }
++#else
++    char curve_name[80];
++
++    int rc = EVP_PKEY_get_utf8_string_param(key, OSSL_PKEY_PARAM_GROUP_NAME,
++                                            curve_name, sizeof(curve_name), NULL);
++    if (!rc) {
++        LOG_ERR("Could not read ECC curve name");
++        goto out;
++    }
++    nid = OBJ_txt2nid(curve_name);
++    keysize = (EVP_PKEY_bits(key) + 7) / 8;
++
++    rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_X, &x);
++    if (!rc) {
++        LOG_ERR("Could not read public X coordinate");
++        goto out;
++    }
++
++    rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_Y, &y);
++    if (!rc) {
++        LOG_ERR("Could not read public Y coordinate");
++        goto out;
++    }
++#endif
++
++    /*
++     * Set the curve type
++     */
++    TPM2_ECC_CURVE curve_id = ossl_nid_to_curve(nid); // Not sure what lines up with NIST 256...
++    if (curve_id == TPM2_ALG_ERROR) {
++        goto out;
++    }
++    pp->curveID = curve_id;
+ 
+     /*
+      * Copy the X and Y coordinate data into the ECC unique field,
+@@ -730,28 +774,26 @@ static bool load_public_ECC_from_key(EC_KEY *k, TPM2B_PUBLIC *pub) {
+     TPM2B_ECC_PARAMETER *X = &pub->publicArea.unique.ecc.x;
+     TPM2B_ECC_PARAMETER *Y = &pub->publicArea.unique.ecc.y;
+ 
+-    unsigned x_size = (EC_GROUP_get_degree(group) + 7) / 8;
+-    if (x_size > sizeof(X->buffer)) {
++    if (keysize > sizeof(X->buffer)) {
+         LOG_ERR("X coordinate is too big. Got %u expected less than or equal to"
+-                " %zu", x_size, sizeof(X->buffer));
++                " %zu", keysize, sizeof(X->buffer));
+         goto out;
+     }
+ 
+-    unsigned y_size = (EC_GROUP_get_degree(group) + 7) / 8;
+-    if (y_size > sizeof(Y->buffer)) {
++    if (keysize > sizeof(Y->buffer)) {
+         LOG_ERR("X coordinate is too big. Got %u expected less than or equal to"
+-                " %zu", y_size, sizeof(Y->buffer));
++                " %zu", keysize, sizeof(Y->buffer));
+         goto out;
+     }
+ 
+-    X->size = BN_bn2binpad(x, X->buffer, x_size);
+-    if (X->size != x_size) {
++    X->size = BN_bn2binpad(x, X->buffer, keysize);
++    if (X->size != keysize) {
+         LOG_ERR("Error converting X point BN to binary");
+         goto out;
+     }
+ 
+-    Y->size = BN_bn2binpad(y, Y->buffer, y_size);
+-    if (Y->size != y_size) {
++    Y->size = BN_bn2binpad(y, Y->buffer, keysize);
++    if (Y->size != keysize) {
+         LOG_ERR("Error converting Y point BN to binary");
+         goto out;
+     }
+@@ -771,43 +813,28 @@ static bool load_public_ECC_from_key(EC_KEY *k, TPM2B_PUBLIC *pub) {
+     sym->mode.sym = TPM2_ALG_NULL;
+ 
+     result = true;
+-
+ out:
+-    if (x) {
+-        BN_free(x);
+-    }
+-    if (y) {
+-        BN_free(y);
+-    }
+-
++    BN_free(x);
++    BN_free(y);
+     return result;
+ }
+ 
+-EC_KEY *tpm2_openssl_get_public_ECC_from_pem(FILE *f, const char *path) {
+-
+-    EC_KEY *pub = PEM_read_EC_PUBKEY(f, NULL, NULL, NULL);
+-    if (!pub) {
+-        ERR_print_errors_fp(stderr);
+-        LOG_ERR("Reading public PEM file \"%s\" failed", path);
+-        return NULL;
+-    }
+-
+-    return pub;
+-}
+-
+ static bool load_public_ECC_from_pem(FILE *f, const char *path,
+         TPM2B_PUBLIC *pub) {
+ 
+-    EC_KEY *k = tpm2_openssl_get_public_ECC_from_pem(f, path);
++    EVP_PKEY *k = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+     if (!k) {
+         ERR_print_errors_fp(stderr);
+         LOG_ERR("Reading PEM file \"%s\" failed", path);
+         return false;
+     }
+ 
+-    bool result = load_public_ECC_from_key(k, pub);
++    bool result = false;
++    if (EVP_PKEY_base_id(k) == EVP_PKEY_EC) {
++        result = load_public_ECC_from_key(k, pub);
++    }
+ 
+-    EC_KEY_free(k);
++    EVP_PKEY_free(k);
+ 
+     return result;
+ }
+@@ -852,11 +879,27 @@ static bool load_public_AES_from_file(FILE *f, const char *path,
+     return tpm2_util_calc_unique(name_alg, key, seed, unique);
+ }
+ 
+-static bool load_private_RSA_from_key(RSA *k, TPM2B_SENSITIVE *priv) {
++static bool load_private_RSA_from_key(EVP_PKEY *key, TPM2B_SENSITIVE *priv) {
+ 
+-    const BIGNUM *p; /* the private key exponent */
++    bool result = false;
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    const BIGNUM *p = NULL; /* the private key exponent */
+ 
++    RSA *k = EVP_PKEY_get0_RSA(key);
++    if (!k) {
++        LOG_ERR("Could not retrieve RSA key");
++        goto out;
++    }
+     RSA_get0_factors(k, &p, NULL);
++#else
++    BIGNUM *p = NULL; /* the private key exponent */
++
++    int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_FACTOR1, &p);
++    if (!rc) {
++        LOG_ERR("Could not read private key");
++        goto out;
++    }
++#endif
+ 
+     TPMT_SENSITIVE *sa = &priv->sensitiveArea;
+ 
+@@ -868,7 +911,7 @@ static bool load_private_RSA_from_key(RSA *k, TPM2B_SENSITIVE *priv) {
+     if (priv_bytes > sizeof(pkr->buffer)) {
+         LOG_ERR("Expected prime \"d\" to be less than or equal to %zu,"
+                 " got: %u", sizeof(pkr->buffer), priv_bytes);
+-        return false;
++        goto out;
+     }
+ 
+     pkr->size = priv_bytes;
+@@ -877,10 +920,16 @@ static bool load_private_RSA_from_key(RSA *k, TPM2B_SENSITIVE *priv) {
+     if (!success) {
+         ERR_print_errors_fp(stderr);
+         LOG_ERR("Could not copy private exponent \"d\"");
+-        return false;
++        goto out;
+     }
+-
+-    return true;
++    result = true;
++out:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    /* k,p point to internal structrues and must not be freed after use */
++#else
++    BN_free(p);
++#endif
++    return result;
+ }
+ 
+ bool tpm2_openssl_load_public(const char *path, TPMI_ALG_PUBLIC alg,
+@@ -912,8 +961,9 @@ bool tpm2_openssl_load_public(const char *path, TPMI_ALG_PUBLIC alg,
+     return result;
+ }
+ 
+-static bool load_private_ECC_from_key(EC_KEY *k, TPM2B_SENSITIVE *priv) {
++static bool load_private_ECC_from_key(EVP_PKEY *key, TPM2B_SENSITIVE *priv) {
+ 
++    bool result = false;
+     /*
+      * private data
+      */
+@@ -921,22 +971,45 @@ static bool load_private_ECC_from_key(EC_KEY *k, TPM2B_SENSITIVE *priv) {
+ 
+     TPM2B_ECC_PARAMETER *p = &priv->sensitiveArea.sensitive.ecc;
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    EC_KEY *k = EVP_PKEY_get0_EC_KEY(key);
++    if (!k) {
++        LOG_ERR("Could not retrieve ECC key");
++        goto out;
++    }
++
+     const EC_GROUP *group = EC_KEY_get0_group(k);
+     const BIGNUM *b = EC_KEY_get0_private_key(k);
+-
+     unsigned priv_bytes = (EC_GROUP_get_degree(group) + 7) / 8;
++#else
++    BIGNUM *b = NULL; /* the private key exponent */
++
++    int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_PRIV_KEY, &b);
++    if (!rc) {
++        LOG_ERR("Could not read ECC private key");
++        goto out;
++    }
++    unsigned priv_bytes = (EVP_PKEY_bits(key) + 7) / 8;
++#endif
++
+     if (priv_bytes > sizeof(p->buffer)) {
+         LOG_ERR("Expected ECC private portion to be less than or equal to %zu,"
+                 " got: %u", sizeof(p->buffer), priv_bytes);
+-        return false;
++        goto out;
+     }
+ 
+     p->size = BN_bn2binpad(b, p->buffer, priv_bytes);
+     if (p->size != priv_bytes) {
+-        return false;
++        goto out;
+     }
+-
+-    return true;
++    result = true;
++out:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    /* k,b point to internal structrues and must not be freed after use */
++#else
++    BN_free(b);
++#endif
++    return result;
+ }
+ 
+ static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path,
+@@ -950,8 +1023,7 @@ static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path,
+         return lprc_error;
+     }
+ 
+-    EC_KEY *k = PEM_read_ECPrivateKey(f, NULL,
+-    NULL, (void *) pass);
++    EVP_PKEY *k = PEM_read_PrivateKey(f, NULL, NULL, (void *) pass);
+     free(pass);
+     if (!k) {
+         ERR_print_errors_fp(stderr);
+@@ -976,14 +1048,14 @@ static tpm2_openssl_load_rc load_private_ECC_from_pem(FILE *f, const char *path,
+     rc |= lprc_public;
+ 
+ out:
+-    EC_KEY_free(k);
++    EVP_PKEY_free(k);
+     return rc;
+ }
+ 
+ static tpm2_openssl_load_rc load_private_RSA_from_pem(FILE *f, const char *path,
+         const char *passin, TPM2B_PUBLIC *pub, TPM2B_SENSITIVE *priv) {
+ 
+-    RSA *k = NULL;
++    EVP_PKEY *k = NULL;
+ 
+     tpm2_openssl_load_rc rc = lprc_error;
+ 
+@@ -993,8 +1065,7 @@ static tpm2_openssl_load_rc load_private_RSA_from_pem(FILE *f, const char *path,
+         return lprc_error;
+     }
+ 
+-    k = PEM_read_RSAPrivateKey(f, NULL,
+-    NULL, (void *) pass);
++    k = PEM_read_PrivateKey(f, NULL, NULL, (void *) pass);
+     free(pass);
+     if (!k) {
+         ERR_print_errors_fp(stderr);
+@@ -1016,7 +1087,7 @@ static tpm2_openssl_load_rc load_private_RSA_from_pem(FILE *f, const char *path,
+         rc |= lprc_public;
+     }
+ out:
+-    RSA_free(k);
++    EVP_PKEY_free(k);
+     return rc;
+ }
+ 
+diff --git a/lib/tpm2_openssl.h b/lib/tpm2_openssl.h
+index b757baa5..5579ae45 100644
+--- a/lib/tpm2_openssl.h
++++ b/lib/tpm2_openssl.h
+@@ -196,18 +196,6 @@ tpm2_openssl_load_rc tpm2_openssl_load_private(const char *path,
+ bool tpm2_openssl_load_public(const char *path, TPMI_ALG_PUBLIC alg,
+         TPM2B_PUBLIC *pub);
+ 
+-/**
+- * Retrieves a public portion of an ECC key from a PEM file.
+- *
+- * @param f
+- *  The FILE object that is open for reading the path.
+- * @param path
+- *  The path to load from.
+- * @return
+- *  The public structure.
+- */
+-EC_KEY* tpm2_openssl_get_public_ECC_from_pem(FILE *f, const char *path);
+-
+ /**
+  * Maps an ECC curve to an openssl nid value.
+  * @param curve
+-- 
+2.31.1
+
diff --git a/SOURCES/0015-openssl-Implement-EVP_PKEY-based-key-export.patch b/SOURCES/0015-openssl-Implement-EVP_PKEY-based-key-export.patch
new file mode 100644
index 0000000..8b72443
--- /dev/null
+++ b/SOURCES/0015-openssl-Implement-EVP_PKEY-based-key-export.patch
@@ -0,0 +1,484 @@
+From e34d393d7c73a58b3bf6fccbe88ea1eedfe1d7b7 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 15:58:28 +0200
+Subject: [PATCH 14/17] openssl: Implement EVP_PKEY based key export
+
+The `RSA_KEY` and `EC_KEY` are not publicly available in OpenSSL 3.0 and
+the generic `EVP_PKEY` must be used instead.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_convert.c | 319 ++++++++++++++++++++++++++++++++-------------
+ lib/tpm2_convert.h |  20 +++
+ 2 files changed, 245 insertions(+), 94 deletions(-)
+
+diff --git a/lib/tpm2_convert.c b/lib/tpm2_convert.c
+index cc1c18ab..986fc1a7 100644
+--- a/lib/tpm2_convert.c
++++ b/lib/tpm2_convert.c
+@@ -9,6 +9,13 @@
+ #include <openssl/bio.h>
+ #include <openssl/err.h>
+ #include <openssl/pem.h>
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++#include <openssl/rsa.h>
++#else
++#include <openssl/core_names.h>
++#include <openssl/params.h>
++#include <openssl/param_build.h>
++#endif
+ 
+ #include "files.h"
+ #include "log.h"
+@@ -70,36 +77,49 @@ bool tpm2_convert_pubkey_save(TPM2B_PUBLIC *public,
+     return false;
+ }
+ 
+-static bool convert_pubkey_RSA(TPMT_PUBLIC *public,
+-        tpm2_convert_pubkey_fmt format, BIO *bio) {
++EVP_PKEY *convert_pubkey_RSA(TPMT_PUBLIC *public) {
+ 
+-    bool ret = false;
+-    RSA *ssl_rsa_key = NULL;
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    RSA *rsa_key = NULL;
++#else
++    OSSL_PARAM_BLD *build = NULL;
++    OSSL_PARAM *params = NULL;
++    EVP_PKEY_CTX *ctx = NULL;
++#endif
+     BIGNUM *e = NULL, *n = NULL;
++    EVP_PKEY *pkey = NULL;
+ 
+     UINT32 exponent = (public->parameters).rsaDetail.exponent;
+     if (exponent == 0) {
+         exponent = 0x10001;
+     }
+ 
+-    // OpenSSL expects this in network byte order
+-    exponent = tpm2_util_hton_32(exponent);
+-    ssl_rsa_key = RSA_new();
+-    if (!ssl_rsa_key) {
+-        print_ssl_error("Failed to allocate OpenSSL RSA structure");
++    n = BN_bin2bn(public->unique.rsa.buffer, public->unique.rsa.size, NULL);
++    if (!n) {
++        print_ssl_error("Failed to convert data to SSL internal format");
+         goto error;
+     }
+ 
+-    e = BN_bin2bn((void*) &exponent, sizeof(exponent), NULL);
+-    n = BN_bin2bn(public->unique.rsa.buffer, public->unique.rsa.size,
+-    NULL);
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    rsa_key = RSA_new();
++    if (!rsa_key) {
++        print_ssl_error("Failed to allocate OpenSSL RSA structure");
++        goto error;
++    }
+ 
+-    if (!n || !e) {
++    e = BN_new();
++    if (!e) {
++        print_ssl_error("Failed to convert data to SSL internal format");
++        goto error;
++    }
++    int rc = BN_set_word(e, exponent);
++    if (!rc) {
+         print_ssl_error("Failed to convert data to SSL internal format");
+         goto error;
+     }
+ 
+-    if (!RSA_set0_key(ssl_rsa_key, n, e, NULL)) {
++    rc = RSA_set0_key(rsa_key, n, e, NULL);
++    if (!rc) {
+         print_ssl_error("Failed to set RSA modulus and exponent components");
+         goto error;
+     }
+@@ -107,162 +127,273 @@ static bool convert_pubkey_RSA(TPMT_PUBLIC *public,
+     /* modulus and exponent components are now owned by the RSA struct */
+     n = e = NULL;
+ 
+-    int ssl_res = 0;
++    pkey = EVP_PKEY_new();
++    if (!pkey) {
++        print_ssl_error("Failed to allocate OpenSSL EVP structure");
++        goto error;
++    }
+ 
+-    switch (format) {
+-    case pubkey_format_pem:
+-        ssl_res = PEM_write_bio_RSA_PUBKEY(bio, ssl_rsa_key);
+-        break;
+-    case pubkey_format_der:
+-        ssl_res = i2d_RSA_PUBKEY_bio(bio, ssl_rsa_key);
+-        break;
+-    default:
+-        LOG_ERR("Invalid OpenSSL target format %d encountered", format);
++    rc = EVP_PKEY_assign_RSA(pkey, rsa_key);
++    if (!rc) {
++        print_ssl_error("Failed to set OpenSSL EVP structure");
++        EVP_PKEY_free(pkey);
++        pkey = NULL;
++        goto error;
++    }
++    /* rsa key is now owner by the EVP_PKEY struct */
++    rsa_key = NULL;
++#else
++    build = OSSL_PARAM_BLD_new();
++    if (!build) {
++        print_ssl_error("Failed to allocate OpenSSL parameters");
+         goto error;
+     }
+ 
+-    if (ssl_res <= 0) {
+-        print_ssl_error("OpenSSL public key conversion failed");
++    int rc = OSSL_PARAM_BLD_push_BN(build, OSSL_PKEY_PARAM_RSA_N, n);
++    if (!rc) {
++        print_ssl_error("Failed to set RSA modulus");
+         goto error;
+     }
+ 
+-    ret = true;
++    rc = OSSL_PARAM_BLD_push_uint32(build, OSSL_PKEY_PARAM_RSA_E, exponent);
++    if (!rc) {
++        print_ssl_error("Failed to set RSA exponent");
++        goto error;
++    }
+ 
+-    error: if (n) {
+-        BN_free(n);
++    params = OSSL_PARAM_BLD_to_param(build);
++    if (!params) {
++        print_ssl_error("Failed to build OpenSSL parameters");
++        goto error;
+     }
+-    if (e) {
+-        BN_free(e);
++
++    ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
++    if (!ctx) {
++        print_ssl_error("Failed to allocate RSA key context");
++        goto error;
+     }
+-    if (ssl_rsa_key) {
+-        RSA_free(ssl_rsa_key);
++
++    rc = EVP_PKEY_fromdata_init(ctx);
++    if (rc <= 0) {
++        print_ssl_error("Failed to initialize RSA key creation");
++        goto error;
+     }
+ 
+-    return ret;
++    rc = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params);
++    if (rc <= 0) {
++        print_ssl_error("Failed to create a RSA public key");
++        goto error;
++    }
++#endif
++error:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    RSA_free(rsa_key);
++#else
++    EVP_PKEY_CTX_free(ctx);
++    OSSL_PARAM_free(params);
++    OSSL_PARAM_BLD_free(build);
++#endif
++    BN_free(n);
++    BN_free(e);
++    return pkey;
+ }
+ 
+-static bool convert_pubkey_ECC(TPMT_PUBLIC *public,
+-        tpm2_convert_pubkey_fmt format, BIO *bio) {
++EVP_PKEY *convert_pubkey_ECC(TPMT_PUBLIC *public) {
+ 
+     BIGNUM *x = NULL;
+     BIGNUM *y = NULL;
+-    EC_KEY *key = NULL;
+     EC_POINT *point = NULL;
+-    const EC_GROUP *group = NULL;
+-
+-    bool result = false;
++    EC_GROUP *group = NULL;
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    EC_KEY *ec_key = NULL;
++#else
++    OSSL_PARAM_BLD *build = NULL;
++    OSSL_PARAM *params = NULL;
++    EVP_PKEY_CTX *ctx = NULL;
++    unsigned char *puboct = NULL;
++    size_t bsize;
++#endif
++    EVP_PKEY *pkey = NULL;
+ 
+     TPMS_ECC_PARMS *tpm_ecc = &public->parameters.eccDetail;
+     TPMS_ECC_POINT *tpm_point = &public->unique.ecc;
+ 
++    /*
++     * Set the affine coordinates for the point
++     */
++    x = BN_bin2bn(tpm_point->x.buffer, tpm_point->x.size, NULL);
++    if (!x) {
++        print_ssl_error("Could not convert x coordinate to BN");
++        goto out;
++    }
++
++    y = BN_bin2bn(tpm_point->y.buffer, tpm_point->y.size, NULL);
++    if (!y) {
++        print_ssl_error("Could not convert y coordinate to BN");
++        goto out;
++    }
++
+     int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
+     if (nid < 0) {
+-        return false;
++        goto out;
+     }
+ 
+     /*
+-     * Create an empty EC key by the NID
++     * Create a new point in the group, which is the public key.
+      */
+-    key = EC_KEY_new_by_curve_name(nid);
+-    if (!key) {
+-        print_ssl_error("Failed to create EC key from nid");
+-        return false;
+-    }
+-
+-    group = EC_KEY_get0_group(key);
++    group = EC_GROUP_new_by_curve_name(nid);
+     if (!group) {
+         print_ssl_error("EC key missing group");
+         goto out;
+     }
+ 
+-    /*
+-     * Create a new point in the group, which is the public key.
+-     */
+     point = EC_POINT_new(group);
+ 
++    int rc = EC_POINT_set_affine_coordinates_tss(group, point, x, y, NULL);
++    if (!rc) {
++        print_ssl_error("Could not set affine coordinates");
++        goto out;
++    }
++
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+     /*
+-     * Set the affine coordinates for the point
++     * Create an empty EC key by the NID
+      */
+-    x = BN_bin2bn(tpm_point->x.buffer, tpm_point->x.size, NULL);
+-    if (!x) {
+-        print_ssl_error("Could not convert x coordinate to BN");
++    ec_key = EC_KEY_new_by_curve_name(nid);
++    if (!ec_key) {
++        print_ssl_error("Failed to create EC key from nid");
++        return false;
++    }
++
++    rc = EC_KEY_set_public_key(ec_key, point);
++    if (!rc) {
++        print_ssl_error("Could not set point as public key portion");
+         goto out;
+     }
+ 
+-    y = BN_bin2bn(tpm_point->y.buffer, tpm_point->y.size, NULL);
+-    if (!y) {
+-        print_ssl_error("Could not convert y coordinate to BN");
++    if ((pkey = EVP_PKEY_new()) == NULL) {
++        print_ssl_error("Failed to allocate OpenSSL EVP structure");
+         goto out;
+     }
+ 
+-    int rc = EC_POINT_set_affine_coordinates_tss(group, point, x, y, NULL);
++    rc = EVP_PKEY_assign_EC_KEY(pkey, ec_key);
+     if (!rc) {
+-        print_ssl_error("Could not set affine coordinates");
++        print_ssl_error("Failed to set OpenSSL EVP structure");
++        EVP_PKEY_free(pkey);
++        pkey = NULL;
++        goto out;
++    }
++    /* rsa key is now owner by the EVP_PKEY struct */
++    ec_key = NULL;
++#else
++    build = OSSL_PARAM_BLD_new();
++    if (!build) {
++        print_ssl_error("Failed to allocate OpenSSL parameters");
+         goto out;
+     }
+ 
+-    rc = EC_KEY_set_public_key(key, point);
++    rc = OSSL_PARAM_BLD_push_utf8_string(build, OSSL_PKEY_PARAM_GROUP_NAME,
++                                         (char *)OBJ_nid2sn(nid), 0);
+     if (!rc) {
+-        print_ssl_error("Could not set point as public key portion");
++        print_ssl_error("Failed to set the EC group name");
+         goto out;
+     }
+ 
+-    int ssl_res = 0;
+-
+-    switch (format) {
+-    case pubkey_format_pem:
+-        ssl_res = PEM_write_bio_EC_PUBKEY(bio, key);
+-        break;
+-    case pubkey_format_der:
+-        ssl_res = i2d_EC_PUBKEY_bio(bio, key);
+-        break;
+-    default:
+-        LOG_ERR("Invalid OpenSSL target format %d encountered", format);
++    bsize = EC_POINT_point2buf(group, point,
++                               POINT_CONVERSION_COMPRESSED,
++                               &puboct, NULL);
++    if (bsize == 0) {
++        print_ssl_error("Failed compress the EC public key");
+         goto out;
+     }
+ 
+-    if (ssl_res <= 0) {
+-        print_ssl_error("OpenSSL public key conversion failed");
++    rc = OSSL_PARAM_BLD_push_octet_string(build, OSSL_PKEY_PARAM_PUB_KEY,
++                                          puboct, bsize);
++    if (!rc) {
++        print_ssl_error("Failed set the EC public key");
+         goto out;
+     }
+ 
+-    result = true;
+-
+-out:
+-    if (x) {
+-        BN_free(x);
++    params = OSSL_PARAM_BLD_to_param(build);
++    if (!params) {
++        print_ssl_error("Failed to build OpenSSL parameters");
++        goto out;
+     }
+-    if (y) {
+-        BN_free(y);
++
++    ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
++    if (!ctx) {
++        print_ssl_error("Failed to allocate EC key context");
++        goto out;
+     }
+-    if (point) {
+-        EC_POINT_free(point);
++
++    rc = EVP_PKEY_fromdata_init(ctx);
++    if (rc <= 0) {
++        print_ssl_error("Failed to initialize EC key creation");
++        goto out;
+     }
+-    if (key) {
+-        EC_KEY_free(key);
++
++    rc = EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params);
++    if (rc <= 0) {
++        print_ssl_error("Failed to create a EC public key");
++        goto out;
+     }
++#endif
+ 
+-    return result;
++out:
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    EC_KEY_free(ec_key);
++#else
++    EVP_PKEY_CTX_free(ctx);
++    OSSL_PARAM_free(params);
++    OSSL_PARAM_BLD_free(build);
++    OPENSSL_free(puboct);
++#endif
++    EC_POINT_free(point);
++    EC_GROUP_free(group);
++    BN_free(x);
++    BN_free(y);
++    return pkey;
+ }
+ 
+ static bool tpm2_convert_pubkey_bio(TPMT_PUBLIC *public,
+         tpm2_convert_pubkey_fmt format, BIO *bio) {
+ 
+-    bool result = false;
++    EVP_PKEY *pubkey = NULL;
++    int ssl_res = 0;
+ 
+     switch (public->type) {
+     case TPM2_ALG_RSA:
+-        result = convert_pubkey_RSA(public, format, bio);
++        pubkey = convert_pubkey_RSA(public);
+         break;
+     case TPM2_ALG_ECC:
+-        result = convert_pubkey_ECC(public, format, bio);
++        pubkey = convert_pubkey_ECC(public);
+         break;
+     default:
+-        LOG_ERR(
+-                "Unsupported key type for requested output format. Only RSA is supported.");
++        LOG_ERR("Unsupported key type for requested output format.");
+     }
+ 
+-    return result;
++    if (pubkey == NULL)
++        return false;
++
++    switch (format) {
++    case pubkey_format_pem:
++        ssl_res = PEM_write_bio_PUBKEY(bio, pubkey);
++        break;
++    case pubkey_format_der:
++        ssl_res = i2d_PUBKEY_bio(bio, pubkey);
++        break;
++    default:
++        LOG_ERR("Invalid OpenSSL target format %d encountered", format);
++    }
++
++    EVP_PKEY_free(pubkey);
++
++    if (ssl_res <= 0) {
++        print_ssl_error("OpenSSL public key conversion failed");
++        return false;
++    }
++
++    return true;
+ }
+ 
+ static bool tpm2_convert_pubkey_ssl(TPMT_PUBLIC *public,
+diff --git a/lib/tpm2_convert.h b/lib/tpm2_convert.h
+index f8c82155..bddb455d 100644
+--- a/lib/tpm2_convert.h
++++ b/lib/tpm2_convert.h
+@@ -45,6 +45,26 @@ tpm2_convert_pubkey_fmt tpm2_convert_pubkey_fmt_from_optarg(const char *label);
+ bool tpm2_convert_pubkey_save(TPM2B_PUBLIC *public,
+         tpm2_convert_pubkey_fmt format, const char *path);
+ 
++/**
++ * Converts the given RSA public key structure into the EVP_PKEY.
++ *
++ * @param public
++ *  TPM2 public key structure structure.
++ * @return
++ *   OpenSSL key structure, or NULL on error.
++ */
++EVP_PKEY *convert_pubkey_RSA(TPMT_PUBLIC *public);
++
++/**
++ * Converts the given ECC public key structure into the EVP_PKEY.
++ *
++ * @param public
++ *  TPM2 public key structure structure.
++ * @return
++ *   OpenSSL key structure, or NULL on error.
++ */
++EVP_PKEY *convert_pubkey_ECC(TPMT_PUBLIC *public);
++
+ /**
+  * Parses the given command line signature format option string and returns
+  * the corresponding signature_format enum value.
+-- 
+2.31.1
+
diff --git a/SOURCES/0016-openssl-Convert-deprecated-ECDH_compute_key-to-EVP_P.patch b/SOURCES/0016-openssl-Convert-deprecated-ECDH_compute_key-to-EVP_P.patch
new file mode 100644
index 0000000..cedd951
--- /dev/null
+++ b/SOURCES/0016-openssl-Convert-deprecated-ECDH_compute_key-to-EVP_P.patch
@@ -0,0 +1,286 @@
+From 0caac28c1fa2d62dbf7c5a6c65346f6d3399d22c Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 16:26:06 +0200
+Subject: [PATCH 15/17] openssl: Convert deprecated ECDH_compute_key to
+ EVP_PKEY_derive
+
+The EC_KEY functions are replaced by corresponding EVP_PKEY functions.
+The tpm2_get_EC_public_key function is replaced by convert_pubkey_ECC
+from lib/tpm2_convert.c.
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_kdfe.c | 186 +++++++++++++++++++++++-------------------------
+ 1 file changed, 89 insertions(+), 97 deletions(-)
+
+diff --git a/lib/tpm2_kdfe.c b/lib/tpm2_kdfe.c
+index 84718b9f..91027e32 100644
+--- a/lib/tpm2_kdfe.c
++++ b/lib/tpm2_kdfe.c
+@@ -5,12 +5,16 @@
+ #include <string.h>
+ 
+ #include <openssl/bn.h>
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
+ #include <openssl/ecdh.h>
+-
++#else
++#include <openssl/core_names.h>
++#endif
+ #include <tss2/tss2_tpm2_types.h>
+ #include <tss2/tss2_mu.h>
+ 
+ #include "log.h"
++#include "tpm2_convert.h"
+ #include "tpm2_openssl.h"
+ #include "tpm2_alg_util.h"
+ #include "tpm2_util.h"
+@@ -65,72 +69,18 @@ TSS2_RC tpm2_kdfe(
+     return rval;
+ }
+ 
+-static EC_POINT * tpm2_get_EC_public_key(TPM2B_PUBLIC *public) {
+-    EC_POINT *q = NULL;
+-    BIGNUM *bn_qx, *bn_qy;
+-    EC_KEY *key;
+-    const EC_GROUP *group;
+-    bool rval;
+-    TPMS_ECC_PARMS *tpm_ecc   = &public->publicArea.parameters.eccDetail;
+-    TPMS_ECC_POINT *tpm_point = &public->publicArea.unique.ecc;
+-
+-    int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
+-    if (nid < 0) {
+-        return NULL;
+-    }
+-
+-    key = EC_KEY_new_by_curve_name(nid);
+-    if (!key) {
+-        LOG_ERR("Failed to create EC key from nid");
+-        return NULL;
+-    }
+-
+-    bn_qx = BN_bin2bn(tpm_point->x.buffer, tpm_point->x.size, NULL);
+-    bn_qy = BN_bin2bn(tpm_point->y.buffer, tpm_point->y.size, NULL);
+-    if ((bn_qx == NULL) || (bn_qy == NULL)) {
+-        LOG_ERR("Could not convert EC public key to BN");
+-        goto out;
+-    }
+-    group = EC_KEY_get0_group(key);
+-    if (!group) {
+-        LOG_ERR("EC key missing group");
+-        goto out;
+-    }
+-    q = EC_POINT_new(group);
+-    if (q == NULL) {
+-        LOG_ERR("Could not allocate EC_POINT");
+-        goto out;
+-    }
+-
+-    rval = EC_POINT_set_affine_coordinates_tss(group, q, bn_qx, bn_qy, NULL);
+-    if (rval == false) {
+-        LOG_ERR("Could not set affine_coordinates");
+-        EC_POINT_free(q);
+-        q = NULL;
+-    }
+-
+-out:
+-    if (bn_qx) {
+-        BN_free(bn_qx);
+-    }
+-    if (bn_qy) {
+-        BN_free(bn_qy);
+-    }
+-    if (key) {
+-        EC_KEY_free(key);
+-    }
+-
+-    return q;
+-}
+-
+-
+-static bool get_public_key_from_ec_key(EC_KEY *key, TPMS_ECC_POINT *point) {
+-    BIGNUM *x = BN_new();
+-    BIGNUM *y = BN_new();
+-    const EC_POINT *pubkey = EC_KEY_get0_public_key(key);
++static bool get_public_key_from_ec_key(EVP_PKEY *pkey, TPMS_ECC_POINT *point) {
++    BIGNUM *x = NULL;
++    BIGNUM *y = NULL;
+     unsigned int nbx, nby;
+     bool result = false;
+ 
++#if OPENSSL_VERSION_NUMBER < 0x30000000L
++    EC_KEY *key = EVP_PKEY_get0_EC_KEY(pkey);
++    const EC_POINT *pubkey = EC_KEY_get0_public_key(key);
++
++    x = BN_new();
++    y = BN_new();
+     if ((x == NULL) || (y == NULL) || (pubkey == NULL)) {
+         LOG_ERR("Failed to allocate memory to store EC public key.");
+         goto out;
+@@ -138,6 +88,18 @@ static bool get_public_key_from_ec_key(EC_KEY *key, TPMS_ECC_POINT *point) {
+ 
+     EC_POINT_get_affine_coordinates_tss(EC_KEY_get0_group(key),
+             pubkey, x, y, NULL);
++#else
++    int rc = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x);
++    if (!rc) {
++        LOG_ERR("Failed to get EC public key X.");
++        goto out;
++    }
++    rc = EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y);
++    if (!rc) {
++        LOG_ERR("Failed to get EC public key Y.");
++        goto out;
++    }
++#endif
+     nbx = BN_num_bytes(x);
+     nby = BN_num_bytes(y);
+     if ((nbx > sizeof(point->x.buffer))||
+@@ -153,29 +115,41 @@ static bool get_public_key_from_ec_key(EC_KEY *key, TPMS_ECC_POINT *point) {
+     result = true;
+ 
+ out:
+-    if (x) {
+-        BN_free(x);
+-    }
+-    if (y) {
+-        BN_free(y);
+-    }
++    BN_free(x);
++    BN_free(y);
+     return result;
+ }
+ 
+ 
+-static int get_ECDH_shared_secret(EC_KEY *key,
+-        const EC_POINT *p_pub, TPM2B_ECC_PARAMETER *secret) {
++static int get_ECDH_shared_secret(EVP_PKEY *pkey,
++        EVP_PKEY *p_pub, TPM2B_ECC_PARAMETER *secret) {
+ 
+-    int shared_secret_length;
++    EVP_PKEY_CTX *ctx;
++    int result = -1;
+ 
+-    shared_secret_length = EC_GROUP_get_degree(EC_KEY_get0_group(key));
+-    shared_secret_length = (shared_secret_length + 7) / 8;
+-    if ((size_t) shared_secret_length > sizeof(secret->buffer)) {
++    ctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (!ctx)
+         return -1;
+-    }
+-    secret->size = ECDH_compute_key(secret->buffer,
+-            shared_secret_length, p_pub, key, NULL);
+-    return secret->size;
++
++    int rc = EVP_PKEY_derive_init(ctx);
++    if (rc <= 0)
++        goto out;
++
++    rc = EVP_PKEY_derive_set_peer(ctx, p_pub);
++    if (rc <= 0)
++        goto out;
++
++    size_t shared_secret_length = sizeof(secret->buffer);
++    rc = EVP_PKEY_derive(ctx, secret->buffer, &shared_secret_length);
++    if (rc <= 0)
++        goto out;
++
++    secret->size = shared_secret_length;
++    result = secret->size;
++
++out:
++    EVP_PKEY_CTX_free(ctx);
++    return result;
+ }
+ 
+ 
+@@ -190,25 +164,42 @@ bool ecdh_derive_seed_and_encrypted_seed(
+     TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg;
+     UINT16 parent_hash_size = tpm2_alg_util_get_hash_size(parent_name_alg);
+     bool result = false;
+-    EC_KEY *key = NULL;
+-    EC_POINT *qsv = NULL;
++    EVP_PKEY_CTX *ctx;
++    EVP_PKEY *pkey = NULL;
++    EVP_PKEY *qsv = NULL;
+     TPMS_ECC_POINT qeu;
+     bool qeu_is_valid;
+     TPM2B_ECC_PARAMETER ecc_secret;
+ 
+     // generate an ephemeral key
+     int nid = tpm2_ossl_curve_to_nid(tpm_ecc->curveID);
+-    if (nid >= 0) {
+-        key = EC_KEY_new_by_curve_name(nid);
+-    }
+-    if (key == NULL) {
+-        LOG_ERR("Failed to create EC key from curveID");
++
++    ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
++    if (!ctx) {
++        LOG_ERR("Failed to create key creation context");
+         return false;
+     }
+-    EC_KEY_generate_key(key);
++
++    int rc = EVP_PKEY_keygen_init(ctx);
++    if (rc <= 0) {
++        LOG_ERR("Failed to initialize key creation");
++        goto out;
++    }
++
++    rc = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid);
++    if (rc <= 0) {
++        LOG_ERR("Failed to set EC curve NID %i", nid);
++        goto out;
++    }
++
++    rc = EVP_PKEY_keygen(ctx, &pkey);
++    if (rc <= 0) {
++        LOG_ERR("Failed to generate the ephemeral EC key");
++        goto out;
++    }
+ 
+     // get public key for the ephemeral key
+-    qeu_is_valid = get_public_key_from_ec_key(key, &qeu);
++    qeu_is_valid = get_public_key_from_ec_key(pkey, &qeu);
+     if (qeu_is_valid == false) {
+         LOG_ERR("Could not get the ECC public key");
+         goto out;
+@@ -226,13 +217,17 @@ bool ecdh_derive_seed_and_encrypted_seed(
+     out_sym_seed->size = offset;
+ 
+     /* get parents public key */
+-    qsv = tpm2_get_EC_public_key(parent_pub);
++    qsv = convert_pubkey_ECC(&parent_pub->publicArea);
+     if (qsv == NULL) {
+         LOG_ERR("Could not get parent's public key");
+         goto out;
+     }
+ 
+-    get_ECDH_shared_secret(key, qsv, &ecc_secret);
++    rc = get_ECDH_shared_secret(pkey, qsv, &ecc_secret);
++    if (rc <= 0) {
++        LOG_ERR("Could not derive shared secret");
++        goto out;
++    }
+ 
+     /* derive seed using KDFe */
+     TPM2B_ECC_PARAMETER *party_u_info = &qeu.x;
+@@ -244,11 +239,8 @@ bool ecdh_derive_seed_and_encrypted_seed(
+     result = true;
+ 
+ out:
+-    if (qsv) {
+-        EC_POINT_free(qsv);
+-    }
+-    if (key) {
+-        EC_KEY_free(key);
+-    }
++    EVP_PKEY_free(qsv);
++    EVP_PKEY_free(pkey);
++    EVP_PKEY_CTX_free(ctx);
+     return result;
+ }
+-- 
+2.31.1
+
diff --git a/SOURCES/0017-openssl-Reimplement-RSA-OAEP-encryption-using-EVP-fu.patch b/SOURCES/0017-openssl-Reimplement-RSA-OAEP-encryption-using-EVP-fu.patch
new file mode 100644
index 0000000..ba6a3da
--- /dev/null
+++ b/SOURCES/0017-openssl-Reimplement-RSA-OAEP-encryption-using-EVP-fu.patch
@@ -0,0 +1,240 @@
+From 317c1ea1d9893d6f4f837196648c53b7f7dd762f Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Sun, 15 Aug 2021 17:22:44 +0200
+Subject: [PATCH 16/17] openssl: Reimplement RSA OAEP encryption using EVP
+ functions
+
+The RSA_padding_add_PKCS1_OAEP_mgf1 is deprecated and the entire
+semi-custom implementation of OAEP is unnecessary.
+The Part 1, B.10.3 talks about a standard OAEP with a given label,
+which can be easily implemented using the standard EVP functions.
+Also, the public key retrieval can be replaced by invocation of
+convert_pubkey_RSA from lib/tpm2_convert.c
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ lib/tpm2_identity_util.c | 162 +++++++++++----------------------------
+ 1 file changed, 43 insertions(+), 119 deletions(-)
+
+diff --git a/lib/tpm2_identity_util.c b/lib/tpm2_identity_util.c
+index ba0c0e1c..b04a56d6 100644
+--- a/lib/tpm2_identity_util.c
++++ b/lib/tpm2_identity_util.c
+@@ -10,6 +10,7 @@
+ 
+ #include "log.h"
+ #include "tpm2_alg_util.h"
++#include "tpm2_convert.h"
+ #include "tpm2_identity_util.h"
+ #include "tpm2_kdfa.h"
+ #include "tpm2_kdfe.h"
+@@ -17,73 +18,6 @@
+ 
+ // Identity-related functionality that the TPM normally does, but using OpenSSL
+ 
+-#if defined(LIBRESSL_VERSION_NUMBER)
+-static int RSA_padding_add_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
+-        const unsigned char *from, int flen, const unsigned char *param, int plen,
+-        const EVP_MD *md, const EVP_MD *mgf1md) {
+-
+-    int ret = 0;
+-    int i, emlen = tlen - 1;
+-    unsigned char *db, *seed;
+-    unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE];
+-    int mdlen;
+-
+-    if (md == NULL)
+-    md = EVP_sha1();
+-    if (mgf1md == NULL)
+-    mgf1md = md;
+-
+-    mdlen = EVP_MD_size(md);
+-
+-    if (flen > emlen - 2 * mdlen - 1) {
+-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
+-                RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+-        return 0;
+-    }
+-
+-    if (emlen < 2 * mdlen + 1) {
+-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
+-                RSA_R_KEY_SIZE_TOO_SMALL);
+-        return 0;
+-    }
+-
+-    to[0] = 0;
+-    seed = to + 1;
+-    db = to + mdlen + 1;
+-
+-    if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL))
+-    return 0;
+-    memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1);
+-    db[emlen - flen - mdlen - 1] = 0x01;
+-    memcpy(db + emlen - flen - mdlen, from, (unsigned int)flen);
+-    if (RAND_bytes(seed, mdlen) <= 0)
+-    return 0;
+-
+-    dbmask = OPENSSL_malloc(emlen - mdlen);
+-    if (dbmask == NULL) {
+-        RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
+-        return 0;
+-    }
+-
+-    if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0)
+-    goto err;
+-    for (i = 0; i < emlen - mdlen; i++)
+-    db[i] ^= dbmask[i];
+-
+-    if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0)
+-    goto err;
+-    for (i = 0; i < mdlen; i++)
+-    seed[i] ^= seedmask[i];
+-
+-    ret = 1;
+-
+-err:
+-    OPENSSL_free(dbmask);
+-
+-    return ret;
+-}
+-#endif
+-
+ static TPM2_KEY_BITS get_pub_asym_key_bits(TPM2B_PUBLIC *public) {
+ 
+     TPMU_PUBLIC_PARMS *p = &public->publicArea.parameters;
+@@ -102,19 +36,13 @@ static bool share_secret_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed,
+         TPM2B_PUBLIC *parent_pub, unsigned char *label, int label_len,
+         TPM2B_ENCRYPTED_SECRET *encrypted_protection_seed) {
+     bool rval = false;
+-    RSA *rsa = NULL;
+-
+-    // Public modulus (RSA-only!)
+-    TPMI_RSA_KEY_BITS mod_size_bits =
+-            parent_pub->publicArea.parameters.rsaDetail.keyBits;
+-    UINT16 mod_size = mod_size_bits / 8;
+-    TPM2B *pub_key_val = (TPM2B *) &parent_pub->publicArea.unique.rsa;
+-    unsigned char *pub_modulus = malloc(mod_size);
+-    if (pub_modulus == NULL) {
+-        LOG_ERR("Failed to allocate memory to store public key's modulus.");
++    EVP_PKEY_CTX *ctx = NULL;
++
++    EVP_PKEY *pkey = convert_pubkey_RSA(&parent_pub->publicArea);
++    if (pkey == NULL) {
++        LOG_ERR("Failed to retrieve public key");
+         return false;
+     }
+-    memcpy(pub_modulus, pub_key_val->buffer, mod_size);
+ 
+     TPMI_ALG_HASH parent_name_alg = parent_pub->publicArea.nameAlg;
+ 
+@@ -122,70 +50,66 @@ static bool share_secret_with_tpm2_rsa_public_key(TPM2B_DIGEST *protection_seed,
+      * RSA Secret Sharing uses a randomly generated seed (Part 1, B.10.3).
+      */
+     protection_seed->size = tpm2_alg_util_get_hash_size(parent_name_alg);
+-    int return_code = RAND_bytes(protection_seed->buffer, protection_seed->size);
+-    if (return_code != 1) {
++    int rc = RAND_bytes(protection_seed->buffer, protection_seed->size);
++    if (rc != 1) {
+         LOG_ERR("Failed to get random bytes");
+         goto error;
+     }
+ 
+     /*
+-     * This is the biggest buffer value, so it should always be sufficient.
++     * The seed value will be OAEP encrypted with a given L parameter.
+      */
+-    unsigned char encoded[TPM2_MAX_DIGEST_BUFFER];
+-    return_code = RSA_padding_add_PKCS1_OAEP_mgf1(encoded, mod_size,
+-            protection_seed->buffer, protection_seed->size, label, label_len,
+-            tpm2_openssl_md_from_tpmhalg(parent_name_alg), NULL);
+-    if (return_code != 1) {
+-        LOG_ERR("Failed RSA_padding_add_PKCS1_OAEP_mgf1\n");
+-        goto error;
+-    }
+-    BIGNUM* bne = BN_new();
+-    if (!bne) {
+-        LOG_ERR("BN_new for bne failed\n");
++    ctx = EVP_PKEY_CTX_new(pkey, NULL);
++    if (!ctx) {
++        LOG_ERR("Failed EVP_PKEY_CTX_new");
+         goto error;
+     }
+-    return_code = BN_set_word(bne, RSA_F4);
+-    if (return_code != 1) {
+-        LOG_ERR("BN_set_word failed\n");
+-        BN_free(bne);
++
++    rc = EVP_PKEY_encrypt_init(ctx);
++    if (rc <= 0) {
++        LOG_ERR("Failed EVP_PKEY_encrypt_init");
+         goto error;
+     }
+-    rsa = RSA_new();
+-    if (!rsa) {
+-        LOG_ERR("RSA_new failed\n");
+-        BN_free(bne);
++
++    rc = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
++    if (rc <= 0) {
++        LOG_ERR("Failed EVP_PKEY_CTX_set_rsa_padding");
+         goto error;
+     }
+-    return_code = RSA_generate_key_ex(rsa, mod_size_bits, bne, NULL);
+-    BN_free(bne);
+-    if (return_code != 1) {
+-        LOG_ERR("RSA_generate_key_ex failed\n");
++
++    rc = EVP_PKEY_CTX_set_rsa_oaep_md(ctx,
++            tpm2_openssl_md_from_tpmhalg(parent_name_alg));
++    if (rc <= 0) {
++        LOG_ERR("Failed EVP_PKEY_CTX_set_rsa_oaep_md");
+         goto error;
+     }
+-    BIGNUM *n = BN_bin2bn(pub_modulus, mod_size, NULL);
+-    if (n == NULL) {
+-        LOG_ERR("BN_bin2bn failed\n");
++
++    // the library will take ownership of the label
++    char *newlabel = strdup((const char *)label);
++    if (newlabel == NULL) {
++        LOG_ERR("Failed to allocate label");
+         goto error;
+     }
+-    if (!RSA_set0_key(rsa, n, NULL, NULL)) {
+-        LOG_ERR("RSA_set0_key failed\n");
+-        BN_free(n);
++
++    rc = EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, newlabel, label_len);
++    if (rc <= 0) {
++        LOG_ERR("Failed EVP_PKEY_CTX_set0_rsa_oaep_label");
++        free(newlabel);
+         goto error;
+     }
+-    // Encrypting
+-    encrypted_protection_seed->size = mod_size;
+-    return_code = RSA_public_encrypt(mod_size, encoded,
+-            encrypted_protection_seed->secret, rsa, RSA_NO_PADDING);
+-    if (return_code < 0) {
+-        LOG_ERR("Failed RSA_public_encrypt\n");
++
++    size_t outlen = sizeof(TPMU_ENCRYPTED_SECRET);
++    if (EVP_PKEY_encrypt(ctx, encrypted_protection_seed->secret, &outlen,
++            protection_seed->buffer, protection_seed->size) <= 0) {
++        LOG_ERR("Failed EVP_PKEY_encrypt\n");
+         goto error;
+     }
+-
++    encrypted_protection_seed->size = outlen;
+     rval = true;
+ 
+ error:
+-    free(pub_modulus);
+-    RSA_free(rsa);
++    EVP_PKEY_CTX_free(ctx);
++    EVP_PKEY_free(pkey);
+     return rval;
+ }
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0018-Generate-partial-X.509-certificate-using-own-struct.patch b/SOURCES/0018-Generate-partial-X.509-certificate-using-own-struct.patch
new file mode 100644
index 0000000..abdafe1
--- /dev/null
+++ b/SOURCES/0018-Generate-partial-X.509-certificate-using-own-struct.patch
@@ -0,0 +1,282 @@
+From 22ecb8a2c00db7a53508d2106957e0c112a5a020 Mon Sep 17 00:00:00 2001
+From: Petr Gotthard <petr.gotthard@centrum.cz>
+Date: Tue, 31 Aug 2021 12:27:35 +0200
+Subject: [PATCH 17/17] Generate partial X.509 certificate using own struct
+
+The tpm2_certifyX509certutil.c:generate_partial_X509() creates a partial
+(in fact, an incomplete) certificate, see Part 3, 18.8.1. The OpenSSL
+team decided that starting from 3.0 the i2d should not create invalid
+encodings, so we need to create an own ASN.1 structure for this.
+
+The structure is adapted from
+https://github.com/openssl/openssl/issues/16257#issuecomment-895448370.
+
+Fixes: #2813
+
+Signed-off-by: Petr Gotthard <petr.gotthard@centrum.cz>
+---
+ tools/misc/tpm2_certifyX509certutil.c | 179 +++++++++-----------------
+ 1 file changed, 59 insertions(+), 120 deletions(-)
+
+diff --git a/tools/misc/tpm2_certifyX509certutil.c b/tools/misc/tpm2_certifyX509certutil.c
+index 62ed644a..5eea08e8 100644
+--- a/tools/misc/tpm2_certifyX509certutil.c
++++ b/tools/misc/tpm2_certifyX509certutil.c
+@@ -8,6 +8,8 @@
+ #include <sys/stat.h>
+ #include <unistd.h>
+ 
++#include <openssl/asn1.h>
++#include <openssl/asn1t.h>
+ #include <openssl/x509.h>
+ #include <openssl/x509v3.h>
+ #include <openssl/bio.h>
+@@ -15,6 +17,46 @@
+ #include "log.h"
+ #include "tpm2_tool.h"
+ 
++typedef struct {
++    ASN1_TIME *notBefore;
++    ASN1_TIME *notAfter;
++} TPM2_PARTIAL_CERT_VALIDITY;
++
++typedef struct {
++    X509_ALGOR *algorithm;
++    X509_NAME *issuer;
++    TPM2_PARTIAL_CERT_VALIDITY *validity;
++    X509_NAME *subject;
++    STACK_OF(X509_EXTENSION) *extensions;
++} TPM2_PARTIAL_CERT;
++
++ASN1_SEQUENCE(TPM2_PARTIAL_CERT_VALIDITY) = {
++    ASN1_SIMPLE(TPM2_PARTIAL_CERT_VALIDITY, notBefore, ASN1_TIME),
++    ASN1_SIMPLE(TPM2_PARTIAL_CERT_VALIDITY, notAfter, ASN1_TIME),
++} ASN1_SEQUENCE_END(TPM2_PARTIAL_CERT_VALIDITY)
++
++/* partialCertificate per Part 3, 18.8.1 */
++ASN1_SEQUENCE(TPM2_PARTIAL_CERT) = {
++    ASN1_OPT(TPM2_PARTIAL_CERT, algorithm, X509_ALGOR),
++    ASN1_SIMPLE(TPM2_PARTIAL_CERT, issuer, X509_NAME),
++    ASN1_SIMPLE(TPM2_PARTIAL_CERT, validity, TPM2_PARTIAL_CERT_VALIDITY),
++    ASN1_SIMPLE(TPM2_PARTIAL_CERT, subject, X509_NAME),
++    ASN1_EXP_SEQUENCE_OF(TPM2_PARTIAL_CERT, extensions, X509_EXTENSION, 3),
++} ASN1_SEQUENCE_END(TPM2_PARTIAL_CERT)
++
++IMPLEMENT_ASN1_FUNCTIONS(TPM2_PARTIAL_CERT)
++
++int i2d_TPM2_PARTIAL_CERT_bio(BIO *bp, const TPM2_PARTIAL_CERT *a)
++{
++    return ASN1_i2d_bio_of(TPM2_PARTIAL_CERT, i2d_TPM2_PARTIAL_CERT, bp, a);
++}
++
++int TPM2_add_ext(TPM2_PARTIAL_CERT *x, X509_EXTENSION *ex, int loc)
++{
++    return (X509v3_add_ext(&(x->extensions), ex, loc) != NULL);
++}
++
++
+ struct tpm_gen_partial_cert {
+     const char *out_path;
+     const char *valid_str;
+@@ -95,80 +137,6 @@ static struct name_fields names[] = {
+       .def = "CA Unit" },
+ };
+ 
+-static tool_rc fixup_cert(const char *cert) {
+-
+-    int fd = open(cert, O_RDONLY);
+-    if (fd < 0) {
+-        LOG_ERR("open failed");
+-        return tool_rc_general_error;
+-    }
+-
+-    struct stat fs;
+-    int ret = fstat(fd, &fs);
+-    if (ret < 0) {
+-        close(fd);
+-        return tool_rc_general_error;
+-    }
+-
+-    ssize_t size = fs.st_size;
+-    if (size < 100 || size > 255) {
+-        LOG_ERR("Wrong cert size %zd", size);
+-        close(fd);
+-        return tool_rc_general_error; /* there is something wrong with this cert */
+-    }
+-
+-    char* buf = calloc(1, size);
+-    if (!buf) {
+-        LOG_ERR("Alloc failed");
+-        close(fd);
+-        return tool_rc_general_error;
+-    }
+-
+-    tool_rc rc = tool_rc_success;
+-    ret = read(fd, buf, size);
+-    close(fd);
+-    if (ret != size) {
+-        LOG_ERR("read failed");
+-        rc = tool_rc_general_error;
+-        goto out;
+-    }
+-
+-    fd = open(cert, O_WRONLY | O_TRUNC);
+-    if (fd < 0) {
+-        LOG_ERR("second open failed");
+-        rc = tool_rc_general_error;
+-        goto out;
+-    }
+-
+-    /* We need to skip one wrapping sequence (8 bytes) and one
+-     * sequence with one empty byte field at the end (5 bytes).
+-     * Fix the size here */
+-    buf[2] = size - 16;
+-
+-    /* Write the external sequence with the fixed size */
+-    ret = write(fd, buf, 3);
+-    if (ret != 3) {
+-        LOG_ERR("write failed");
+-        rc = tool_rc_general_error;
+-        close(fd);
+-        goto out;
+-    }
+-
+-    /* skip the wrapping sequence the write the rest
+-     * without the 5 bytes at the end */
+-    ret = write(fd, buf + 11, size - 16);
+-    close(fd);
+-    if (ret != size - 16) {
+-        LOG_ERR("second write failed");
+-        rc = tool_rc_general_error;
+-    }
+-
+-out:
+-    free(buf);
+-
+-    return rc;
+-}
+-
+ static int populate_fields(X509_NAME *name, const char *opt) {
+ 
+     char *name_opt = strdup(opt);
+@@ -228,19 +196,14 @@ static tool_rc generate_partial_X509() {
+     }
+ 
+     X509_EXTENSION *extv3 = NULL;
+-    X509 *cert = X509_new();
++    TPM2_PARTIAL_CERT *cert = TPM2_PARTIAL_CERT_new();
+     if (!cert) {
+-        LOG_ERR("X509_new");
+-        goto out_err;
+-    }
+-
+-    X509_NAME *issuer = X509_get_issuer_name(cert);
+-    if (!issuer) {
+-        LOG_ERR("X509_get_issuer_name");
++        LOG_ERR("TPM2_PARTIAL_CERT_new");
+         goto out_err;
+     }
+ 
+-    int fields_added = populate_fields(issuer, ctx.issuer);
++    /* populate issuer */
++    int fields_added = populate_fields(cert->issuer, ctx.issuer);
+     if (fields_added <= 0) {
+         LOG_ERR("Could not parse any issuer fields");
+         goto out_err;
+@@ -248,28 +211,18 @@ static tool_rc generate_partial_X509() {
+         LOG_INFO("Added %d issuer fields", fields_added);
+     }
+ 
+-    int ret = X509_set_issuer_name(cert, issuer); // add issuer
+-    if (ret != 1) {
+-        LOG_ERR("X509_set_issuer_name");
+-        goto out_err;
+-    }
+-
++    /* populate validity */
+     unsigned int valid_days;
+     if (!tpm2_util_string_to_uint32(ctx.valid_str, &valid_days)) {
+         LOG_ERR("string_to_uint32");
+         goto out_err;
+     }
+ 
+-    X509_gmtime_adj(X509_getm_notBefore(cert), 0); // add valid not before
+-    X509_gmtime_adj(X509_getm_notAfter(cert), valid_days * 86400); // add valid not after
+-
+-    X509_NAME *subject = X509_get_subject_name(cert);
+-    if (!subject) {
+-        LOG_ERR("X509_get_subject_name");
+-        goto out_err;
+-    }
++    X509_gmtime_adj(cert->validity->notBefore, 0); // add valid not before
++    X509_gmtime_adj(cert->validity->notAfter, valid_days * 86400); // add valid not after
+ 
+-    fields_added = populate_fields(subject, ctx.subject);
++    /* populate subject */
++    fields_added = populate_fields(cert->subject, ctx.subject);
+     if (fields_added <= 0) {
+         LOG_ERR("Could not parse any subject fields");
+         goto out_err;
+@@ -277,51 +230,37 @@ static tool_rc generate_partial_X509() {
+         LOG_INFO("Added %d subject fields", fields_added);
+     }
+ 
+-    ret = X509_set_subject_name(cert, subject);  // add subject
+-    if (ret != 1) {
+-        LOG_ERR("X509_NAME_add_entry_by_txt");
+-        goto out_err;
+-    }
+-
++    /* populate extensions */
+     extv3 = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage,
+-    "critical,digitalSignature,keyCertSign,cRLSign");
++                "critical,digitalSignature,keyCertSign,cRLSign");
+     if (!extv3) {
+         LOG_ERR("X509V3_EXT_conf_nid");
+         goto out_err;
+     }
+ 
+-    ret = X509_add_ext(cert, extv3, -1); // add required v3 extention: key usage
++    int ret = TPM2_add_ext(cert, extv3, -1); // add required v3 extention: key usage
+     if (ret != 1) {
+         LOG_ERR("X509_add_ext");
+         goto out_err;
+     }
+ 
+-    ret = i2d_X509_bio(cert_out, cert); // print cert in DER format
++    /* output */
++    ret = i2d_TPM2_PARTIAL_CERT_bio(cert_out, cert); // print cert in DER format
+     if (ret != 1) {
+         LOG_ERR("i2d_X509_bio");
+         goto out_err;
+     }
+ 
+     X509_EXTENSION_free(extv3);
+-    X509_free(cert);
++    TPM2_PARTIAL_CERT_free(cert);
+     BIO_free_all(cert_out);
+ 
+-    ret = fixup_cert(ctx.out_path);
+-    if (ret) {
+-        LOG_ERR("fixup_cert");
+-        return tool_rc_general_error;
+-    }
+-
+     return tool_rc_success;
+ 
+ out_err:
+     BIO_free_all(cert_out);
+-    if (cert) {
+-        X509_free(cert);
+-    }
+-    if (extv3) {
+-        X509_EXTENSION_free(extv3);
+-    }
++    X509_EXTENSION_free(extv3);
++    TPM2_PARTIAL_CERT_free(cert);
+ 
+     return tool_rc_general_error;
+ }
+-- 
+2.31.1
+
diff --git a/SOURCES/0019-build-Use-hardcoded-version-variable.patch b/SOURCES/0019-build-Use-hardcoded-version-variable.patch
new file mode 100644
index 0000000..ba05609
--- /dev/null
+++ b/SOURCES/0019-build-Use-hardcoded-version-variable.patch
@@ -0,0 +1,32 @@
+From 395651f059ceb21d56c44cddda05e055caa0fd19 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Hor=C3=A1=C4=8Dek?=
+ <shoracek@redhat.com>
+Date: Mon, 18 Oct 2021 19:04:54 +0200
+Subject: [PATCH] build: Use hardcoded version variable
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Before this commit the version was generated from git tag/commit hash.
+This caused problems with having empty version variable while building
+outside of git. Fix this by hardcoding the variable.
+
+Signed-off-by: Štěpán Horáček <shoracek@redhat.com>
+---
+ configure.ac | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 9561fa86..2bf3a790 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,5 +1,4 @@
+-AC_INIT([tpm2-tools],
+-    [m4_esyscmd_s([git describe --tags --always --dirty])])
++AC_INIT([tpm2-tools], [5.0])
+ AC_CONFIG_MACRO_DIR([m4])
+ 
+ AX_IS_RELEASE([dash-version])
+-- 
+2.31.1
+
diff --git a/SPECS/tpm2-tools.spec b/SPECS/tpm2-tools.spec
index 3b54d42..699846d 100644
--- a/SPECS/tpm2-tools.spec
+++ b/SPECS/tpm2-tools.spec
@@ -2,13 +2,31 @@
 
 Name:    tpm2-tools
 Version: 5.0
-Release: 8%{?candidate:.%{candidate}}%{?dist}
+Release: 10%{?candidate:.%{candidate}}%{?dist}
 Summary: A bunch of TPM testing toolS build upon tpm2-tss
 
 License: BSD
 URL:     https://github.com/tpm2-software/tpm2-tools
 Source0: https://github.com/tpm2-software/tpm2-tools/releases/download/%{version}%{?candidate:-%{candidate}}/%{name}-%{version}%{?candidate:-%{candidate}}.tar.gz
 Patch0: 0001-tpm2_import-fix-fixed-AES-key-CVE-2021-3565.patch
+Patch1: 0002-Don-t-assume-end-of-argv-is-NULL.patch
+Patch2: 0003-tpm2_options-fix-possible-null-ptr-passed-to-strdup.patch
+Patch3: 0004-tpm2_identity_util-move-create_name-into-utility-lib.patch
+Patch4: 0005-openssl-Remove-support-for-OpenSSL-1.1.0.patch
+Patch5: 0006-openssl-Remove-functions-that-have-no-effect-in-Open.patch
+Patch6: 0007-openssl-Remove-unnecesary-EVP_CIPHER_CTX-and-HMAC_CT.patch
+Patch7: 0008-openssl-Replace-SHA256_CTX-by-EVP_MD_CTX.patch
+Patch8: 0009-openssl-Replace-deprecated-X509_get_-by-X509_getm_.patch
+Patch9: 0010-openssl-Convert-deprecated-SHA256-384-digesters-to-E.patch
+Patch10: 0011-openssl-Rename-tpm2_openssl_halg_from_tpmhalg.patch
+Patch11: 0012-openssl-Use-EVP_MAC_update-instead-HMAC_Update-on-Op.patch
+Patch12: 0013-openssl-Remove-unnecessary-compatibility-function.patch
+Patch13: 0014-openssl-Implement-EVP_PKEY-based-key-import.patch
+Patch14: 0015-openssl-Implement-EVP_PKEY-based-key-export.patch
+Patch15: 0016-openssl-Convert-deprecated-ECDH_compute_key-to-EVP_P.patch
+Patch16: 0017-openssl-Reimplement-RSA-OAEP-encryption-using-EVP-fu.patch
+Patch17: 0018-Generate-partial-X.509-certificate-using-own-struct.patch
+Patch18: 0019-build-Use-hardcoded-version-variable.patch
 
 BuildRequires: make
 BuildRequires: gcc-c++
@@ -33,6 +51,7 @@ tpm2-tools is a batch of tools for tpm2.0. It is based on tpm2-tss.
 %autosetup -p1 -n %{name}-%{version}%{?candidate:-%{candidate}}
 
 %build
+autoreconf -i
 # LTO exposes a latent uninitialized variable "value" in the function # "nt".
 # This has been reported to the maintainer (Yunying), but they have not
 # responded and I am not comfortable enough with the code to know if a trivial
@@ -58,6 +77,14 @@ tpm2-tools is a batch of tools for tpm2.0. It is based on tpm2-tss.
 %{_mandir}/man1/tss2_*.1.gz
 
 %changelog
+* Mon Oct 25 2021 Štěpán Horáček <shoracek@redhat.com> - 5.0-10
+- Fix the version not being reported
+  Resolves: rhbz#2015941
+
+* Fri Oct 1 2021 Štěpán Horáček <shoracek@redhat.com> - 5.0-9
+- Fix a segfault on ppc64le and add support for OpenSSL 3
+  Resolves: rhbz#1989617
+
 * Tue Aug 10 2021 Mohan Boddu <mboddu@redhat.com> - 5.0-8
 - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
   Related: rhbz#1991688