]> git.proxmox.com Git - libtpms.git/blobdiff - src/tpm_library.c
Move common debug, memory & nvfile units to src/
[libtpms.git] / src / tpm_library.c
index e7a1f6482833577a9a83454846c196ef3650e319..460cd59c0fec08e4c5eb124a6678e119702828ad 100644 (file)
 
 #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;
@@ -74,25 +80,68 @@ static const struct tags_and_indices {
 
 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;
 }
 
 /*
@@ -108,7 +157,8 @@ TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size,
                           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);
 }
 
@@ -120,7 +170,15 @@ TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_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();
 }
 
 /*
@@ -138,30 +196,67 @@ TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop,
         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;
@@ -205,7 +300,6 @@ static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
     BIO *b64, *bmem;
     unsigned char *res = NULL;
     int n;
-    TPM_RESULT rc;
 
     b64 = BIO_new(BIO_f_base64());
     if (!b64) {
@@ -220,14 +314,15 @@ static unsigned char *TPMLIB_OpenSSL_Base64Decode(char *input,
     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;
     }
@@ -261,8 +356,12 @@ static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end,
 
     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 */
@@ -414,24 +513,157 @@ int TPMLIB_LogPrintf(const char *format, ...)
 
 /*
  * 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;
+}