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