Merge "Added 3 more TPM2 Plugin APIs"
[aaf/sshsm.git] / TPM2-Plugin / lib / tpm2_plugin_api.c
1 /* Copyright 2018 Intel Corporation, Inc
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *       http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <sapi/tpm20.h>
17 #include <stdbool.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include "tpm2_plugin_api.h"
21 #ifdef HAVE_TCTI_DEV
22 #include <tcti/tcti_device.h>
23 #endif
24 #ifdef HAVE_TCTI_SOCK
25 #include <tcti/tcti_socket.h>
26 #endif
27 #ifdef HAVE_TCTI_TABRMD
28 #include <tcti/tcti-tabrmd.h>
29 #endif
30 #define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
31
32 bool output_enabled = true;
33 bool hexPasswd = false;
34 TPM_HANDLE handle2048rsa;
35 const char *tcti_path="libtss2-tcti-device.so";
36
37 static void tcti_teardown(TSS2_TCTI_CONTEXT *tcti_context)
38 {
39     if (tcti_context == NULL)
40         return;
41     tss2_tcti_finalize (tcti_context);
42     free (tcti_context);
43 }
44
45 static void sapi_teardown(TSS2_SYS_CONTEXT *sapi_context)
46 {
47     if (sapi_context == NULL)
48         return;
49     Tss2_Sys_Finalize (sapi_context);
50     free (sapi_context);
51 }
52
53 static void sapi_teardown_full (TSS2_SYS_CONTEXT *sapi_context)
54 {
55     TSS2_TCTI_CONTEXT *tcti_context = NULL;
56     TSS2_RC rc;
57
58     rc = Tss2_Sys_GetTctiContext (sapi_context, &tcti_context);
59     if (rc != TSS2_RC_SUCCESS)
60         return;
61     sapi_teardown (sapi_context);
62     tcti_teardown (tcti_context);
63 }
64
65 int tpm2_plugin_init()
66 {
67     printf("Init API done for TPM plugin ! \n");
68     return 0;
69 }
70
71 int tpm2_plugin_uninit()
72 {
73     printf("UnInit API done for TPM plugin ! \n");
74     return 0;
75 }
76
77 TPM_HANDLE srk_handle;
78 int tpm2_plugin_activate(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *activate_in_info)
79 {
80     /*
81     */
82     char *handle;
83     printf("number of buffers %d ! \n", activate_in_info->num_buffers);
84     if (activate_in_info->num_buffers!=1){
85         printf("activate failed ! \n");
86         return 1;
87     }
88     printf("number of buffers %d ! \n", activate_in_info->num_buffers);
89     handle = malloc(activate_in_info->buffer_info[0]->length_of_buffer);
90     memcpy(handle, activate_in_info->buffer_info[0]->buffer, activate_in_info->buffer_info[0]->length_of_buffer);
91     srk_handle = strtol(handle, NULL, 16);
92     printf("Activate API done for TPM plugin ! \n");
93     return 0;
94 }
95
96 TPMI_DH_OBJECT handle_load;
97
98 #ifdef HAVE_TCTI_DEV
99 TSS2_TCTI_CONTEXT*
100 tcti_device_init (char const *device_file)
101 {
102     TCTI_DEVICE_CONF conf = {
103         .device_path = device_file,
104         .logCallback = NULL,
105         .logData     = NULL,
106     };
107     size_t size;
108     TSS2_RC rc;
109     TSS2_TCTI_CONTEXT *tcti_ctx;
110
111     rc = InitDeviceTcti (NULL, &size, 0);
112     if (rc != TSS2_RC_SUCCESS) {
113         fprintf (stderr,
114                  "Failed to get allocation size for device tcti context: "
115                  "0x%x\n", rc);
116         return NULL;
117     }
118     tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
119     if (tcti_ctx == NULL) {
120         fprintf (stderr,
121                  "Allocation for device TCTI context failed: %s\n",
122                  strerror (errno));
123         return NULL;
124     }
125     rc = InitDeviceTcti (tcti_ctx, &size, &conf);
126     if (rc != TSS2_RC_SUCCESS) {
127         fprintf (stderr,
128                  "Failed to initialize device TCTI context: 0x%x\n",
129                  rc);
130         free (tcti_ctx);
131         return NULL;
132     }
133     return tcti_ctx;
134 }
135 #endif
136
137 #ifdef HAVE_TCTI_SOCK
138 TSS2_TCTI_CONTEXT* tcti_socket_init (char const *address, uint16_t port)
139 {
140     TCTI_SOCKET_CONF conf = {
141         .hostname          = address,
142         .port              = port,
143         .logCallback       = NULL,
144         .logBufferCallback = NULL,
145         .logData           = NULL,
146     };
147     size_t size;
148     TSS2_RC rc;
149     TSS2_TCTI_CONTEXT *tcti_ctx;
150
151     rc = InitSocketTcti (NULL, &size, &conf, 0);
152     if (rc != TSS2_RC_SUCCESS) {
153         fprintf (stderr, "Faled to get allocation size for tcti context: "
154                  "0x%x\n", rc);
155         return NULL;
156     }
157     tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
158     if (tcti_ctx == NULL) {
159         fprintf (stderr, "Allocation for tcti context failed: %s\n",
160                  strerror (errno));
161         return NULL;
162     }
163     rc = InitSocketTcti (tcti_ctx, &size, &conf, 0);
164     if (rc != TSS2_RC_SUCCESS) {
165         fprintf (stderr, "Failed to initialize tcti context: 0x%x\n", rc);
166         free (tcti_ctx);
167         return NULL;
168     }
169     return tcti_ctx;
170 }
171 #endif
172 #ifdef HAVE_TCTI_TABRMD
173 TSS2_TCTI_CONTEXT *tcti_tabrmd_init (void)
174 {
175     TSS2_TCTI_CONTEXT *tcti_ctx;
176     TSS2_RC rc;
177     size_t size;
178
179     rc = tss2_tcti_tabrmd_init(NULL, &size);
180     if (rc != TSS2_RC_SUCCESS) {
181         printf("Failed to get size for TABRMD TCTI context: 0x%x", rc);
182         return NULL;
183     }
184     tcti_ctx = (TSS2_TCTI_CONTEXT*)calloc (1, size);
185     if (tcti_ctx == NULL) {
186         printf("Allocation for TABRMD TCTI context failed: %s", strerror (errno));
187         return NULL;
188     }
189     rc = tss2_tcti_tabrmd_init (tcti_ctx, &size);
190     if (rc != TSS2_RC_SUCCESS) {
191         printf("Failed to initialize TABRMD TCTI context: 0x%x", rc);
192         free(tcti_ctx);
193         return NULL;
194     }
195     return tcti_ctx;
196 }
197 #endif
198 TSS2_TCTI_CONTEXT *tcti_init_from_options(common_opts_t *options)
199 {
200     switch (options->tcti_type) {
201 #ifdef HAVE_TCTI_DEV
202     case DEVICE_TCTI:
203         return tcti_device_init (options->device_file);
204 #endif
205 #ifdef HAVE_TCTI_SOCK
206     case SOCKET_TCTI:
207         return tcti_socket_init (options->socket_address,
208                                  options->socket_port);
209 #endif
210 #ifdef HAVE_TCTI_TABRMD
211     case TABRMD_TCTI:
212         return tcti_tabrmd_init ();
213 #endif
214     default:
215         return NULL;
216     }
217 }
218
219 static TSS2_SYS_CONTEXT *sapi_ctx_init (TSS2_TCTI_CONTEXT *tcti_ctx)
220 {
221     TSS2_SYS_CONTEXT *sapi_ctx;
222     TSS2_RC rc;
223     size_t size;
224     TSS2_ABI_VERSION abi_version = {
225         .tssCreator = TSSWG_INTEROP,
226         .tssFamily  = TSS_SAPI_FIRST_FAMILY,
227         .tssLevel   = TSS_SAPI_FIRST_LEVEL,
228         .tssVersion = TSS_SAPI_FIRST_VERSION,
229     };
230
231     size = Tss2_Sys_GetContextSize (0);
232     sapi_ctx = (TSS2_SYS_CONTEXT*)calloc (1, size);
233     if (sapi_ctx == NULL) {
234         fprintf (stderr,
235                  "Failed to allocate 0x%zx bytes for the SAPI context\n",
236                  size);
237         return NULL;
238     }
239     rc = Tss2_Sys_Initialize (sapi_ctx, size, tcti_ctx, &abi_version);
240     if (rc != TSS2_RC_SUCCESS) {
241         fprintf (stderr, "Failed to initialize SAPI context: 0x%x\n", rc);
242         free (sapi_ctx);
243         return NULL;
244     }
245     return sapi_ctx;
246 }
247
248 #define BUFFER_SIZE(type, field) (sizeof((((type *)NULL)->t.field)))
249 #define TPM2B_TYPE_INIT(type, field) { .t = { .size = BUFFER_SIZE(type, field), }, }
250 TPMS_AUTH_COMMAND sessionData;
251 int hex2ByteStructure(const char *inStr, UINT16 *byteLength, BYTE *byteBuffer)
252 {
253     int strLength;//if the inStr likes "1a2b...", no prefix "0x"
254     int i = 0;
255     if(inStr == NULL || byteLength == NULL || byteBuffer == NULL)
256         return -1;
257     strLength = strlen(inStr);
258     if(strLength%2)
259         return -2;
260     for(i = 0; i < strLength; i++)
261     {
262         if(!isxdigit(inStr[i]))
263             return -3;
264     }
265
266     if(*byteLength < strLength/2)
267         return -4;
268
269     *byteLength = strLength/2;
270
271     for(i = 0; i < *byteLength; i++)
272     {
273         char tmpStr[4] = {0};
274         tmpStr[0] = inStr[i*2];
275         tmpStr[1] = inStr[i*2+1];
276         byteBuffer[i] = strtol(tmpStr, NULL, 16);
277     }
278     return 0;
279 }
280 int load_key(TSS2_SYS_CONTEXT *sapi_context,
281              TPMI_DH_OBJECT    parentHandle,
282              TPM2B_PUBLIC     *inPublic,
283              TPM2B_PRIVATE    *inPrivate,
284              int               P_flag)
285 {
286     UINT32 rval;
287     TPMS_AUTH_RESPONSE sessionDataOut;
288     TSS2_SYS_CMD_AUTHS sessionsData;
289     TSS2_SYS_RSP_AUTHS sessionsDataOut;
290     TPMS_AUTH_COMMAND *sessionDataArray[1];
291     TPMS_AUTH_RESPONSE *sessionDataOutArray[1];
292
293     TPM2B_NAME nameExt = TPM2B_TYPE_INIT(TPM2B_NAME, name);
294
295     sessionDataArray[0] = &sessionData;
296     sessionDataOutArray[0] = &sessionDataOut;
297
298     sessionsDataOut.rspAuths = &sessionDataOutArray[0];
299     sessionsData.cmdAuths = &sessionDataArray[0];
300
301     sessionsDataOut.rspAuthsCount = 1;
302     sessionsData.cmdAuthsCount = 1;
303
304     sessionData.sessionHandle = TPM_RS_PW;
305     sessionData.nonce.t.size = 0;
306
307     if(P_flag == 0)
308         sessionData.hmac.t.size = 0;
309
310     *((UINT8 *)((void *)&sessionData.sessionAttributes)) = 0;
311     if (sessionData.hmac.t.size > 0 && hexPasswd)
312     {
313         sessionData.hmac.t.size = sizeof(sessionData.hmac) - 2;
314         if (hex2ByteStructure((char *)sessionData.hmac.t.buffer,
315                               &sessionData.hmac.t.size,
316                               sessionData.hmac.t.buffer) != 0)
317         {
318             printf( "Failed to convert Hex format password for parent Passwd.\n");
319             return -1;
320         }
321     }
322
323     rval = Tss2_Sys_Load (sapi_context,
324                           parentHandle,
325                           &sessionsData,
326                           inPrivate,
327                           inPublic,
328                           &handle2048rsa,
329                           &nameExt,
330                           &sessionsDataOut);
331     if(rval != TPM_RC_SUCCESS)
332     {
333         printf("\nLoad Object Failed ! ErrorCode: 0x%0x\n\n",rval);
334         return -1;
335     }
336     printf("\nLoad succ.\nLoadedHandle: 0x%08x\n\n",handle2048rsa);
337
338     return 0;
339 }
340
341 int read_public(TSS2_SYS_CONTEXT *sapi_context,
342                 TPM_HANDLE handle,
343                 SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t *importkey_info)
344 {
345
346     TPMS_AUTH_RESPONSE session_out_data;
347     TSS2_SYS_RSP_AUTHS sessions_out_data;
348     TPMS_AUTH_RESPONSE *session_out_data_array[1];
349
350     TPM2B_PUBLIC public = {
351             { 0, }
352     };
353
354     TPM2B_NAME name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
355
356     TPM2B_NAME qualified_name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
357
358     session_out_data_array[0] = &session_out_data;
359     sessions_out_data.rspAuths = &session_out_data_array[0];
360     sessions_out_data.rspAuthsCount = ARRAY_LEN(session_out_data_array);
361
362     TPM_RC rval = Tss2_Sys_ReadPublic(sapi_context, handle, 0,
363             &public, &name, &qualified_name, &sessions_out_data);
364     if (rval != TPM_RC_SUCCESS) {
365         printf("TPM2_ReadPublic error: rval = 0x%0x", rval);
366         return false;
367     }
368
369     printf("\nTPM2_ReadPublic OutPut: \n");
370     printf("name: \n");
371     UINT16 i;
372     for (i = 0; i < name.t.size; i++)
373         printf("%02x ", name.t.name[i]);
374     printf("\n");
375
376     printf("qualified_name: \n");
377     for (i = 0; i < qualified_name.t.size; i++)
378         printf("%02x ", qualified_name.t.name[i]);
379     printf("\n");
380
381     printf("public.t.publicArea.parameters.rsaDetail.keyBits = %d \n", public.t.publicArea.parameters.rsaDetail.keyBits);
382     printf("public.t.publicArea.parameters.rsaDetail.exponent = %d \n", public.t.publicArea.parameters.rsaDetail.exponent);
383
384     importkey_info->modulus_size = public.t.publicArea.unique.rsa.t.size;
385     printf("importkey_info->modulus_size = %ld \n", importkey_info->modulus_size);
386     memcpy(importkey_info->modulus, &public.t.publicArea.unique.rsa.t.buffer, importkey_info->modulus_size);
387
388     importkey_info->exponent_size = sizeof(public.t.publicArea.parameters.rsaDetail.exponent);
389     printf("importkey_info->exponent_size = %ld \n", importkey_info->exponent_size);
390     memcpy(importkey_info->exponent, &public.t.publicArea.parameters.rsaDetail.exponent, importkey_info->exponent_size);
391     //*importkey_info->exponent = public.t.publicArea.parameters.rsaDetail.exponent;
392
393     return 0;
394 }
395
396 TPMS_CONTEXT loaded_key_context;
397
398 int load_key_execute(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *loadkey_in_info,
399                      void **keyHandle, TSS2_SYS_CONTEXT *sapi_context,
400                      SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t *importkey_info)
401 {
402
403     TPMI_DH_OBJECT parentHandle;
404     TPM2B_PUBLIC  inPublic;
405     TPM2B_PRIVATE inPrivate;
406     UINT16 size;
407     int returnVal = 0;
408
409     memset(&inPublic,0,sizeof(TPM2B_PUBLIC));
410     memset(&inPrivate,0,sizeof(TPM2B_SENSITIVE));
411
412     setbuf(stdout, NULL);
413     setvbuf (stdout, NULL, _IONBF, BUFSIZ);
414
415     //parentHandle = 0x81000011;
416     parentHandle = srk_handle;
417
418     if (loadkey_in_info->num_buffers != 2)
419         return -1;
420     memcpy(&inPublic, loadkey_in_info->buffer_info[0]->buffer,
421            loadkey_in_info->buffer_info[0]->length_of_buffer);
422     memcpy(&inPrivate, loadkey_in_info->buffer_info[1]->buffer,
423            loadkey_in_info->buffer_info[1]->length_of_buffer);
424
425     returnVal = load_key (sapi_context,
426                           parentHandle,
427                           &inPublic,
428                           &inPrivate,
429                           0);
430     returnVal = read_public(sapi_context,
431                             handle2048rsa,
432                             importkey_info);
433
434     TPM_RC rval = Tss2_Sys_ContextSave(sapi_context, handle2048rsa, &loaded_key_context);
435     if (rval != TPM_RC_SUCCESS) {
436         printf("Tss2_Sys_ContextSave: Saving handle 0x%x context failed. TPM Error:0x%x", handle2048rsa, rval);
437         return -1;
438     }
439     *keyHandle = &handle2048rsa;
440     return 0;
441 }
442
443 int tpm2_plugin_load_key(SSHSM_HW_PLUGIN_ACTIVATE_LOAD_IN_INFO_t *loadkey_in_info,
444                          void **keyHandle,
445                          SSHSM_HW_PLUGIN_IMPORT_PUBLIC_KEY_INFO_t *importkey_info)
446 {
447     int ret = 1;
448     common_opts_t opts = COMMON_OPTS_INITIALIZER;
449     TSS2_TCTI_CONTEXT *tcti_ctx;
450     tcti_ctx = tcti_init_from_options(&opts);
451     if (tcti_ctx == NULL)
452         return -1;
453
454     TSS2_SYS_CONTEXT *sapi_context = NULL;
455     if (tcti_ctx) {
456         sapi_context = sapi_ctx_init(tcti_ctx);
457         if (!sapi_context) {
458             free(tcti_ctx);
459             return -1;
460         }
461     }
462
463     ret = load_key_execute(loadkey_in_info, keyHandle, sapi_context, importkey_info);
464     if (ret !=0)
465         printf("Load key API failed in TPM plugin ! \n");
466
467     sapi_teardown_full(sapi_context);
468
469     printf("Load key API successful in TPM plugin ! \n");
470     return 0;
471
472 }
473
474 typedef struct tpm_sign_ctx tpm_sign_ctx;
475 struct tpm_sign_ctx {
476     TPMT_TK_HASHCHECK validation;
477     TPMS_AUTH_COMMAND sessionData;
478     TPMI_DH_OBJECT keyHandle;
479     TPMI_ALG_HASH halg;
480     char outFilePath[PATH_MAX];
481     BYTE *msg;
482     UINT16 length;
483     TSS2_SYS_CONTEXT *sapi_context;
484 };
485
486 //create a table to consolidate all parts of data from multiple SignUpdate from sessions
487 CONCATENATE_DATA_SIGNUPDATE_t data_signupdate_session[MAX_SESSIONS];
488 unsigned long sign_sequence_id = 0;
489 int tpm2_plugin_rsa_sign_init(
490         void *keyHandle,
491         unsigned long mechanism,
492         void *param,
493         int len,
494         void **plugin_data_ref
495        )
496 {
497     printf("rsa_sign_init API mechanism is %ld \n", mechanism);
498     printf("rsa_sign_init API len is %d \n", len);
499     int i, j;
500
501     sign_sequence_id++;
502     unsigned long hSession = sign_sequence_id;
503
504     for (i = 0; i < MAX_SESSIONS; i++){
505         if (data_signupdate_session[i].session_handle == 0){
506             data_signupdate_session[i].session_handle = hSession;
507             for (j = 0; j < MAX_DATA_SIGNUPDATE; j++ )
508                 data_signupdate_session[i].data_signupdate[j] = 0;
509             data_signupdate_session[i].data_length = 0;
510         }
511     }
512     *plugin_data_ref = (void *)hSession;
513
514     printf("rsa_sign_init API done for tpm2_plugin... \n");
515     return 0;
516 }
517
518 /** This function is called by SSHSM only if there sign_final function is not called.
519 If sign_final function is called, it is assumed that plugin would have cleaned this up.
520 ***/
521
522 int tpm2_plugin_rsa_sign_cleanup(
523          void *keyHandle,
524          unsigned long mechnaism,
525          void *plugin_data_ref
526         )
527 {
528     int i, j;
529     unsigned long hSession = (unsigned long)plugin_data_ref;
530     for (i = 0; i < MAX_SESSIONS; i++)    {
531         if (data_signupdate_session[i].session_handle == hSession){
532             data_signupdate_session[i].session_handle = 0;
533             for (j =0; j < MAX_DATA_SIGNUPDATE; j++ )
534                 data_signupdate_session[i].data_signupdate[j] =0;
535             data_signupdate_session[i].data_length = 0;
536         }
537     }
538
539     if (sign_sequence_id>0xfffffffe)
540         sign_sequence_id =0;
541     return 0;
542 }
543
544
545 UINT32 tpm_hash(TSS2_SYS_CONTEXT *sapi_context, TPMI_ALG_HASH hashAlg,
546         UINT16 size, BYTE *data, TPM2B_DIGEST *result) {
547     TPM2B_MAX_BUFFER dataSizedBuffer;
548
549     dataSizedBuffer.t.size = size;
550     memcpy(dataSizedBuffer.t.buffer, data, size);
551     return Tss2_Sys_Hash(sapi_context, 0, &dataSizedBuffer, hashAlg,
552             TPM_RH_NULL, result, 0, 0);
553 }
554
555 static TPM_RC hash_sequence_ex(TSS2_SYS_CONTEXT *sapi_context,
556
557     TPMI_ALG_HASH hashAlg, UINT32 numBuffers, TPM2B_MAX_BUFFER *bufferList,
558     TPM2B_DIGEST *result) {
559     TPM_RC rval;
560     TPM2B_AUTH nullAuth;
561     TPMI_DH_OBJECT sequenceHandle;
562     TPM2B emptyBuffer;
563     TPMT_TK_HASHCHECK validation;
564
565     TPMS_AUTH_COMMAND cmdAuth;
566     TPMS_AUTH_COMMAND *cmdSessionArray[1] = { &cmdAuth };
567     TSS2_SYS_CMD_AUTHS cmdAuthArray = { 1, &cmdSessionArray[0] };
568
569     nullAuth.t.size = 0;
570     emptyBuffer.size = 0;
571
572     // Set result size to 0, in case any errors occur
573     result->b.size = 0;
574
575     // Init input sessions struct
576     cmdAuth.sessionHandle = TPM_RS_PW;
577     cmdAuth.nonce.t.size = 0;
578     *((UINT8 *) ((void *) &cmdAuth.sessionAttributes)) = 0;
579     cmdAuth.hmac.t.size = 0;
580
581     rval = Tss2_Sys_HashSequenceStart(sapi_context, 0, &nullAuth, hashAlg,
582             &sequenceHandle, 0);
583     if (rval != TPM_RC_SUCCESS) {
584         return rval;
585     }
586
587     unsigned i;
588     for (i = 0; i < numBuffers; i++) {
589         rval = Tss2_Sys_SequenceUpdate(sapi_context, sequenceHandle,
590                 &cmdAuthArray, &bufferList[i], 0);
591
592         if (rval != TPM_RC_SUCCESS) {
593             return rval;
594         }
595     }
596
597     rval = Tss2_Sys_SequenceComplete(sapi_context, sequenceHandle,
598             &cmdAuthArray, (TPM2B_MAX_BUFFER *) &emptyBuffer,
599             TPM_RH_PLATFORM, result, &validation, 0);
600
601     if (rval != TPM_RC_SUCCESS) {
602         return rval;
603     }
604
605     return rval;
606 }
607
608 int tpm_hash_compute_data(TSS2_SYS_CONTEXT *sapi_context, BYTE *buffer,
609         UINT16 length, TPMI_ALG_HASH halg, TPM2B_DIGEST *result) {
610
611     if (length <= MAX_DIGEST_BUFFER) {
612         if (tpm_hash(sapi_context, halg, length, buffer,
613                 result) == TPM_RC_SUCCESS){
614             printf("Single hash result size: %d\n", result->t.size);
615             return 0;
616         }
617         else
618             return -1;
619     }
620
621     UINT8 numBuffers = (length - 1) / MAX_DIGEST_BUFFER + 1;
622
623     TPM2B_MAX_BUFFER *bufferList = (TPM2B_MAX_BUFFER *) calloc(numBuffers,
624             sizeof(TPM2B_MAX_BUFFER));
625     if (bufferList == NULL)
626         return -2;
627
628     UINT32 i;
629     for (i = 0; i < (UINT32)(numBuffers - 1); i++) {
630         bufferList[i].t.size = MAX_DIGEST_BUFFER;
631         memcpy(bufferList[i].t.buffer, buffer + i * MAX_DIGEST_BUFFER,
632                 MAX_DIGEST_BUFFER);
633     }
634     bufferList[i].t.size = length - i * MAX_DIGEST_BUFFER;
635     memcpy(bufferList[i].t.buffer, buffer + i * MAX_DIGEST_BUFFER,
636             bufferList[i].t.size);
637
638     TPM_RC rval = hash_sequence_ex(sapi_context, halg, numBuffers, bufferList, result);
639     free(bufferList);
640     printf("Sequence hash result size: %d\n", result->t.size);
641     return rval == TPM_RC_SUCCESS ? 0 : -3;
642 }
643
644
645 static bool get_key_type(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT objectHandle,
646         TPMI_ALG_PUBLIC *type) {
647
648     TPMS_AUTH_RESPONSE session_data_out;
649
650     TPMS_AUTH_RESPONSE *session_data_out_array[1] = {
651             &session_data_out
652     };
653
654     TSS2_SYS_RSP_AUTHS sessions_data_out = {
655             1,
656             &session_data_out_array[0]
657     };
658
659     TPM2B_PUBLIC out_public = {
660             { 0, }
661     };
662
663     TPM2B_NAME name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
664
665     TPM2B_NAME qaulified_name = TPM2B_TYPE_INIT(TPM2B_NAME, name);
666
667     TPM_RC rval = Tss2_Sys_ReadPublic(sapi_context, objectHandle, 0, &out_public, &name,
668             &qaulified_name, &sessions_data_out);
669     if (rval != TPM_RC_SUCCESS) {
670         printf("Sys_ReadPublic failed, error code: 0x%x", rval);
671         return false;
672     }
673     *type = out_public.t.publicArea.type;
674     return true;
675 }
676
677 static bool set_scheme(TSS2_SYS_CONTEXT *sapi_context, TPMI_DH_OBJECT keyHandle,
678         TPMI_ALG_HASH halg, TPMT_SIG_SCHEME *inScheme) {
679
680     TPM_ALG_ID type;
681     bool result = get_key_type(sapi_context, keyHandle, &type);
682     if (!result) {
683         return false;
684     }
685
686     switch (type) {
687     case TPM_ALG_RSA :
688         inScheme->scheme = TPM_ALG_RSASSA;
689         inScheme->details.rsassa.hashAlg = halg;
690         break;
691     case TPM_ALG_KEYEDHASH :
692         inScheme->scheme = TPM_ALG_HMAC;
693         inScheme->details.hmac.hashAlg = halg;
694         break;
695     case TPM_ALG_ECC :
696         inScheme->scheme = TPM_ALG_ECDSA;
697         inScheme->details.ecdsa.hashAlg = halg;
698         break;
699     case TPM_ALG_SYMCIPHER :
700     default:
701         printf("Unknown key type, got: 0x%x", type);
702         return false;
703     }
704
705     return true;
706 }
707 static bool sign_and_save(tpm_sign_ctx *ctx, TPMT_SIGNATURE *sig) {
708     TPM2B_DIGEST digest = TPM2B_TYPE_INIT(TPM2B_DIGEST, buffer);
709
710     TPMT_SIG_SCHEME in_scheme;
711     TSS2_SYS_CMD_AUTHS sessions_data;
712     TPMS_AUTH_RESPONSE session_data_out;
713     TSS2_SYS_RSP_AUTHS sessions_data_out;
714     TPMS_AUTH_COMMAND *session_data_array[1];
715     TPMS_AUTH_RESPONSE *session_data_out_array[1];
716
717     session_data_array[0] = &ctx->sessionData;
718     sessions_data.cmdAuths = &session_data_array[0];
719     session_data_out_array[0] = &session_data_out;
720     sessions_data_out.rspAuths = &session_data_out_array[0];
721     sessions_data_out.rspAuthsCount = 1;
722     sessions_data.cmdAuthsCount = 1;
723
724     int rc = tpm_hash_compute_data(ctx->sapi_context, ctx->msg, ctx->length, ctx->halg, &digest);
725     if (rc) {
726         printf("Compute message hash failed!");
727         return false;
728     }
729
730     printf("Compute message hash digest size : %d \n", digest.t.size);
731
732     bool result = set_scheme(ctx->sapi_context, ctx->keyHandle, ctx->halg, &in_scheme);
733     if (!result) {
734         return false;
735     }
736
737     TPM_RC rval = Tss2_Sys_Sign(ctx->sapi_context, ctx->keyHandle,
738                                 &sessions_data, &digest, &in_scheme,
739                                 &ctx->validation, sig,
740                                 &sessions_data_out);
741
742     if (rval != TPM_RC_SUCCESS) {
743         printf("Sys_Sign failed, error code: 0x%x", rval);
744         return false;
745     }
746     
747     return true;
748 }
749
750 int tpm2_plugin_rsa_sign(
751         void  *keyHandle,
752         unsigned long mechanism,
753         unsigned char *msg,
754         int msg_len,
755         void *plugin_data_ref,
756         unsigned char *sig,
757         int *sig_len)
758 {
759     TPM_RC rval;
760     common_opts_t opts = COMMON_OPTS_INITIALIZER;
761     TPMT_SIGNATURE signature;
762     TSS2_TCTI_CONTEXT *tcti_ctx;
763     tcti_ctx = tcti_init_from_options(&opts);
764     if (tcti_ctx == NULL)
765         return -1;
766
767     TSS2_SYS_CONTEXT *sapi_context = NULL;
768     if (tcti_ctx) {
769        sapi_context = sapi_ctx_init(tcti_ctx);
770        if (!sapi_context) {
771            free(tcti_ctx);
772            return -1;
773        }
774     }
775
776     tpm_sign_ctx ctx = {
777             .msg = NULL,
778             .sessionData = { 0 },
779             .halg = 0,
780             .keyHandle = 0,
781             .validation = { 0 },
782             .sapi_context = sapi_context
783     };
784
785     printf("rsa_sign API mechanism is %lx \n", mechanism);
786     ctx.sessionData.sessionHandle = TPM_RS_PW;
787     ctx.validation.tag = TPM_ST_HASHCHECK;
788     ctx.validation.hierarchy = TPM_RH_NULL;
789     if (mechanism == 7)
790         ctx.halg = TPM_ALG_SHA256;
791     else
792         printf("mechanism not supported! \n");
793     ctx.keyHandle = *(TPMI_DH_OBJECT *)keyHandle;
794
795     rval = Tss2_Sys_ContextLoad(ctx.sapi_context, &loaded_key_context, &ctx.keyHandle);
796     if (rval != TPM_RC_SUCCESS) {
797         printf("ContextLoad Error in RSA Sign API. TPM Error:0x%x", rval);
798         goto out;
799     }
800     ctx.length = msg_len;
801     ctx.msg = msg;
802
803     if (!sign_and_save(&ctx, &signature)){
804         printf("RSA sign failed\n");
805         goto out;
806     }
807
808     *sig_len = (int)signature.signature.rsassa.sig.t.size;
809     printf("signature length:  %d \n", *sig_len);
810     memcpy(sig, signature.signature.rsassa.sig.t.buffer, *sig_len);
811     printf("signature buffer size:  %ld \n", sizeof(signature.signature.rsassa.sig.t.buffer));
812     printf("RSA sign API successful in TPM plugin ! \n");
813
814 out:
815     sapi_teardown_full(sapi_context);
816
817     return 0;
818
819 }
820
821 int tpm2_plugin_rsa_sign_update(
822          void *keyHandle,
823          unsigned long mechanism,
824          unsigned char *msg,
825          int msg_len,
826          void *plugin_data_ref
827         )
828 {
829     int i, j, n;
830     unsigned long hSession = (unsigned long)plugin_data_ref;
831     for (i = 0; i < MAX_SESSIONS; i++){
832         if (data_signupdate_session[i].session_handle == hSession){
833             n = data_signupdate_session[i].data_length;
834             for (j =0; j < msg_len; j++ )
835                 data_signupdate_session[i].data_signupdate[n + j] = msg[j];
836             data_signupdate_session[i].data_length += msg_len;
837             return 0;
838         }
839     }
840     return -1;
841 }
842
843 int tpm2_plugin_rsa_sign_final(
844          void *keyHandle,
845          unsigned long mechanism,
846          void *plugin_data_ref,
847          unsigned char *outsig,
848          int *outsiglen
849         )
850 {
851     int i, j;
852     unsigned long hSession = (unsigned long)plugin_data_ref;
853     unsigned char *msg;
854     int msg_len;
855     for (i = 0; i < MAX_SESSIONS; i++){
856         if (data_signupdate_session[i].session_handle == hSession){
857             msg = data_signupdate_session[i].data_signupdate;
858             msg_len = data_signupdate_session[i].data_length;
859             tpm2_plugin_rsa_sign(keyHandle, mechanism, msg, msg_len, plugin_data_ref, outsig, outsiglen);
860             tpm2_plugin_rsa_sign_cleanup(keyHandle, mechanism, plugin_data_ref);
861             return 0;
862         }
863     }
864
865     return -1;
866 }
867