#include <assert.h>
#include <string.h>
+#if defined __FreeBSD__
+# define _WITH_DPRINTF
+#endif
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <ctype.h>
+#include <unistd.h>
+#include <stdbool.h>
#ifdef USE_FREEBL_CRYPTO_LIBRARY
# include <plbase64.h>
# include <openssl/evp.h>
#endif
-#include "tpm12/tpm_debug.h"
+#include "tpm_debug.h"
#include "tpm_error.h"
#include "tpm_library.h"
#include "tpm_library_intern.h"
-#include "tpm_memory.h"
+#include "tpm_nvfilename.h"
+#include "tpm_tis.h"
static const struct tags_and_indices {
const char *starttag;
static const struct tpm_interface *const tpm_iface[] = {
&TPM12Interface,
+#if WITH_TPM2
+ &TPM2Interface,
+#endif
+ NULL,
};
static int debug_fd = -1;
static unsigned debug_level = 0;
static char *debug_prefix = NULL;
+static struct sized_buffer cached_blobs[TPMLIB_STATE_SAVE_STATE + 1];
+
+static int tpmvers_choice = 0; /* default is TPM1.2 */
+static TPM_BOOL tpmvers_locked = FALSE;
+
uint32_t TPMLIB_GetVersion(void)
{
return TPM_LIBRARY_VERSION;
}
+TPM_RESULT TPMLIB_ChooseTPMVersion(TPMLIB_TPMVersion ver)
+{
+ TPM_RESULT ret = TPM_SUCCESS;
+
+ /* TPMLIB_Terminate will reset previous choice */
+ if (tpmvers_locked)
+ return TPM_FAIL;
+
+ switch (ver) {
+ case TPMLIB_TPM_VERSION_1_2:
+ if (tpmvers_choice != 0)
+ ClearAllCachedState();
+
+ tpmvers_choice = 0; // entry 0 in tpm_iface
+ break;
+ case TPMLIB_TPM_VERSION_2:
+#if WITH_TPM2
+ if (tpmvers_choice != 1)
+ ClearAllCachedState();
+
+ tpmvers_choice = 1; // entry 1 in tpm_iface
+ break;
+#endif
+ default:
+ ret = TPM_FAIL;
+ }
+
+ return ret;
+}
+
TPM_RESULT TPMLIB_MainInit(void)
{
- return tpm_iface[0]->MainInit();
+ tpmvers_locked = TRUE;
+
+ return tpm_iface[tpmvers_choice]->MainInit();
}
void TPMLIB_Terminate(void)
{
- tpm_iface[0]->Terminate();
+ tpm_iface[tpmvers_choice]->Terminate();
+
+ tpmvers_locked = FALSE;
}
/*
uint32_t *respbufsize,
unsigned char *command, uint32_t command_size)
{
- return tpm_iface[0]->Process(respbuffer, resp_size, respbufsize,
+ return tpm_iface[tpmvers_choice]->Process(respbuffer,
+ resp_size, respbufsize,
command, command_size);
}
TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer,
uint32_t *buflen)
{
- return tpm_iface[0]->VolatileAllStore(buffer, buflen);
+ return tpm_iface[tpmvers_choice]->VolatileAllStore(buffer, buflen);
+}
+
+/*
+ * Have the TPM cancel an ongoing command
+ */
+TPM_RESULT TPMLIB_CancelCommand(void)
+{
+ return tpm_iface[tpmvers_choice]->CancelCommand();
}
/*
break;
default:
- return tpm_iface[0]->GetTPMProperty(prop, result);
+ return tpm_iface[tpmvers_choice]->GetTPMProperty(prop, result);
}
return TPM_SUCCESS;
}
+char *TPMLIB_GetInfo(enum TPMLIB_InfoFlags flags)
+{
+ return tpm_iface[tpmvers_choice]->GetInfo(flags);
+}
+
+TPM_RESULT TPMLIB_SetState(enum TPMLIB_StateType st,
+ const unsigned char *buffer, uint32_t buflen)
+{
+ return tpm_iface[tpmvers_choice]->SetState(st, buffer, buflen);
+}
+
+TPM_RESULT TPMLIB_GetState(enum TPMLIB_StateType st,
+ unsigned char **buffer, uint32_t *buflen)
+{
+ return tpm_iface[tpmvers_choice]->GetState(st, buffer, buflen);
+}
+
TPM_RESULT TPM_IO_Hash_Start(void)
{
- return tpm_iface[0]->HashStart();
+ return tpm_iface[tpmvers_choice]->HashStart();
}
TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, uint32_t data_length)
{
- return tpm_iface[0]->HashData(data, data_length);
+ return tpm_iface[tpmvers_choice]->HashData(data, data_length);
}
TPM_RESULT TPM_IO_Hash_End(void)
{
- return tpm_iface[0]->HashEnd();
+ return tpm_iface[tpmvers_choice]->HashEnd();
}
TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished)
{
- return tpm_iface[0]->TpmEstablishedGet(tpmEstablished);
+ return tpm_iface[tpmvers_choice]->TpmEstablishedGet(tpmEstablished);
+}
+
+TPM_RESULT TPM_IO_TpmEstablished_Reset(void)
+{
+ return tpm_iface[tpmvers_choice]->TpmEstablishedReset();
+}
+
+uint32_t TPMLIB_SetBufferSize(uint32_t wanted_size,
+ uint32_t *min_size,
+ uint32_t *max_size)
+{
+ return tpm_iface[tpmvers_choice]->SetBufferSize(wanted_size,
+ min_size,
+ max_size);
+}
+
+TPM_RESULT TPMLIB_ValidateState(enum TPMLIB_StateType st,
+ unsigned int flags)
+{
+ return tpm_iface[tpmvers_choice]->ValidateState(st, flags);
}
static struct libtpms_callbacks libtpms_cbs;
BIO *b64, *bmem;
unsigned char *res = NULL;
int n;
- TPM_RESULT rc;
b64 = BIO_new(BIO_f_base64());
if (!b64) {
bmem = BIO_push(b64, bmem);
BIO_set_flags(bmem, BIO_FLAGS_BASE64_NO_NL);
- rc = TPM_Malloc(&res, outputlen);
- if (rc != TPM_SUCCESS) {
+ res = malloc(outputlen);
+ if (!res) {
+ TPMLIB_LogError("Could not allocate %u bytes.\n", outputlen);
goto cleanup;
}
n = BIO_read(bmem, res, outputlen);
if (n <= 0) {
- TPM_Free(res);
+ free(res);
res = NULL;
goto cleanup;
}
end++;
- if (TPM_Malloc((unsigned char **)&input, end - start + 1) != TPM_SUCCESS)
+ input = malloc(end - start + 1);
+ if (!input) {
+ TPMLIB_LogError("Could not allocate %u bytes.\n",
+ (unsigned int)(end - start + 1));
return NULL;
+ }
/* copy from source string skipping '\n' and '\r' and using
'=' to calculate the exact length */
}
if (debug_prefix)
- vdprintf(debug_fd, debug_prefix, NULL);
- vdprintf(debug_fd, buffer, NULL);
+ dprintf(debug_fd, "%s", debug_prefix);
+ dprintf(debug_fd, "%s", buffer);
return i;
}
/*
* TPMLIB_LogPrintfA: Printf to the logfd without indentation check
+ *
+ * @indent: how many spaces to indent; indent of ~0 forces logging
+ * with indent 0 even if not debug_level is set
+ * @format: format to use for formatting the following parameters
+ * @...: varargs
*/
void TPMLIB_LogPrintfA(unsigned int indent, const char *format, ...)
{
va_list args;
char spaces[20];
+ int fd;
- if (!debug_fd || !debug_level)
- return;
+ if (indent != (unsigned int)~0) {
+ if (!debug_fd || !debug_level)
+ return;
+ fd = debug_fd;
+ } else {
+ indent = 0;
+ fd = (debug_fd >= 0) ? debug_fd : STDERR_FILENO;
+ }
if (indent) {
if (indent > sizeof(spaces) - 1)
indent = sizeof(spaces) - 1;
memset(spaces, ' ', indent);
spaces[indent] = 0;
- vdprintf(debug_fd, spaces, NULL);
+ dprintf(fd, "%s", spaces);
}
va_start(args, format);
- vdprintf(debug_fd, format, args);
+ vdprintf(fd, format, args);
va_end(args);
}
+
+/*
+ * TPMLIB_LogArray: Display an array of data
+ *
+ * @indent: how many spaces to indent; indent of ~0 forces logging
+ * with indent 0 even if not debug_level is set
+ * @data: the data to print
+ * @datalen: length of the data
+ */
+void TPMLIB_LogArray(unsigned int indent, const unsigned char *data,
+ size_t datalen)
+{
+ char line[80];
+ size_t i, o = 0;
+
+ for (i = 0; i < datalen; i++) {
+ snprintf(&line[o], sizeof(line) - o, "%02x ", data[i]);
+ o += 3;
+ if (o >= 16 * 3) {
+ TPMLIB_LogPrintfA(indent, "%s\n", line);
+ o = 0;
+ }
+ }
+ if (o > 0) {
+ TPMLIB_LogPrintfA(indent, "%s\n", line);
+ }
+}
+
+void ClearCachedState(enum TPMLIB_StateType st)
+{
+ free(cached_blobs[st].buffer);
+ cached_blobs[st].buffer = NULL;
+ cached_blobs[st].buflen = 0;
+}
+
+void ClearAllCachedState(void)
+{
+ ClearCachedState(TPMLIB_STATE_VOLATILE);
+ ClearCachedState(TPMLIB_STATE_PERMANENT);
+ ClearCachedState(TPMLIB_STATE_SAVE_STATE);
+}
+
+/*
+ * Set buffer for cached state; we allow setting an empty cached state
+ * by the caller passing a NULL pointer for the buffer.
+ */
+void SetCachedState(enum TPMLIB_StateType st,
+ unsigned char *buffer, uint32_t buflen)
+{
+ free(cached_blobs[st].buffer);
+ cached_blobs[st].buffer = buffer;
+ cached_blobs[st].buflen = buffer ? buflen : BUFLEN_EMPTY_BUFFER;
+}
+
+void GetCachedState(enum TPMLIB_StateType st,
+ unsigned char **buffer, uint32_t *buflen,
+ bool *is_empty_buffer)
+{
+ /* caller owns blob now */
+ *buffer = cached_blobs[st].buffer;
+ *buflen = cached_blobs[st].buflen;
+ *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
+ cached_blobs[st].buffer = NULL;
+ cached_blobs[st].buflen = 0;
+}
+
+bool HasCachedState(enum TPMLIB_StateType st)
+{
+ return (cached_blobs[st].buffer != NULL || cached_blobs[st].buflen != 0);
+}
+
+TPM_RESULT CopyCachedState(enum TPMLIB_StateType st,
+ unsigned char **buffer, uint32_t *buflen,
+ bool *is_empty_buffer)
+{
+ TPM_RESULT ret = TPM_SUCCESS;
+
+ /* buflen may indicate an empty buffer */
+ *buflen = cached_blobs[st].buflen;
+ *is_empty_buffer = (*buflen == BUFLEN_EMPTY_BUFFER);
+
+ if (cached_blobs[st].buffer) {
+ *buffer = malloc(*buflen);
+ if (!*buffer) {
+ TPMLIB_LogError("Could not allocate %u bytes.\n", *buflen);
+ ret = TPM_SIZE;
+ } else {
+ memcpy(*buffer, cached_blobs[st].buffer, *buflen);
+ }
+ } else {
+ *buffer = NULL;
+ }
+
+ return ret;
+}
+
+const char *TPMLIB_StateTypeToName(enum TPMLIB_StateType st)
+{
+ switch (st) {
+ case TPMLIB_STATE_PERMANENT:
+ return TPM_PERMANENT_ALL_NAME;
+ case TPMLIB_STATE_VOLATILE:
+ return TPM_VOLATILESTATE_NAME;
+ case TPMLIB_STATE_SAVE_STATE:
+ return TPM_SAVESTATE_NAME;
+ }
+ return NULL;
+}
+
+enum TPMLIB_StateType TPMLIB_NameToStateType(const char *name)
+{
+ if (!name)
+ return 0;
+ if (!strcmp(name, TPM_PERMANENT_ALL_NAME))
+ return TPMLIB_STATE_PERMANENT;
+ if (!strcmp(name, TPM_VOLATILESTATE_NAME))
+ return TPMLIB_STATE_VOLATILE;
+ if (!strcmp(name, TPM_SAVESTATE_NAME))
+ return TPMLIB_STATE_SAVE_STATE;
+ return 0;
+}