blob: 2e073a1367af9b230ddd38effc7d27be9993b754 [file] [log] [blame]
/*
* TPM Code for hid gadget driver
*
* Copyright (C) 2019 James.Bottomley@HansenPartnership.com
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <tss.h>
#include <tssresponsecode.h>
#include <tsscryptoh.h>
#include <tssmarshal.h>
#include <openssl/ecdsa.h>
#include "hidgd.h"
static char *dir = NULL;
static TSS_CONTEXT *tssContext;
static void tpm2_error(TPM_RC rc, const char *reason)
{
const char *msg, *submsg, *num;
fprintf(stderr, "%s failed with %d\n", reason, rc);
TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
fprintf(stderr, "%s%s%s\n", msg, submsg, num);
}
static void tpm2_rm_keyfile(TPM_HANDLE key)
{
char keyfile[1024];
snprintf(keyfile, sizeof(keyfile), "%s/h%08x.bin", dir, key);
unlink(keyfile);
snprintf(keyfile, sizeof(keyfile), "%s/hp%08x.bin", dir, key);
unlink(keyfile);
}
static void tpm2_delete(void)
{
if (rmdir(dir) < 0) {
fprintf(stderr, "Unlinking %s", dir);
perror(":");
}
TSS_Delete(tssContext);
dir = NULL;
tssContext = NULL;
}
static TPM_RC tpm2_create(void)
{
char *prefix = getenv("XDG_RUNTIME_DIR");
char *template;
TPM_RC rc;
if (!prefix)
prefix = "/tmp";
rc = TSS_Create(&tssContext);
if (rc) {
tpm2_error(rc, "TSS_Create");
return rc;
}
if (!dir) {
int len;
len = snprintf(NULL, 0, "%s/tss2.XXXXXX", prefix);
template = malloc(len + 1);
snprintf(template, len + 1, "%s/tss2.XXXXXX", prefix);
dir = mkdtemp(template);
}
printf("DIR IS %s\n", dir);
rc = TSS_SetProperty(tssContext, TPM_DATA_DIR, dir);
if (rc) {
tpm2_error(rc, "TSS_SetProperty");
return rc;
}
return TPM_RC_SUCCESS;
}
static TPM_HANDLE tpm2_create_primary(uint32_t hierarchy)
{
TPM_RC rc;
CreatePrimary_In in;
CreatePrimary_Out out;
/* SPS owner */
in.primaryHandle = hierarchy;
in.inSensitive.sensitive.userAuth.t.size = 0;
/* no sensitive date for storage keys */
in.inSensitive.sensitive.data.t.size = 0;
/* no outside info */
in.outsideInfo.t.size = 0;
/* no PCR state */
in.creationPCR.count = 0;
/* public parameters for an ECC key */
in.inPublic.publicArea.type = TPM_ALG_ECC;
in.inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
in.inPublic.publicArea.objectAttributes.val =
TPMA_OBJECT_NODA |
TPMA_OBJECT_SENSITIVEDATAORIGIN |
TPMA_OBJECT_FIXEDPARENT |
TPMA_OBJECT_FIXEDTPM |
TPMA_OBJECT_USERWITHAUTH |
TPMA_OBJECT_DECRYPT |
TPMA_OBJECT_RESTRICTED;
in.inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
in.inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
in.inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
in.inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
in.inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
in.inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
in.inPublic.publicArea.unique.ecc.x.t.size = 0;
in.inPublic.publicArea.unique.ecc.y.t.size = 0;
in.inPublic.publicArea.authPolicy.t.size = 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);
if (rc) {
tpm2_error(rc, "TSS_CreatePrimary");
return 0;
}
return out.objectHandle;
}
static void tpm2_flush_handle(TPM_HANDLE h)
{
FlushContext_In in;
if (!h)
return;
in.flushHandle = h;
TSS_Execute(tssContext, NULL,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_FlushContext,
TPM_RH_NULL, NULL, 0);
}
static uint32_t tpm2_get_parent(uint32_t parent)
{
if (parent == 0)
/* choose default parent */
parent = TPM_RH_OWNER;
if ((parent & 0xff000000) == 0x40000000)
parent = tpm2_create_primary(parent);
return parent;
}
static void tpm2_put_parent(uint32_t parent)
{
if ((parent & 0xff000000) == 0x80000000)
tpm2_flush_handle(parent);
tpm2_rm_keyfile(parent);
}
int tpm_get_public_point(uint32_t parent, U2F_EC_POINT *pub, uint8_t *handle)
{
Create_In in;
Create_Out out;
TPM_RC rc;
INT32 size;
uint16_t len;
TPMS_ECC_POINT *pt;
rc = tpm2_create();
if (rc)
return 0;
parent = tpm2_get_parent(parent);
in.inPublic.publicArea.type = TPM_ALG_ECC;
in.inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
in.inPublic.publicArea.authPolicy.t.size = 0;
in.inPublic.publicArea.objectAttributes.val =
TPMA_OBJECT_SIGN |
TPMA_OBJECT_USERWITHAUTH |
TPMA_OBJECT_NODA |
TPMA_OBJECT_SENSITIVEDATAORIGIN;
in.inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL;
in.inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
in.inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
in.inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
in.inPublic.publicArea.unique.ecc.x.t.size = 0;
in.inPublic.publicArea.unique.ecc.y.t.size = 0;
in.inSensitive.sensitive.userAuth.b.size = 0;
in.inSensitive.sensitive.data.t.size = 0;
in.parentHandle = parent;
in.outsideInfo.t.size = 0;
in.creationPCR.count = 0;
rc = TSS_Execute(tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_Create,
TPM_RS_PW, NULL, 0,
TPM_RH_NULL, NULL, 0);
tpm2_put_parent(parent);
tpm2_delete();
if (rc) {
tpm2_error(rc, "TPM2_Create");
return 0;
}
size = 255; /* max by U2F standard */
len = 0;
rc = TSS_TPM2B_PUBLIC_Marshal(&out.outPublic, &len, &handle, &size);
if (rc) {
tpm2_error(rc, "PUBLIC_Marshal");
return 0;
}
rc = TSS_TPM2B_PRIVATE_Marshal(&out.outPrivate, &len, &handle, &size);
if (rc) {
tpm2_error(rc, "PRIVATE_Marshal");
return 0;
}
pt = &out.outPublic.publicArea.unique.ecc;
pub->pointFormat = U2F_POINT_UNCOMPRESSED;
printf("PUBLIC POINTS %d,%d\n", pt->x.t.size, pt->y.t.size);
memcpy(pub->x, pt->x.t.buffer, pt->x.t.size);
memcpy(pub->y, pt->y.t.buffer, pt->y.t.size);
printf("DONE\n");
return len;
}