Blame SOURCES/gnutls-3.7.3-libtss2-dlopen.patch

5dccd1
From f5e5ab910b8b1d69f962ca033d1295c3e1e1e131 Mon Sep 17 00:00:00 2001
5dccd1
From: Daiki Ueno <ueno@gnu.org>
5dccd1
Date: Wed, 23 Feb 2022 19:48:52 +0100
5dccd1
Subject: [PATCH] tpm2: dynamically load tss2 libraries as needed
5dccd1
5dccd1
libtss2-esys links to OpenSSL or mbed TLS for cryptography, which may
5dccd1
cause packaging issues.  This instead dlopen's tss2 libraries as
5dccd1
needed so non-TPM applications continue working without loading
5dccd1
multiple crypto libraries.
5dccd1
5dccd1
Signed-off-by: Daiki Ueno <ueno@gnu.org>
5dccd1
---
5dccd1
 configure.ac        |  11 +-
5dccd1
 lib/Makefile.am     |   6 +-
5dccd1
 lib/tpm2.c          |   2 +-
5dccd1
 lib/tpm2.h          |   2 +-
5dccd1
 lib/tpm2_esys.c     | 273 ++++++++++++++++++++++++++++++++++++--------
5dccd1
 tests/Makefile.am   |   3 +-
5dccd1
 tests/sanity-lib.sh |  40 +++++++
5dccd1
 tests/tpm2.sh       |  14 ++-
5dccd1
 8 files changed, 296 insertions(+), 55 deletions(-)
5dccd1
 create mode 100644 tests/sanity-lib.sh
5dccd1
5dccd1
diff --git a/configure.ac b/configure.ac
5dccd1
index 53c3aefca1..721ff208f0 100644
5dccd1
--- a/configure.ac
5dccd1
+++ b/configure.ac
5dccd1
@@ -882,6 +882,8 @@ AM_CONDITIONAL(P11KIT_0_23_11_API, $PKG_CONFIG --atleast-version=0.23.11 p11-kit
5dccd1
 
5dccd1
 AM_CONDITIONAL(ENABLE_PKCS11, test "$with_p11_kit" != "no")
5dccd1
 
5dccd1
+need_ltlibdl=no
5dccd1
+
5dccd1
 AC_ARG_WITH(tpm2,
5dccd1
 	AS_HELP_STRING([--without-tpm2],
5dccd1
 		[Disable TPM2 support.]),
5dccd1
@@ -892,6 +894,7 @@ if test "$with_tpm2" != "no"; then
5dccd1
 	if test "$have_tpm2" = "yes"; then
5dccd1
 		tss2lib="tss2-esys tss2-mu tss2-tctildr"
5dccd1
 		AC_DEFINE([HAVE_TSS2], 1, [Have TSS2])
5dccd1
+		need_ltlibdl=yes
5dccd1
 	elif test "$with_tpm2" = "yes"; then
5dccd1
 		AC_MSG_ERROR([[
5dccd1
 ***
5dccd1
@@ -920,7 +923,8 @@ if test "$with_tpm" != "no"; then
5dccd1
 		   AC_SUBST([TSS_LIBS], [-ltspi])
5dccd1
 		   AC_SUBST([TSS_CFLAGS], [])
5dccd1
 		   AC_DEFINE([HAVE_TROUSERS], 1, [Enable TPM])
5dccd1
-		   with_tpm=yes],
5dccd1
+		   with_tpm=yes,
5dccd1
+		   need_ltlibdl=yes],
5dccd1
 		  [AC_MSG_RESULT(no)
5dccd1
 		   AC_MSG_WARN([[
5dccd1
 *** 
5dccd1
@@ -957,6 +961,9 @@ fi
5dccd1
 AC_DEFINE_UNQUOTED([TROUSERS_LIB], ["$ac_trousers_lib"], [the location of the trousers library])
5dccd1
 AC_SUBST(TROUSERS_LIB)
5dccd1
 
5dccd1
+
5dccd1
+AM_CONDITIONAL(NEED_LTLIBDL, test "$need_ltlibdl" = yes)
5dccd1
+
5dccd1
 # For minitasn1.
5dccd1
 AC_CHECK_SIZEOF(unsigned long int, 4)
5dccd1
 AC_CHECK_SIZEOF(unsigned int, 4)
5dccd1
@@ -1312,7 +1319,7 @@ AC_MSG_NOTICE([External hardware support:
5dccd1
   Random gen. variant:  $rnd_variant
5dccd1
   PKCS#11 support:      $with_p11_kit
5dccd1
   TPM support:          $with_tpm
5dccd1
-  TPM2 support:         $have_tpm2
5dccd1
+  TPM2 support:         $with_tpm2
5dccd1
   KTLS support:         $enable_ktls
5dccd1
 ])
5dccd1
 
5dccd1
diff --git a/lib/Makefile.am b/lib/Makefile.am
5dccd1
index 35df35ee8d..e61ee1b6ae 100644
5dccd1
--- a/lib/Makefile.am
5dccd1
+++ b/lib/Makefile.am
5dccd1
@@ -44,7 +44,7 @@ AM_CPPFLAGS = \
5dccd1
 	-I$(srcdir)/x509			\
5dccd1
 	$(LIBTASN1_CFLAGS)			\
5dccd1
 	$(P11_KIT_CFLAGS)			\
5dccd1
-	$(TPM2_CFLAGS)
5dccd1
+	$(TSS2_CFLAGS)
5dccd1
 
5dccd1
 if !HAVE_LIBUNISTRING
5dccd1
 SUBDIRS += unistring
5dccd1
@@ -156,7 +156,7 @@ libgnutls_la_LIBADD = ../gl/libgnu.la x509/libgnutls_x509.la \
5dccd1
 	auth/libgnutls_auth.la algorithms/libgnutls_alg.la \
5dccd1
 	extras/libgnutls_extras.la
5dccd1
 thirdparty_libadd = $(LTLIBZ) $(LTLIBINTL) $(LIBSOCKET) $(LTLIBNSL) \
5dccd1
-	$(P11_KIT_LIBS) $(LIB_SELECT) $(TSS2_LIBS) $(GNUTLS_LIBS_PRIVATE)
5dccd1
+	$(P11_KIT_LIBS) $(LIB_SELECT) $(GNUTLS_LIBS_PRIVATE)
5dccd1
 
5dccd1
 if HAVE_LIBIDN2
5dccd1
 thirdparty_libadd += $(LIBIDN2_LIBS)
5dccd1
@@ -203,7 +203,7 @@ all-local: $(hmac_files)
5dccd1
 CLEANFILES = $(hmac_files)
5dccd1
 endif
5dccd1
 
5dccd1
-if ENABLE_TROUSERS
5dccd1
+if NEED_LTLIBDL
5dccd1
 thirdparty_libadd += $(LTLIBDL)
5dccd1
 endif
5dccd1
 
5dccd1
diff --git a/lib/tpm2.c b/lib/tpm2.c
5dccd1
index 076cc7f407..750eadc777 100644
5dccd1
--- a/lib/tpm2.c
5dccd1
+++ b/lib/tpm2.c
5dccd1
@@ -297,5 +297,5 @@ int _gnutls_load_tpm2_key(gnutls_privkey_t pkey, const gnutls_datum_t *fdata)
5dccd1
 
5dccd1
 void _gnutls_tpm2_deinit(void)
5dccd1
 {
5dccd1
-	tpm2_tcti_deinit();
5dccd1
+	tpm2_esys_deinit();
5dccd1
 }
5dccd1
diff --git a/lib/tpm2.h b/lib/tpm2.h
5dccd1
index e40dc01df7..7966e2d811 100644
5dccd1
--- a/lib/tpm2.h
5dccd1
+++ b/lib/tpm2.h
5dccd1
@@ -37,7 +37,7 @@ struct tpm2_info_st;
5dccd1
 
5dccd1
 struct tpm2_info_st *tpm2_info_init(struct pin_info_st *pin);
5dccd1
 
5dccd1
-void tpm2_tcti_deinit(void);
5dccd1
+void tpm2_esys_deinit(void);
5dccd1
 
5dccd1
 void release_tpm2_ctx(struct tpm2_info_st *info);
5dccd1
 
5dccd1
diff --git a/lib/tpm2_esys.c b/lib/tpm2_esys.c
5dccd1
index 93e54413ba..4000c1b76e 100644
5dccd1
--- a/lib/tpm2_esys.c
5dccd1
+++ b/lib/tpm2_esys.c
5dccd1
@@ -72,6 +72,170 @@
5dccd1
 #include <tss2/tss2_esys.h>
5dccd1
 #include <tss2/tss2_tctildr.h>
5dccd1
 
5dccd1
+#include <dlfcn.h>
5dccd1
+
5dccd1
+/* We don't want to link to libtss2-esys, as it brings in other
5dccd1
+ * crypto libraries.  Instead, only dlopen it as needed.
5dccd1
+ */
5dccd1
+
5dccd1
+static void *_gnutls_tss2_esys_dlhandle;
5dccd1
+static void *_gnutls_tss2_mu_dlhandle;
5dccd1
+static void *_gnutls_tss2_tctildr_dlhandle;
5dccd1
+
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Esys_GetCapability)(ESYS_CONTEXT *esysContext,
5dccd1
+				   ESYS_TR shandle1,
5dccd1
+				   ESYS_TR shandle2,
5dccd1
+				   ESYS_TR shandle3,
5dccd1
+				   TPM2_CAP capability,
5dccd1
+				   UINT32 property,
5dccd1
+				   UINT32 propertyCount,
5dccd1
+				   TPMI_YES_NO *moreData,
5dccd1
+				   TPMS_CAPABILITY_DATA **capabilityData);
5dccd1
+static void (*_gnutls_tss2_Esys_Free)(void *__ptr);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext,
5dccd1
+					       ESYS_TR handle,
5dccd1
+					       TPM2B_AUTH const *authValue);
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext,
5dccd1
+				   ESYS_TR primaryHandle,
5dccd1
+				   ESYS_TR shandle1,
5dccd1
+				   ESYS_TR shandle2,
5dccd1
+				   ESYS_TR shandle3,
5dccd1
+				   const TPM2B_SENSITIVE_CREATE *inSensitive,
5dccd1
+				   const TPM2B_PUBLIC *inPublic,
5dccd1
+				   const TPM2B_DATA *outsideInfo,
5dccd1
+				   const TPML_PCR_SELECTION *creationPCR,
5dccd1
+				   ESYS_TR *objectHandle,
5dccd1
+				   TPM2B_PUBLIC **outPublic,
5dccd1
+				   TPM2B_CREATION_DATA **creationData,
5dccd1
+				   TPM2B_DIGEST **creationHash,
5dccd1
+				   TPMT_TK_CREATION **creationTicket);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_Initialize)(ESYS_CONTEXT **esys_context,
5dccd1
+					       TSS2_TCTI_CONTEXT *tcti,
5dccd1
+					       TSS2_ABI_VERSION *abiVersion);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_Startup)(ESYS_CONTEXT *esysContext,
5dccd1
+					    TPM2_SU startupType);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_TR_FromTPMPublic)(ESYS_CONTEXT *esysContext,
5dccd1
+						     TPM2_HANDLE tpm_handle,
5dccd1
+						     ESYS_TR optionalSession1,
5dccd1
+						     ESYS_TR optionalSession2,
5dccd1
+						     ESYS_TR optionalSession3,
5dccd1
+						     ESYS_TR *object);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_ReadPublic)(ESYS_CONTEXT *esysContext,
5dccd1
+					       ESYS_TR objectHandle,
5dccd1
+					       ESYS_TR shandle1,
5dccd1
+					       ESYS_TR shandle2,
5dccd1
+					       ESYS_TR shandle3,
5dccd1
+					       TPM2B_PUBLIC **outPublic,
5dccd1
+					       TPM2B_NAME **name,
5dccd1
+					       TPM2B_NAME **qualifiedName);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_Load)(ESYS_CONTEXT *esysContext,
5dccd1
+					 ESYS_TR parentHandle,
5dccd1
+					 ESYS_TR shandle1,
5dccd1
+					 ESYS_TR shandle2,
5dccd1
+					 ESYS_TR shandle3,
5dccd1
+					 const TPM2B_PRIVATE *inPrivate,
5dccd1
+					 const TPM2B_PUBLIC *inPublic,
5dccd1
+					 ESYS_TR *objectHandle);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_FlushContext)(ESYS_CONTEXT *esysContext,
5dccd1
+						 ESYS_TR flushHandle);
5dccd1
+static void (*_gnutls_tss2_Esys_Finalize)(ESYS_CONTEXT **context);
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Esys_RSA_Decrypt)(ESYS_CONTEXT *esysContext,
5dccd1
+				 ESYS_TR keyHandle,
5dccd1
+				 ESYS_TR shandle1,
5dccd1
+				 ESYS_TR shandle2,
5dccd1
+				 ESYS_TR shandle3,
5dccd1
+				 const TPM2B_PUBLIC_KEY_RSA *cipherText,
5dccd1
+				 const TPMT_RSA_DECRYPT *inScheme,
5dccd1
+				 const TPM2B_DATA *label,
5dccd1
+				 TPM2B_PUBLIC_KEY_RSA **message);
5dccd1
+static TSS2_RC (*_gnutls_tss2_Esys_Sign)(ESYS_CONTEXT *esysContext,
5dccd1
+					 ESYS_TR keyHandle,
5dccd1
+					 ESYS_TR shandle1,
5dccd1
+					 ESYS_TR shandle2,
5dccd1
+					 ESYS_TR shandle3,
5dccd1
+					 const TPM2B_DIGEST *digest,
5dccd1
+					 const TPMT_SIG_SCHEME *inScheme,
5dccd1
+					 const TPMT_TK_HASHCHECK *validation,
5dccd1
+					 TPMT_SIGNATURE **signature);
5dccd1
+
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[],
5dccd1
+						size_t buffer_size,
5dccd1
+						size_t *offset,
5dccd1
+						TPM2B_PRIVATE *dest);
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[],
5dccd1
+					       size_t buffer_size,
5dccd1
+					       size_t *offset,
5dccd1
+					       TPM2B_PUBLIC *dest);
5dccd1
+
5dccd1
+static TSS2_RC
5dccd1
+(*_gnutls_tss2_Tss2_TctiLdr_Initialize)(const char *nameConf,
5dccd1
+					TSS2_TCTI_CONTEXT **context);
5dccd1
+static void (*_gnutls_tss2_Tss2_TctiLdr_Finalize)(TSS2_TCTI_CONTEXT **context);
5dccd1
+
5dccd1
+#define DLSYM_TSS2(sys, sym)						\
5dccd1
+	_gnutls_tss2_##sym = dlsym(_gnutls_tss2_##sys##_dlhandle, #sym); \
5dccd1
+	if (!_gnutls_tss2_##sym) {					\
5dccd1
+		return -1;						\
5dccd1
+	}
5dccd1
+
5dccd1
+static int
5dccd1
+init_tss2_funcs(void)
5dccd1
+{
5dccd1
+	if (!_gnutls_tss2_esys_dlhandle) {
5dccd1
+		_gnutls_tss2_esys_dlhandle =
5dccd1
+			dlopen("libtss2-esys.so.0", RTLD_NOW | RTLD_GLOBAL);
5dccd1
+		if (!_gnutls_tss2_esys_dlhandle) {
5dccd1
+			_gnutls_debug_log("tpm2: unable to dlopen libtss2-esys\n");
5dccd1
+			return -1;
5dccd1
+		}
5dccd1
+	}
5dccd1
+
5dccd1
+	DLSYM_TSS2(esys, Esys_GetCapability)
5dccd1
+	DLSYM_TSS2(esys, Esys_Free)
5dccd1
+	DLSYM_TSS2(esys, Esys_TR_SetAuth)
5dccd1
+	DLSYM_TSS2(esys, Esys_CreatePrimary)
5dccd1
+	DLSYM_TSS2(esys, Esys_Initialize)
5dccd1
+	DLSYM_TSS2(esys, Esys_Startup)
5dccd1
+	DLSYM_TSS2(esys, Esys_TR_FromTPMPublic)
5dccd1
+	DLSYM_TSS2(esys, Esys_ReadPublic)
5dccd1
+	DLSYM_TSS2(esys, Esys_Load)
5dccd1
+	DLSYM_TSS2(esys, Esys_FlushContext)
5dccd1
+	DLSYM_TSS2(esys, Esys_Finalize)
5dccd1
+	DLSYM_TSS2(esys, Esys_RSA_Decrypt)
5dccd1
+	DLSYM_TSS2(esys, Esys_Sign)
5dccd1
+
5dccd1
+	if (!_gnutls_tss2_mu_dlhandle) {
5dccd1
+		_gnutls_tss2_mu_dlhandle =
5dccd1
+			dlopen("libtss2-mu.so.0", RTLD_NOW | RTLD_GLOBAL);
5dccd1
+		if (!_gnutls_tss2_mu_dlhandle) {
5dccd1
+			_gnutls_debug_log("tpm2: unable to dlopen libtss2-mu\n");
5dccd1
+			return -1;
5dccd1
+		}
5dccd1
+	}
5dccd1
+
5dccd1
+	DLSYM_TSS2(mu, Tss2_MU_TPM2B_PRIVATE_Unmarshal)
5dccd1
+	DLSYM_TSS2(mu, Tss2_MU_TPM2B_PUBLIC_Unmarshal)
5dccd1
+
5dccd1
+	if (!_gnutls_tss2_tctildr_dlhandle) {
5dccd1
+		_gnutls_tss2_tctildr_dlhandle =
5dccd1
+			dlopen("libtss2-tctildr.so.0", RTLD_NOW | RTLD_GLOBAL);
5dccd1
+		if (!_gnutls_tss2_tctildr_dlhandle) {
5dccd1
+			_gnutls_debug_log("tpm2: unable to dlopen libtss2-tctildr\n");
5dccd1
+			return -1;
5dccd1
+		}
5dccd1
+	}
5dccd1
+
5dccd1
+	DLSYM_TSS2(tctildr, Tss2_TctiLdr_Initialize)
5dccd1
+	DLSYM_TSS2(tctildr, Tss2_TctiLdr_Finalize)
5dccd1
+
5dccd1
+	return 0;
5dccd1
+}
5dccd1
+
5dccd1
 struct tpm2_info_st {
5dccd1
 	TPM2B_PUBLIC pub;
5dccd1
 	TPM2B_PRIVATE priv;
5dccd1
@@ -227,10 +391,10 @@ get_primary_template(ESYS_CONTEXT *ctx)
5dccd1
 	UINT32 i;
5dccd1
 	TSS2_RC rc;
5dccd1
 
5dccd1
-	rc = Esys_GetCapability (ctx,
5dccd1
-				 ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
-				 TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS,
5dccd1
-				 NULL, &capability_data);
5dccd1
+	rc = _gnutls_tss2_Esys_GetCapability(ctx,
5dccd1
+				ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
+				TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS,
5dccd1
+				NULL, &capability_data);
5dccd1
 	if (rc) {
5dccd1
 		_gnutls_debug_log("tpm2: Esys_GetCapability failed: 0x%x\n", rc);
5dccd1
 		return NULL;
5dccd1
@@ -239,7 +403,7 @@ get_primary_template(ESYS_CONTEXT *ctx)
5dccd1
 	for (i = 0; i < capability_data->data.algorithms.count; i++) {
5dccd1
 		if (capability_data->data.algorithms.algProperties[i].alg ==
5dccd1
 		    TPM2_ALG_ECC) {
5dccd1
-			Esys_Free(capability_data);
5dccd1
+			_gnutls_tss2_Esys_Free(capability_data);
5dccd1
 			return &primary_template_ecc;
5dccd1
 		}
5dccd1
 	}
5dccd1
@@ -247,12 +411,12 @@ get_primary_template(ESYS_CONTEXT *ctx)
5dccd1
 	for (i = 0; i < capability_data->data.algorithms.count; i++) {
5dccd1
 		if (capability_data->data.algorithms.algProperties[i].alg ==
5dccd1
 		    TPM2_ALG_RSA) {
5dccd1
-			Esys_Free(capability_data);
5dccd1
+			_gnutls_tss2_Esys_Free(capability_data);
5dccd1
 			return &primary_template_rsa;
5dccd1
 		}
5dccd1
         }
5dccd1
 
5dccd1
-	Esys_Free(capability_data);
5dccd1
+	_gnutls_tss2_Esys_Free(capability_data);
5dccd1
 	_gnutls_debug_log("tpm2: unable to find primary template\n");
5dccd1
 	return NULL;
5dccd1
 }
5dccd1
@@ -320,7 +484,7 @@ static int init_tpm2_primary(struct tpm2_info_st *info,
5dccd1
 		install_tpm_passphrase(&info->ownerauth, pass);
5dccd1
 		info->need_ownerauth = false;
5dccd1
 	}
5dccd1
-	rc = Esys_TR_SetAuth(ctx, hierarchy, &info->ownerauth);
5dccd1
+	rc = _gnutls_tss2_Esys_TR_SetAuth(ctx, hierarchy, &info->ownerauth);
5dccd1
 	if (rc) {
5dccd1
 		_gnutls_debug_log("tpm2: Esys_TR_SetAuth failed: 0x%x\n", rc);
5dccd1
 		return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
5dccd1
@@ -329,7 +493,7 @@ static int init_tpm2_primary(struct tpm2_info_st *info,
5dccd1
 	if (!primary_template) {
5dccd1
 		return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
5dccd1
 	}
5dccd1
-	rc = Esys_CreatePrimary(ctx, hierarchy,
5dccd1
+	rc = _gnutls_tss2_Esys_CreatePrimary(ctx, hierarchy,
5dccd1
 				ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
 				&primary_sensitive,
5dccd1
 				primary_template,
5dccd1
@@ -359,14 +523,14 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 
5dccd1
 	_gnutls_debug_log("tpm2: establishing connection with TPM\n");
5dccd1
 
5dccd1
-	rc = Esys_Initialize(ctx, tcti_ctx, NULL);
5dccd1
+	rc = _gnutls_tss2_Esys_Initialize(ctx, tcti_ctx, NULL);
5dccd1
 	if (rc) {
5dccd1
 		gnutls_assert();
5dccd1
 		_gnutls_debug_log("tpm2: Esys_Initialize failed: 0x%x\n", rc);
5dccd1
 		goto error;
5dccd1
 	}
5dccd1
 
5dccd1
-	rc = Esys_Startup(*ctx, TPM2_SU_CLEAR);
5dccd1
+	rc = _gnutls_tss2_Esys_Startup(*ctx, TPM2_SU_CLEAR);
5dccd1
 	if (rc == TPM2_RC_INITIALIZE) {
5dccd1
 		_gnutls_debug_log("tpm2: was already started up thus false positive failing in tpm2tss log\n");
5dccd1
 	} else if (rc) {
5dccd1
@@ -381,7 +545,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 			goto error;
5dccd1
 		}
5dccd1
 	} else {
5dccd1
-		rc = Esys_TR_FromTPMPublic(*ctx, info->parent,
5dccd1
+		rc = _gnutls_tss2_Esys_TR_FromTPMPublic(*ctx, info->parent,
5dccd1
 					   ESYS_TR_NONE,
5dccd1
 					   ESYS_TR_NONE,
5dccd1
 					   ESYS_TR_NONE,
5dccd1
@@ -399,7 +563,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 		if (!info->did_ownerauth && !info->ownerauth.size) {
5dccd1
 			TPM2B_PUBLIC *pub = NULL;
5dccd1
 
5dccd1
-			rc = Esys_ReadPublic(*ctx, parent_handle,
5dccd1
+			rc = _gnutls_tss2_Esys_ReadPublic(*ctx, parent_handle,
5dccd1
 					     ESYS_TR_NONE,
5dccd1
 					     ESYS_TR_NONE,
5dccd1
 					     ESYS_TR_NONE,
5dccd1
@@ -408,7 +572,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 			    !(pub->publicArea.objectAttributes & TPMA_OBJECT_NODA)) {
5dccd1
 				info->need_ownerauth = true;
5dccd1
 			}
5dccd1
-			Esys_Free(pub);
5dccd1
+			_gnutls_tss2_Esys_Free(pub);
5dccd1
 		}
5dccd1
 	reauth:
5dccd1
 		if (info->need_ownerauth) {
5dccd1
@@ -420,7 +584,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 			install_tpm_passphrase(&info->ownerauth, pass);
5dccd1
 			info->need_ownerauth = false;
5dccd1
 		}
5dccd1
-		rc = Esys_TR_SetAuth(*ctx, parent_handle, &info->ownerauth);
5dccd1
+		rc = _gnutls_tss2_Esys_TR_SetAuth(*ctx, parent_handle, &info->ownerauth);
5dccd1
 		if (rc) {
5dccd1
 			gnutls_assert();
5dccd1
 			_gnutls_debug_log("tpm2: Esys_TR_SetAuth failed: 0x%x\n",
5dccd1
@@ -432,7 +596,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 	_gnutls_debug_log("tpm2: loading TPM2 key blob, parent handle 0x%x\n",
5dccd1
 			  parent_handle);
5dccd1
 
5dccd1
-	rc = Esys_Load(*ctx, parent_handle,
5dccd1
+	rc = _gnutls_tss2_Esys_Load(*ctx, parent_handle,
5dccd1
 		       ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
 		       &info->priv, &info->pub,
5dccd1
 		       key_handle);
5dccd1
@@ -450,7 +614,7 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 	info->did_ownerauth = true;
5dccd1
 
5dccd1
 	if (parent_is_generated(info->parent)) {
5dccd1
-		rc = Esys_FlushContext(*ctx, parent_handle);
5dccd1
+		rc = _gnutls_tss2_Esys_FlushContext(*ctx, parent_handle);
5dccd1
 		if (rc) {
5dccd1
 			_gnutls_debug_log("tpm2: Esys_FlushContext for generated primary failed: 0x%x\n",
5dccd1
 					  rc);
5dccd1
@@ -461,14 +625,14 @@ static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *key_handle,
5dccd1
 	return 0;
5dccd1
  error:
5dccd1
 	if (parent_is_generated(info->parent) && parent_handle != ESYS_TR_NONE) {
5dccd1
-		Esys_FlushContext(*ctx, parent_handle);
5dccd1
+		_gnutls_tss2_Esys_FlushContext(*ctx, parent_handle);
5dccd1
 	}
5dccd1
 	if (*key_handle != ESYS_TR_NONE) {
5dccd1
-		Esys_FlushContext(*ctx, *key_handle);
5dccd1
+		_gnutls_tss2_Esys_FlushContext(*ctx, *key_handle);
5dccd1
 	}
5dccd1
 	*key_handle = ESYS_TR_NONE;
5dccd1
 
5dccd1
-	Esys_Finalize(ctx);
5dccd1
+	_gnutls_tss2_Esys_Finalize(ctx);
5dccd1
 	return GNUTLS_E_TPM_ERROR;
5dccd1
 }
5dccd1
 
5dccd1
@@ -488,7 +652,7 @@ auth_tpm2_key(struct tpm2_info_st *info, ESYS_CONTEXT *ctx, ESYS_TR key_handle)
5dccd1
 		info->need_userauth = false;
5dccd1
 	}
5dccd1
 
5dccd1
-	rc = Esys_TR_SetAuth(ctx, key_handle, &info->userauth);
5dccd1
+	rc = _gnutls_tss2_Esys_TR_SetAuth(ctx, key_handle, &info->userauth);
5dccd1
 	if (rc) {
5dccd1
 		_gnutls_debug_log("tpm2: Esys_TR_SetAuth failed: 0x%x\n", rc);
5dccd1
 		return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
5dccd1
@@ -574,7 +738,7 @@ int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
5dccd1
 		goto out;
5dccd1
 	}
5dccd1
 
5dccd1
-	rc = Esys_RSA_Decrypt(ectx, key_handle,
5dccd1
+	rc = _gnutls_tss2_Esys_RSA_Decrypt(ectx, key_handle,
5dccd1
 			      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
 			      &digest, &in_scheme, &label, &tsig);
5dccd1
 	if (rc_is_key_auth_failed(rc)) {
5dccd1
@@ -591,14 +755,14 @@ int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
5dccd1
 
5dccd1
 	ret = _gnutls_set_datum(sig, tsig->buffer, tsig->size);
5dccd1
  out:
5dccd1
-	Esys_Free(tsig);
5dccd1
+	_gnutls_tss2_Esys_Free(tsig);
5dccd1
 
5dccd1
 	if (key_handle != ESYS_TR_NONE) {
5dccd1
-		Esys_FlushContext(ectx, key_handle);
5dccd1
+		_gnutls_tss2_Esys_FlushContext(ectx, key_handle);
5dccd1
 	}
5dccd1
 
5dccd1
 	if (ectx) {
5dccd1
-		Esys_Finalize(&ectx);
5dccd1
+		_gnutls_tss2_Esys_Finalize(&ectx);
5dccd1
 	}
5dccd1
 
5dccd1
 	return ret;
5dccd1
@@ -661,7 +825,7 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
5dccd1
 		goto out;
5dccd1
 	}
5dccd1
 
5dccd1
-	rc = Esys_Sign(ectx, key_handle,
5dccd1
+	rc = _gnutls_tss2_Esys_Sign(ectx, key_handle,
5dccd1
 		       ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
5dccd1
 		       &digest, &in_scheme, &validation,
5dccd1
 		       &tsig);
5dccd1
@@ -682,31 +846,23 @@ int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
5dccd1
 
5dccd1
 	ret = gnutls_encode_rs_value(sig, &sig_r, &sig_s);
5dccd1
  out:
5dccd1
-	Esys_Free(tsig);
5dccd1
+	_gnutls_tss2_Esys_Free(tsig);
5dccd1
 
5dccd1
 	if (key_handle != ESYS_TR_NONE) {
5dccd1
-		Esys_FlushContext(ectx, key_handle);
5dccd1
+		_gnutls_tss2_Esys_FlushContext(ectx, key_handle);
5dccd1
 	}
5dccd1
 
5dccd1
 	if (ectx) {
5dccd1
-		Esys_Finalize(&ectx);
5dccd1
+		_gnutls_tss2_Esys_Finalize(&ectx);
5dccd1
 	}
5dccd1
 
5dccd1
 	return ret;
5dccd1
 }
5dccd1
 
5dccd1
-GNUTLS_ONCE(tcti_once);
5dccd1
-
5dccd1
-void
5dccd1
-tpm2_tcti_deinit(void)
5dccd1
-{
5dccd1
-	if (tcti_ctx) {
5dccd1
-		Tss2_TctiLdr_Finalize(&tcti_ctx);
5dccd1
-	}
5dccd1
-}
5dccd1
+GNUTLS_ONCE(tpm2_esys_once);
5dccd1
 
5dccd1
 static void
5dccd1
-tcti_once_init(void)
5dccd1
+tpm2_esys_once_init(void)
5dccd1
 {
5dccd1
 	const char *tcti;
5dccd1
 	const char * const tcti_vars[] = {
5dccd1
@@ -718,6 +874,11 @@ tcti_once_init(void)
5dccd1
 	size_t i;
5dccd1
 	TSS2_RC rc;
5dccd1
 
5dccd1
+	if (init_tss2_funcs() < 0) {
5dccd1
+		_gnutls_debug_log("tpm2: unable to initialize TSS2 functions\n");
5dccd1
+		return;
5dccd1
+	}
5dccd1
+
5dccd1
 	for (i = 0; i < sizeof(tcti_vars) / sizeof(tcti_vars[0]); i++) {
5dccd1
 		tcti = secure_getenv(tcti_vars[i]);
5dccd1
 		if (tcti && *tcti != '\0') {
5dccd1
@@ -727,7 +888,7 @@ tcti_once_init(void)
5dccd1
 		}
5dccd1
 	}
5dccd1
 	if (tcti && *tcti != '\0') {
5dccd1
-		rc = Tss2_TctiLdr_Initialize(tcti, &tcti_ctx);
5dccd1
+		rc = _gnutls_tss2_Tss2_TctiLdr_Initialize(tcti, &tcti_ctx);
5dccd1
 		if (rc) {
5dccd1
 			_gnutls_debug_log("tpm2: TSS2_TctiLdr_Initialize failed: 0x%x\n",
5dccd1
 					  rc);
5dccd1
@@ -735,13 +896,35 @@ tcti_once_init(void)
5dccd1
 	}
5dccd1
 }
5dccd1
 
5dccd1
+/* called by the global destructor through _gnutls_tpm2_deinit */
5dccd1
+void
5dccd1
+tpm2_esys_deinit(void)
5dccd1
+{
5dccd1
+	if (tcti_ctx) {
5dccd1
+		_gnutls_tss2_Tss2_TctiLdr_Finalize(&tcti_ctx);
5dccd1
+		tcti_ctx = NULL;
5dccd1
+	}
5dccd1
+	if (_gnutls_tss2_esys_dlhandle) {
5dccd1
+		dlclose(_gnutls_tss2_esys_dlhandle);
5dccd1
+		_gnutls_tss2_esys_dlhandle = NULL;
5dccd1
+	}
5dccd1
+	if (_gnutls_tss2_mu_dlhandle) {
5dccd1
+		dlclose(_gnutls_tss2_mu_dlhandle);
5dccd1
+		_gnutls_tss2_mu_dlhandle = NULL;
5dccd1
+	}
5dccd1
+	if (_gnutls_tss2_tctildr_dlhandle) {
5dccd1
+		dlclose(_gnutls_tss2_tctildr_dlhandle);
5dccd1
+		_gnutls_tss2_tctildr_dlhandle = NULL;
5dccd1
+	}
5dccd1
+}
5dccd1
+
5dccd1
 int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey,
5dccd1
 		     unsigned int parent, bool emptyauth,
5dccd1
 		     gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
5dccd1
 {
5dccd1
 	TSS2_RC rc;
5dccd1
 
5dccd1
-	(void)gnutls_once(&tcti_once, tcti_once_init);
5dccd1
+	(void)gnutls_once(&tpm2_esys_once, tpm2_esys_once_init);
5dccd1
 
5dccd1
 	if (!tcti_ctx) {
5dccd1
 		return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
5dccd1
@@ -757,16 +940,16 @@ int install_tpm2_key(struct tpm2_info_st *info, gnutls_privkey_t pkey,
5dccd1
 
5dccd1
 	info->parent = parent;
5dccd1
 
5dccd1
-	rc = Tss2_MU_TPM2B_PRIVATE_Unmarshal(privdata->data, privdata->size, NULL,
5dccd1
-					     &info->priv);
5dccd1
+	rc = _gnutls_tss2_Tss2_MU_TPM2B_PRIVATE_Unmarshal(privdata->data, privdata->size, NULL,
5dccd1
+							     &info->priv);
5dccd1
 	if (rc) {
5dccd1
 		_gnutls_debug_log("tpm2: failed to import private key data: 0x%x\n",
5dccd1
 				  rc);
5dccd1
 		return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
5dccd1
 	}
5dccd1
 
5dccd1
-	rc = Tss2_MU_TPM2B_PUBLIC_Unmarshal(pubdata->data, pubdata->size, NULL,
5dccd1
-					    &info->pub);
5dccd1
+	rc = _gnutls_tss2_Tss2_MU_TPM2B_PUBLIC_Unmarshal(pubdata->data, pubdata->size, NULL,
5dccd1
+							    &info->pub);
5dccd1
 	if (rc) {
5dccd1
 		_gnutls_debug_log("tpm2: failed to import public key data: 0x%x\n",
5dccd1
 				  rc);
5dccd1
diff --git a/tests/Makefile.am b/tests/Makefile.am
5dccd1
index 529f1cc077..64ce470a02 100644
5dccd1
--- a/tests/Makefile.am
5dccd1
+++ b/tests/Makefile.am
5dccd1
@@ -515,7 +515,8 @@ dist_check_SCRIPTS += fastopen.sh pkgconfig.sh starttls.sh starttls-ftp.sh start
5dccd1
 	psktool.sh ocsp-tests/ocsp-load-chain.sh gnutls-cli-save-data.sh gnutls-cli-debug.sh \
5dccd1
 	sni-resume.sh ocsp-tests/ocsptool.sh cert-reencoding.sh pkcs7-cat.sh long-crl.sh \
5dccd1
 	serv-udp.sh logfile-option.sh gnutls-cli-resume.sh profile-tests.sh \
5dccd1
-	server-weak-keys.sh ocsp-tests/ocsp-signer-verify.sh cfg-test.sh
5dccd1
+	server-weak-keys.sh ocsp-tests/ocsp-signer-verify.sh cfg-test.sh \
5dccd1
+	sanity-lib.sh
5dccd1
 
5dccd1
 if !DISABLE_SYSTEM_CONFIG
5dccd1
 dist_check_SCRIPTS += system-override-sig.sh system-override-hash.sh \
5dccd1
diff --git a/tests/sanity-lib.sh b/tests/sanity-lib.sh
5dccd1
new file mode 100644
5dccd1
index 0000000000..1e3612781b
5dccd1
--- /dev/null
5dccd1
+++ b/tests/sanity-lib.sh
5dccd1
@@ -0,0 +1,40 @@
5dccd1
+#!/bin/sh
5dccd1
+
5dccd1
+# Copyright (C) 2022 Red Hat, Inc.
5dccd1
+#
5dccd1
+# Author: Daiki Ueno
5dccd1
+#
5dccd1
+# This file is part of GnuTLS.
5dccd1
+#
5dccd1
+# GnuTLS is free software; you can redistribute it and/or modify it
5dccd1
+# under the terms of the GNU General Public License as published by the
5dccd1
+# Free Software Foundation; either version 3 of the License, or (at
5dccd1
+# your option) any later version.
5dccd1
+#
5dccd1
+# GnuTLS is distributed in the hope that it will be useful, but
5dccd1
+# WITHOUT ANY WARRANTY; without even the implied warranty of
5dccd1
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5dccd1
+# General Public License for more details.
5dccd1
+#
5dccd1
+# You should have received a copy of the GNU Lesser General Public License
5dccd1
+# along with this program.  If not, see <https://www.gnu.org/licenses/>
5dccd1
+
5dccd1
+: ${top_builddir=..}
5dccd1
+: ${CLI_DEBUG=../src/gnutls-cli-debug${EXEEXT}}
5dccd1
+: ${LDD=ldd}
5dccd1
+: ${LIBTOOL=libtool}
5dccd1
+
5dccd1
+if ! test -x "${CLI_DEBUG}"; then
5dccd1
+	exit 77
5dccd1
+fi
5dccd1
+
5dccd1
+# ldd.sh doesn't check recursive dependencies
5dccd1
+${LDD} --version >/dev/null || exit 77
5dccd1
+
5dccd1
+# We use gnutls-cli-debug, as it has the fewest dependencies among our
5dccd1
+# commands (e.g., gnutls-cli pulls in OpenSSL through libunbound).
5dccd1
+if ${LIBTOOL} --mode=execute ${LDD} ${CLI_DEBUG} | \
5dccd1
+    grep '^[[:space:]]*\(libcrypto\.\|libssl\.\|libgcrypt\.\)'; then
5dccd1
+    echo "gnutls-cli-debug links to other crypto library"
5dccd1
+    exit 1
5dccd1
+fi
5dccd1
diff --git a/tests/tpm2.sh b/tests/tpm2.sh
5dccd1
index 854986c552..6f8e44c64b 100755
5dccd1
--- a/tests/tpm2.sh
5dccd1
+++ b/tests/tpm2.sh
5dccd1
@@ -21,8 +21,6 @@
5dccd1
 # along with GnuTLS; if not, write to the Free Software Foundation,
5dccd1
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
5dccd1
 
5dccd1
-set +e
5dccd1
-
5dccd1
 : ${srcdir=.}
5dccd1
 : ${CERTTOOL=../src/certtool${EXEEXT}}
5dccd1
 KEYPEMFILE=tpmkey.$$.key.pem
5dccd1
@@ -192,6 +190,10 @@ run_tests()
5dccd1
 
5dccd1
 	echo " - Generating ${KEYPEMFILE}"
5dccd1
 	tpm2tss-genkey -a ${kalg} -o ${OPASS} ${KEYPEMFILE}
5dccd1
+	if [ $? -ne 0 ]; then
5dccd1
+		echo "unable to generate key"
5dccd1
+		return 1
5dccd1
+	fi
5dccd1
 	cat ${KEYPEMFILE}
5dccd1
 
5dccd1
 	echo " - Generating certificate based on key"
5dccd1
@@ -200,6 +202,10 @@ run_tests()
5dccd1
 	"${CERTTOOL}" --generate-self-signed -d 3 \
5dccd1
 		--load-privkey "${KEYPEMFILE}" \
5dccd1
 		--template "${srcdir}/cert-tests/templates/template-test.tmpl"
5dccd1
+	if [ $? -ne 0 ]; then
5dccd1
+		echo "unable to generate certificate"
5dccd1
+		return 1
5dccd1
+	fi
5dccd1
 
5dccd1
 	if test "${kalg}" = "rsa";then
5dccd1
 		echo " - Generating RSA-PSS certificate based on key"
5dccd1
@@ -207,6 +213,10 @@ run_tests()
5dccd1
 			--load-privkey "${KEYPEMFILE}" \
5dccd1
 			--sign-params rsa-pss \
5dccd1
 			--template "${srcdir}/cert-tests/templates/template-test.tmpl"
5dccd1
+		if [ $? -ne 0 ]; then
5dccd1
+			echo "unable to generate certificate"
5dccd1
+			return 1
5dccd1
+		fi
5dccd1
 	fi
5dccd1
 
5dccd1
 	stop_swtpm
5dccd1
-- 
5dccd1
2.34.1
5dccd1