gnome-keyring [RFC 2/2] gkm: add the TPM as a signing engine



This implements the gkm backend to do signing within the TPM based on
TPM keys.  The tpm keys are passed through gnome-keyring as
s-expressions, but they're never actually seen by libgcrypt (it's just
an easy way of handling them).  Once they're filtered out, the signing
is passed off to the TPM.

This scheme involves loading up the wrapped key using the SRK as the
parent (and assuming well known SRK authority) and signing with the
key before unloading.  This is slightly suboptimal, because it
involves the TPM doing *two* RSA operations per signature (one to
unwrap the key and one to sign) but it does prevent the TPM becoming
full of keys and refusing to work.

Signed-off-by: James Bottomley <James Bottomley HansenPartnership com>
---
 configure.ac                   |  24 ++++++
 pkcs11/gkm/Makefile.am         |   2 +
 pkcs11/gkm/gkm-crypto.c        |  12 ++-
 pkcs11/gkm/gkm-tpm-mechanism.c | 168 +++++++++++++++++++++++++++++++++++++++++
 pkcs11/gkm/gkm-tpm-mechanism.h |  17 +++++
 5 files changed, 220 insertions(+), 3 deletions(-)
 create mode 100644 pkcs11/gkm/gkm-tpm-mechanism.c
 create mode 100644 pkcs11/gkm/gkm-tpm-mechanism.h

diff --git a/configure.ac b/configure.ac
index cbab29f..119f3cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -442,6 +442,30 @@ AC_DEFINE_UNQUOTED(DOTLOCK_EXT_SYM_PREFIX,[_gkm_],
                   [Prefix used for external functions of dotlock.])
 
 # ----------------------------------------------------------------------
+# trousers
+for l in /usr/lib64 /usr/lib /lib64 /lib /usr/lib/x86_64-linux-gnu/; do
+    if test -f "${l}/libtspi.so.1";then
+        default_trousers_lib="${l}/libtspi.so.1"
+        break
+    fi
+done
+
+AC_ARG_WITH(trousers-lib, AS_HELP_STRING([--with-trousers-lib=LIB],
+                                 [set the location of the trousers library]),
+            ac_trousers_lib=$withval, ac_trousers_lib=$default_trousers_lib)
+
+if test -z "$ac_trousers_lib"; then
+    AC_MSG_ERROR([[
+  ***
+  *** unable to find trousers library, please specify with --with-trousers-lib=<lib file>
+  ***
+  ]])
+fi
+
+AC_DEFINE_UNQUOTED([TROUSERS_LIB], ["$ac_trousers_lib"], [the location of the trousers library])
+AC_SUBST(TROUSERS_LIB)
+
+# ----------------------------------------------------------------------
 # p11-tests
 
 AC_ARG_ENABLE(p11_tests,
diff --git a/pkcs11/gkm/Makefile.am b/pkcs11/gkm/Makefile.am
index 949aec3..518e42d 100644
--- a/pkcs11/gkm/Makefile.am
+++ b/pkcs11/gkm/Makefile.am
@@ -92,6 +92,8 @@ libgkm_la_SOURCES = \
        pkcs11/gkm/gkm-test.h \
        pkcs11/gkm/gkm-timer.c \
        pkcs11/gkm/gkm-timer.h \
+       pkcs11/gkm/gkm-tpm-mechanism.c \
+       pkcs11/gkm/gkm-tpm-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 710b503..4a71392 100644
--- a/pkcs11/gkm/gkm-crypto.c
+++ b/pkcs11/gkm/gkm-crypto.c
@@ -24,6 +24,7 @@
 #include "gkm-aes-mechanism.h"
 #include "gkm-dh-mechanism.h"
 #include "gkm-dsa-mechanism.h"
+#include "gkm-tpm-mechanism.h"
 #include "gkm-hkdf-mechanism.h"
 #include "gkm-null-mechanism.h"
 #include "gkm-rsa-mechanism.h"
@@ -256,15 +257,20 @@ CK_RV
 gkm_crypto_sign (GkmSession *session, CK_MECHANISM_TYPE mech, CK_BYTE_PTR data,
                  CK_ULONG n_data, CK_BYTE_PTR signature, CK_ULONG_PTR n_signature)
 {
-       GkmSexp *sexp;
+       GkmSexp *sexp = gkm_session_get_crypto_state (session);
+       gcry_sexp_t s_key = gkm_sexp_get (sexp);
+
+       /* check if this is a TPM key first */
+       if (gcry_sexp_find_token (s_key, "tpm", 0))
+               return gkm_tpm_mechanism_sign (s_key, mech, data,
+                                              n_data, signature, n_signature);
 
        switch (mech) {
        case CKM_RSA_PKCS:
        case CKM_RSA_X_509:
        case CKM_DSA:
-               sexp = gkm_session_get_crypto_state (session);
                g_return_val_if_fail (sexp, CKR_GENERAL_ERROR);
-               return gkm_crypto_sign_xsa (gkm_sexp_get (sexp), mech, data, n_data, signature, n_signature);
+               return gkm_crypto_sign_xsa (s_key, mech, data, n_data, signature, n_signature);
        default:
                g_return_val_if_reached (CKR_GENERAL_ERROR);
        }
diff --git a/pkcs11/gkm/gkm-tpm-mechanism.c b/pkcs11/gkm/gkm-tpm-mechanism.c
new file mode 100644
index 0000000..8933560
--- /dev/null
+++ b/pkcs11/gkm/gkm-tpm-mechanism.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 James Bottomley HansenPartnership com
+ *
+ * LGPL-2.1
+ */
+
+#include "config.h"
+
+#include "gkm-tpm-mechanism.h"
+
+#include <gcrypt.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <trousers/tss.h>
+#include <trousers/trousers.h>
+
+/* List of trousers 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 _TROUSERS_LIST(F)                      \
+       F(Tspi_Context_Create);                 \
+       F(Tspi_Context_Connect);                \
+       F(Tspi_Context_Close);                  \
+       F(Tspi_Context_LoadKeyByUUID);          \
+       F(Tspi_GetPolicyObject);                \
+       F(Tspi_Policy_SetSecret);               \
+       F(Tspi_Context_LoadKeyByBlob);          \
+       F(Trspi_Error_String);                  \
+       F(Trspi_Error_Layer);                   \
+       F(Tspi_GetAttribUint32);                \
+       F(Tspi_Context_CreateObject);           \
+       F(Tspi_Policy_AssignToObject);          \
+       F(Tspi_Hash_SetHashValue);              \
+       F(Tspi_Hash_Sign)
+
+/* create static declarations for the function pointers */
+#define _DL_DECLARE(func) \
+       static typeof(func) *p##func
+_TROUSERS_LIST(_DL_DECLARE);
+
+/* More macro jiggery-pokery: most of the Tspi functions are
+ * invoked as a do something, check error and fail, so macroize that */
+#define _TROUSERS_CHECK(f, a)                                  \
+       err = p##f a;                                           \
+       if (err != TSS_SUCCESS) {                               \
+               g_message("%s gave TPM (%s) Error: %s\n",       \
+                         #f, pTrspi_Error_Layer(err),          \
+                         pTrspi_Error_String(err));            \
+               goto out_close;                                 \
+       }
+
+static CK_RV tpm_init(void)
+{
+       static int inited = 0;
+       const char *sym;
+       void *dl;
+
+       if (inited)
+               return CKR_OK;
+
+       dl = dlopen(TROUSERS_LIB, RTLD_LAZY);
+
+       if (!dl) {
+               g_message("opening of trousers 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
+       _TROUSERS_LIST(_DL_SYM);
+
+       inited = 1;
+       return CKR_OK;
+
+ out_symfail:
+       g_message("Failed to find symbol %s in trousers library %s\n",
+                 sym, TROUSERS_LIB);
+       return CKR_DEVICE_ERROR;
+}
+
+CK_RV
+gkm_tpm_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)
+{
+       TSS_HCONTEXT ctx;
+       TSS_HKEY srk, ckey;
+       TSS_HPOLICY srk_policy, ckey_policy;
+       TSS_HHASH hash;
+       BYTE *sig;
+       UINT32 n_sig;
+       int err;
+       CK_RV ret;
+       uint32_t authusage;
+       gcry_sexp_t tpm_parms, exp;
+       const char *blob, *auth;
+       size_t n_blob, n_auth;
+
+       static unsigned char zero_auth[20];
+       static const TSS_UUID srk_uuid = TSS_UUID_SRK;
+
+       if (!signature) {
+               /* Just wants to know the buffer size: TPM RSA keys
+                * are all 2048 bits */
+               *n_signature = 2048/8;
+               return CKR_OK;
+       }
+
+       tpm_parms = gcry_sexp_find_token(key, "tpm", 0);
+       if (!tpm_parms)
+               return CKR_GENERAL_ERROR;
+       exp = gcry_sexp_find_token(tpm_parms, "blob", 0);
+       if (!exp)
+               return CKR_GENERAL_ERROR;
+       blob = gcry_sexp_nth_data(exp, 1, &n_blob);
+       exp = gcry_sexp_find_token(tpm_parms, "auth", 0);
+       if (!exp)
+               return CKR_GENERAL_ERROR;
+       auth = gcry_sexp_nth_data(exp, 1, &n_auth);
+
+       ret = tpm_init();
+       if (ret)
+               goto out;
+
+       ret = CKR_GENERAL_ERROR;
+
+       _TROUSERS_CHECK(Tspi_Context_Create, (&ctx));
+       _TROUSERS_CHECK(Tspi_Context_Connect, (ctx, NULL));
+       _TROUSERS_CHECK(Tspi_Context_LoadKeyByUUID, (ctx, TSS_PS_TYPE_SYSTEM, srk_uuid, &srk));
+       _TROUSERS_CHECK(Tspi_GetPolicyObject, (srk, TSS_POLICY_USAGE, &srk_policy));
+       _TROUSERS_CHECK(Tspi_Policy_SetSecret, (srk_policy, TSS_SECRET_MODE_SHA1, sizeof(zero_auth), 
zero_auth));
+       _TROUSERS_CHECK(Tspi_Context_LoadKeyByBlob, (ctx, srk, n_blob, (BYTE *)blob, &ckey));
+       _TROUSERS_CHECK(Tspi_GetAttribUint32, (ckey, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, 
&authusage));
+
+       if (authusage) {
+               if (n_auth == 0) {
+                       ret = CKR_KEY_UNEXTRACTABLE;
+                       goto out_close;
+               }
+               _TROUSERS_CHECK(Tspi_Context_CreateObject, (ctx, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE, 
&ckey_policy));
+               _TROUSERS_CHECK(Tspi_Policy_AssignToObject, (ckey_policy,ckey));
+               _TROUSERS_CHECK(Tspi_Policy_SetSecret, (ckey_policy, TSS_SECRET_MODE_PLAIN, n_auth, (BYTE 
*)auth));
+       }
+       _TROUSERS_CHECK(Tspi_Context_CreateObject, (ctx, TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER, &hash));
+       _TROUSERS_CHECK(Tspi_Hash_SetHashValue, (hash, n_data, data));
+       _TROUSERS_CHECK(Tspi_Hash_Sign, (hash, ckey, &n_sig, &sig));
+
+       ret = CKR_BUFFER_TOO_SMALL;
+       if (n_sig > *n_signature)
+               goto out_free;
+
+       ret = CKR_OK;
+
+       memcpy(signature, sig, n_sig);
+       *n_signature = n_sig;
+ out_free:
+       free(sig);
+ out_close:
+       /* easy cleanup: all objects get killed with the context */
+       pTspi_Context_Close(ctx);
+ out:
+       return ret;
+}
diff --git a/pkcs11/gkm/gkm-tpm-mechanism.h b/pkcs11/gkm/gkm-tpm-mechanism.h
new file mode 100644
index 0000000..19a996b
--- /dev/null
+++ b/pkcs11/gkm/gkm-tpm-mechanism.h
@@ -0,0 +1,17 @@
+#ifndef GKM_TPM_MECHANISM_H_
+#define GKM_TPM_MECHANISM_H_
+
+#include "gkm-crypto.h"
+#include "gkm-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+CK_RV
+gkm_tpm_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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]