blob: b9fc75b55bfbf1f93049bc5efa839256a19ad743 [file] [log] [blame]
/* Copyright 2018 Intel Corporation, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sapi/tpm20.h>
#include <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include "tpm2_plugin_api.h"
#ifdef HAVE_TCTI_DEV
#include <tcti/tcti_device.h>
#endif
#ifdef HAVE_TCTI_SOCK
#include <tcti/tcti_socket.h>
#endif
#ifdef HAVE_TCTI_TABRMD
#include <tcti/tcti-tabrmd.h>
#endif
bool output_enabled = true;
bool hexPasswd = false;
TPM_HANDLE handle2048rsa;
const char *tcti_path="libtss2-tcti-device.so";
static void tcti_teardown(TSS2_TCTI_CONTEXT *tcti_context)
{
if (tcti_context == NULL)
return;
tss2_tcti_finalize (tcti_context);
free (tcti_context);
}
static void sapi_teardown(TSS2_SYS_CONTEXT *sapi_context)
{
if (sapi_context == NULL)
return;
Tss2_Sys_Finalize (sapi_context);
free (sapi_context);
}
static void sapi_teardown_full (TSS2_SYS_CONTEXT *sapi_context)
{
TSS2_TCTI_CONTEXT *tcti_context = NULL;
TSS2_RC rc;
rc = Tss2_Sys_GetTctiContext (sapi_context, &tcti_context);
if (rc != TSS2_RC_SUCCESS)
return;
sapi_teardown (sapi_context);
tcti_teardown (tcti_context);
}
int tpm2_plugin_init()
{
printf("Init API done for TPM plugin ! \n");
return 0;
}
int tpm2_plugin_uninit()
{
printf("UnInit API done for TPM plugin ! \n");
return 0;
}
TPM_HANDLE srk_handle;
int tpm2_plugin_activate(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *activate_in_info)
{
/*
*/
char *handle;
printf("number of buffers %d ! \n", activate_in_info->num_buffers);
if (activate_in_info->num_buffers!=1){
printf("activate failed ! \n");
return 1;
}
printf("number of buffers %d ! \n", activate_in_info->num_buffers);
handle = malloc(activate_in_info->buffer_info[0]->length_of_buffer);
memcpy(handle, activate_in_info->buffer_info[0]->buffer, activate_in_info->buffer_info[0]->length_of_buffer);
srk_handle = strtol(handle, NULL, 16);
printf("Activate API done for TPM plugin ! \n");
return 0;
}
TPMI_DH_OBJECT handle_load;
#ifdef HAVE_TCTI_DEV
TSS2_TCTI_CONTEXT*
tcti_device_init (char const *device_file)
{
TCTI_DEVICE_CONF conf = {
.device_path = device_file,
.logCallback = NULL,
.logData = NULL,
};
size_t size;
TSS2_RC rc;
TSS2_TCTI_CONTEXT *tcti_ctx;
rc = InitDeviceTcti (NULL, &size, 0);
if (rc != TSS2_RC_SUCCESS) {
fprintf (stderr,
"Failed to get allocation size for device tcti context: "
"0x%x\n", rc);
return NULL;
}
tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
if (tcti_ctx == NULL) {
fprintf (stderr,
"Allocation for device TCTI context failed: %s\n",
strerror (errno));
return NULL;
}
rc = InitDeviceTcti (tcti_ctx, &size, &conf);
if (rc != TSS2_RC_SUCCESS) {
fprintf (stderr,
"Failed to initialize device TCTI context: 0x%x\n",
rc);
free (tcti_ctx);
return NULL;
}
return tcti_ctx;
}
#endif
#ifdef HAVE_TCTI_SOCK
TSS2_TCTI_CONTEXT* tcti_socket_init (char const *address, uint16_t port)
{
TCTI_SOCKET_CONF conf = {
.hostname = address,
.port = port,
.logCallback = NULL,
.logBufferCallback = NULL,
.logData = NULL,
};
size_t size;
TSS2_RC rc;
TSS2_TCTI_CONTEXT *tcti_ctx;
rc = InitSocketTcti (NULL, &size, &conf, 0);
if (rc != TSS2_RC_SUCCESS) {
fprintf (stderr, "Faled to get allocation size for tcti context: "
"0x%x\n", rc);
return NULL;
}
tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
if (tcti_ctx == NULL) {
fprintf (stderr, "Allocation for tcti context failed: %s\n",
strerror (errno));
return NULL;
}
rc = InitSocketTcti (tcti_ctx, &size, &conf, 0);
if (rc != TSS2_RC_SUCCESS) {
fprintf (stderr, "Failed to initialize tcti context: 0x%x\n", rc);
free (tcti_ctx);
return NULL;
}
return tcti_ctx;
}
#endif
#ifdef HAVE_TCTI_TABRMD
TSS2_TCTI_CONTEXT *tcti_tabrmd_init (void)
{
TSS2_TCTI_CONTEXT *tcti_ctx;
TSS2_RC rc;
size_t size;
rc = tss2_tcti_tabrmd_init(NULL, &size);
if (rc != TSS2_RC_SUCCESS) {
printf("Failed to get size for TABRMD TCTI context: 0x%x", rc);
return NULL;
}
tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
if (tcti_ctx == NULL) {
printf("Allocation for TABRMD TCTI context failed: %s", strerror (errno));
return NULL;
}
rc = tss2_tcti_tabrmd_init (tcti_ctx, &size);
if (rc != TSS2_RC_SUCCESS) {
printf("Failed to initialize TABRMD TCTI context: 0x%x", rc);
free(tcti_ctx);
return NULL;
}
return tcti_ctx;
}
#endif
TSS2_TCTI_CONTEXT *tcti_init_from_options(common_opts_t *options)
{
switch (options->tcti_type) {
#ifdef HAVE_TCTI_DEV
case DEVICE_TCTI:
return tcti_device_init (options->device_file);
#endif
#ifdef HAVE_TCTI_SOCK
case SOCKET_TCTI:
return tcti_socket_init (options->socket_address,
options->socket_port);
#endif
#ifdef HAVE_TCTI_TABRMD
case TABRMD_TCTI:
return tcti_tabrmd_init ();
#endif
default:
return NULL;
}
}
static TSS2_SYS_CONTEXT *sapi_ctx_init (TSS2_TCTI_CONTEXT *tcti_ctx)
{
TSS2_SYS_CONTEXT *sapi_ctx;
TSS2_RC rc;
size_t size;
TSS2_ABI_VERSION abi_version = {
.tssCreator = TSSWG_INTEROP,
.tssFamily = TSS_SAPI_FIRST_FAMILY,
.tssLevel = TSS_SAPI_FIRST_LEVEL,
.tssVersion = TSS_SAPI_FIRST_VERSION,
};
size = Tss2_Sys_GetContextSize (0);
sapi_ctx = (TSS2_SYS_CONTEXT*)calloc (1, size);
if (sapi_ctx == NULL) {
fprintf (stderr,
"Failed to allocate 0x%zx bytes for the SAPI context\n",
size);
return NULL;
}
rc = Tss2_Sys_Initialize (sapi_ctx, size, tcti_ctx, &abi_version);
if (rc != TSS2_RC_SUCCESS) {
fprintf (stderr, "Failed to initialize SAPI context: 0x%x\n", rc);
free (sapi_ctx);
return NULL;
}
return sapi_ctx;
}
#define BUFFER_SIZE(type, field) (sizeof((((type *)NULL)->t.field)))
#define TPM2B_TYPE_INIT(type, field) { .t = { .size = BUFFER_SIZE(type, field), }, }
TPMS_AUTH_COMMAND sessionData;
int hex2ByteStructure(const char *inStr, UINT16 *byteLength, BYTE *byteBuffer)
{
int strLength;//if the inStr likes "1a2b...", no prefix "0x"
int i = 0;
if(inStr == NULL || byteLength == NULL || byteBuffer == NULL)
return -1;
strLength = strlen(inStr);
if(strLength%2)
return -2;
for(i = 0; i < strLength; i++)
{
if(!isxdigit(inStr[i]))
return -3;
}
if(*byteLength < strLength/2)
return -4;
*byteLength = strLength/2;
for(i = 0; i < *byteLength; i++)
{
char tmpStr[4] = {0};
tmpStr[0] = inStr[i*2];
tmpStr[1] = inStr[i*2+1];
byteBuffer[i] = strtol(tmpStr, NULL, 16);
}
return 0;
}
int load_key(TSS2_SYS_CONTEXT *sapi_context,
TPMI_DH_OBJECT parentHandle,
TPM2B_PUBLIC *inPublic,
TPM2B_PRIVATE *inPrivate,
int P_flag)
{
UINT32 rval;
TPMS_AUTH_RESPONSE sessionDataOut;
TSS2_SYS_CMD_AUTHS sessionsData;
TSS2_SYS_RSP_AUTHS sessionsDataOut;
TPMS_AUTH_COMMAND *sessionDataArray[1];
TPMS_AUTH_RESPONSE *sessionDataOutArray[1];
TPM2B_NAME nameExt = TPM2B_TYPE_INIT(TPM2B_NAME, name);
sessionDataArray[0] = &sessionData;
sessionDataOutArray[0] = &sessionDataOut;
sessionsDataOut.rspAuths = &sessionDataOutArray[0];
sessionsData.cmdAuths = &sessionDataArray[0];
sessionsDataOut.rspAuthsCount = 1;
sessionsData.cmdAuthsCount = 1;
sessionData.sessionHandle = TPM_RS_PW;
sessionData.nonce.t.size = 0;
if(P_flag == 0)
sessionData.hmac.t.size = 0;
*((UINT8 *)((void *)&sessionData.sessionAttributes)) = 0;
if (sessionData.hmac.t.size > 0 && hexPasswd)
{
sessionData.hmac.t.size = sizeof(sessionData.hmac) - 2;
if (hex2ByteStructure((char *)sessionData.hmac.t.buffer,
&sessionData.hmac.t.size,
sessionData.hmac.t.buffer) != 0)
{
printf( "Failed to convert Hex format password for parent Passwd.\n");
return -1;
}
}
rval = Tss2_Sys_Load (sapi_context,
parentHandle,
&sessionsData,
inPrivate,
inPublic,
&handle2048rsa,
&nameExt,
&sessionsDataOut);
if(rval != TPM_RC_SUCCESS)
{
printf("\nLoad Object Failed ! ErrorCode: 0x%0x\n\n",rval);
return -1;
}
printf("\nLoad succ.\nLoadedHandle: 0x%08x\n\n",handle2048rsa);
return 0;
}
TPMS_CONTEXT loaded_key_context;
int load_key_execute(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *loadkey_in_info,
void **keyHandle, TSS2_SYS_CONTEXT *sapi_context)
{
TPMI_DH_OBJECT parentHandle;
TPM2B_PUBLIC inPublic;
TPM2B_PRIVATE inPrivate;
UINT16 size;
int returnVal = 0;
memset(&inPublic,0,sizeof(TPM2B_PUBLIC));
memset(&inPrivate,0,sizeof(TPM2B_SENSITIVE));
setbuf(stdout, NULL);
setvbuf (stdout, NULL, _IONBF, BUFSIZ);
//parentHandle = 0x81000011;
parentHandle = srk_handle;
if (loadkey_in_info->num_buffers != 2)
return -1;
memcpy(&inPublic, loadkey_in_info->buffer_info[0]->buffer,
loadkey_in_info->buffer_info[0]->length_of_buffer);
memcpy(&inPrivate, loadkey_in_info->buffer_info[1]->buffer,
loadkey_in_info->buffer_info[1]->length_of_buffer);
printf("we are here now\n");
returnVal = load_key (sapi_context,
parentHandle,
&inPublic,
&inPrivate,
0);
TPM_RC rval = Tss2_Sys_ContextSave(sapi_context, handle2048rsa, &loaded_key_context);
if (rval != TPM_RC_SUCCESS) {
printf("Tss2_Sys_ContextSave: Saving handle 0x%x context failed. TPM Error:0x%x", handle2048rsa, rval);
return -1;
}
*keyHandle = &handle2048rsa;
return 0;
}
int tpm2_plugin_load_key(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *loadkey_in_info,
void **keyHandle)
{
int ret = 1;
common_opts_t opts = COMMON_OPTS_INITIALIZER;
TSS2_TCTI_CONTEXT *tcti_ctx;
tcti_ctx = tcti_init_from_options(&opts);
if (tcti_ctx == NULL)
return -1;
TSS2_SYS_CONTEXT *sapi_context = NULL;
if (tcti_ctx) {
sapi_context = sapi_ctx_init(tcti_ctx);
if (!sapi_context) {
free(tcti_ctx);
return -1;
}
}
ret = load_key_execute(loadkey_in_info, keyHandle, sapi_context);
if (ret !=0)
printf("Load key API failed in TPM plugin ! \n");
sapi_teardown_full(sapi_context);
printf("Load key API successful in TPM plugin ! \n");
return 0;
}
typedef struct tpm_sign_ctx tpm_sign_ctx;
struct tpm_sign_ctx {
TPMT_TK_HASHCHECK validation;
TPMS_AUTH_COMMAND sessionData;
TPMI_DH_OBJECT keyHandle;
TPMI_ALG_HASH halg;
char outFilePath[PATH_MAX];
BYTE *msg;
UINT16 length;
TSS2_SYS_CONTEXT *sapi_context;
};
int tpm2_plugin_rsa_sign_init(
void *keyHandle,
unsigned long mechanism,
void *param,
int len)
{
printf("rsa_sign_init API mechanism is %lx \n", mechanism);
printf("rsa_sign_init API done for tpm2_plugin... \n");
return 0;
}
UINT32 tpm_hash(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH hashAlg,
UINT16 size, BYTE *data, TPM2B_DIGEST *result) {
TPM2B_MAX_BUFFER dataSizedBuffer;
dataSizedBuffer.t.size = size;
memcpy(dataSizedBuffer.t.buffer, data, size);
return Tss2_Sys_Hash(sapi_context, 0, &dataSizedBuffer, hashAlg,
TPM_RH_NULL, result, 0, 0);
}
static TPM_RC hash_sequence_ex(TSS2_SYS_CONTEXT *sapi_context,
TPMI_ALG_HASH hashAlg, UINT32 numBuffers, TPM2B_MAX_BUFFER *bufferList,
TPM2B_DIGEST *result) {
TPM_RC rval;
TPM2B_AUTH nullAuth;
TPMI_DH_OBJECT sequenceHandle;
TPM2B emptyBuffer;
TPMT_TK_HASHCHECK validation;
TPMS_AUTH_COMMAND cmdAuth;
TPMS_AUTH_COMMAND *cmdSessionArray[1] = { &cmdAuth };
TSS2_SYS_CMD_AUTHS cmdAuthArray = { 1, &cmdSessionArray[0] };
nullAuth.t.size = 0;
emptyBuffer.size = 0;
// Set result size to 0, in case any errors occur
result->b.size = 0;
// Init input sessions struct
cmdAuth.sessionHandle = TPM_RS_PW;
cmdAuth.nonce.t.size = 0;
*((UINT8 *) ((void *) &cmdAuth.sessionAttributes)) = 0;
cmdAuth.hmac.t.size = 0;
rval = Tss2_Sys_HashSequenceStart(sapi_context, 0, &nullAuth, hashAlg,
&sequenceHandle, 0);
if (rval != TPM_RC_SUCCESS) {
return rval;
}
unsigned i;
for (i = 0; i < numBuffers; i++) {
rval = Tss2_Sys_SequenceUpdate(sapi_context, sequenceHandle,
&cmdAuthArray, &bufferList[i], 0);
if (rval != TPM_RC_SUCCESS) {
return rval;
}
}
rval = Tss2_Sys_SequenceComplete(sapi_context, sequenceHandle,
&cmdAuthArray, (TPM2B_MAX_BUFFER *) &emptyBuffer,
TPM_RH_PLATFORM, result, &validation, 0);
if (rval != TPM_RC_SUCCESS) {
return rval;
}
return rval;
}
int tpm_hash_compute_data(TSS2_SYS_CONTEXT *sapi_context, BYTE *buffer,
UINT16 length, TPMI_ALG_HASH halg, TPM2B_DIGEST *result) {
if (length <= MAX_DIGEST_BUFFER) {
if (tpm_hash(sapi_context, halg, length, buffer,
result) == TPM_RC_SUCCESS)
return 0;
else
return -1;
}
UINT8 numBuffers = (length - 1) / MAX_DIGEST_BUFFER + 1;
TPM2B_MAX_BUFFER *bufferList = (TPM2B_MAX_BUFFER *) calloc(numBuffers,
sizeof(TPM2B_MAX_BUFFER));
if (bufferList == NULL)
return -2;
UINT32 i;
for (i = 0; i < (UINT32)(numBuffers - 1); i++) {
bufferList[i].t.size = MAX_DIGEST_BUFFER;
memcpy(bufferList[i].t.buffer, buffer + i * MAX_DIGEST_BUFFER,
MAX_DIGEST_BUFFER);
}
bufferList[i].t.size = length - i * MAX_DIGEST_BUFFER;
memcpy(bufferList[i].t.buffer, buffer + i * MAX_DIGEST_BUFFER,
bufferList[i].t.size);
TPM_RC rval = hash_sequence_ex(sapi_context, halg, numBuffers, bufferList, result);
free(bufferList);
return rval == TPM_RC_SUCCESS ? 0 : -3;
}
static bool get_key_type(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT objectHandle,
TPMI_ALG_PUBLIC *type) {
TPMS_AUTH_RESPONSE session_data_out;
TPMS_AUTH_RESPONSE *session_data_out_array[1] = {
&session_data_out
};
TSS2_SYS_RSP_AUTHS sessions_data_out = {
1,
&session_data_out_array[0]
};
TPM2B_PUBLIC out_public = {
{ 0, }
};
TPM2B_NAME name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
TPM2B_NAME qaulified_name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
TPM_RC rval = Tss2_Sys_ReadPublic(sapi_context, objectHandle, 0, &out_public, &name,
&qaulified_name, &sessions_data_out);
if (rval != TPM_RC_SUCCESS) {
printf("Sys_ReadPublic failed, error code: 0x%x", rval);
return false;
}
*type = out_public.t.publicArea.type;
return true;
}
static bool set_scheme(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT keyHandle,
TPMI_ALG_HASH halg, TPMT_SIG_SCHEME *inScheme) {
TPM_ALG_ID type;
bool result = get_key_type(sapi_context, keyHandle, &type);
if (!result) {
return false;
}
switch (type) {
case TPM_ALG_RSA :
inScheme->scheme = TPM_ALG_RSASSA;
inScheme->details.rsassa.hashAlg = halg;
break;
case TPM_ALG_KEYEDHASH :
inScheme->scheme = TPM_ALG_HMAC;
inScheme->details.hmac.hashAlg = halg;
break;
case TPM_ALG_ECC :
inScheme->scheme = TPM_ALG_ECDSA;
inScheme->details.ecdsa.hashAlg = halg;
break;
case TPM_ALG_SYMCIPHER :
default:
printf("Unknown key type, got: 0x%x", type);
return false;
}
return true;
}
static bool sign_and_save(tpm_sign_ctx *ctx, unsigned char *sig, int *sig_len) {
TPM2B_DIGEST digest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer);
TPMT_SIG_SCHEME in_scheme;
TPMT_SIGNATURE signature;
int signature_len;
TSS2_SYS_CMD_AUTHS sessions_data;
TPMS_AUTH_RESPONSE session_data_out;
TSS2_SYS_RSP_AUTHS sessions_data_out;
TPMS_AUTH_COMMAND *session_data_array[1];
TPMS_AUTH_RESPONSE *session_data_out_array[1];
session_data_array[0] = &ctx->sessionData;
sessions_data.cmdAuths = &session_data_array[0];
session_data_out_array[0] = &session_data_out;
sessions_data_out.rspAuths = &session_data_out_array[0];
sessions_data_out.rspAuthsCount = 1;
sessions_data.cmdAuthsCount = 1;
int rc = tpm_hash_compute_data(ctx->sapi_context, ctx->msg, ctx->length, ctx->halg, &digest);
if (rc) {
printf("Compute message hash failed!");
return false;
}
bool result = set_scheme(ctx->sapi_context, ctx->keyHandle, ctx->halg, &in_scheme);
if (!result) {
return false;
}
TPM_RC rval = Tss2_Sys_Sign(ctx->sapi_context, ctx->keyHandle,
&sessions_data, &digest, &in_scheme,
&ctx->validation, &signature,
&sessions_data_out);
if (rval != TPM_RC_SUCCESS) {
printf("Sys_Sign failed, error code: 0x%x", rval);
return false;
}
signature_len = sizeof(signature);
sig_len = &signature_len;
sig = (unsigned char *)&signature;
return true;
}
int tpm2_plugin_rsa_sign(
void *keyHandle,
unsigned long mechanism,
unsigned char *msg,
int msg_len,
unsigned char *sig,
int *sig_len)
{
TPM_RC rval;
common_opts_t opts = COMMON_OPTS_INITIALIZER;
TSS2_TCTI_CONTEXT *tcti_ctx;
tcti_ctx = tcti_init_from_options(&opts);
if (tcti_ctx == NULL)
return -1;
TSS2_SYS_CONTEXT *sapi_context = NULL;
if (tcti_ctx) {
sapi_context = sapi_ctx_init(tcti_ctx);
if (!sapi_context) {
free(tcti_ctx);
return -1;
}
}
tpm_sign_ctx ctx = {
.msg = NULL,
.sessionData = { 0 },
.halg = 0,
.keyHandle = 0,
.validation = { 0 },
.sapi_context = sapi_context
};
printf("rsa_sign API mechanism is %lx \n", mechanism);
ctx.sessionData.sessionHandle = TPM_RS_PW;
ctx.validation.tag = TPM_ST_HASHCHECK;
ctx.validation.hierarchy = TPM_RH_NULL;
ctx.halg = TPM_ALG_SHA256;
ctx.keyHandle = *(TPMI_DH_OBJECT *)keyHandle;
rval = Tss2_Sys_ContextLoad(ctx.sapi_context, &loaded_key_context, &ctx.keyHandle);
if (rval != TPM_RC_SUCCESS) {
printf("ContextLoad Error in RSA Sign API. TPM Error:0x%x", rval);
goto out;
}
ctx.length = msg_len;
ctx.msg = msg;
if (!sign_and_save(&ctx, sig, sig_len)){
printf("RSA sign failed\n");
goto out;
}
printf("RSA sign API successful in TPM plugin ! \n");
out:
sapi_teardown_full(sapi_context);
return 0;
}