blob: 05a4a26efdb6fd746b7225167715ca88038fa3d7 [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 <openssl/ecdsa.h>
#include "hidgd-tpm.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;
}
void tpm_get_public_point(uint32_t handle, U2F_EC_POINT *pub)
{
ReadPublic_In in;
ReadPublic_Out out;
TPM_RC rc;
TPMS_ECC_POINT *pt;
rc = tpm2_create();
if (rc)
return;
in.objectHandle = handle;
rc = TSS_Execute(tssContext,
(RESPONSE_PARAMETERS *)&out,
(COMMAND_PARAMETERS *)&in,
NULL,
TPM_CC_ReadPublic,
TPM_RH_NULL, NULL, 0);
if (rc) {
tpm2_error(rc, "TPM2_ReadPublic");
return;
}
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");
}
int tpm_fill_register_sig(uint32_t parent, U2F_REGISTER_REQ *req,
U2F_REGISTER_RESP *resp, uint8_t *sig)
{
TPMT_HA digest;
TPM_RC rc;
Sign_In in;
Sign_Out out;
uint8_t prefix[1];
ECDSA_SIG *osig;
BIGNUM *r,*s;
int len;
/* conventional prefix containing zero byte */
prefix[0] = 0x00;
digest.hashAlg = TPM_ALG_SHA256;
TSS_Hash_Generate(&digest,
sizeof(prefix), prefix,
sizeof(req->appId), req->appId,
sizeof(req->chal), req->chal,
resp->keyHandleLen, resp->keyHandleCertSig,
sizeof(resp->pubKey), &resp->pubKey,
0, NULL);
in.inScheme.details.ecdsa.hashAlg = digest.hashAlg;
in.keyHandle = parent;
in.inScheme.scheme = TPM_ALG_ECDSA;
in.digest.t.size = TSS_GetDigestSize(digest.hashAlg);
memcpy(in.digest.t.buffer, digest.digest.tssmax, in.digest.t.size);
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,
TPM_RS_PW, NULL, 0,
TPM_RH_NULL, NULL, 0);
if (rc) {
tpm2_error(rc, "TPM2_Sign");
return 0;
}
osig = ECDSA_SIG_new();
r = BN_bin2bn(out.signature.signature.ecdsa.signatureR.t.buffer,
out.signature.signature.ecdsa.signatureR.t.size,
NULL);
s = BN_bin2bn(out.signature.signature.ecdsa.signatureS.t.buffer,
out.signature.signature.ecdsa.signatureS.t.size,
NULL);
ECDSA_SIG_set0(osig, r, s);
len = i2d_ECDSA_SIG(osig, &sig);
ECDSA_SIG_free(osig);
tpm2_rm_keyfile(parent);
tpm2_delete();
return len;
}