/* 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 #include #include #include #include "tpm2_plugin_api.h" #ifdef HAVE_TCTI_DEV #include #endif #ifdef HAVE_TCTI_SOCK #include #endif #ifdef HAVE_TCTI_TABRMD #include #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; }