1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*******************************************************************************
3  * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
4  * Copyright 2019, Intel Corporation
5  * All rights reserved.
6  *******************************************************************************/
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <errno.h>
13 #include <inttypes.h>
14 #if defined(__linux__)
15 #include <linux/limits.h>
16 #elif defined(_MSC_VER)
17 #include <windows.h>
18 #include <limits.h>
19 #ifndef PATH_MAX
20 #define PATH_MAX MAX_PATH
21 
strndup(const char * s,size_t n)22 static char *strndup(const char* s, size_t n)
23 {
24     char *dst = NULL;
25 
26     if (n + 1 >= USHRT_MAX)
27         return NULL;
28 
29     dst = calloc(1, n + 1);
30 
31     if (dst == NULL)
32         return NULL;
33 
34     memcpy(dst, s, n);
35     return dst;
36 }
37 #endif
38 #else
39 #include <limits.h>
40 #endif
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "tss2_tpm2_types.h"
45 #include "tss2_tcti.h"
46 
47 #include "tcti-common.h"
48 #include "tctildr.h"
49 #include "tctildr-interface.h"
50 #define LOGMODULE tcti
51 #include "util/log.h"
52 
53 TSS2_RC
tcti_from_init(TSS2_TCTI_INIT_FUNC init,const char * conf,TSS2_TCTI_CONTEXT ** tcti)54 tcti_from_init(TSS2_TCTI_INIT_FUNC init,
55                const char* conf,
56                TSS2_TCTI_CONTEXT **tcti)
57 {
58     TSS2_RC r;
59     size_t size;
60 
61     LOG_TRACE("Initializing TCTI for config: %s", conf);
62 
63     if (init == NULL || tcti == NULL)
64         return TSS2_TCTI_RC_BAD_REFERENCE;
65     r = init(NULL, &size, conf);
66     if (r != TSS2_RC_SUCCESS) {
67         LOG_WARNING("TCTI init for function %p failed with %" PRIx32, init, r);
68         return r;
69     }
70 
71     *tcti = (TSS2_TCTI_CONTEXT *) calloc(1, size);
72     if (*tcti == NULL) {
73         LOG_ERROR("Memory allocation for tcti failed: %s", strerror(errno));
74         return TSS2_ESYS_RC_MEMORY;
75     }
76 
77     r = init(*tcti, &size, conf);
78     if (r != TSS2_RC_SUCCESS) {
79         LOG_WARNING("TCTI init for function %p failed with %" PRIx32, init, r);
80         free(*tcti);
81         *tcti=NULL;
82         return r;
83     }
84 
85     LOG_DEBUG("Initialized TCTI for config: %s", conf);
86 
87     return TSS2_RC_SUCCESS;
88 }
89 
90 TSS2_RC
tcti_from_info(TSS2_TCTI_INFO_FUNC infof,const char * conf,TSS2_TCTI_CONTEXT ** tcti)91 tcti_from_info(TSS2_TCTI_INFO_FUNC infof,
92                const char* conf,
93                TSS2_TCTI_CONTEXT **tcti)
94 {
95     TSS2_RC r;
96     LOG_TRACE("Attempting to load TCTI info");
97 
98     const TSS2_TCTI_INFO* info = infof();
99     if (info == NULL) {
100         LOG_ERROR("TCTI info function failed");
101         return TSS2_ESYS_RC_GENERAL_FAILURE;
102     }
103     LOG_TRACE("Loaded TCTI info named: %s", info->name);
104     LOG_TRACE("TCTI description: %s", info->description);
105     LOG_TRACE("TCTI config_help: %s", info->config_help);
106 
107     r = tcti_from_init(info->init, conf, tcti);
108     if (r != TSS2_RC_SUCCESS) {
109         LOG_WARNING("Could not initialize TCTI named: %s", info->name);
110         return r;
111     }
112 
113     LOG_DEBUG("Initialized TCTI named: %s", info->name);
114 
115     return TSS2_RC_SUCCESS;
116 }
117 /*
118  * name_conf in the form "tcti-name:tcti-conf"
119  * copies 'tcti-name' component to 'name' buffer
120  * copies 'tcti-conf' component to 'conf' buffer
121  * handled name_conf forms:
122  * - "", ":" -> both name and conf are left unchanged
123  * - "tcti-name", "tcti-name:" -> tcti-name copied to 'name', 'conf'
124  *   unchanged
125  * - ":tcti-conf" -> tcti-conf copied to 'conf', 'name' unchanged
126  * - "tcti-name:tcti-conf" - "tcti-name" copied to 'name,', "tcti-conf"
127  *   copied to 'conf'
128  */
129 TSS2_RC
tctildr_conf_parse(const char * name_conf,char * name,char * conf)130 tctildr_conf_parse (const char *name_conf,
131                     char *name,
132                     char *conf)
133 {
134     char *split;
135     size_t combined_length;
136 
137     if (name_conf == NULL) {
138         LOG_ERROR ("'name_conf' param may NOT be NULL");
139         return TSS2_TCTI_RC_BAD_REFERENCE;
140     }
141     combined_length = strlen (name_conf);
142     if (combined_length > PATH_MAX - 1) {
143         LOG_ERROR ("combined conf length must be between 0 and PATH_MAX");
144         return TSS2_TCTI_RC_BAD_VALUE;
145     }
146 
147     LOG_DEBUG ("name_conf: \"%s\"", name_conf);
148     if (combined_length == 0)
149         return TSS2_RC_SUCCESS;
150     split = strchr (name_conf, ':');
151     if (name != NULL && split == NULL) {
152         /* no ':' tcti name only */
153         strcpy (name, name_conf);
154         LOG_DEBUG ("TCTI name: \"%s\"", name);
155         return TSS2_RC_SUCCESS;
156     }
157     if (name != NULL && name_conf[0] != '\0' && name_conf[0] != ':') {
158         /* name is more than empty string */
159         size_t name_length = split - name_conf;
160         if (name_length > PATH_MAX) {
161             return TSS2_TCTI_RC_BAD_VALUE;
162         }
163         memcpy (name, name_conf, name_length);
164         name [name_length] = '\0';
165         LOG_DEBUG ("TCTI name: \"%s\"", name);
166     }
167     if (conf != NULL && split && split [1] != '\0') {
168         /* conf is more than empty string */
169         strcpy (conf, &split [1]);
170         LOG_DEBUG ("TCTI conf: \"%s\"", conf);
171     }
172 
173     return TSS2_RC_SUCCESS;
174 }
175 TSS2_TCTILDR_CONTEXT*
tctildr_context_cast(TSS2_TCTI_CONTEXT * ctx)176 tctildr_context_cast (TSS2_TCTI_CONTEXT *ctx)
177 {
178     if (ctx != NULL && TSS2_TCTI_MAGIC (ctx) == TCTILDR_MAGIC) {
179         return (TSS2_TCTILDR_CONTEXT*)ctx;
180     }
181     return NULL;
182 }
183 TSS2_RC
tctildr_transmit(TSS2_TCTI_CONTEXT * tctiContext,size_t command_size,const uint8_t * command_buffer)184 tctildr_transmit (
185     TSS2_TCTI_CONTEXT *tctiContext,
186     size_t command_size,
187     const uint8_t *command_buffer)
188 {
189     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
190     if (ldr_ctx == NULL) {
191         return TSS2_TCTI_RC_BAD_CONTEXT;
192     }
193     return Tss2_Tcti_Transmit (ldr_ctx->tcti, command_size, command_buffer);
194 }
195 TSS2_RC
tctildr_receive(TSS2_TCTI_CONTEXT * tctiContext,size_t * response_size,uint8_t * response_buffer,int32_t timeout)196 tctildr_receive (
197     TSS2_TCTI_CONTEXT *tctiContext,
198     size_t *response_size,
199     uint8_t *response_buffer,
200     int32_t timeout)
201 {
202     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
203     if (ldr_ctx == NULL) {
204         return TSS2_TCTI_RC_BAD_CONTEXT;
205     }
206     return Tss2_Tcti_Receive (ldr_ctx->tcti,
207                               response_size,
208                               response_buffer,
209                               timeout);
210 }
211 TSS2_RC
tctildr_cancel(TSS2_TCTI_CONTEXT * tctiContext)212 tctildr_cancel (
213     TSS2_TCTI_CONTEXT *tctiContext)
214 {
215     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
216     if (ldr_ctx == NULL) {
217         return TSS2_TCTI_RC_BAD_CONTEXT;
218     }
219     return Tss2_Tcti_Cancel (ldr_ctx->tcti);
220 }
221 TSS2_RC
tctildr_get_poll_handles(TSS2_TCTI_CONTEXT * tctiContext,TSS2_TCTI_POLL_HANDLE * handles,size_t * num_handles)222 tctildr_get_poll_handles (
223     TSS2_TCTI_CONTEXT *tctiContext,
224     TSS2_TCTI_POLL_HANDLE *handles,
225     size_t *num_handles)
226 {
227     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
228     if (ldr_ctx == NULL) {
229         return TSS2_TCTI_RC_BAD_CONTEXT;
230     }
231     return Tss2_Tcti_GetPollHandles (ldr_ctx->tcti, handles, num_handles);
232 }
233 TSS2_RC
tctildr_set_locality(TSS2_TCTI_CONTEXT * tctiContext,uint8_t locality)234 tctildr_set_locality (
235     TSS2_TCTI_CONTEXT *tctiContext,
236     uint8_t locality)
237 {
238     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
239     if (ldr_ctx == NULL) {
240         return TSS2_TCTI_RC_BAD_CONTEXT;
241     }
242     return Tss2_Tcti_SetLocality (ldr_ctx->tcti, locality);
243 }
244 TSS2_RC
tctildr_make_sticky(TSS2_TCTI_CONTEXT * tctiContext,TPM2_HANDLE * handle,uint8_t sticky)245 tctildr_make_sticky (
246     TSS2_TCTI_CONTEXT *tctiContext,
247     TPM2_HANDLE *handle,
248     uint8_t sticky)
249 {
250     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
251     if (ldr_ctx == NULL) {
252         return TSS2_TCTI_RC_BAD_CONTEXT;
253     }
254     return Tss2_Tcti_MakeSticky (ldr_ctx->tcti, handle, sticky);
255 }
256 
257 void
tctildr_finalize(TSS2_TCTI_CONTEXT * tctiContext)258 tctildr_finalize (
259     TSS2_TCTI_CONTEXT *tctiContext)
260 {
261     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
262     if (ldr_ctx == NULL) {
263         return;
264     }
265     if (ldr_ctx->tcti != NULL) {
266         Tss2_Tcti_Finalize (ldr_ctx->tcti);
267         free (ldr_ctx->tcti);
268         ldr_ctx->tcti = NULL;
269     }
270 }
271 
272 void
Tss2_TctiLdr_Finalize(TSS2_TCTI_CONTEXT ** tctiContext)273 Tss2_TctiLdr_Finalize (TSS2_TCTI_CONTEXT **tctiContext)
274 {
275     TSS2_TCTILDR_CONTEXT *ldr_ctx;
276     if (tctiContext == NULL) {
277         return;
278     }
279     ldr_ctx = tctildr_context_cast (*tctiContext);
280     if (ldr_ctx == NULL) {
281         return;
282     }
283     tctildr_finalize (*tctiContext);
284     tctildr_finalize_data (&ldr_ctx->library_handle);
285     free (ldr_ctx);
286     *tctiContext = NULL;
287 }
288 
289 TSS2_RC
copy_info(const TSS2_TCTI_INFO * info_src,TSS2_TCTI_INFO * info_dst)290 copy_info (const TSS2_TCTI_INFO *info_src,
291            TSS2_TCTI_INFO *info_dst)
292 {
293     TSS2_RC rc = TSS2_RC_SUCCESS;
294     const char *tmp = NULL;
295 
296     if (info_src == NULL || info_dst == NULL) {
297         LOG_ERROR("parameters cannot be NULL");
298         return TSS2_TCTI_RC_BAD_REFERENCE;
299     }
300     tmp = strndup (info_src->name, PATH_MAX);
301     if (tmp != NULL) {
302         info_dst->name = tmp;
303     } else {
304         LOG_ERROR("strndup failed on name: %s", strerror(errno));
305         return TSS2_TCTI_RC_GENERAL_FAILURE;
306     }
307     tmp = strndup (info_src->description, PATH_MAX);
308     if (tmp != NULL) {
309         info_dst->description = tmp;
310     } else {
311         LOG_ERROR("strndup failed on description: %s", strerror(errno));
312         free ((char*)info_dst->name);
313         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
314         goto out;
315     }
316     tmp = strndup (info_src->config_help, PATH_MAX);
317     if (tmp != NULL) {
318         info_dst->config_help = tmp;
319     } else {
320         LOG_ERROR("strndup failed on config_help: %s", strerror(errno));
321         free ((char*)info_dst->name);
322         free ((char*)info_dst->description);
323         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
324         goto out;
325     }
326     info_dst->version = info_src->version;
327 out:
328     return rc;
329 }
330 
331 TSS2_RC
Tss2_TctiLdr_GetInfo(const char * name,TSS2_TCTI_INFO ** info)332 Tss2_TctiLdr_GetInfo (const char *name,
333                       TSS2_TCTI_INFO **info)
334 {
335     TSS2_RC rc;
336     const TSS2_TCTI_INFO *info_lib = NULL;
337     TSS2_TCTI_INFO *info_tmp = NULL;
338     void *data = NULL;
339     char name_buf [PATH_MAX] = { 0, }, *name_ptr = NULL;
340 
341     if (info == NULL) {
342         return TSS2_TCTI_RC_BAD_REFERENCE;
343     }
344     if (name != NULL) {
345         rc = tctildr_conf_parse (name, name_buf, NULL);
346         if (rc != TSS2_RC_SUCCESS)
347             return rc;
348         name_ptr = name_buf;
349     }
350     rc = tctildr_get_info (name_ptr, &info_lib, &data);
351     if (rc != TSS2_RC_SUCCESS)
352         return rc;
353     info_tmp = calloc (1, sizeof (*info_tmp));
354     if (info_tmp == NULL) {
355         LOG_ERROR("calloc failed: %s", strerror (errno));
356         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
357         goto out;
358     }
359     rc = copy_info (info_lib, info_tmp);
360     if (rc != TSS2_RC_SUCCESS) {
361         free (info_tmp);
362         info_tmp = NULL;
363         goto out;
364     }
365     info_tmp->init = NULL;
366 out:
367     tctildr_finalize_data (&data);
368     *info = info_tmp;
369     return rc;
370 }
371 
372 void
Tss2_TctiLdr_FreeInfo(TSS2_TCTI_INFO ** info)373 Tss2_TctiLdr_FreeInfo (TSS2_TCTI_INFO **info)
374 {
375     TSS2_TCTI_INFO *info_tmp;
376 
377     if (info == NULL || *info == NULL) {
378         return;
379     }
380     info_tmp = *info;
381     if (info_tmp->name != NULL) {
382         free ((char*)info_tmp->name);
383     }
384     if (info_tmp->description != NULL) {
385         free ((char*)info_tmp->description);
386     }
387     if (info_tmp->config_help != NULL) {
388         free ((char*)info_tmp->config_help);
389     }
390     free (info_tmp);
391     *info = NULL;
392 }
393 TSS2_RC
Tss2_TctiLdr_Initialize_Ex(const char * name,const char * conf,TSS2_TCTI_CONTEXT ** tctiContext)394 Tss2_TctiLdr_Initialize_Ex (const char *name,
395                             const char *conf,
396                             TSS2_TCTI_CONTEXT **tctiContext)
397 {
398     TSS2_TCTILDR_CONTEXT *ldr_ctx = NULL;
399     TSS2_RC rc;
400     void *dl_handle = NULL;
401     const char *local_name = NULL, *local_conf = NULL;
402 
403     if (tctiContext == NULL) {
404         return TSS2_TCTI_RC_BAD_VALUE;
405     }
406     *tctiContext = NULL;
407     /* Ignore 'name' and 'conf' if they're NULL or empty string */
408     if (name != NULL && strcmp (name, "")) {
409         local_name = name;
410     }
411     if (conf != NULL && strcmp (conf, "")) {
412         local_conf = conf;
413     }
414     rc = tctildr_get_tcti (local_name, local_conf, tctiContext, &dl_handle);
415     if (rc != TSS2_RC_SUCCESS) {
416         LOG_ERROR ("Failed to instantiate TCTI");
417         goto err;
418     }
419     ldr_ctx = calloc (1, sizeof (TSS2_TCTILDR_CONTEXT));
420     if (ldr_ctx == NULL) {
421         rc = TSS2_TCTI_RC_MEMORY;
422         goto err;
423     }
424     TSS2_TCTI_MAGIC (ldr_ctx) = TCTILDR_MAGIC;
425     TSS2_TCTI_VERSION (ldr_ctx) = TCTI_VERSION;
426     TSS2_TCTI_TRANSMIT (ldr_ctx) = tctildr_transmit;
427     TSS2_TCTI_RECEIVE (ldr_ctx) = tctildr_receive;
428     TSS2_TCTI_FINALIZE (ldr_ctx) = tctildr_finalize;
429     TSS2_TCTI_CANCEL (ldr_ctx) = tctildr_cancel;
430     TSS2_TCTI_GET_POLL_HANDLES (ldr_ctx) = tctildr_get_poll_handles;
431     TSS2_TCTI_SET_LOCALITY (ldr_ctx) = tctildr_set_locality;
432     TSS2_TCTI_MAKE_STICKY (ldr_ctx) = tctildr_make_sticky;
433     ldr_ctx->library_handle = dl_handle;
434     ldr_ctx->tcti = *tctiContext;
435     *tctiContext = (TSS2_TCTI_CONTEXT*)ldr_ctx;
436     return rc;
437 err:
438     if (*tctiContext != NULL) {
439         Tss2_Tcti_Finalize (*tctiContext);
440         free (*tctiContext);
441         *tctiContext = NULL;
442     }
443     tctildr_finalize_data (&dl_handle);
444     return rc;
445 }
446 
447 TSS2_RC
Tss2_TctiLdr_Initialize(const char * nameConf,TSS2_TCTI_CONTEXT ** tctiContext)448 Tss2_TctiLdr_Initialize (const char *nameConf,
449                          TSS2_TCTI_CONTEXT **tctiContext)
450 {
451     char name [PATH_MAX] = { 0, }, conf [PATH_MAX] = { 0, };
452     TSS2_RC rc;
453 
454     if (nameConf == NULL) {
455         return Tss2_TctiLdr_Initialize_Ex (NULL, NULL, tctiContext);
456     }
457     rc = tctildr_conf_parse (nameConf, name, conf);
458     if (rc != TSS2_RC_SUCCESS)
459         return rc;
460     return Tss2_TctiLdr_Initialize_Ex (name, conf, tctiContext);
461 }
462