gnupg/tpm2d/ibm-tss.h

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