1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-13 00:09:51 +02:00
gnupg/tpm2d/ibm-tss.h
James Bottomley 62a7854816
tpm2d: Add tpm2daemon code
* tpm2d: New directory.
* Makefile.am (SUBDIRS): Add directory.
* configure.ac: Detect libtss and decide whether to build tpm2d.
* am/cmacros.am: Add a define.
* util.h (GNUPG_MODULE_NAME_TPM2DAEMON): New.
* common/homedir.c (gnupg_module_name): Add tpm2d.
* common/mapstrings.c (macros): Add "TPM2DAEMON".
* tools/gpgconf.h (GC_COMPONENT_TPM2DAEMON): New.
* tools/gpgconf-comp.c (known_options_tpm2daemon): New.
(gc_component): Add TPM2.
(tpm2daemon_runtime_change): New.
* tpm2d/Makefile.am: New.
* tpm2d/command.c: New.
* tpm2d/ibm-tss.h: New.
* tpm2d/tpm2.c: New.
* tpm2d/tpm2.h: New.
* tpm2d/tpm2daemon.c: New.
* tpm2d/tpm2daemon.h: New.

---
This commit adds and plumbs in a tpm2daemon to the build to mirror the
operation of scdaemon.  The architecture of the code is that
tpm2daemon.c itself is pretty much a clone of scd/scdaemon.c just with
updated function prefixes (this argues there could be some further
consolidation of the daemon handling code).  Note that although this
commit causes the daemon to be built and installed, nothing actually
starts it or uses it yet.

Command handling
----------------

command.c is copied from the command handler in scd.c except that the
command implementation is now done in terms of tpm2 commands and the
wire protocol is far simpler.  The tpm2daemon only responds to 4
commands

IMPORT:    import a standard s-expression private key and export it to
           TPM2 format.  This conversion cannot be undone and the
           private key now can *only* be used by the TPM2.  To anyone
           who gets hold of the private key now, it's just an
           encrypted binary blob.

PKSIGN:    create a signature from the tpm2 key.  The TPM2 form private
           key is retrieved by KEYDATA and the hash to be signed by
           EXTRA.  Note there is no hash specifier because the tpm2
           tss deduces the hash type from the length of the EXTRA
           data.  This is actually a limitation of the tpm2 command
           API and it will be interesting to see how this fares if the
           tpm2 ever supports say sha3-256 hashes.

PKDECRYPT: decrypt (RSA case) or derive (ECC case) a symmetric key.
	   The tpm2 for private key is retrieved by KEYDATA and the
	   information used to create the symmetric key by EXTRA.

KILLTPM2D: stop the daemon

All the tpm2 primitives used by command.c are in tpm2.h and all the
tpm2 specific gunk is confined to tpm2.c, which is the only piece of
this that actually does calls into the tss library.

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

Changes from James' patch:

- gpgconf: The displayed name is "TPM" and not "TPM2".  That
  string is used by GUIs and should be something the user
  understands.  For example we also use "network" instead
  of "Dirmngr".
- Removed some commented includes.
- Use 16 as emulation of GPG_ERR_SOURCE_TPM2.
- Silenced a C90 compiler warning and flags unused parameters.
- Removed "if HAVE_LIBS" from tpm2/Makefile.am and add missing
  files so that make distcheck works.

Signed-off-by: Werner Koch <wk@gnupg.org>
2021-03-10 12:33:08 +01:00

382 lines
8.5 KiB
C

/*
* Copyright (C) 2021 James Bottomley <James.Bottomley@HansenPartnership.com>
*
* Supporting TPM routines for the IBM TSS
*/
#ifndef _TPM2_IBM_TSS_H
#define _TPM2_IBM_TSS_H
#define TSSINCLUDE(x) < TSS_INCLUDE/x >
#include TSSINCLUDE(tss.h)
#include TSSINCLUDE(tssutils.h)
#include TSSINCLUDE(tssresponsecode.h)
#include TSSINCLUDE(tssmarshal.h)
#include TSSINCLUDE(Unmarshal_fp.h)
#include TSSINCLUDE(tsscryptoh.h)
#define EXT_TPM_RH_OWNER TPM_RH_OWNER
#define VAL(X) X.val
#define VAL_2B(X, MEMBER) X.t.MEMBER
static const char *tpm2_dir;
/* The TPM builds a small database of active files representing key
* parameters used for authentication and session encryption. Make sure
* they're contained in a separate directory to avoid stepping on any
* other application uses of the TPM */
static inline const char *
tpm2_set_unique_tssdir (void)
{
char *prefix = getenv ("XDG_RUNTIME_DIR"), *template,
*dir;
int len = 0;
if (!prefix)
prefix = "/tmp";
len = snprintf (NULL, 0, "%s/tss2.XXXXXX", prefix);
if (len <= 0)
return NULL;
template = xtrymalloc (len + 1);
if (!template)
return NULL;
len++;
len = snprintf (template, len, "%s/tss2.XXXXXX", prefix);
dir = mkdtemp (template);
return dir;
}
static inline void
tpm2_error (TPM_RC rc, const char *prefix)
{
const char *msg, *submsg, *num;
TSS_ResponseCode_toString (&msg, &submsg, &num, rc);
log_error ("%s gave TPM2 Error: %s%s%s", prefix, msg, submsg, num);
}
static inline int
TSS_start (TSS_CONTEXT **tssc)
{
TPM_RC rc;
tpm2_dir = tpm2_set_unique_tssdir ();
if (!tpm2_dir)
/* make this non fatal */
log_error ("Failed to set unique TPM directory\n");
rc = TSS_Create (tssc);
if (rc)
{
tpm2_error (rc, "TSS_Create");
return GPG_ERR_CARD;
}
rc = TSS_SetProperty (*tssc, TPM_DATA_DIR, tpm2_dir);
if (rc)
/* make this non fatal */
tpm2_error (rc, "TSS_SetProperty");
return 0;
}
static inline TPM_RC
tpm2_CreatePrimary (TSS_CONTEXT *tssContext, TPM_HANDLE primaryHandle,
TPM2B_SENSITIVE_CREATE *inSensitive,
TPM2B_PUBLIC *inPublic, TPM_HANDLE *objectHandle)
{
CreatePrimary_In in;
CreatePrimary_Out out;
TPM_RC rc;
in.primaryHandle = primaryHandle;
in.inSensitive = *inSensitive;
in.inPublic = *inPublic;
/* no outside info */
in.outsideInfo.t.size = 0;
/* no PCR state */
in.creationPCR.count = 0;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_CreatePrimary,
TPM_RS_PW, NULL, 0,
TPM_RH_NULL, NULL, 0);
*objectHandle = out.objectHandle;
return rc;
}
static inline TPM_RC
tpm2_FlushContext (TSS_CONTEXT *tssContext, TPM_HANDLE flushHandle)
{
FlushContext_In in;
TPM_RC rc;
in.flushHandle = flushHandle;
rc = TSS_Execute (tssContext,
NULL,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_FlushContext,
TPM_RH_NULL, NULL, 0);
return rc;
}
static inline TPM_RC
tpm2_ReadPublic (TSS_CONTEXT *tssContext, TPM_HANDLE objectHandle,
TPMT_PUBLIC *pub, TPM_HANDLE auth)
{
ReadPublic_In rin;
ReadPublic_Out rout;
TPM_RC rc;
UINT32 flags = 0;
if (auth != TPM_RH_NULL)
flags = TPMA_SESSION_ENCRYPT;
rin.objectHandle = objectHandle;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&rout,
(COMMAND_PARAMETERS *)&rin,
NULL,
TPM_CC_ReadPublic,
auth, NULL, flags,
TPM_RH_NULL, NULL, 0);
if (rc)
{
tpm2_error (rc, "TPM2_ReadPublic");
return rc;
}
if (pub)
*pub = rout.outPublic.publicArea;
return rc;
}
static inline TPM_RC
tpm2_StartAuthSession (TSS_CONTEXT *tssContext, TPM_HANDLE tpmKey,
TPM_HANDLE bind, TPM_SE sessionType,
TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash,
TPM_HANDLE *sessionHandle,
const char *bindPassword)
{
StartAuthSession_In in;
StartAuthSession_Out out;
StartAuthSession_Extra extra;
TPM_RC rc;
memset (&in, 0, sizeof(in));
memset (&extra, 0 , sizeof(extra));
extra.bindPassword = bindPassword;
in.tpmKey = tpmKey;
in.bind = bind;
in.sessionType = sessionType;
in.symmetric = *symmetric;
in.authHash = authHash;
if (tpmKey != TPM_RH_NULL)
{
/*
* For the TSS to use a key as salt, it must have
* access to the public part. It does this by keeping
* key files, but request the public part just to make
* sure
*/
tpm2_ReadPublic (tssContext, tpmKey, NULL, TPM_RH_NULL);
/*
* don't care what rout returns, the purpose of the
* operation was to get the public key parameters into
* the tss so it can construct the salt
*/
}
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
(EXTRA_PARAMETERS *)&extra,
TPM_CC_StartAuthSession,
TPM_RH_NULL, NULL, 0);
*sessionHandle = out.sessionHandle;
return rc;
}
static inline TPM_RC
tpm2_Sign (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle, DIGEST_2B *digest,
TPMT_SIG_SCHEME *inScheme, TPMT_SIGNATURE *signature,
TPM_HANDLE auth, const char *authVal)
{
Sign_In in;
Sign_Out out;
TPM_RC rc;
in.keyHandle = keyHandle;
in.digest.t = *digest;
in.inScheme = *inScheme;
in.validation.tag = TPM_ST_HASHCHECK;
in.validation.hierarchy = TPM_RH_NULL;
in.validation.digest.t.size = 0;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_Sign,
auth, authVal, 0,
TPM_RH_NULL, NULL, 0);
*signature = out.signature;
return rc;
}
static inline TPM_RC
tpm2_ECDH_ZGen (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle,
TPM2B_ECC_POINT *inPoint, TPM2B_ECC_POINT *outPoint,
TPM_HANDLE auth, const char *authVal)
{
ECDH_ZGen_In in;
ECDH_ZGen_Out out;
TPM_RC rc;
in.keyHandle = keyHandle;
in.inPoint = *inPoint;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_ECDH_ZGen,
auth, authVal, TPMA_SESSION_ENCRYPT,
TPM_RH_NULL, NULL, 0);
*outPoint = out.outPoint;
return rc;
}
static inline TPM_RC
tpm2_RSA_Decrypt (TSS_CONTEXT *tssContext, TPM_HANDLE keyHandle,
PUBLIC_KEY_RSA_2B *cipherText, TPMT_RSA_DECRYPT *inScheme,
PUBLIC_KEY_RSA_2B *message,
TPM_HANDLE auth, const char *authVal, int flags)
{
RSA_Decrypt_In in;
RSA_Decrypt_Out out;
TPM_RC rc;
in.keyHandle = keyHandle;
in.inScheme = *inScheme;
in.cipherText.t = *cipherText;
in.label.t.size = 0;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_RSA_Decrypt,
auth, authVal, flags,
TPM_RH_NULL, NULL, 0);
*message = out.message.t;
return rc;
}
static inline TPM_RC
tpm2_Load (TSS_CONTEXT *tssContext, TPM_HANDLE parentHandle,
PRIVATE_2B *inPrivate, TPM2B_PUBLIC *inPublic,
TPM_HANDLE *objectHandle,
TPM_HANDLE auth, const char *authVal)
{
Load_In in;
Load_Out out;
TPM_RC rc;
in.parentHandle = parentHandle;
in.inPrivate.t = *inPrivate;
in.inPublic = *inPublic;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_Load,
auth, authVal, 0,
TPM_RH_NULL, NULL, 0);
if (rc == TPM_RC_SUCCESS)
*objectHandle = out.objectHandle;
return rc;
}
static inline TPM_RC
tpm2_Import (TSS_CONTEXT *tssContext, TPM_HANDLE parentHandle,
DATA_2B *encryptionKey, TPM2B_PUBLIC *objectPublic,
PRIVATE_2B *duplicate, ENCRYPTED_SECRET_2B *inSymSeed,
TPMT_SYM_DEF_OBJECT *symmetricAlg, PRIVATE_2B *outPrivate,
TPM_HANDLE auth, const char *authVal)
{
Import_In iin;
Import_Out iout;
TPM_RC rc;
iin.parentHandle = parentHandle;
iin.encryptionKey.t = *encryptionKey;
iin.objectPublic = *objectPublic;
iin.duplicate.t = *duplicate;
iin.inSymSeed.t = *inSymSeed;
iin.symmetricAlg = *symmetricAlg;
rc = TSS_Execute (tssContext,
(RESPONSE_PARAMETERS *)&iout,
(COMMAND_PARAMETERS *)&iin,
NULL,
TPM_CC_Import,
auth, authVal, TPMA_SESSION_DECRYPT,
TPM_RH_NULL, NULL, 0);
*outPrivate = iout.outPrivate.t;
return rc;
}
static inline TPM_HANDLE
tpm2_handle_int (TSS_CONTEXT *tssContext, TPM_HANDLE h)
{
(void)tssContext;
return h;
}
static inline TPM_HANDLE
tpm2_handle_ext (TSS_CONTEXT *tssContext, TPM_HANDLE h)
{
(void)tssContext;
return h;
}
static inline int
tpm2_handle_mso (TSS_CONTEXT *tssContext, TPM_HANDLE h, UINT32 mso)
{
(void)tssContext;
return (h >> 24) == mso;
}
#endif