1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2015 - 2018 Intel Corporation
4  * All rights reserved.
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 
11 #include <inttypes.h>
12 #include <limits.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #ifndef _WIN32
18 #include <sys/time.h>
19 #include <unistd.h>
20 #endif
21 
22 #include "tss2_mu.h"
23 #include "tss2_tcti_mssim.h"
24 
25 #include "tcti-mssim.h"
26 #include "tcti-common.h"
27 #include "util/key-value-parse.h"
28 #define LOGMODULE tcti
29 #include "util/log.h"
30 
31 /*
32  * This function wraps the "up-cast" of the opaque TCTI context type to the
33  * type for the mssim TCTI context. If passed a NULL context the function
34  * returns a NULL ptr. The function doesn't check magic number anymore
35  * It should checked by the appropriate tcti_common_checks.
36  */
37 TSS2_TCTI_MSSIM_CONTEXT*
tcti_mssim_context_cast(TSS2_TCTI_CONTEXT * tcti_ctx)38 tcti_mssim_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx)
39 {
40     if (tcti_ctx == NULL)
41         return NULL;
42 
43     return (TSS2_TCTI_MSSIM_CONTEXT*)tcti_ctx;
44 }
45 /*
46  * This function down-casts the mssim TCTI context to the common context
47  * defined in the tcti-common module.
48  */
49 TSS2_TCTI_COMMON_CONTEXT*
tcti_mssim_down_cast(TSS2_TCTI_MSSIM_CONTEXT * tcti_mssim)50 tcti_mssim_down_cast (TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim)
51 {
52     if (tcti_mssim == NULL) {
53         return NULL;
54     }
55     return &tcti_mssim->common;
56 }
57 /*
58  * This function is for sending one of the MS_SIM_* platform commands to the
59  * Microsoft TPM2 simulator. These are sent over the platform socket.
60  */
tcti_platform_command(TSS2_TCTI_CONTEXT * tctiContext,UINT32 cmd)61 TSS2_RC tcti_platform_command (
62     TSS2_TCTI_CONTEXT *tctiContext,
63     UINT32 cmd)
64 {
65     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
66     uint8_t buf [sizeof (cmd)] = { 0 };
67     UINT32 rsp = 0;
68     TSS2_RC rc = TSS2_RC_SUCCESS;
69     int ret;
70     ssize_t read_ret;
71 
72     if (tcti_mssim == NULL) {
73         return TSS2_TCTI_RC_BAD_REFERENCE;
74     }
75 
76     if (TSS2_TCTI_MAGIC (tcti_mssim) != TCTI_MSSIM_MAGIC) {
77         return TSS2_TCTI_RC_BAD_CONTEXT;
78     }
79 
80     rc = Tss2_MU_UINT32_Marshal (cmd, buf, sizeof (cmd), NULL);
81     if (rc != TSS2_RC_SUCCESS) {
82         LOG_ERROR ("Failed to marshal platform command %" PRIu32 ", rc: 0x%"
83                    PRIx32, cmd, rc);
84         return rc;
85     }
86 
87     LOGBLOB_DEBUG(buf, sizeof (cmd), "Sending %zu bytes to socket %" PRIu32
88                   ":", sizeof (cmd), tcti_mssim->platform_sock);
89     ret = write_all (tcti_mssim->platform_sock, buf, sizeof (cmd));
90     if (ret < (ssize_t) sizeof (cmd)) {
91         LOG_ERROR("Failed to send platform command %d with error: %d",
92                   cmd, ret);
93         return TSS2_TCTI_RC_IO_ERROR;
94     }
95 
96 #ifdef _WIN32
97     read_ret = recv (tcti_mssim->platform_sock, (char *) buf, sizeof (buf), 0);
98     if (read_ret < (ssize_t) sizeof (buf)) {
99         LOG_ERROR ("Failed to get response to platform command, errno %d: %s",
100                    WSAGetLastError(), strerror (WSAGetLastError()));
101         return TSS2_TCTI_RC_IO_ERROR;
102     }
103 #else
104     read_ret = read(tcti_mssim->platform_sock, buf, sizeof (buf));
105     if (read_ret < (ssize_t) sizeof (buf)) {
106         LOG_ERROR ("Failed to get response to platform command, errno %d: %s",
107                    errno, strerror (errno));
108         return TSS2_TCTI_RC_IO_ERROR;
109     }
110 #endif
111     LOGBLOB_DEBUG (buf, sizeof (buf), "Received %zu bytes from socket 0x%"
112                    PRIx32 ":", read_ret, tcti_mssim->platform_sock);
113     rc = Tss2_MU_UINT32_Unmarshal (buf, sizeof (rsp), NULL, &rsp);
114     if (rc != TSS2_RC_SUCCESS) {
115         LOG_ERROR ("Failed to unmarshal response to platform command. rc: 0x%"
116                    PRIx32, rc);
117         return rc;
118     }
119     if (rsp != 0) {
120         LOG_INFO ("Platform command failed with error: %" PRIu32, rsp);
121         return TSS2_TCTI_RC_IO_ERROR;
122     }
123     return rc;
124 }
125 /*
126  * This function sends the special TPM_SESSION_END message over the provided
127  * socket.
128  */
129 TSS2_RC
send_sim_session_end(SOCKET sock)130 send_sim_session_end (
131     SOCKET sock)
132 {
133     uint8_t buf [4] = { 0, };
134     TSS2_RC rc;
135 
136     rc = Tss2_MU_UINT32_Marshal (TPM_SESSION_END, buf, sizeof (buf), NULL);
137     if (rc == TSS2_RC_SUCCESS) {
138         return rc;
139     }
140     return socket_xmit_buf (sock, buf, sizeof (buf));
141 }
142 
143 /*
144  * This function is used to send the simulator a sort of command message
145  * that tells it we're about to send it a TPM command. This requires that
146  * we first send it a 4 byte code that's defined by the simulator. Then
147  * another byte identifying the locality and finally the size of the TPM
148  * command buffer that we're about to send. After these 9 bytes are sent
149  * the simulator will accept a TPM command buffer.
150  */
151 #define SIM_CMD_SIZE (sizeof (UINT32) + sizeof (UINT8) + sizeof (UINT32))
152 TSS2_RC
send_sim_cmd_setup(TSS2_TCTI_MSSIM_CONTEXT * tcti_mssim,UINT32 size)153 send_sim_cmd_setup (
154     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim,
155     UINT32 size)
156 {
157     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
158     uint8_t buf [SIM_CMD_SIZE] = { 0 };
159     size_t offset = 0;
160     TSS2_RC rc;
161 
162     rc = Tss2_MU_UINT32_Marshal (MS_SIM_TPM_SEND_COMMAND,
163                                  buf,
164                                  sizeof (buf),
165                                  &offset);
166     if (rc != TSS2_RC_SUCCESS) {
167         return rc;
168     }
169 
170     rc = Tss2_MU_UINT8_Marshal (tcti_common->locality,
171                                 buf,
172                                 sizeof (buf),
173                                 &offset);
174     if (rc != TSS2_RC_SUCCESS) {
175         return rc;
176     }
177 
178     rc = Tss2_MU_UINT32_Marshal (size, buf, sizeof (buf), &offset);
179     if (rc != TSS2_RC_SUCCESS) {
180         return rc;
181     }
182 
183     return socket_xmit_buf (tcti_mssim->tpm_sock, buf, sizeof (buf));
184 }
185 
186 TSS2_RC
tcti_mssim_transmit(TSS2_TCTI_CONTEXT * tcti_ctx,size_t size,const uint8_t * cmd_buf)187 tcti_mssim_transmit (
188     TSS2_TCTI_CONTEXT *tcti_ctx,
189     size_t size,
190     const uint8_t *cmd_buf)
191 {
192     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tcti_ctx);
193     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
194     tpm_header_t header;
195     TSS2_RC rc;
196 
197     rc = tcti_common_transmit_checks (tcti_common, cmd_buf, TCTI_MSSIM_MAGIC);
198     if (rc != TSS2_RC_SUCCESS) {
199         return rc;
200     }
201     rc = header_unmarshal (cmd_buf, &header);
202     if (rc != TSS2_RC_SUCCESS) {
203         return rc;
204     }
205     if (header.size != size) {
206         LOG_ERROR ("Buffer size parameter: %zu, and TPM2 command header size "
207                    "field: %" PRIu32 " disagree.", size, header.size);
208         return TSS2_TCTI_RC_BAD_VALUE;
209     }
210 
211     LOG_DEBUG ("Sending command with TPM_CC 0x%" PRIx32 " and size %" PRIu32,
212                header.code, header.size);
213     rc = send_sim_cmd_setup (tcti_mssim, header.size);
214     if (rc != TSS2_RC_SUCCESS) {
215         return rc;
216     }
217     rc = socket_xmit_buf (tcti_mssim->tpm_sock, cmd_buf, size);
218     if (rc != TSS2_RC_SUCCESS) {
219         return rc;
220     }
221 
222     tcti_common->state = TCTI_STATE_RECEIVE;
223 
224     return rc;
225 }
226 
227 TSS2_RC
tcti_mssim_cancel(TSS2_TCTI_CONTEXT * tctiContext)228 tcti_mssim_cancel (
229     TSS2_TCTI_CONTEXT *tctiContext)
230 {
231     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
232     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
233     TSS2_RC rc;
234 
235     rc = tcti_common_cancel_checks (tcti_common, TCTI_MSSIM_MAGIC);
236     if (rc != TSS2_RC_SUCCESS) {
237         return rc;
238     }
239     rc = tcti_platform_command (tctiContext, MS_SIM_CANCEL_ON);
240     if (rc != TSS2_RC_SUCCESS) {
241         return rc;
242     }
243 
244     tcti_common->state = TCTI_STATE_TRANSMIT;
245     tcti_mssim->cancel = 1;
246 
247     return rc;
248 }
249 
250 TSS2_RC
tcti_mssim_set_locality(TSS2_TCTI_CONTEXT * tctiContext,uint8_t locality)251 tcti_mssim_set_locality (
252     TSS2_TCTI_CONTEXT *tctiContext,
253     uint8_t locality)
254 {
255     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
256     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
257     TSS2_RC rc;
258 
259     rc = tcti_common_set_locality_checks (tcti_common, TCTI_MSSIM_MAGIC);
260     if (rc != TSS2_RC_SUCCESS) {
261         return rc;
262     }
263 
264     tcti_common->locality = locality;
265     return TSS2_RC_SUCCESS;
266 }
267 
268 TSS2_RC
tcti_mssim_get_poll_handles(TSS2_TCTI_CONTEXT * tctiContext,TSS2_TCTI_POLL_HANDLE * handles,size_t * num_handles)269 tcti_mssim_get_poll_handles (
270     TSS2_TCTI_CONTEXT *tctiContext,
271     TSS2_TCTI_POLL_HANDLE *handles,
272     size_t *num_handles)
273 {
274     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
275 
276     if (num_handles == NULL || tcti_mssim == NULL) {
277         return TSS2_TCTI_RC_BAD_REFERENCE;
278     }
279 
280     if (handles != NULL && *num_handles < 1) {
281         return TSS2_TCTI_RC_BAD_VALUE;
282     }
283 
284     *num_handles = 1;
285     if (handles != NULL) {
286 #ifdef _WIN32
287         *handles = tcti_mssim->tpm_sock;
288 #else
289         handles->fd = tcti_mssim->tpm_sock;
290         handles->events = POLLIN | POLLOUT;
291 #endif
292     }
293 
294     return TSS2_RC_SUCCESS;
295 }
296 
297 void
tcti_mssim_finalize(TSS2_TCTI_CONTEXT * tctiContext)298 tcti_mssim_finalize(
299     TSS2_TCTI_CONTEXT *tctiContext)
300 {
301     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
302 
303     if (tcti_mssim == NULL) {
304         return;
305     }
306     send_sim_session_end (tcti_mssim->platform_sock);
307     send_sim_session_end (tcti_mssim->tpm_sock);
308     socket_close (&tcti_mssim->platform_sock);
309     socket_close (&tcti_mssim->tpm_sock);
310 }
311 
312 TSS2_RC
tcti_mssim_receive(TSS2_TCTI_CONTEXT * tctiContext,size_t * response_size,unsigned char * response_buffer,int32_t timeout)313 tcti_mssim_receive (
314     TSS2_TCTI_CONTEXT *tctiContext,
315     size_t *response_size,
316     unsigned char *response_buffer,
317     int32_t timeout)
318 {
319 #ifdef TEST_FAPI_ASYNC
320     /* Used for simulating a timeout. */
321     static int wait = 0;
322 #endif
323     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = tcti_mssim_context_cast (tctiContext);
324     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
325     TSS2_RC rc;
326     UINT32 trash;
327     int ret;
328 
329     rc = tcti_common_receive_checks (tcti_common,
330                                      response_size,
331                                      TCTI_MSSIM_MAGIC);
332     if (rc != TSS2_RC_SUCCESS) {
333         return rc;
334     }
335 
336     if (timeout != TSS2_TCTI_TIMEOUT_BLOCK) {
337 #ifdef TEST_FAPI_ASYNC
338         if (wait < 1) {
339             LOG_TRACE("Simulating Async by requesting another invocation.");
340             wait += 1;
341             return TSS2_TCTI_RC_TRY_AGAIN;
342         } else {
343             LOG_TRACE("Sending the actual result.");
344             wait = 0;
345         }
346 #endif /* TEST_FAPI_ASYNC */
347     }
348 
349     if (tcti_common->header.size == 0) {
350         /* Receive the size of the response. */
351         uint8_t size_buf [sizeof (UINT32)];
352 
353         ret = socket_poll(tcti_mssim->tpm_sock, timeout);
354         if (ret != TSS2_RC_SUCCESS) {
355             if (ret == TSS2_TCTI_RC_TRY_AGAIN) {
356                 return ret;
357             }
358             rc = ret;
359             goto out;
360         }
361         ret = socket_recv_buf (tcti_mssim->tpm_sock, size_buf, sizeof(UINT32));
362         if (ret != sizeof (UINT32)) {
363             rc = TSS2_TCTI_RC_IO_ERROR;
364             goto out;
365         }
366 
367         rc = Tss2_MU_UINT32_Unmarshal (size_buf,
368                                        sizeof (size_buf), 0,
369                                        &tcti_common->header.size);
370         if (rc != TSS2_RC_SUCCESS) {
371             LOG_WARNING ("Failed to unmarshal size from tpm2 simulator "
372                          "protocol: 0x%" PRIu32, rc);
373             goto out;
374         }
375 
376         LOG_DEBUG ("response size: %" PRIu32, tcti_common->header.size);
377     }
378 
379     if (response_buffer == NULL) {
380         *response_size = tcti_common->header.size;
381         return TSS2_RC_SUCCESS;
382     }
383 
384     if (*response_size < tcti_common->header.size) {
385         *response_size = tcti_common->header.size;
386         LOG_ERROR("Response size to big: %zu > %u", *response_size, tcti_common->header.size);
387         return TSS2_TCTI_RC_INSUFFICIENT_BUFFER;
388     }
389     *response_size = tcti_common->header.size;
390 
391     /* Receive the TPM response. */
392     LOG_DEBUG ("Reading response of size %" PRIu32, tcti_common->header.size);
393     ret = socket_poll(tcti_mssim->tpm_sock, timeout);
394     if (ret != TSS2_RC_SUCCESS) {
395         if (ret == TSS2_TCTI_RC_TRY_AGAIN) {
396             return ret;
397         }
398         rc = ret;
399         goto out;
400     }
401     ret = socket_recv_buf (tcti_mssim->tpm_sock,
402                            (unsigned char *)response_buffer,
403                            tcti_common->header.size);
404     if (ret < (ssize_t)tcti_common->header.size) {
405         rc = TSS2_TCTI_RC_IO_ERROR;
406         goto out;
407     }
408     LOGBLOB_DEBUG(response_buffer, tcti_common->header.size,
409                   "Response buffer received:");
410 
411     ret = socket_poll (tcti_mssim->tpm_sock, timeout);
412     if (ret != TSS2_RC_SUCCESS) {
413         if (ret == TSS2_TCTI_RC_TRY_AGAIN) {
414             return ret;
415         }
416         rc = ret;
417         goto out;
418     }
419 
420     /* Receive the appended four bytes of 0's */
421     ret = socket_recv_buf (tcti_mssim->tpm_sock,
422                            (unsigned char *)&trash, 4);
423     if (ret != 4) {
424         LOG_DEBUG ("Error reading last 4 bytes %" PRIu32, ret);
425         rc = TSS2_TCTI_RC_IO_ERROR;
426         goto out;
427     }
428 
429     if (tcti_mssim->cancel) {
430         rc = tcti_platform_command (tctiContext, MS_SIM_CANCEL_OFF);
431         tcti_mssim->cancel = 0;
432     }
433     /*
434      * Executing code beyond this point transitions the state machine to
435      * TRANSMIT. Another call to this function will not be possible until
436      * another command is sent to the TPM.
437      */
438 out:
439     tcti_common->header.size = 0;
440     tcti_common->state = TCTI_STATE_TRANSMIT;
441 
442     return rc;
443 }
444 
445 /**
446  * This function sends the Microsoft simulator the MS_SIM_POWER_ON and
447  * MS_SIM_NV_ON commands using the platform command mechanism. Without
448  * these the simulator will respond with zero sized buffer which causes
449  * the TSS to freak out. Sending this command more than once is harmless,
450  * so it's advisable to call this function as part of the TCTI context
451  * initialization just to be sure.
452  *
453  * NOTE: The caller will still need to call Tss2_Sys_Startup. If they
454  * don't, an error will be returned from each call till they do but
455  * the error will at least be meaningful (TPM2_RC_INITIALIZE).
456  */
457 static TSS2_RC
simulator_setup(TSS2_TCTI_CONTEXT * tctiContext)458 simulator_setup (
459     TSS2_TCTI_CONTEXT *tctiContext)
460 {
461     TSS2_RC rc;
462 
463     LOG_TRACE ("Initializing TCTI context 0x%" PRIxPTR,
464                (uintptr_t)tctiContext);
465     rc = tcti_platform_command (tctiContext, MS_SIM_POWER_ON);
466     if (rc != TSS2_RC_SUCCESS) {
467         LOG_WARNING ("Failed to send MS_SIM_POWER_ON platform command.");
468         return rc;
469     }
470 
471     rc = tcti_platform_command (tctiContext, MS_SIM_NV_ON);
472     if (rc != TSS2_RC_SUCCESS) {
473         LOG_WARNING ("Failed to send MS_SIM_NV_ON platform command.");
474     }
475 
476     return rc;
477 }
478 
479 /*
480  * This is a utility function to extract a TCP port number from a string.
481  * The string must be 6 characters long. If the supplied string contains an
482  * invalid port number then 0 is returned.
483  */
484 static uint16_t
string_to_port(char port_str[6])485 string_to_port (char port_str[6])
486 {
487     uint32_t port = 0;
488 
489     if (sscanf (port_str, "%" SCNu32, &port) == EOF || port > UINT16_MAX) {
490         return 0;
491     }
492     return port;
493 }
494 /*
495  * This function is a callback conforming to the KeyValueFunc prototype. It
496  * is called by the key-value-parse module for each key / value pair extracted
497  * from the configuration string. Its sole purpose is to identify valid keys
498  * from the conf string and to store their corresponding values in the
499  * mssim_conf_t structure which is passed through the 'user_data' parameter.
500  */
501 TSS2_RC
mssim_kv_callback(const key_value_t * key_value,void * user_data)502 mssim_kv_callback (const key_value_t *key_value,
503                    void *user_data)
504 {
505     mssim_conf_t *mssim_conf = (mssim_conf_t*)user_data;
506 
507     LOG_TRACE ("key_value: 0x%" PRIxPTR " and user_data: 0x%" PRIxPTR,
508                (uintptr_t)key_value, (uintptr_t)user_data);
509     if (key_value == NULL || user_data == NULL) {
510         LOG_WARNING ("%s passed NULL parameter", __func__);
511         return TSS2_TCTI_RC_GENERAL_FAILURE;
512     }
513     LOG_DEBUG ("key: %s / value: %s\n", key_value->key, key_value->value);
514     if (strcmp (key_value->key, "host") == 0) {
515         mssim_conf->host = key_value->value;
516         return TSS2_RC_SUCCESS;
517     } else if (strcmp (key_value->key, "port") == 0) {
518         mssim_conf->port = string_to_port (key_value->value);
519         if (mssim_conf->port == 0) {
520             return TSS2_TCTI_RC_BAD_VALUE;
521         }
522         return TSS2_RC_SUCCESS;
523     } else {
524         return TSS2_TCTI_RC_BAD_VALUE;
525     }
526 }
527 void
tcti_mssim_init_context_data(TSS2_TCTI_COMMON_CONTEXT * tcti_common)528 tcti_mssim_init_context_data (
529     TSS2_TCTI_COMMON_CONTEXT *tcti_common)
530 {
531     TSS2_TCTI_MAGIC (tcti_common) = TCTI_MSSIM_MAGIC;
532     TSS2_TCTI_VERSION (tcti_common) = TCTI_VERSION;
533     TSS2_TCTI_TRANSMIT (tcti_common) = tcti_mssim_transmit;
534     TSS2_TCTI_RECEIVE (tcti_common) = tcti_mssim_receive;
535     TSS2_TCTI_FINALIZE (tcti_common) = tcti_mssim_finalize;
536     TSS2_TCTI_CANCEL (tcti_common) = tcti_mssim_cancel;
537     TSS2_TCTI_GET_POLL_HANDLES (tcti_common) = tcti_mssim_get_poll_handles;
538     TSS2_TCTI_SET_LOCALITY (tcti_common) = tcti_mssim_set_locality;
539     TSS2_TCTI_MAKE_STICKY (tcti_common) = tcti_make_sticky_not_implemented;
540     tcti_common->state = TCTI_STATE_TRANSMIT;
541     tcti_common->locality = 0;
542     memset (&tcti_common->header, 0, sizeof (tcti_common->header));
543 }
544 /*
545  * This is an implementation of the standard TCTI initialization function for
546  * this module.
547  */
548 TSS2_RC
Tss2_Tcti_Mssim_Init(TSS2_TCTI_CONTEXT * tctiContext,size_t * size,const char * conf)549 Tss2_Tcti_Mssim_Init (
550     TSS2_TCTI_CONTEXT *tctiContext,
551     size_t *size,
552     const char *conf)
553 {
554     TSS2_TCTI_MSSIM_CONTEXT *tcti_mssim = (TSS2_TCTI_MSSIM_CONTEXT*)tctiContext;
555     TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_mssim_down_cast (tcti_mssim);
556     TSS2_RC rc;
557     char *conf_copy = NULL;
558     mssim_conf_t mssim_conf = MSSIM_CONF_DEFAULT_INIT;
559 
560     if (conf == NULL) {
561         LOG_TRACE ("tctiContext: 0x%" PRIxPTR ", size: 0x%" PRIxPTR ""
562                    " default configuration will be used.",
563                    (uintptr_t)tctiContext, (uintptr_t)size);
564     } else {
565         LOG_TRACE ("tctiContext: 0x%" PRIxPTR ", size: 0x%" PRIxPTR ", conf: %s",
566                    (uintptr_t)tctiContext, (uintptr_t)size, conf);
567     }
568     if (size == NULL) {
569         return TSS2_TCTI_RC_BAD_VALUE;
570     }
571     if (tctiContext == NULL) {
572         *size = sizeof (TSS2_TCTI_MSSIM_CONTEXT);
573         return TSS2_RC_SUCCESS;
574     }
575 
576     if (conf != NULL) {
577         LOG_TRACE ("conf is not NULL");
578         if (strlen (conf) > TCTI_MSSIM_CONF_MAX) {
579             LOG_WARNING ("Provided conf string exceeds maximum of %u",
580                          TCTI_MSSIM_CONF_MAX);
581             return TSS2_TCTI_RC_BAD_VALUE;
582         }
583         conf_copy = strdup (conf);
584         if (conf_copy == NULL) {
585             LOG_ERROR ("Failed to allocate buffer: %s", strerror (errno));
586             rc = TSS2_TCTI_RC_GENERAL_FAILURE;
587             goto fail_out;
588         }
589         LOG_DEBUG ("Dup'd conf string to: 0x%" PRIxPTR,
590                    (uintptr_t)conf_copy);
591         rc = parse_key_value_string (conf_copy,
592                                      mssim_kv_callback,
593                                      &mssim_conf);
594         if (rc != TSS2_RC_SUCCESS) {
595             goto fail_out;
596         }
597     }
598     LOG_DEBUG ("Initializing mssim TCTI with host: %s, port: %" PRIu16,
599                mssim_conf.host, mssim_conf.port);
600 
601     tcti_mssim->tpm_sock = -1;
602     tcti_mssim->platform_sock = -1;
603 
604     rc = socket_connect (mssim_conf.host,
605                          mssim_conf.port,
606                          &tcti_mssim->tpm_sock);
607     if (rc != TSS2_RC_SUCCESS) {
608         goto fail_out;
609     }
610 
611     rc = socket_set_nonblock (tcti_mssim->tpm_sock);
612     if (rc != TSS2_RC_SUCCESS) {
613         goto fail_out;
614     }
615 
616     rc = socket_connect (mssim_conf.host,
617                          mssim_conf.port + 1,
618                          &tcti_mssim->platform_sock);
619     if (rc != TSS2_RC_SUCCESS) {
620         goto fail_out;
621     }
622 
623     tcti_mssim_init_context_data (tcti_common);
624     rc = simulator_setup (tctiContext);
625     if (rc != TSS2_RC_SUCCESS) {
626         goto fail_out;
627     }
628 
629     if (conf_copy != NULL) {
630         free (conf_copy);
631     }
632     return TSS2_RC_SUCCESS;
633 
634 fail_out:
635     if (conf_copy != NULL) {
636         free (conf_copy);
637     }
638     socket_close (&tcti_mssim->tpm_sock);
639     socket_close (&tcti_mssim->platform_sock);
640 
641     return rc;
642 }
643 
644 /* public info structure */
645 const TSS2_TCTI_INFO tss2_tcti_info = {
646     .version = TCTI_VERSION,
647     .name = "tcti-socket",
648     .description = "TCTI module for communication with the Microsoft TPM2 Simulator.",
649     .config_help = "Key / value string in the form \"host=localhost,port=2321\".",
650     .init = Tss2_Tcti_Mssim_Init,
651 };
652 
653 const TSS2_TCTI_INFO*
Tss2_Tcti_Info(void)654 Tss2_Tcti_Info (void)
655 {
656     return &tss2_tcti_info;
657 }
658