VirtualBox

source: vbox/trunk/src/libs/libtpms-0.9.6/src/tpm_library.c

Last change on this file was 91612, checked in by vboxsync, 3 years ago

src/libs: Export libtpms-0.9.0, bugref:10078

File size: 18.0 KB
Line 
1/********************************************************************************/
2/* */
3/* LibTPM interface functions */
4/* Written by Stefan Berger */
5/* IBM Thomas J. Watson Research Center */
6/* $Id: tpm_library.c 4615 2011-08-30 15:35:24Z stefanb $ */
7/* */
8/* (c) Copyright IBM Corporation 2010. */
9/* */
10/* All rights reserved. */
11/* */
12/* Redistribution and use in source and binary forms, with or without */
13/* modification, are permitted provided that the following conditions are */
14/* met: */
15/* */
16/* Redistributions of source code must retain the above copyright notice, */
17/* this list of conditions and the following disclaimer. */
18/* */
19/* Redistributions in binary form must reproduce the above copyright */
20/* notice, this list of conditions and the following disclaimer in the */
21/* documentation and/or other materials provided with the distribution. */
22/* */
23/* Neither the names of the IBM Corporation nor the names of its */
24/* contributors may be used to endorse or promote products derived from */
25/* this software without specific prior written permission. */
26/* */
27/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
28/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
29/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
30/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
31/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
32/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
33/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
34/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
35/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
36/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
37/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38/********************************************************************************/
39
40#include <config.h>
41
42#include <assert.h>
43#include <string.h>
44#if defined __FreeBSD__
45# define _WITH_DPRINTF
46#endif
47#include <stdio.h>
48#include <stdlib.h>
49#include <stdarg.h>
50#include <ctype.h>
51#ifndef VBOX
52#include <unistd.h>
53#endif
54#include <stdbool.h>
55
56#ifdef USE_FREEBL_CRYPTO_LIBRARY
57# include <plbase64.h>
58#endif
59
60#ifdef USE_OPENSSL_CRYPTO_LIBRARY
61# ifndef VBOX
62# include <openssl/bio.h>
63# include <openssl/evp.h>
64# else
65# include <iprt/errcore.h>
66# include <iprt/base64.h>
67# endif
68#endif
69
70#include "tpm_debug.h"
71#include "tpm_error.h"
72#include "tpm_library.h"
73#include "tpm_library_intern.h"
74#include "tpm_nvfilename.h"
75#include "tpm_tis.h"
76
77static const struct tags_and_indices {
78 const char *starttag;
79 const char *endtag;
80} tags_and_indices[] = {
81 [TPMLIB_BLOB_TYPE_INITSTATE] =
82 {
83 .starttag = TPMLIB_INITSTATE_START_TAG,
84 .endtag = TPMLIB_INITSTATE_END_TAG,
85 },
86};
87
88static const struct tpm_interface *const tpm_iface[] = {
89#if WITH_TPM1
90 &TPM12Interface,
91#else
92 &DisabledInterface,
93#endif
94#if WITH_TPM2
95 &TPM2Interface,
96#else
97 &DisabledInterface,
98#endif
99 NULL,
100};
101
102static int debug_fd = -1;
103static unsigned debug_level = 0;
104static char *debug_prefix = NULL;
105
106static struct sized_buffer cached_blobs[TPMLIB_STATE_SAVE_STATE + 1];
107
108static int tpmvers_choice = 0; /* default is TPM1.2 */
109static TPM_BOOL tpmvers_locked = FALSE;
110
111uint32_t TPMLIB_GetVersion(void)
112{
113 return TPM_LIBRARY_VERSION;
114}
115
116TPM_RESULT TPMLIB_ChooseTPMVersion(TPMLIB_TPMVersion ver)
117{
118 /* TPMLIB_Terminate will reset previous choice */
119 if (tpmvers_locked)
120 return TPM_FAIL;
121
122 switch (ver) {
123#if WITH_TPM1
124 case TPMLIB_TPM_VERSION_1_2:
125 if (tpmvers_choice != 0)
126 ClearAllCachedState();
127
128 tpmvers_choice = 0; // entry 0 in tpm_iface
129 return TPM_SUCCESS;
130#endif
131#if WITH_TPM2
132 case TPMLIB_TPM_VERSION_2:
133 if (tpmvers_choice != 1)
134 ClearAllCachedState();
135
136 tpmvers_choice = 1; // entry 1 in tpm_iface
137 return TPM_SUCCESS;
138#endif
139 default:
140 return TPM_FAIL;
141 }
142}
143
144TPM_RESULT TPMLIB_MainInit(void)
145{
146 if (!tpm_iface[tpmvers_choice]) {
147 return TPM_FAIL;
148 }
149
150 tpmvers_locked = TRUE;
151
152 return tpm_iface[tpmvers_choice]->MainInit();
153}
154
155void TPMLIB_Terminate(void)
156{
157 tpm_iface[tpmvers_choice]->Terminate();
158
159 tpmvers_locked = FALSE;
160}
161
162/*
163 * Send a command to the TPM. The command buffer must hold a well formatted
164 * TPM command and the command_size indicate the size of the command.
165 * The respbuffer parameter may be provided by the user and grow if
166 * the respbufsize size indicator is determined to be too small for the
167 * response. In that case a new buffer will be allocated and the size of that
168 * buffer returned in the respbufsize parameter. resp_size describes the
169 * size of the actual response within the respbuffer.
170 */
171TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size,
172 uint32_t *respbufsize,
173 unsigned char *command, uint32_t command_size)
174{
175 return tpm_iface[tpmvers_choice]->Process(respbuffer,
176 resp_size, respbufsize,
177 command, command_size);
178}
179
180/*
181 * Get the volatile state from the TPM. This function will return the
182 * buffer and the length of the buffer to the caller in case everything
183 * went alright.
184 */
185TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer,
186 uint32_t *buflen)
187{
188 return tpm_iface[tpmvers_choice]->VolatileAllStore(buffer, buflen);
189}
190
191/*
192 * Have the TPM cancel an ongoing command
193 */
194TPM_RESULT TPMLIB_CancelCommand(void)
195{
196 return tpm_iface[tpmvers_choice]->CancelCommand();
197}
198
199/*
200 * Get a property of the TPM. The functions currently only
201 * return compile-time #defines but this may change in future
202 * versions where we may return parameters with which the TPM
203 * was created (rather than compiled).
204 */
205TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop,
206 int *result)
207{
208 switch (prop) {
209 case TPMPROP_TPM_BUFFER_MAX:
210 *result = TPM_BUFFER_MAX;
211 break;
212
213 default:
214 return tpm_iface[tpmvers_choice]->GetTPMProperty(prop, result);
215 }
216
217 return TPM_SUCCESS;
218}
219
220char *TPMLIB_GetInfo(enum TPMLIB_InfoFlags flags)
221{
222 return tpm_iface[tpmvers_choice]->GetInfo(flags);
223}
224
225TPM_RESULT TPMLIB_SetState(enum TPMLIB_StateType st,
226 const unsigned char *buffer, uint32_t buflen)
227{
228 return tpm_iface[tpmvers_choice]->SetState(st, buffer, buflen);
229}
230
231TPM_RESULT TPMLIB_GetState(enum TPMLIB_StateType st,
232 unsigned char **buffer, uint32_t *buflen)
233{
234 return tpm_iface[tpmvers_choice]->GetState(st, buffer, buflen);
235}
236
237TPM_RESULT TPM_IO_Hash_Start(void)
238{
239 return tpm_iface[tpmvers_choice]->HashStart();
240}
241
242TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, uint32_t data_length)
243{
244 return tpm_iface[tpmvers_choice]->HashData(data, data_length);
245}
246
247TPM_RESULT TPM_IO_Hash_End(void)
248{
249 return tpm_iface[tpmvers_choice]->HashEnd();
250}
251
252TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished)
253{
254 return tpm_iface[tpmvers_choice]->TpmEstablishedGet(tpmEstablished);
255}
256
257TPM_RESULT TPM_IO_TpmEstablished_Reset(void)
258{
259 return tpm_iface[tpmvers_choice]->TpmEstablishedReset();
260}
261
262uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size,
263 uint32_t *min_size,
264 uint32_t *max_size)
265{
266 return tpm_iface[tpmvers_choice]->SetBufferSize(wanted_size,
267 min_size,
268 max_size);
269}
270
271TPM_RESULT TPMLIB_ValidateState(enum TPMLIB_StateType st,
272 unsigned int flags)
273{
274 return tpm_iface[tpmvers_choice]->ValidateState(st, flags);
275}
276
277static struct libtpms_callbacks libtpms_cbs;
278
279struct libtpms_callbacks *TPMLIB_GetCallbacks(void)
280{
281 return &libtpms_cbs;
282}
283
284TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *callbacks)
285{
286 int max_size = sizeof(struct libtpms_callbacks);
287
288 /* restrict the size of the structure to what we know currently
289 future versions may know more callbacks */
290 if (callbacks->sizeOfStruct < max_size)
291 max_size = callbacks->sizeOfStruct;
292
293 /* clear the internal callback structure and copy the user provided
294 callbacks into it */
295 memset(&libtpms_cbs, 0x0, sizeof(libtpms_cbs));
296 memcpy(&libtpms_cbs, callbacks, max_size);
297
298 return TPM_SUCCESS;
299}
300
301static int is_base64ltr(char c)
302{
303 return ((c >= 'A' && c <= 'Z') ||
304 (c >= 'a' && c <= 'z') ||
305 (c >= '0' && c <= '9') ||
306 c == '+' ||
307 c == '/' ||
308 c == '=');
309}
310
311#ifdef USE_OPENSSL_CRYPTO_LIBRARY
312static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
313 unsigned int outputlen)
314{
315#ifndef VBOX
316 BIO *b64, *bmem;
317 unsigned char *res = NULL;
318 int n;
319
320 b64 = BIO_new(BIO_f_base64());
321 if (!b64) {
322 return NULL;
323 }
324
325 bmem = BIO_new_mem_buf(input, strlen(input));
326 if (!bmem) {
327 BIO_free(b64);
328 goto cleanup;
329 }
330 bmem = BIO_push(b64, bmem);
331 BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
332
333 res = malloc(outputlen);
334 if (!res) {
335 TPMLIB_LogError("Could not allocate %u bytes.\n", outputlen);
336 goto cleanup;
337 }
338
339 n = BIO_read(bmem, res, outputlen);
340 if (n <= 0) {
341 free(res);
342 res = NULL;
343 goto cleanup;
344 }
345
346cleanup:
347 BIO_free_all(bmem);
348
349 return res;
350#else
351 ssize_t cbDec = RTBase64DecodedSize(input, NULL /*ppszEnd*/);
352 if (cbDec > 0)
353 {
354 void *pvData = malloc(cbDec);
355 if (pvData)
356 {
357 int rc = RTBase64Decode(input, pvData, cbDec, NULL /*pcbActual*/, NULL /*ppszEnd*/);
358 if (RT_SUCCESS(rc))
359 return (uint8_t *)pvData;
360
361 free(pvData);
362 }
363 }
364
365 return NULL;
366#endif
367}
368#endif
369
370/*
371 * Base64 decode the string starting at 'start' and the last
372 * valid character may be a 'end'. The length of the decoded string
373 * is returned in *length.
374 */
375static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end,
376 size_t *length)
377{
378 unsigned char *ret = NULL;
379 char *input = NULL, *d;
380 const char *s;
381 char c;
382 unsigned int numbase64chars = 0;
383
384 if (end < start)
385 return NULL;
386
387 while (end > start && !is_base64ltr(*end))
388 end--;
389
390 end++;
391
392 input = malloc(end - start + 1);
393 if (!input) {
394 TPMLIB_LogError("Could not allocate %u bytes.\n",
395 (unsigned int)(end - start + 1));
396 return NULL;
397 }
398
399 /* copy from source string skipping '\n' and '\r' and using
400 '=' to calculate the exact length */
401 d = input;
402 s = start;
403
404 while (s < end) {
405 c = *s;
406 if (is_base64ltr(c)) {
407 *d = c;
408 d++;
409 if (c != '=') {
410 numbase64chars++;
411 }
412 } else if (c == 0) {
413 break;
414 }
415 s++;
416 }
417 *d = 0;
418
419 *length = (numbase64chars / 4) * 3;
420 switch (numbase64chars % 4) {
421 case 2:
422 case 3:
423 *length += (numbase64chars % 4) - 1;
424 break;
425 case 0:
426 break;
427 case 1:
428 fprintf(stderr,"malformed base64\n");
429 goto err_exit;
430 break;
431 }
432
433#ifdef USE_FREEBL_CRYPTO_LIBRARY
434 ret = (unsigned char *)PL_Base64Decode(input, 0, NULL);
435#endif
436
437#ifdef USE_OPENSSL_CRYPTO_LIBRARY
438 ret = TPMLIB_OpenSSL_Base64Decode(input, *length);
439#endif
440
441err_exit:
442 free(input);
443
444 return ret;
445}
446
447static unsigned char *TPMLIB_GetPlaintext(const char *stream,
448 const char *starttag,
449 const char *endtag,
450 size_t *length)
451{
452 char *start, *end;
453 unsigned char *plaintext = NULL;
454
455 start = strstr(stream, starttag);
456 if (start) {
457 start += strlen(starttag);
458 while (isspace((int)*start))
459 start++;
460 end = strstr(start, endtag);
461 if (end) {
462 plaintext = TPMLIB_Base64Decode(start, --end, length);
463 }
464 }
465 return plaintext;
466}
467
468TPM_RESULT TPMLIB_DecodeBlob(const char *buffer, enum TPMLIB_BlobType type,
469 unsigned char **result, size_t *result_len)
470{
471 TPM_RESULT res = TPM_SUCCESS;
472
473 *result = TPMLIB_GetPlaintext(buffer,
474 tags_and_indices[type].starttag,
475 tags_and_indices[type].endtag,
476 result_len);
477
478 if (*result == NULL) {
479 res = TPM_FAIL;
480 }
481
482 return res;
483}
484
485void TPMLIB_SetDebugFD(int fd)
486{
487 debug_fd = fd;
488}
489
490void TPMLIB_SetDebugLevel(unsigned level)
491{
492 debug_level = level;
493}
494
495TPM_RESULT TPMLIB_SetDebugPrefix(const char *prefix)
496{
497 free(debug_prefix);
498
499 if (prefix) {
500 debug_prefix = strdup(prefix);
501 if (!debug_prefix)
502 return TPM_FAIL;
503 } else {
504 debug_prefix = NULL;
505 }
506
507 return TPM_SUCCESS;
508}
509
510int TPMLIB_LogPrintf(const char *format, ...)
511{
512#ifndef VBOX
513 unsigned level = debug_level, i;
514 va_list args;
515 char buffer[256];
516 int n;
517
518 if (!debug_fd || !debug_level)
519 return -1;
520
521 va_start(args, format);
522 n = vsnprintf(buffer, sizeof(buffer), format, args);
523 va_end(args);
524
525 if (n < 0 || n >= (int)sizeof(buffer))
526 return -1;
527
528 level--;
529
530 i = 0;
531 while (1) {
532 if (buffer[i] == 0)
533 return -1;
534 if (buffer[i] != ' ')
535 break;
536 if (i == level)
537 return -1;
538 i++;
539 }
540
541 if (debug_prefix)
542 dprintf(debug_fd, "%s", debug_prefix);
543 dprintf(debug_fd, "%s", buffer);
544
545 return i;
546#else
547 return 0;
548#endif
549}
550
551/*
552 * TPMLIB_LogPrintfA: Printf to the logfd without indentation check
553 *
554 * @indent: how many spaces to indent; indent of ~0 forces logging
555 * with indent 0 even if not debug_level is set
556 * @format: format to use for formatting the following parameters
557 * @...: varargs
558 */
559void TPMLIB_LogPrintfA(unsigned int indent, const char *format, ...)
560{
561#ifndef VBOX
562 va_list args;
563 char spaces[20];
564 int fd;
565
566 if (indent != (unsigned int)~0) {
567 if (!debug_fd || !debug_level)
568 return;
569 fd = debug_fd;
570 } else {
571 indent = 0;
572 fd = (debug_fd >= 0) ? debug_fd : STDERR_FILENO;
573 }
574
575 if (indent) {
576 if (indent > sizeof(spaces) - 1)
577 indent = sizeof(spaces) - 1;
578 memset(spaces, ' ', indent);
579 spaces[indent] = 0;
580 dprintf(fd, "%s", spaces);
581 }
582
583 va_start(args, format);
584 vdprintf(fd, format, args);
585 va_end(args);
586#endif
587}
588
589/*
590 * TPMLIB_LogArray: Display an array of data
591 *
592 * @indent: how many spaces to indent; indent of ~0 forces logging
593 * with indent 0 even if not debug_level is set
594 * @data: the data to print
595 * @datalen: length of the data
596 */
597void TPMLIB_LogArray(unsigned int indent, const unsigned char *data,
598 size_t datalen)
599{
600 char line[80];
601 size_t i, o = 0;
602
603 for (i = 0; i < datalen; i++) {
604 snprintf(&line[o], sizeof(line) - o, "%02x ", data[i]);
605 o += 3;
606 if (o >= 16 * 3) {
607 TPMLIB_LogPrintfA(indent, "%s\n", line);
608 o = 0;
609 }
610 }
611 if (o > 0) {
612 TPMLIB_LogPrintfA(indent, "%s\n", line);
613 }
614}
615
616void ClearCachedState(enum TPMLIB_StateType st)
617{
618 free(cached_blobs[st].buffer);
619 cached_blobs[st].buffer = NULL;
620 cached_blobs[st].buflen = 0;
621}
622
623void ClearAllCachedState(void)
624{
625 ClearCachedState(TPMLIB_STATE_VOLATILE);
626 ClearCachedState(TPMLIB_STATE_PERMANENT);
627 ClearCachedState(TPMLIB_STATE_SAVE_STATE);
628}
629
630/*
631 * Set buffer for cached state; we allow setting an empty cached state
632 * by the caller passing a NULL pointer for the buffer.
633 */
634void SetCachedState(enum TPMLIB_StateType st,
635 unsigned char *buffer, uint32_t buflen)
636{
637 free(cached_blobs[st].buffer);
638 cached_blobs[st].buffer = buffer;
639 cached_blobs[st].buflen = buffer ? buflen : BUFLEN_EMPTY_BUFFER;
640}
641
642void GetCachedState(enum TPMLIB_StateType st,
643 unsigned char **buffer, uint32_t *buflen,
644 bool *is_empty_buffer)
645{
646 /* caller owns blob now */
647 *buffer = cached_blobs[st].buffer;
648 *buflen = cached_blobs[st].buflen;
649 *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
650 cached_blobs[st].buffer = NULL;
651 cached_blobs[st].buflen = 0;
652}
653
654bool HasCachedState(enum TPMLIB_StateType st)
655{
656 return (cached_blobs[st].buffer != NULL || cached_blobs[st].buflen != 0);
657}
658
659TPM_RESULT CopyCachedState(enum TPMLIB_StateType st,
660 unsigned char **buffer, uint32_t *buflen,
661 bool *is_empty_buffer)
662{
663 TPM_RESULT ret = TPM_SUCCESS;
664
665 /* buflen may indicate an empty buffer */
666 *buflen = cached_blobs[st].buflen;
667 *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
668
669 if (cached_blobs[st].buffer) {
670 *buffer = malloc(*buflen);
671 if (!*buffer) {
672 TPMLIB_LogError("Could not allocate %u bytes.\n", *buflen);
673 ret = TPM_SIZE;
674 } else {
675 memcpy(*buffer, cached_blobs[st].buffer, *buflen);
676 }
677 } else {
678 *buffer = NULL;
679 }
680
681 return ret;
682}
683
684const char *TPMLIB_StateTypeToName(enum TPMLIB_StateType st)
685{
686 switch (st) {
687 case TPMLIB_STATE_PERMANENT:
688 return TPM_PERMANENT_ALL_NAME;
689 case TPMLIB_STATE_VOLATILE:
690 return TPM_VOLATILESTATE_NAME;
691 case TPMLIB_STATE_SAVE_STATE:
692 return TPM_SAVESTATE_NAME;
693 }
694 return NULL;
695}
696
697enum TPMLIB_StateType TPMLIB_NameToStateType(const char *name)
698{
699 if (!name)
700 return 0;
701 if (!strcmp(name, TPM_PERMANENT_ALL_NAME))
702 return TPMLIB_STATE_PERMANENT;
703 if (!strcmp(name, TPM_VOLATILESTATE_NAME))
704 return TPMLIB_STATE_VOLATILE;
705 if (!strcmp(name, TPM_SAVESTATE_NAME))
706 return TPMLIB_STATE_SAVE_STATE;
707 return 0;
708}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use