1 /********************************************************************************/
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 $ */
8 /* (c) Copyright IBM Corporation 2010. */
10 /* All rights reserved. */
12 /* Redistribution and use in source and binary forms, with or without */
13 /* modification, are permitted provided that the following conditions are */
16 /* Redistributions of source code must retain the above copyright notice, */
17 /* this list of conditions and the following disclaimer. */
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. */
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. */
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 /********************************************************************************/
44 #if defined __FreeBSD__
45 # define _WITH_DPRINTF
54 #ifdef USE_FREEBL_CRYPTO_LIBRARY
55 # include <plbase64.h>
58 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
59 # include <openssl/bio.h>
60 # include <openssl/evp.h>
63 #include "tpm12/tpm_debug.h"
64 #include "tpm_error.h"
65 #include "tpm_library.h"
66 #include "tpm_library_intern.h"
67 #include "tpm_nvfilename.h"
69 static const struct tags_and_indices
{
72 } tags_and_indices
[] = {
73 [TPMLIB_BLOB_TYPE_INITSTATE
] =
75 .starttag
= TPMLIB_INITSTATE_START_TAG
,
76 .endtag
= TPMLIB_INITSTATE_END_TAG
,
80 static const struct tpm_interface
*const tpm_iface
[] = {
88 static int debug_fd
= -1;
89 static unsigned debug_level
= 0;
90 static char *debug_prefix
= NULL
;
92 static struct sized_buffer cached_blobs
[TPMLIB_STATE_SAVE_STATE
+ 1];
94 static int tpmvers_choice
= 0; /* default is TPM1.2 */
95 static TPM_BOOL tpmvers_locked
= FALSE
;
97 uint32_t TPMLIB_GetVersion(void)
99 return TPM_LIBRARY_VERSION
;
102 TPM_RESULT
TPMLIB_ChooseTPMVersion(TPMLIB_TPMVersion ver
)
104 TPM_RESULT ret
= TPM_SUCCESS
;
106 /* TPMLIB_Terminate will reset previous choice */
111 case TPMLIB_TPM_VERSION_1_2
:
112 if (tpmvers_choice
!= 0)
113 ClearAllCachedState();
115 tpmvers_choice
= 0; // entry 0 in tpm_iface
117 case TPMLIB_TPM_VERSION_2
:
119 if (tpmvers_choice
!= 1)
120 ClearAllCachedState();
122 tpmvers_choice
= 1; // entry 1 in tpm_iface
132 TPM_RESULT
TPMLIB_MainInit(void)
134 tpmvers_locked
= TRUE
;
136 return tpm_iface
[tpmvers_choice
]->MainInit();
139 void TPMLIB_Terminate(void)
141 tpm_iface
[tpmvers_choice
]->Terminate();
143 tpmvers_locked
= FALSE
;
147 * Send a command to the TPM. The command buffer must hold a well formatted
148 * TPM command and the command_size indicate the size of the command.
149 * The respbuffer parameter may be provided by the user and grow if
150 * the respbufsize size indicator is determined to be too small for the
151 * response. In that case a new buffer will be allocated and the size of that
152 * buffer returned in the respbufsize parameter. resp_size describes the
153 * size of the actual response within the respbuffer.
155 TPM_RESULT
TPMLIB_Process(unsigned char **respbuffer
, uint32_t *resp_size
,
156 uint32_t *respbufsize
,
157 unsigned char *command
, uint32_t command_size
)
159 return tpm_iface
[tpmvers_choice
]->Process(respbuffer
,
160 resp_size
, respbufsize
,
161 command
, command_size
);
165 * Get the volatile state from the TPM. This function will return the
166 * buffer and the length of the buffer to the caller in case everything
169 TPM_RESULT
TPMLIB_VolatileAll_Store(unsigned char **buffer
,
172 return tpm_iface
[tpmvers_choice
]->VolatileAllStore(buffer
, buflen
);
176 * Have the TPM cancel an ongoing command
178 TPM_RESULT
TPMLIB_CancelCommand(void)
180 return tpm_iface
[tpmvers_choice
]->CancelCommand();
184 * Get a property of the TPM. The functions currently only
185 * return compile-time #defines but this may change in future
186 * versions where we may return parameters with which the TPM
187 * was created (rather than compiled).
189 TPM_RESULT
TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop
,
193 case TPMPROP_TPM_BUFFER_MAX
:
194 *result
= TPM_BUFFER_MAX
;
198 return tpm_iface
[tpmvers_choice
]->GetTPMProperty(prop
, result
);
204 char *TPMLIB_GetInfo(enum TPMLIB_InfoFlags flags
)
206 return tpm_iface
[tpmvers_choice
]->GetInfo(flags
);
209 TPM_RESULT
TPMLIB_SetState(enum TPMLIB_StateType st
,
210 const unsigned char *buffer
, uint32_t buflen
)
212 return tpm_iface
[tpmvers_choice
]->SetState(st
, buffer
, buflen
);
215 TPM_RESULT
TPMLIB_GetState(enum TPMLIB_StateType st
,
216 unsigned char **buffer
, uint32_t *buflen
)
218 return tpm_iface
[tpmvers_choice
]->GetState(st
, buffer
, buflen
);
221 TPM_RESULT
TPM_IO_Hash_Start(void)
223 return tpm_iface
[tpmvers_choice
]->HashStart();
226 TPM_RESULT
TPM_IO_Hash_Data(const unsigned char *data
, uint32_t data_length
)
228 return tpm_iface
[tpmvers_choice
]->HashData(data
, data_length
);
231 TPM_RESULT
TPM_IO_Hash_End(void)
233 return tpm_iface
[tpmvers_choice
]->HashEnd();
236 TPM_RESULT
TPM_IO_TpmEstablished_Get(TPM_BOOL
*tpmEstablished
)
238 return tpm_iface
[tpmvers_choice
]->TpmEstablishedGet(tpmEstablished
);
241 TPM_RESULT
TPM_IO_TpmEstablished_Reset(void)
243 return tpm_iface
[tpmvers_choice
]->TpmEstablishedReset();
246 uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size
,
250 return tpm_iface
[tpmvers_choice
]->SetBufferSize(wanted_size
,
255 TPM_RESULT
TPMLIB_ValidateState(enum TPMLIB_StateType st
,
258 return tpm_iface
[tpmvers_choice
]->ValidateState(st
, flags
);
261 static struct libtpms_callbacks libtpms_cbs
;
263 struct libtpms_callbacks
*TPMLIB_GetCallbacks(void)
268 TPM_RESULT
TPMLIB_RegisterCallbacks(struct libtpms_callbacks
*callbacks
)
270 int max_size
= sizeof(struct libtpms_callbacks
);
272 /* restrict the size of the structure to what we know currently
273 future versions may know more callbacks */
274 if (callbacks
->sizeOfStruct
< max_size
)
275 max_size
= callbacks
->sizeOfStruct
;
277 /* clear the internal callback structure and copy the user provided
279 memset(&libtpms_cbs
, 0x0, sizeof(libtpms_cbs
));
280 memcpy(&libtpms_cbs
, callbacks
, max_size
);
285 static int is_base64ltr(char c
)
287 return ((c
>= 'A' && c
<= 'Z') ||
288 (c
>= 'a' && c
<= 'z') ||
289 (c
>= '0' && c
<= '9') ||
295 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
296 static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input
,
297 unsigned int outputlen
)
300 unsigned char *res
= NULL
;
303 b64
= BIO_new(BIO_f_base64());
308 bmem
= BIO_new_mem_buf(input
, strlen(input
));
313 bmem
= BIO_push(b64
, bmem
);
314 BIO_set_flags(bmem
, BIO_FLAGS_BASE64_NO_NL
);
316 res
= malloc(outputlen
);
318 TPMLIB_LogError("Could not allocate %u bytes.\n", outputlen
);
322 n
= BIO_read(bmem
, res
, outputlen
);
337 * Base64 decode the string starting at 'start' and the last
338 * valid character may be a 'end'. The length of the decoded string
339 * is returned in *length.
341 static unsigned char *TPMLIB_Base64Decode(const char *start
, const char *end
,
344 unsigned char *ret
= NULL
;
345 char *input
= NULL
, *d
;
348 unsigned int numbase64chars
= 0;
353 while (end
> start
&& !is_base64ltr(*end
))
358 input
= malloc(end
- start
+ 1);
360 TPMLIB_LogError("Could not allocate %u bytes.\n",
361 (unsigned int)(end
- start
+ 1));
365 /* copy from source string skipping '\n' and '\r' and using
366 '=' to calculate the exact length */
372 if (is_base64ltr(c
)) {
385 *length
= (numbase64chars
/ 4) * 3;
386 switch (numbase64chars
% 4) {
389 *length
+= (numbase64chars
% 4) - 1;
394 fprintf(stderr
,"malformed base64\n");
399 #ifdef USE_FREEBL_CRYPTO_LIBRARY
400 ret
= (unsigned char *)PL_Base64Decode(input
, 0, NULL
);
403 #ifdef USE_OPENSSL_CRYPTO_LIBRARY
404 ret
= TPMLIB_OpenSSL_Base64Decode(input
, *length
);
413 static unsigned char *TPMLIB_GetPlaintext(const char *stream
,
414 const char *starttag
,
419 unsigned char *plaintext
= NULL
;
421 start
= strstr(stream
, starttag
);
423 start
+= strlen(starttag
);
424 while (isspace((int)*start
))
426 end
= strstr(start
, endtag
);
428 plaintext
= TPMLIB_Base64Decode(start
, --end
, length
);
434 TPM_RESULT
TPMLIB_DecodeBlob(const char *buffer
, enum TPMLIB_BlobType type
,
435 unsigned char **result
, size_t *result_len
)
437 TPM_RESULT res
= TPM_SUCCESS
;
439 *result
= TPMLIB_GetPlaintext(buffer
,
440 tags_and_indices
[type
].starttag
,
441 tags_and_indices
[type
].endtag
,
444 if (*result
== NULL
) {
451 void TPMLIB_SetDebugFD(int fd
)
456 void TPMLIB_SetDebugLevel(unsigned level
)
461 TPM_RESULT
TPMLIB_SetDebugPrefix(const char *prefix
)
466 debug_prefix
= strdup(prefix
);
476 int TPMLIB_LogPrintf(const char *format
, ...)
478 unsigned level
= debug_level
, i
;
483 if (!debug_fd
|| !debug_level
)
486 va_start(args
, format
);
487 n
= vsnprintf(buffer
, sizeof(buffer
), format
, args
);
490 if (n
< 0 || n
>= (int)sizeof(buffer
))
499 if (buffer
[i
] != ' ')
507 dprintf(debug_fd
, "%s", debug_prefix
);
508 dprintf(debug_fd
, "%s", buffer
);
514 * TPMLIB_LogPrintfA: Printf to the logfd without indentation check
516 * @indent: how many spaces to indent; indent of ~0 forces logging
517 * with indent 0 even if not debug_level is set
518 * @format: format to use for formatting the following parameters
521 void TPMLIB_LogPrintfA(unsigned int indent
, const char *format
, ...)
527 if (indent
!= (unsigned int)~0) {
528 if (!debug_fd
|| !debug_level
)
533 fd
= (debug_fd
>= 0) ? debug_fd
: STDERR_FILENO
;
537 if (indent
> sizeof(spaces
) - 1)
538 indent
= sizeof(spaces
) - 1;
539 memset(spaces
, ' ', indent
);
541 dprintf(fd
, "%s", spaces
);
544 va_start(args
, format
);
545 vdprintf(fd
, format
, args
);
549 void ClearCachedState(enum TPMLIB_StateType st
)
551 free(cached_blobs
[st
].buffer
);
552 cached_blobs
[st
].buffer
= NULL
;
553 cached_blobs
[st
].buflen
= 0;
556 void ClearAllCachedState(void)
558 ClearCachedState(TPMLIB_STATE_VOLATILE
);
559 ClearCachedState(TPMLIB_STATE_PERMANENT
);
560 ClearCachedState(TPMLIB_STATE_SAVE_STATE
);
564 * Set buffer for cached state; we allow setting an empty cached state
565 * by the caller passing a NULL pointer for the buffer.
567 void SetCachedState(enum TPMLIB_StateType st
,
568 unsigned char *buffer
, uint32_t buflen
)
570 free(cached_blobs
[st
].buffer
);
571 cached_blobs
[st
].buffer
= buffer
;
572 cached_blobs
[st
].buflen
= buffer
? buflen
: BUFLEN_EMPTY_BUFFER
;
575 void GetCachedState(enum TPMLIB_StateType st
,
576 unsigned char **buffer
, uint32_t *buflen
,
577 bool *is_empty_buffer
)
579 /* caller owns blob now */
580 *buffer
= cached_blobs
[st
].buffer
;
581 *buflen
= cached_blobs
[st
].buflen
;
582 *is_empty_buffer
= (*buflen
== BUFLEN_EMPTY_BUFFER
);
583 cached_blobs
[st
].buffer
= NULL
;
584 cached_blobs
[st
].buflen
= 0;
587 bool HasCachedState(enum TPMLIB_StateType st
)
589 return (cached_blobs
[st
].buffer
!= NULL
|| cached_blobs
[st
].buflen
!= 0);
592 TPM_RESULT
CopyCachedState(enum TPMLIB_StateType st
,
593 unsigned char **buffer
, uint32_t *buflen
,
594 bool *is_empty_buffer
)
596 TPM_RESULT ret
= TPM_SUCCESS
;
598 /* buflen may indicate an empty buffer */
599 *buflen
= cached_blobs
[st
].buflen
;
600 *is_empty_buffer
= (*buflen
== BUFLEN_EMPTY_BUFFER
);
602 if (cached_blobs
[st
].buffer
) {
603 *buffer
= malloc(*buflen
);
605 TPMLIB_LogError("Could not allocate %u bytes.\n", *buflen
);
608 memcpy(*buffer
, cached_blobs
[st
].buffer
, *buflen
);
617 const char *TPMLIB_StateTypeToName(enum TPMLIB_StateType st
)
620 case TPMLIB_STATE_PERMANENT
:
621 return TPM_PERMANENT_ALL_NAME
;
622 case TPMLIB_STATE_VOLATILE
:
623 return TPM_VOLATILESTATE_NAME
;
624 case TPMLIB_STATE_SAVE_STATE
:
625 return TPM_SAVESTATE_NAME
;
630 enum TPMLIB_StateType
TPMLIB_NameToStateType(const char *name
)
634 if (!strcmp(name
, TPM_PERMANENT_ALL_NAME
))
635 return TPMLIB_STATE_PERMANENT
;
636 if (!strcmp(name
, TPM_VOLATILESTATE_NAME
))
637 return TPMLIB_STATE_VOLATILE
;
638 if (!strcmp(name
, TPM_SAVESTATE_NAME
))
639 return TPMLIB_STATE_SAVE_STATE
;