LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File 0005-gkm-add-TPM-2.0-as-a-signing-engine.patch of Package gnome-keyring (Project home:jejb1:Tumbleweed)

From 04dd4a33eab28d374557836fb7583bc879238b75 Mon Sep 17 00:00:00 2001
From: James Bottomley <James.Bottomley@HansenPartnership.com>
Date: Sun, 1 Jan 2017 12:19:39 -0800
Subject: [PATCH 5/6] gkm: add TPM 2.0 as a signing engine

This implements the gkm backend to do signing with TPM2.  TPM2 is very
picky about its signature types, so signing is actualy implemented
with a decrypt function meaning we have to pad the data ourselves
(this works because libtss is actually linked with libcrypto) We now
also need openssl-devel because of the requirement for the function
prototype for the padding.

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

--

v2 - add HMAC authorization
---
 configure.ac                    |   6 +
 pkcs11/gkm/Makefile.am          |   2 +
 pkcs11/gkm/gkm-crypto.c         |   5 +
 pkcs11/gkm/gkm-tpm2-mechanism.c | 245 ++++++++++++++++++++++++++++++++++++++++
 pkcs11/gkm/gkm-tpm2-mechanism.h |  17 +++
 5 files changed, 275 insertions(+)
 create mode 100644 pkcs11/gkm/gkm-tpm2-mechanism.c
 create mode 100644 pkcs11/gkm/gkm-tpm2-mechanism.h

diff --git a/configure.ac b/configure.ac
index 119f3cd..2f989a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -465,6 +465,12 @@ fi
 AC_DEFINE_UNQUOTED([TROUSERS_LIB], ["$ac_trousers_lib"], [the location of the trousers library])
 AC_SUBST(TROUSERS_LIB)
 
+
+# ----------------------------------------------------------------------
+# tss2
+AC_CHECK_LIB(tss, TSS_Create, , AC_MSG_ERROR([Can't find libtss have you installed tss2-devel?]))
+AC_CHECK_HEADER(openssl/rsa.h,,AC_MSG_ERROR([Can't fined openssl/rsa.h have you installed openssl-devel?]))
+
 # ----------------------------------------------------------------------
 # p11-tests
 
diff --git a/pkcs11/gkm/Makefile.am b/pkcs11/gkm/Makefile.am
index 518e42d..21a99cc 100644
--- a/pkcs11/gkm/Makefile.am
+++ b/pkcs11/gkm/Makefile.am
@@ -94,6 +94,8 @@ libgkm_la_SOURCES = \
 	pkcs11/gkm/gkm-timer.h \
 	pkcs11/gkm/gkm-tpm-mechanism.c \
 	pkcs11/gkm/gkm-tpm-mechanism.h \
+	pkcs11/gkm/gkm-tpm2-mechanism.c \
+	pkcs11/gkm/gkm-tpm2-mechanism.h \
 	pkcs11/gkm/gkm-transaction.c \
 	pkcs11/gkm/gkm-transaction.h \
 	pkcs11/gkm/gkm-trust.c \
diff --git a/pkcs11/gkm/gkm-crypto.c b/pkcs11/gkm/gkm-crypto.c
index 4a71392..9a879a6 100644
--- a/pkcs11/gkm/gkm-crypto.c
+++ b/pkcs11/gkm/gkm-crypto.c
@@ -25,6 +25,7 @@
 #include "gkm-dh-mechanism.h"
 #include "gkm-dsa-mechanism.h"
 #include "gkm-tpm-mechanism.h"
+#include "gkm-tpm2-mechanism.h"
 #include "gkm-hkdf-mechanism.h"
 #include "gkm-null-mechanism.h"
 #include "gkm-rsa-mechanism.h"
@@ -265,6 +266,10 @@ gkm_crypto_sign (GkmSession *session, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
 		return gkm_tpm_mechanism_sign (s_key, mech, data,
 					       n_data, signature, n_signature);
 
+	if (gcry_sexp_find_token (s_key, "tpm2", 0))
+		return gkm_tpm2_mechanism_sign (s_key, mech, data,
+					       n_data, signature, n_signature);
+
 	switch (mech) {
 	case CKM_RSA_PKCS:
 	case CKM_RSA_X_509:
diff --git a/pkcs11/gkm/gkm-tpm2-mechanism.c b/pkcs11/gkm/gkm-tpm2-mechanism.c
new file mode 100644
index 0000000..ac815a9
--- /dev/null
+++ b/pkcs11/gkm/gkm-tpm2-mechanism.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2016 James.Bottomley@HansenPartnership.com
+ *
+ * LGPL-2.1
+ */
+
+#include "config.h"
+
+#include "gkm-tpm2-mechanism.h"
+
+#include <gcrypt.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include <tss2/tss.h>
+#include <tss2/tssutils.h>
+#include <tss2/tssresponsecode.h>
+#include <tss2/Unmarshal_fp.h>
+
+/* needed for padding: libgcrypt doesn't expose its padding functions */
+#include <openssl/rsa.h>
+
+#define TSS2_LIB "libtss.so.0"
+
+/* List of tss2 functions we use.  This is macro jiggery-pokery:
+ * the F argument gives us the ability to run an arbitrary macro over
+ * the function list as for each function do macro F */
+#define _TSS2_LIST(F)			\
+	F(TSS_Create);			\
+	F(TSS_SetProperty);		\
+	F(TSS_Execute);			\
+	F(TSS_ResponseCode_toString);	\
+	F(TPM2B_PUBLIC_Unmarshal);	\
+	F(TPM2B_PRIVATE_Unmarshal);	\
+	F(RSA_padding_add_PKCS1_type_1);\
+	F(TSS_Delete);
+
+/* create static declarations for the function pointers */
+#define _DL_DECLARE(func) \
+	static typeof(func) *p##func
+_TSS2_LIST(_DL_DECLARE);
+
+static CK_RV tpm2_init(void)
+{
+	static int inited = 0;
+	const char *sym;
+	void *dl;
+
+	if (inited)
+		return CKR_OK;
+
+	dl = dlopen(TSS2_LIB, RTLD_LAZY);
+
+	if (!dl) {
+		g_message("opening of tss2 library failed %s\n", strerror(errno));
+		return CKR_DEVICE_ERROR;
+	}
+
+	/* load each symbol pointer and check for existence */
+	#define _DL_SYM(func)			\
+		sym = #func;			\
+		p##func = dlsym(dl, #func);	\
+		if (p##func == NULL)		\
+			goto out_symfail
+	_TSS2_LIST(_DL_SYM);
+
+	inited = 1;
+	return CKR_OK;
+
+ out_symfail:
+	g_message("Failed to find symbol %s in tss2 library\n", sym);
+	return CKR_DEVICE_ERROR;
+}
+
+static void tpm2_error(TPM_RC rc, char *prefix)
+{
+	const char *msg, *submsg, *num;
+
+	pTSS_ResponseCode_toString(&msg, &submsg, &num, rc);
+	g_message("%s gave TPM2 Error: %s%s%s", prefix, msg, submsg, num);
+}
+
+static void
+gkm_tpm2_flush(TSS_CONTEXT *ctx, TPM_HANDLE h)
+{
+	FlushContext_In in;
+
+	in.flushHandle = h;
+
+	pTSS_Execute(ctx,
+		     NULL,
+		     (COMMAND_PARAMETERS *)&in,
+		     NULL,
+		     TPM_CC_FlushContext,
+		     TPM_RH_NULL, NULL, 0);
+}
+
+/* More macro jiggery-pokery: most of the Tspi functions are
+ * invoked as a do something, check error and fail, so macroize that */
+#define _TSS2_CHECK(f, a)					\
+	rc = p##f a;						\
+	if (rc) {						\
+		tpm2_error(rc, #f);				\
+		goto out_close;					\
+	}
+
+CK_RV
+gkm_tpm2_mechanism_sign (gcry_sexp_t key, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
+			 CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
+{
+	CK_RV ret;
+	gcry_sexp_t tpm_parms, exp;
+	const char *pub, *priv, *auth, *parent_str;
+	size_t n_pub, n_priv, n_auth, n_parent_str;
+	unsigned int parent;
+	int sig_size;
+	char localauth[64];
+
+	TPM_RC rc;
+	TSS_CONTEXT *ctx;
+	Load_In lin;
+	Load_Out lout;
+	RSA_Decrypt_In din;
+	RSA_Decrypt_Out dout;
+	StartAuthSession_In ain;
+	StartAuthSession_Out aout;
+	BYTE *buf;
+	INT32 size;
+
+	tpm_parms = gcry_sexp_find_token(key, "tpm2", 0);
+	if (!tpm_parms)
+		return CKR_GENERAL_ERROR;
+	exp = gcry_sexp_find_token(tpm_parms, "pub", 0);
+	if (!exp)
+		return CKR_GENERAL_ERROR;
+	pub = gcry_sexp_nth_data(exp, 1, &n_pub);
+	exp = gcry_sexp_find_token(tpm_parms, "priv", 0);
+	if (!exp)
+		return CKR_GENERAL_ERROR;
+	priv = gcry_sexp_nth_data(exp, 1, &n_priv);
+	exp = gcry_sexp_find_token(tpm_parms, "auth", 0);
+	if (!exp)
+		return CKR_GENERAL_ERROR;
+	auth = gcry_sexp_nth_data(exp, 1, &n_auth);
+	if (n_auth > sizeof(localauth) - 1)
+		return CKR_GENERAL_ERROR;
+
+	strncpy(localauth, auth, n_auth);
+	localauth[n_auth] = '\0';
+
+	exp = gcry_sexp_find_token(tpm_parms, "parent", 0);
+	if (!exp)
+		return CKR_GENERAL_ERROR;
+	parent_str = gcry_sexp_nth_data(exp, 1, &n_parent_str);
+	parent = atoi(parent_str);
+
+	ret = tpm2_init();
+	if (ret)
+		return CKR_GENERAL_ERROR;
+
+	buf = (BYTE *)pub;
+	size = n_pub;
+	_TSS2_CHECK(TPM2B_PUBLIC_Unmarshal, (&lin.inPublic, &buf, &size, FALSE));
+	sig_size = lin.inPublic.publicArea.parameters.rsaDetail.keyBits/8;
+
+	if (!signature) {
+		*n_signature = sig_size;
+		return CKR_OK;
+	}
+	if (*n_signature < sig_size)
+		return CKR_BUFFER_TOO_SMALL;
+
+	ret = CKR_GENERAL_ERROR;
+
+	_TSS2_CHECK(TSS_Create, (&ctx));
+	/* gnome keyring may not be able to write to cwd */
+	_TSS2_CHECK(TSS_SetProperty, (ctx, TPM_DATA_DIR, "/tmp"));
+	lin.parentHandle = parent;
+	buf = (BYTE *)priv;
+	size = n_priv;
+	_TSS2_CHECK(TPM2B_PRIVATE_Unmarshal, (&lin.inPrivate, &buf, &size));
+	rc = pTSS_Execute(ctx,
+		     (RESPONSE_PARAMETERS *)&lout,
+		     (COMMAND_PARAMETERS *)&lin,
+		     NULL,
+		     TPM_CC_Load,
+		     TPM_RS_PW, NULL, 0,
+		     TPM_RH_NULL, NULL, 0);
+
+	if (rc) {
+		tpm2_error(rc, "TPM2_Load");
+		goto out_close;
+	}
+	din.keyHandle = lout.objectHandle;
+
+	din.inScheme.scheme = TPM_ALG_NULL;
+	din.cipherText.t.size = sig_size;
+	pRSA_padding_add_PKCS1_type_1(din.cipherText.t.buffer, sig_size, data, n_data);
+	din.label.t.size = 0;
+
+	memset(&ain, 0, sizeof(ain));
+	ain.sessionType = TPM_SE_HMAC;
+	ain.authHash = TPM_ALG_SHA256;
+	ain.tpmKey = TPM_RH_NULL;
+	ain.symmetric.algorithm = TPM_ALG_AES;
+	ain.symmetric.keyBits.aes = 128;
+	ain.symmetric.mode.aes = TPM_ALG_CFB;
+
+	rc = pTSS_Execute(ctx,
+			  (RESPONSE_PARAMETERS *)&aout,
+			  (COMMAND_PARAMETERS *)&ain,
+			  NULL,
+			  TPM_CC_StartAuthSession,
+			  TPM_RH_NULL, NULL, 0);
+	if (rc) {
+		tpm2_error(rc, "TPM2_StartAuthSession");
+		goto out_close;
+	}
+
+	rc = pTSS_Execute(ctx,
+			   (RESPONSE_PARAMETERS *)&dout,
+			   (COMMAND_PARAMETERS *)&din,
+			   NULL,
+			   TPM_CC_RSA_Decrypt,
+			   aout.sessionHandle, localauth, 0,
+			   TPM_RH_NULL, NULL, 0);
+	if (rc) {
+		tpm2_error(rc, "TPM2_RSA_Decrypt");
+		gkm_tpm2_flush(ctx, aout.sessionHandle);
+		goto out_close;
+	}
+
+	ret = CKR_OK;
+
+	memcpy(signature, dout.message.t.buffer, dout.message.t.size);
+	*n_signature = dout.message.t.size;
+
+ out_close:
+	/* easy cleanup: all objects get killed with the context */
+	pTSS_Delete(ctx);
+
+	return ret;
+}
diff --git a/pkcs11/gkm/gkm-tpm2-mechanism.h b/pkcs11/gkm/gkm-tpm2-mechanism.h
new file mode 100644
index 0000000..d4be56e
--- /dev/null
+++ b/pkcs11/gkm/gkm-tpm2-mechanism.h
@@ -0,0 +1,17 @@
+#ifndef GKM_TPM2_MECHANISM_H_
+#define GKM_TPM2_MECHANISM_H_
+
+#include "gkm-crypto.h"
+#include "gkm-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+CK_RV
+gkm_tpm2_mechanism_sign (gcry_sexp_t sexp, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
+                        CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG_PTR n_signature);
+
+#endif
-- 
2.6.6