]> git.proxmox.com Git - libtpms.git/blob - src/tpm_library.c
tpm2: Clear the cached states when a different TPM version is chosen
[libtpms.git] / src / tpm_library.c
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 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stdarg.h>
47 #include <ctype.h>
48 #include <unistd.h>
49 #include <stdbool.h>
50
51 #ifdef USE_FREEBL_CRYPTO_LIBRARY
52 # include <plbase64.h>
53 #endif
54
55 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
56 # include <openssl/bio.h>
57 # include <openssl/evp.h>
58 #endif
59
60 #include "tpm12/tpm_debug.h"
61 #include "tpm_error.h"
62 #include "tpm_library.h"
63 #include "tpm_library_intern.h"
64 #include "tpm_memory.h"
65 #include "tpm_nvfilename.h"
66
67 static const struct tags_and_indices {
68 const char *starttag;
69 const char *endtag;
70 } tags_and_indices[] = {
71 [TPMLIB_BLOB_TYPE_INITSTATE] =
72 {
73 .starttag = TPMLIB_INITSTATE_START_TAG,
74 .endtag = TPMLIB_INITSTATE_END_TAG,
75 },
76 };
77
78 static const struct tpm_interface *const tpm_iface[] = {
79 &TPM12Interface,
80 #if WITH_TPM2
81 &TPM2Interface,
82 #endif
83 NULL,
84 };
85
86 static int debug_fd = -1;
87 static unsigned debug_level = 0;
88 static char *debug_prefix = NULL;
89
90 static struct sized_buffer cached_blobs[TPMLIB_STATE_SAVE_STATE + 1];
91
92 static int tpmvers_choice = 0; /* default is TPM1.2 */
93 static TPM_BOOL tpmvers_locked = FALSE;
94
95 uint32_t TPMLIB_GetVersion(void)
96 {
97 return TPM_LIBRARY_VERSION;
98 }
99
100 TPM_RESULT TPMLIB_ChooseTPMVersion(TPMLIB_TPMVersion ver)
101 {
102 TPM_RESULT ret = TPM_SUCCESS;
103
104 /* TPMLIB_Terminate will reset previous choice */
105 if (tpmvers_locked)
106 return TPM_FAIL;
107
108 switch (ver) {
109 case TPMLIB_TPM_VERSION_1_2:
110 if (tpmvers_choice != 0)
111 ClearAllCachedState();
112
113 tpmvers_choice = 0; // entry 0 in tpm_iface
114 break;
115 case TPMLIB_TPM_VERSION_2:
116 #if WITH_TPM2
117 if (tpmvers_choice != 1)
118 ClearAllCachedState();
119
120 tpmvers_choice = 1; // entry 1 in tpm_iface
121 break;
122 #endif
123 default:
124 ret = TPM_FAIL;
125 }
126
127 return ret;
128 }
129
130 TPM_RESULT TPMLIB_MainInit(void)
131 {
132 tpmvers_locked = TRUE;
133
134 return tpm_iface[tpmvers_choice]->MainInit();
135 }
136
137 void TPMLIB_Terminate(void)
138 {
139 tpm_iface[tpmvers_choice]->Terminate();
140
141 tpmvers_locked = FALSE;
142 }
143
144 /*
145 * Send a command to the TPM. The command buffer must hold a well formatted
146 * TPM command and the command_size indicate the size of the command.
147 * The respbuffer parameter may be provided by the user and grow if
148 * the respbufsize size indicator is determined to be too small for the
149 * response. In that case a new buffer will be allocated and the size of that
150 * buffer returned in the respbufsize parameter. resp_size describes the
151 * size of the actual response within the respbuffer.
152 */
153 TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size,
154 uint32_t *respbufsize,
155 unsigned char *command, uint32_t command_size)
156 {
157 return tpm_iface[tpmvers_choice]->Process(respbuffer,
158 resp_size, respbufsize,
159 command, command_size);
160 }
161
162 /*
163 * Get the volatile state from the TPM. This function will return the
164 * buffer and the length of the buffer to the caller in case everything
165 * went alright.
166 */
167 TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer,
168 uint32_t *buflen)
169 {
170 return tpm_iface[tpmvers_choice]->VolatileAllStore(buffer, buflen);
171 }
172
173 /*
174 * Have the TPM cancel an ongoing command
175 */
176 TPM_RESULT TPMLIB_CancelCommand(void)
177 {
178 return tpm_iface[tpmvers_choice]->CancelCommand();
179 }
180
181 /*
182 * Get a property of the TPM. The functions currently only
183 * return compile-time #defines but this may change in future
184 * versions where we may return parameters with which the TPM
185 * was created (rather than compiled).
186 */
187 TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop,
188 int *result)
189 {
190 switch (prop) {
191 case TPMPROP_TPM_BUFFER_MAX:
192 *result = TPM_BUFFER_MAX;
193 break;
194
195 default:
196 return tpm_iface[tpmvers_choice]->GetTPMProperty(prop, result);
197 }
198
199 return TPM_SUCCESS;
200 }
201
202 char *TPMLIB_GetInfo(enum TPMLIB_InfoFlags flags)
203 {
204 return tpm_iface[tpmvers_choice]->GetInfo(flags);
205 }
206
207 TPM_RESULT TPMLIB_SetState(enum TPMLIB_StateType st,
208 const unsigned char *buffer, uint32_t buflen)
209 {
210 return tpm_iface[0]->SetState(st, buffer, buflen);
211 }
212
213 TPM_RESULT TPMLIB_GetState(enum TPMLIB_StateType st,
214 unsigned char **buffer, uint32_t *buflen)
215 {
216 return tpm_iface[0]->GetState(st, buffer, buflen);
217 }
218
219 TPM_RESULT TPM_IO_Hash_Start(void)
220 {
221 return tpm_iface[tpmvers_choice]->HashStart();
222 }
223
224 TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, uint32_t data_length)
225 {
226 return tpm_iface[tpmvers_choice]->HashData(data, data_length);
227 }
228
229 TPM_RESULT TPM_IO_Hash_End(void)
230 {
231 return tpm_iface[tpmvers_choice]->HashEnd();
232 }
233
234 TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished)
235 {
236 return tpm_iface[tpmvers_choice]->TpmEstablishedGet(tpmEstablished);
237 }
238
239 TPM_RESULT TPM_IO_TpmEstablished_Reset(void)
240 {
241 return tpm_iface[tpmvers_choice]->TpmEstablishedReset();
242 }
243
244 uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size,
245 uint32_t *min_size,
246 uint32_t *max_size)
247 {
248 return tpm_iface[tpmvers_choice]->SetBufferSize(wanted_size,
249 min_size,
250 max_size);
251 }
252
253 TPM_RESULT TPMLIB_ValidateState(enum TPMLIB_StateType st,
254 unsigned int flags)
255 {
256 return tpm_iface[tpmvers_choice]->ValidateState(st, flags);
257 }
258
259 static struct libtpms_callbacks libtpms_cbs;
260
261 struct libtpms_callbacks *TPMLIB_GetCallbacks(void)
262 {
263 return &libtpms_cbs;
264 }
265
266 TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *callbacks)
267 {
268 int max_size = sizeof(struct libtpms_callbacks);
269
270 /* restrict the size of the structure to what we know currently
271 future versions may know more callbacks */
272 if (callbacks->sizeOfStruct < max_size)
273 max_size = callbacks->sizeOfStruct;
274
275 /* clear the internal callback structure and copy the user provided
276 callbacks into it */
277 memset(&libtpms_cbs, 0x0, sizeof(libtpms_cbs));
278 memcpy(&libtpms_cbs, callbacks, max_size);
279
280 return TPM_SUCCESS;
281 }
282
283 static int is_base64ltr(char c)
284 {
285 return ((c >= 'A' && c <= 'Z') ||
286 (c >= 'a' && c <= 'z') ||
287 (c >= '0' && c <= '9') ||
288 c == '+' ||
289 c == '/' ||
290 c == '=');
291 }
292
293 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
294 static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
295 unsigned int outputlen)
296 {
297 BIO *b64, *bmem;
298 unsigned char *res = NULL;
299 int n;
300
301 b64 = BIO_new(BIO_f_base64());
302 if (!b64) {
303 return NULL;
304 }
305
306 bmem = BIO_new_mem_buf(input, strlen(input));
307 if (!bmem) {
308 BIO_free(b64);
309 goto cleanup;
310 }
311 bmem = BIO_push(b64, bmem);
312 BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
313
314 res = malloc(outputlen);
315 if (!res) {
316 TPMLIB_LogError("Could not allocate %u bytes.\n", outputlen);
317 goto cleanup;
318 }
319
320 n = BIO_read(bmem, res, outputlen);
321 if (n <= 0) {
322 free(res);
323 res = NULL;
324 goto cleanup;
325 }
326
327 cleanup:
328 BIO_free_all(bmem);
329
330 return res;
331 }
332 #endif
333
334 /*
335 * Base64 decode the string starting at 'start' and the last
336 * valid character may be a 'end'. The length of the decoded string
337 * is returned in *length.
338 */
339 static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end,
340 size_t *length)
341 {
342 unsigned char *ret = NULL;
343 char *input = NULL, *d;
344 const char *s;
345 char c;
346 unsigned int numbase64chars = 0;
347
348 if (end < start)
349 return NULL;
350
351 while (end > start && !is_base64ltr(*end))
352 end--;
353
354 end++;
355
356 input = malloc(end - start + 1);
357 if (!input) {
358 TPMLIB_LogError("Could not allocate %u bytes.\n",
359 (unsigned int)(end - start + 1));
360 return NULL;
361 }
362
363 /* copy from source string skipping '\n' and '\r' and using
364 '=' to calculate the exact length */
365 d = input;
366 s = start;
367
368 while (s < end) {
369 c = *s;
370 if (is_base64ltr(c)) {
371 *d = c;
372 d++;
373 if (c != '=') {
374 numbase64chars++;
375 }
376 } else if (c == 0) {
377 break;
378 }
379 s++;
380 }
381 *d = 0;
382
383 *length = (numbase64chars / 4) * 3;
384 switch (numbase64chars % 4) {
385 case 2:
386 case 3:
387 *length += (numbase64chars % 4) - 1;
388 break;
389 case 0:
390 break;
391 case 1:
392 fprintf(stderr,"malformed base64\n");
393 goto err_exit;
394 break;
395 }
396
397 #ifdef USE_FREEBL_CRYPTO_LIBRARY
398 ret = (unsigned char *)PL_Base64Decode(input, 0, NULL);
399 #endif
400
401 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
402 ret = TPMLIB_OpenSSL_Base64Decode(input, *length);
403 #endif
404
405 err_exit:
406 free(input);
407
408 return ret;
409 }
410
411 static unsigned char *TPMLIB_GetPlaintext(const char *stream,
412 const char *starttag,
413 const char *endtag,
414 size_t *length)
415 {
416 char *start, *end;
417 unsigned char *plaintext = NULL;
418
419 start = strstr(stream, starttag);
420 if (start) {
421 start += strlen(starttag);
422 while (isspace((int)*start))
423 start++;
424 end = strstr(start, endtag);
425 if (end) {
426 plaintext = TPMLIB_Base64Decode(start, --end, length);
427 }
428 }
429 return plaintext;
430 }
431
432 TPM_RESULT TPMLIB_DecodeBlob(const char *buffer, enum TPMLIB_BlobType type,
433 unsigned char **result, size_t *result_len)
434 {
435 TPM_RESULT res = TPM_SUCCESS;
436
437 *result = TPMLIB_GetPlaintext(buffer,
438 tags_and_indices[type].starttag,
439 tags_and_indices[type].endtag,
440 result_len);
441
442 if (*result == NULL) {
443 res = TPM_FAIL;
444 }
445
446 return res;
447 }
448
449 void TPMLIB_SetDebugFD(int fd)
450 {
451 debug_fd = fd;
452 }
453
454 void TPMLIB_SetDebugLevel(unsigned level)
455 {
456 debug_level = level;
457 }
458
459 TPM_RESULT TPMLIB_SetDebugPrefix(const char *prefix)
460 {
461 free(debug_prefix);
462
463 if (prefix) {
464 debug_prefix = strdup(prefix);
465 if (!debug_prefix)
466 return TPM_FAIL;
467 } else {
468 debug_prefix = NULL;
469 }
470
471 return TPM_SUCCESS;
472 }
473
474 int TPMLIB_LogPrintf(const char *format, ...)
475 {
476 unsigned level = debug_level, i;
477 va_list args;
478 char buffer[256];
479 int n;
480
481 if (!debug_fd || !debug_level)
482 return -1;
483
484 va_start(args, format);
485 n = vsnprintf(buffer, sizeof(buffer), format, args);
486 va_end(args);
487
488 if (n < 0 || n >= (int)sizeof(buffer))
489 return -1;
490
491 level--;
492
493 i = 0;
494 while (1) {
495 if (buffer[i] == 0)
496 return -1;
497 if (buffer[i] != ' ')
498 break;
499 if (i == level)
500 return -1;
501 i++;
502 }
503
504 if (debug_prefix)
505 dprintf(debug_fd, "%s", debug_prefix);
506 dprintf(debug_fd, "%s", buffer);
507
508 return i;
509 }
510
511 /*
512 * TPMLIB_LogPrintfA: Printf to the logfd without indentation check
513 *
514 * @indent: how many spaces to indent; indent of ~0 forces logging
515 * with indent 0 even if not debug_level is set
516 * @format: format to use for formatting the following parameters
517 * @...: varargs
518 */
519 void TPMLIB_LogPrintfA(unsigned int indent, const char *format, ...)
520 {
521 va_list args;
522 char spaces[20];
523 int fd;
524
525 if (indent != (unsigned int)~0) {
526 if (!debug_fd || !debug_level)
527 return;
528 fd = debug_fd;
529 } else {
530 indent = 0;
531 fd = (debug_fd >= 0) ? debug_fd : STDERR_FILENO;
532 }
533
534 if (indent) {
535 if (indent > sizeof(spaces) - 1)
536 indent = sizeof(spaces) - 1;
537 memset(spaces, ' ', indent);
538 spaces[indent] = 0;
539 dprintf(fd, "%s", spaces);
540 }
541
542 va_start(args, format);
543 vdprintf(fd, format, args);
544 va_end(args);
545 }
546
547 void ClearCachedState(enum TPMLIB_StateType st)
548 {
549 free(cached_blobs[st].buffer);
550 cached_blobs[st].buffer = NULL;
551 cached_blobs[st].buflen = 0;
552 }
553
554 void ClearAllCachedState(void)
555 {
556 ClearCachedState(TPMLIB_STATE_VOLATILE);
557 ClearCachedState(TPMLIB_STATE_PERMANENT);
558 ClearCachedState(TPMLIB_STATE_SAVE_STATE);
559 }
560
561 /*
562 * Set buffer for cached state; we allow setting an empty cached state
563 * by the caller passing a NULL pointer for the buffer.
564 */
565 void SetCachedState(enum TPMLIB_StateType st,
566 unsigned char *buffer, uint32_t buflen)
567 {
568 free(cached_blobs[st].buffer);
569 cached_blobs[st].buffer = buffer;
570 cached_blobs[st].buflen = buffer ? buflen : BUFLEN_EMPTY_BUFFER;
571 }
572
573 void GetCachedState(enum TPMLIB_StateType st,
574 unsigned char **buffer, uint32_t *buflen,
575 bool *is_empty_buffer)
576 {
577 /* caller owns blob now */
578 *buffer = cached_blobs[st].buffer;
579 *buflen = cached_blobs[st].buflen;
580 *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
581 cached_blobs[st].buffer = NULL;
582 cached_blobs[st].buflen = 0;
583 }
584
585 bool HasCachedState(enum TPMLIB_StateType st)
586 {
587 return (cached_blobs[st].buffer != NULL || cached_blobs[st].buflen != 0);
588 }
589
590 TPM_RESULT CopyCachedState(enum TPMLIB_StateType st,
591 unsigned char **buffer, uint32_t *buflen,
592 bool *is_empty_buffer)
593 {
594 TPM_RESULT ret = TPM_SUCCESS;
595
596 /* buflen may indicate an empty buffer */
597 *buflen = cached_blobs[st].buflen;
598 *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
599
600 if (cached_blobs[st].buffer) {
601 *buffer = malloc(*buflen);
602 if (!*buffer) {
603 TPMLIB_LogError("Could not allocate %u bytes.\n", *buflen);
604 ret = TPM_SIZE;
605 } else {
606 memcpy(*buffer, cached_blobs[st].buffer, *buflen);
607 }
608 } else {
609 *buffer = NULL;
610 }
611
612 return ret;
613 }
614
615 const char *TPMLIB_StateTypeToName(enum TPMLIB_StateType st)
616 {
617 switch (st) {
618 case TPMLIB_STATE_PERMANENT:
619 return TPM_PERMANENT_ALL_NAME;
620 case TPMLIB_STATE_VOLATILE:
621 return TPM_VOLATILESTATE_NAME;
622 case TPMLIB_STATE_SAVE_STATE:
623 return TPM_SAVESTATE_NAME;
624 }
625 return NULL;
626 }
627
628 enum TPMLIB_StateType TPMLIB_NameToStateType(const char *name)
629 {
630 if (!name)
631 return 0;
632 if (!strcmp(name, TPM_PERMANENT_ALL_NAME))
633 return TPMLIB_STATE_PERMANENT;
634 if (!strcmp(name, TPM_VOLATILESTATE_NAME))
635 return TPMLIB_STATE_VOLATILE;
636 if (!strcmp(name, TPM_SAVESTATE_NAME))
637 return TPMLIB_STATE_SAVE_STATE;
638 return 0;
639 }