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