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     /* Unless tcti loglevel is log_debug or higher
78      * (i.e. TSS2_LOG=tcti+debug) turn the logging
79      * from loaded tctis off completely, including warnings
80      * and error logs. It makes too much noise when tcti
81      * loader tries them all one by one and what we want
82      * use is the last one.
83      */
84     log_level old_loglevel = LOGMODULE_status;
85     if (LOGMODULE_status < LOGLEVEL_INFO)
86         LOGMODULE_status = LOGLEVEL_NONE;
87 
88     r = init(*tcti, &size, conf);
89     LOGMODULE_status = old_loglevel;
90 
91     if (r != TSS2_RC_SUCCESS) {
92         LOG_DEBUG("TCTI init for function %p failed with %" PRIx32, init, r);
93         free(*tcti);
94         *tcti=NULL;
95         return r;
96     }
97 
98     LOG_DEBUG("Initialized TCTI for config: %s", conf);
99 
100     return TSS2_RC_SUCCESS;
101 }
102 
103 TSS2_RC
tcti_from_info(TSS2_TCTI_INFO_FUNC infof,const char * conf,TSS2_TCTI_CONTEXT ** tcti)104 tcti_from_info(TSS2_TCTI_INFO_FUNC infof,
105                const char* conf,
106                TSS2_TCTI_CONTEXT **tcti)
107 {
108     TSS2_RC r;
109     LOG_TRACE("Attempting to load TCTI info");
110 
111     const TSS2_TCTI_INFO* info = infof();
112     if (info == NULL) {
113         LOG_ERROR("TCTI info function failed");
114         return TSS2_ESYS_RC_GENERAL_FAILURE;
115     }
116     LOG_TRACE("Loaded TCTI info named: %s", info->name);
117     LOG_TRACE("TCTI description: %s", info->description);
118     LOG_TRACE("TCTI config_help: %s", info->config_help);
119 
120     r = tcti_from_init(info->init, conf, tcti);
121     if (r != TSS2_RC_SUCCESS) {
122         LOG_DEBUG("Could not initialize TCTI named: %s", info->name);
123         return r;
124     }
125     LOG_INFO("Initialized TCTI named: %s", info->name);
126 
127     return TSS2_RC_SUCCESS;
128 }
129 /*
130  * name_conf in the form "tcti-name:tcti-conf"
131  * copies 'tcti-name' component to 'name' buffer
132  * copies 'tcti-conf' component to 'conf' buffer
133  * handled name_conf forms:
134  * - "", ":" -> both name and conf are left unchanged
135  * - "tcti-name", "tcti-name:" -> tcti-name copied to 'name', 'conf'
136  *   unchanged
137  * - ":tcti-conf" -> tcti-conf copied to 'conf', 'name' unchanged
138  * - "tcti-name:tcti-conf" - "tcti-name" copied to 'name,', "tcti-conf"
139  *   copied to 'conf'
140  */
141 TSS2_RC
tctildr_conf_parse(const char * name_conf,char * name,char * conf)142 tctildr_conf_parse (const char *name_conf,
143                     char *name,
144                     char *conf)
145 {
146     char *split;
147     size_t combined_length;
148 
149     if (name_conf == NULL) {
150         LOG_ERROR ("'name_conf' param may NOT be NULL");
151         return TSS2_TCTI_RC_BAD_REFERENCE;
152     }
153     combined_length = strlen (name_conf);
154     if (combined_length > PATH_MAX - 1) {
155         LOG_ERROR ("combined conf length must be between 0 and PATH_MAX");
156         return TSS2_TCTI_RC_BAD_VALUE;
157     }
158 
159     LOG_DEBUG ("name_conf: \"%s\"", name_conf);
160     if (combined_length == 0)
161         return TSS2_RC_SUCCESS;
162     split = strchr (name_conf, ':');
163     if (name != NULL && split == NULL) {
164         /* no ':' tcti name only */
165         strcpy (name, name_conf);
166         LOG_DEBUG ("TCTI name: \"%s\"", name);
167         return TSS2_RC_SUCCESS;
168     }
169     if (name != NULL && name_conf[0] != '\0' && name_conf[0] != ':') {
170         /* name is more than empty string */
171         size_t name_length = split - name_conf;
172         if (name_length > PATH_MAX) {
173             return TSS2_TCTI_RC_BAD_VALUE;
174         }
175         memcpy (name, name_conf, name_length);
176         name [name_length] = '\0';
177         LOG_DEBUG ("TCTI name: \"%s\"", name);
178     }
179     if (conf != NULL && split && split [1] != '\0') {
180         /* conf is more than empty string */
181         strcpy (conf, &split [1]);
182         LOG_DEBUG ("TCTI conf: \"%s\"", conf);
183     }
184 
185     return TSS2_RC_SUCCESS;
186 }
187 TSS2_TCTILDR_CONTEXT*
tctildr_context_cast(TSS2_TCTI_CONTEXT * ctx)188 tctildr_context_cast (TSS2_TCTI_CONTEXT *ctx)
189 {
190     if (ctx != NULL && TSS2_TCTI_MAGIC (ctx) == TCTILDR_MAGIC) {
191         return (TSS2_TCTILDR_CONTEXT*)ctx;
192     }
193     return NULL;
194 }
195 TSS2_RC
tctildr_transmit(TSS2_TCTI_CONTEXT * tctiContext,size_t command_size,const uint8_t * command_buffer)196 tctildr_transmit (
197     TSS2_TCTI_CONTEXT *tctiContext,
198     size_t command_size,
199     const uint8_t *command_buffer)
200 {
201     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
202     if (ldr_ctx == NULL) {
203         return TSS2_TCTI_RC_BAD_REFERENCE;
204     }
205     return Tss2_Tcti_Transmit (ldr_ctx->tcti, command_size, command_buffer);
206 }
207 TSS2_RC
tctildr_receive(TSS2_TCTI_CONTEXT * tctiContext,size_t * response_size,uint8_t * response_buffer,int32_t timeout)208 tctildr_receive (
209     TSS2_TCTI_CONTEXT *tctiContext,
210     size_t *response_size,
211     uint8_t *response_buffer,
212     int32_t timeout)
213 {
214     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
215     if (ldr_ctx == NULL) {
216         return TSS2_TCTI_RC_BAD_REFERENCE;
217     }
218     return Tss2_Tcti_Receive (ldr_ctx->tcti,
219                               response_size,
220                               response_buffer,
221                               timeout);
222 }
223 TSS2_RC
tctildr_cancel(TSS2_TCTI_CONTEXT * tctiContext)224 tctildr_cancel (
225     TSS2_TCTI_CONTEXT *tctiContext)
226 {
227     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
228     if (ldr_ctx == NULL) {
229         return TSS2_TCTI_RC_BAD_REFERENCE;
230     }
231     return Tss2_Tcti_Cancel (ldr_ctx->tcti);
232 }
233 TSS2_RC
tctildr_get_poll_handles(TSS2_TCTI_CONTEXT * tctiContext,TSS2_TCTI_POLL_HANDLE * handles,size_t * num_handles)234 tctildr_get_poll_handles (
235     TSS2_TCTI_CONTEXT *tctiContext,
236     TSS2_TCTI_POLL_HANDLE *handles,
237     size_t *num_handles)
238 {
239     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
240     if (ldr_ctx == NULL) {
241         return TSS2_TCTI_RC_BAD_REFERENCE;
242     }
243     return Tss2_Tcti_GetPollHandles (ldr_ctx->tcti, handles, num_handles);
244 }
245 TSS2_RC
tctildr_set_locality(TSS2_TCTI_CONTEXT * tctiContext,uint8_t locality)246 tctildr_set_locality (
247     TSS2_TCTI_CONTEXT *tctiContext,
248     uint8_t locality)
249 {
250     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
251     if (ldr_ctx == NULL) {
252         return TSS2_TCTI_RC_BAD_REFERENCE;
253     }
254     return Tss2_Tcti_SetLocality (ldr_ctx->tcti, locality);
255 }
256 TSS2_RC
tctildr_make_sticky(TSS2_TCTI_CONTEXT * tctiContext,TPM2_HANDLE * handle,uint8_t sticky)257 tctildr_make_sticky (
258     TSS2_TCTI_CONTEXT *tctiContext,
259     TPM2_HANDLE *handle,
260     uint8_t sticky)
261 {
262     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
263     if (ldr_ctx == NULL) {
264         return TSS2_TCTI_RC_BAD_REFERENCE;
265     }
266     return Tss2_Tcti_MakeSticky (ldr_ctx->tcti, handle, sticky);
267 }
268 
269 void
tctildr_finalize(TSS2_TCTI_CONTEXT * tctiContext)270 tctildr_finalize (
271     TSS2_TCTI_CONTEXT *tctiContext)
272 {
273     TSS2_TCTILDR_CONTEXT *ldr_ctx = tctildr_context_cast (tctiContext);
274     if (ldr_ctx == NULL) {
275         return;
276     }
277     if (ldr_ctx->tcti != NULL) {
278         Tss2_Tcti_Finalize (ldr_ctx->tcti);
279         free (ldr_ctx->tcti);
280         ldr_ctx->tcti = NULL;
281     }
282 }
283 
284 void
Tss2_TctiLdr_Finalize(TSS2_TCTI_CONTEXT ** tctiContext)285 Tss2_TctiLdr_Finalize (TSS2_TCTI_CONTEXT **tctiContext)
286 {
287     TSS2_TCTILDR_CONTEXT *ldr_ctx;
288     if (tctiContext == NULL) {
289         return;
290     }
291     ldr_ctx = tctildr_context_cast (*tctiContext);
292     if (ldr_ctx == NULL) {
293         return;
294     }
295     tctildr_finalize (*tctiContext);
296     tctildr_finalize_data (&ldr_ctx->library_handle);
297     free (ldr_ctx);
298     *tctiContext = NULL;
299 }
300 
301 TSS2_RC
copy_info(const TSS2_TCTI_INFO * info_src,TSS2_TCTI_INFO * info_dst)302 copy_info (const TSS2_TCTI_INFO *info_src,
303            TSS2_TCTI_INFO *info_dst)
304 {
305     TSS2_RC rc = TSS2_RC_SUCCESS;
306     const char *tmp = NULL;
307 
308     if (info_src == NULL || info_dst == NULL) {
309         LOG_ERROR("parameters cannot be NULL");
310         return TSS2_TCTI_RC_BAD_REFERENCE;
311     }
312     tmp = strndup (info_src->name, PATH_MAX);
313     if (tmp != NULL) {
314         info_dst->name = tmp;
315     } else {
316         LOG_ERROR("strndup failed on name: %s", strerror(errno));
317         return TSS2_TCTI_RC_GENERAL_FAILURE;
318     }
319     tmp = strndup (info_src->description, PATH_MAX);
320     if (tmp != NULL) {
321         info_dst->description = tmp;
322     } else {
323         LOG_ERROR("strndup failed on description: %s", strerror(errno));
324         free ((char*)info_dst->name);
325         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
326         goto out;
327     }
328     tmp = strndup (info_src->config_help, PATH_MAX);
329     if (tmp != NULL) {
330         info_dst->config_help = tmp;
331     } else {
332         LOG_ERROR("strndup failed on config_help: %s", strerror(errno));
333         free ((char*)info_dst->name);
334         free ((char*)info_dst->description);
335         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
336         goto out;
337     }
338     info_dst->version = info_src->version;
339 out:
340     return rc;
341 }
342 
343 TSS2_RC
Tss2_TctiLdr_GetInfo(const char * name,TSS2_TCTI_INFO ** info)344 Tss2_TctiLdr_GetInfo (const char *name,
345                       TSS2_TCTI_INFO **info)
346 {
347     TSS2_RC rc;
348     const TSS2_TCTI_INFO *info_lib = NULL;
349     TSS2_TCTI_INFO *info_tmp = NULL;
350     void *data = NULL;
351     char name_buf [PATH_MAX] = { 0, }, *name_ptr = NULL;
352 
353     if (info == NULL) {
354         return TSS2_TCTI_RC_BAD_REFERENCE;
355     }
356     if (name != NULL) {
357         rc = tctildr_conf_parse (name, name_buf, NULL);
358         if (rc != TSS2_RC_SUCCESS)
359             return rc;
360         name_ptr = name_buf;
361     }
362     rc = tctildr_get_info (name_ptr, &info_lib, &data);
363     if (rc != TSS2_RC_SUCCESS)
364         return rc;
365     info_tmp = calloc (1, sizeof (*info_tmp));
366     if (info_tmp == NULL) {
367         LOG_ERROR("calloc failed: %s", strerror (errno));
368         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
369         goto out;
370     }
371     rc = copy_info (info_lib, info_tmp);
372     if (rc != TSS2_RC_SUCCESS) {
373         free (info_tmp);
374         info_tmp = NULL;
375         goto out;
376     }
377     info_tmp->init = NULL;
378 out:
379     tctildr_finalize_data (&data);
380     *info = info_tmp;
381     return rc;
382 }
383 
384 void
Tss2_TctiLdr_FreeInfo(TSS2_TCTI_INFO ** info)385 Tss2_TctiLdr_FreeInfo (TSS2_TCTI_INFO **info)
386 {
387     TSS2_TCTI_INFO *info_tmp;
388 
389     if (info == NULL || *info == NULL) {
390         return;
391     }
392     info_tmp = *info;
393     if (info_tmp->name != NULL) {
394         free ((char*)info_tmp->name);
395     }
396     if (info_tmp->description != NULL) {
397         free ((char*)info_tmp->description);
398     }
399     if (info_tmp->config_help != NULL) {
400         free ((char*)info_tmp->config_help);
401     }
402     free (info_tmp);
403     *info = NULL;
404 }
405 TSS2_RC
Tss2_TctiLdr_Initialize_Ex(const char * name,const char * conf,TSS2_TCTI_CONTEXT ** tctiContext)406 Tss2_TctiLdr_Initialize_Ex (const char *name,
407                             const char *conf,
408                             TSS2_TCTI_CONTEXT **tctiContext)
409 {
410     TSS2_TCTILDR_CONTEXT *ldr_ctx = NULL;
411     TSS2_RC rc;
412     void *dl_handle = NULL;
413     const char *local_name = NULL, *local_conf = NULL;
414 
415     if (tctiContext == NULL) {
416         return TSS2_TCTI_RC_BAD_VALUE;
417     }
418     *tctiContext = NULL;
419     /* Ignore 'name' and 'conf' if they're NULL or empty string */
420     if (name != NULL && strcmp (name, "")) {
421         local_name = name;
422     }
423     if (conf != NULL && strcmp (conf, "")) {
424         local_conf = conf;
425     }
426     rc = tctildr_get_tcti (local_name, local_conf, tctiContext, &dl_handle);
427     if (rc != TSS2_RC_SUCCESS) {
428         LOG_ERROR ("Failed to instantiate TCTI");
429         goto err;
430     }
431     ldr_ctx = calloc (1, sizeof (TSS2_TCTILDR_CONTEXT));
432     if (ldr_ctx == NULL) {
433         rc = TSS2_TCTI_RC_MEMORY;
434         goto err;
435     }
436     TSS2_TCTI_MAGIC (ldr_ctx) = TCTILDR_MAGIC;
437     TSS2_TCTI_VERSION (ldr_ctx) = TCTI_VERSION;
438     TSS2_TCTI_TRANSMIT (ldr_ctx) = tctildr_transmit;
439     TSS2_TCTI_RECEIVE (ldr_ctx) = tctildr_receive;
440     TSS2_TCTI_FINALIZE (ldr_ctx) = tctildr_finalize;
441     TSS2_TCTI_CANCEL (ldr_ctx) = tctildr_cancel;
442     TSS2_TCTI_GET_POLL_HANDLES (ldr_ctx) = tctildr_get_poll_handles;
443     TSS2_TCTI_SET_LOCALITY (ldr_ctx) = tctildr_set_locality;
444     TSS2_TCTI_MAKE_STICKY (ldr_ctx) = tctildr_make_sticky;
445     ldr_ctx->library_handle = dl_handle;
446     ldr_ctx->tcti = *tctiContext;
447     *tctiContext = (TSS2_TCTI_CONTEXT*)ldr_ctx;
448     return rc;
449 err:
450     if (*tctiContext != NULL) {
451         Tss2_Tcti_Finalize (*tctiContext);
452         free (*tctiContext);
453         *tctiContext = NULL;
454     }
455     tctildr_finalize_data (&dl_handle);
456     return rc;
457 }
458 
459 TSS2_RC
Tss2_TctiLdr_Initialize(const char * nameConf,TSS2_TCTI_CONTEXT ** tctiContext)460 Tss2_TctiLdr_Initialize (const char *nameConf,
461                          TSS2_TCTI_CONTEXT **tctiContext)
462 {
463     char name [PATH_MAX] = { 0, }, conf [PATH_MAX] = { 0, };
464     TSS2_RC rc;
465 
466     if (nameConf == NULL) {
467         return Tss2_TctiLdr_Initialize_Ex (NULL, NULL, tctiContext);
468     }
469     rc = tctildr_conf_parse (nameConf, name, conf);
470     if (rc != TSS2_RC_SUCCESS)
471         return rc;
472     return Tss2_TctiLdr_Initialize_Ex (name, conf, tctiContext);
473 }
474