summaryrefslogtreecommitdiff
path: root/src/tcs/ps/ps_utils.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2012-11-25 14:36:20 +0000
committerIgor Pashev <pashev.igor@gmail.com>2012-11-25 14:36:20 +0000
commitc3649a2def02c41d837ae1f79dda729ccb91e677 (patch)
treebea46dff212fdef977fe9094a70a939e8cc21885 /src/tcs/ps/ps_utils.c
downloadtrousers-upstream/0.3.9.tar.gz
Imported Upstream version 0.3.9upstream/0.3.9upstream
Diffstat (limited to 'src/tcs/ps/ps_utils.c')
-rw-r--r--src/tcs/ps/ps_utils.c538
1 files changed, 538 insertions, 0 deletions
diff --git a/src/tcs/ps/ps_utils.c b/src/tcs/ps/ps_utils.c
new file mode 100644
index 0000000..2e7f502
--- /dev/null
+++ b/src/tcs/ps/ps_utils.c
@@ -0,0 +1,538 @@
+/*
+ * Licensed Materials - Property of IBM
+ *
+ * trousers - An open source TCG Software Stack
+ *
+ * (C) Copyright International Business Machines Corp. 2004
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if defined(HAVE_BYTEORDER_H)
+#include <sys/byteorder.h>
+#elif defined(HTOLE_DEFINED)
+#include <endian.h>
+#define LE_16 htole16
+#define LE_32 htole32
+#define LE_64 htole64
+#else
+#define LE_16(x) (x)
+#define LE_32(x) (x)
+#define LE_64(x) (x)
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "trousers/tss.h"
+#include "trousers_types.h"
+#include "tcs_int_literals.h"
+#include "tcsps.h"
+#include "tcs_tsp.h"
+#include "tcs_utils.h"
+#include "tcslog.h"
+
+struct key_disk_cache *key_disk_cache_head = NULL;
+
+
+#ifdef SOLARIS
+TSS_RESULT
+#else
+inline TSS_RESULT
+#endif
+read_data(int fd, void *data, UINT32 size)
+{
+ int rc;
+
+ rc = read(fd, data, size);
+ if (rc == -1) {
+ LogError("read of %d bytes: %s", size, strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ } else if ((unsigned)rc != size) {
+ LogError("read of %d bytes (only %d read)", size, rc);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ return TSS_SUCCESS;
+}
+
+
+#ifdef SOLARIS
+TSS_RESULT
+#else
+inline TSS_RESULT
+#endif
+write_data(int fd, void *data, UINT32 size)
+{
+ int rc;
+
+ rc = write(fd, data, size);
+ if (rc == -1) {
+ LogError("write of %d bytes: %s", size, strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ } else if ((unsigned)rc != size) {
+ LogError("write of %d bytes (only %d written)", size, rc);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ return TSS_SUCCESS;
+}
+
+/*
+ * called by write_key_init to find the next available location in the PS file to
+ * write a new key to.
+ */
+int
+find_write_offset(UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size)
+{
+ struct key_disk_cache *tmp;
+ unsigned int offset;
+
+ MUTEX_LOCK(disk_cache_lock);
+
+ tmp = key_disk_cache_head;
+ while (tmp) {
+ /* if we find a deleted key of the right size, return its offset */
+ if (!(tmp->flags & CACHE_FLAG_VALID) &&
+ tmp->pub_data_size == pub_data_size &&
+ tmp->blob_size == blob_size &&
+ tmp->vendor_data_size == vendor_data_size) {
+ offset = tmp->offset;
+ MUTEX_UNLOCK(disk_cache_lock);
+ return offset;
+ }
+ tmp = tmp->next;
+ }
+
+ MUTEX_UNLOCK(disk_cache_lock);
+
+ /* no correctly sized holes */
+ return -1;
+}
+
+/*
+ * move the file pointer to the point where the next key can be written and return
+ * that offset
+ */
+int
+write_key_init(int fd, UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size)
+{
+ UINT32 num_keys;
+ BYTE version;
+ int rc, offset;
+
+ /* seek to the PS version */
+ rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+
+ /* go to NUM_KEYS */
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+
+ /* read the number of keys */
+ rc = read(fd, &num_keys, sizeof(UINT32));
+ num_keys = LE_32(num_keys);
+ if (rc == -1) {
+ LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
+ return -1;
+ } else if (rc == 0) {
+ /* This is the first key being written */
+ num_keys = 1;
+ version = 1;
+
+ /* seek to the PS version */
+ rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+
+ /* write out the version info byte */
+ if ((rc = write_data(fd, &version, sizeof(BYTE)))) {
+ LogError("%s", __FUNCTION__);
+ return rc;
+ }
+
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+
+ num_keys = LE_32(num_keys);
+ if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) {
+ LogError("%s", __FUNCTION__);
+ return rc;
+ }
+
+ /* return the offset */
+ return (TSSPS_NUM_KEYS_OFFSET + sizeof(UINT32));
+ }
+
+ /* if there is a hole in the file we can write to, find it */
+ offset = find_write_offset(pub_data_size, blob_size, vendor_data_size);
+
+ if (offset != -1) {
+ /* we found a hole, seek to it and don't increment the # of keys on disk */
+ rc = lseek(fd, offset, SEEK_SET);
+ } else {
+ /* we didn't find a hole, increment the number of keys on disk and seek
+ * to the end of the file
+ */
+ num_keys++;
+
+ /* go to the beginning */
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+ num_keys = LE_32(num_keys);
+ if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) {
+ LogError("%s", __FUNCTION__);
+ return rc;
+ }
+
+ rc = lseek(fd, 0, SEEK_END);
+ }
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return -1;
+ }
+
+ /* lseek returns the number of bytes of offset from the beginning of the file */
+ return rc;
+}
+
+/*
+ * add a new cache entry for a written key
+ */
+TSS_RESULT
+cache_key(UINT32 offset, UINT16 flags,
+ TSS_UUID *uuid, TSS_UUID *parent_uuid,
+ UINT16 pub_data_size, UINT32 blob_size,
+ UINT32 vendor_data_size)
+{
+ struct key_disk_cache *tmp;
+
+ MUTEX_LOCK(disk_cache_lock);
+
+ tmp = key_disk_cache_head;
+
+ for (; tmp; tmp = tmp->next) {
+ /* reuse an invalidated key cache entry */
+ if (!(tmp->flags & CACHE_FLAG_VALID))
+ goto fill_cache_entry;
+ }
+
+ tmp = malloc(sizeof(struct key_disk_cache));
+ if (tmp == NULL) {
+ LogError("malloc of %zd bytes failed.", sizeof(struct key_disk_cache));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_OUTOFMEMORY);
+ }
+ tmp->next = key_disk_cache_head;
+ key_disk_cache_head = tmp;
+
+fill_cache_entry:
+ tmp->offset = offset;
+#ifdef TSS_DEBUG
+ if (offset == 0)
+ LogDebug("Storing key with file offset==0!!!");
+#endif
+ tmp->flags = flags;
+ tmp->blob_size = blob_size;
+ tmp->pub_data_size = pub_data_size;
+ tmp->vendor_data_size = vendor_data_size;
+ memcpy(&tmp->uuid, uuid, sizeof(TSS_UUID));
+ memcpy(&tmp->parent_uuid, parent_uuid, sizeof(TSS_UUID));
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+}
+
+/*
+ * read into the PS file and return the number of keys
+ */
+int
+get_num_keys_in_file(int fd)
+{
+ UINT32 num_keys;
+ int rc;
+
+ /* go to the number of keys */
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return 0;
+ }
+
+ rc = read(fd, &num_keys, sizeof(UINT32));
+ if (rc < 0) {
+ LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
+ return 0;
+ } else if ((unsigned)rc < sizeof(UINT32)) {
+ num_keys = 0;
+ }
+ num_keys = LE_32(num_keys);
+
+ return num_keys;
+}
+
+/*
+ * count the number of valid keys in the cache
+ */
+int
+get_num_keys()
+{
+ int num_keys = 0;
+ struct key_disk_cache *tmp;
+
+ MUTEX_LOCK(disk_cache_lock);
+
+ tmp = key_disk_cache_head;
+
+ for (; tmp; tmp = tmp->next) {
+ if (tmp->flags & CACHE_FLAG_VALID)
+ num_keys++;
+ }
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return num_keys;
+}
+
+/*
+ * disk store format:
+ *
+ * TrouSerS 0.2.0 and before:
+ * Version 0: cached?
+ * [UINT32 num_keys_on_disk]
+ * [TSS_UUID uuid0 ] yes
+ * [TSS_UUID uuid_parent0 ] yes
+ * [UINT16 pub_data_size0 ] yes
+ * [UINT16 blob_size0 ] yes
+ * [UINT16 cache_flags0 ] yes
+ * [BYTE[] pub_data0 ]
+ * [BYTE[] blob0 ]
+ * [...]
+ *
+ * TrouSerS 0.2.1+
+ * Version 1: cached?
+ * [BYTE PS version = '\1']
+ * [UINT32 num_keys_on_disk ]
+ * [TSS_UUID uuid0 ] yes
+ * [TSS_UUID uuid_parent0 ] yes
+ * [UINT16 pub_data_size0 ] yes
+ * [UINT16 blob_size0 ] yes
+ * [UINT32 vendor_data_size0] yes
+ * [UINT16 cache_flags0 ] yes
+ * [BYTE[] pub_data0 ]
+ * [BYTE[] blob0 ]
+ * [BYTE[] vendor_data0 ]
+ * [...]
+ *
+ */
+/*
+ * read the PS file pointed to by fd and create a cache based on it
+ */
+int
+init_disk_cache(int fd)
+{
+ UINT32 num_keys = get_num_keys_in_file(fd);
+ UINT16 i;
+ UINT64 tmp_offset;
+ int rc = 0, offset;
+ struct key_disk_cache *tmp, *prev = NULL;
+ BYTE srk_blob[2048];
+ TSS_KEY srk_key;
+#ifdef TSS_DEBUG
+ int valid_keys = 0;
+#endif
+
+ MUTEX_LOCK(disk_cache_lock);
+
+ if (num_keys == 0) {
+ key_disk_cache_head = NULL;
+ MUTEX_UNLOCK(disk_cache_lock);
+ return 0;
+ } else {
+ key_disk_cache_head = tmp = calloc(1, sizeof(struct key_disk_cache));
+ if (tmp == NULL) {
+ LogError("malloc of %zd bytes failed.",
+ sizeof(struct key_disk_cache));
+ rc = -1;
+ goto err_exit;
+ }
+ }
+
+ /* make sure the file pointer is where we expect, just after the number
+ * of keys on disk at the head of the file
+ */
+ offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET);
+ if (offset == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ rc = -1;
+ goto err_exit;
+ }
+
+ for (i=0; i<num_keys; i++) {
+ offset = lseek(fd, 0, SEEK_CUR);
+ if (offset == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ rc = -1;
+ goto err_exit;
+ }
+ tmp->offset = offset;
+#ifdef TSS_DEBUG
+ if (offset == 0)
+ LogDebug("Storing key with file offset==0!!!");
+#endif
+ /* read UUID */
+ if ((rc = read_data(fd, (void *)&tmp->uuid, sizeof(TSS_UUID)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+
+ /* read parent UUID */
+ if ((rc = read_data(fd, (void *)&tmp->parent_uuid, sizeof(TSS_UUID)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+
+ /* pub data size */
+ if ((rc = read_data(fd, &tmp->pub_data_size, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+ tmp->pub_data_size = LE_16(tmp->pub_data_size);
+
+ DBG_ASSERT(tmp->pub_data_size <= 2048 && tmp->pub_data_size > 0);
+
+ /* blob size */
+ if ((rc = read_data(fd, &tmp->blob_size, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+ tmp->blob_size = LE_16(tmp->blob_size);
+ DBG_ASSERT(tmp->blob_size <= 4096 && tmp->blob_size > 0);
+
+ /* vendor data size */
+ if ((rc = read_data(fd, &tmp->vendor_data_size, sizeof(UINT32)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+ tmp->vendor_data_size = LE_32(tmp->vendor_data_size);
+
+ /* cache flags */
+ if ((rc = read_data(fd, &tmp->flags, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+ tmp->flags = LE_16(tmp->flags);
+
+#ifdef TSS_DEBUG
+ if (tmp->flags & CACHE_FLAG_VALID)
+ valid_keys++;
+#endif
+ /* fast forward over the pub key */
+ offset = lseek(fd, tmp->pub_data_size, SEEK_CUR);
+ if (offset == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ rc = -1;
+ goto err_exit;
+ }
+
+ /* if this is the SRK, load it into memory, since its already loaded in
+ * the chip */
+ if (!memcmp(&SRK_UUID, &tmp->uuid, sizeof(TSS_UUID))) {
+ /* read SRK blob from disk */
+ if ((rc = read_data(fd, srk_blob, tmp->blob_size))) {
+ LogError("%s", __FUNCTION__);
+ goto err_exit;
+ }
+
+ tmp_offset = 0;
+ if ((rc = UnloadBlob_TSS_KEY(&tmp_offset, srk_blob, &srk_key)))
+ goto err_exit;
+ /* add to the mem cache */
+ if ((rc = mc_add_entry_init(SRK_TPM_HANDLE, SRK_TPM_HANDLE, &srk_key,
+ &SRK_UUID))) {
+ LogError("Error adding SRK to mem cache.");
+ destroy_key_refs(&srk_key);
+ goto err_exit;
+ }
+ destroy_key_refs(&srk_key);
+ } else {
+ /* fast forward over the blob */
+ offset = lseek(fd, tmp->blob_size, SEEK_CUR);
+ if (offset == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ rc = -1;
+ goto err_exit;
+ }
+
+ /* fast forward over the vendor data */
+ offset = lseek(fd, tmp->vendor_data_size, SEEK_CUR);
+ if (offset == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ rc = -1;
+ goto err_exit;
+ }
+ }
+
+ tmp->next = calloc(1, sizeof(struct key_disk_cache));
+ if (tmp->next == NULL) {
+ LogError("malloc of %zd bytes failed.",
+ sizeof(struct key_disk_cache));
+ rc = -1;
+ goto err_exit;
+ }
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ /* delete the dangling, unfilled cache entry */
+ free(tmp);
+ prev->next = NULL;
+ rc = 0;
+ LogDebug("%s: found %d valid key(s) on disk.\n", __FUNCTION__, valid_keys);
+
+err_exit:
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+}
+
+int
+close_disk_cache(int fd)
+{
+ struct key_disk_cache *tmp, *tmp_next;
+
+ if (key_disk_cache_head == NULL)
+ return 0;
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ do {
+ tmp_next = tmp->next;
+ free(tmp);
+ tmp = tmp_next;
+ } while (tmp);
+
+ MUTEX_UNLOCK(disk_cache_lock);
+
+ return 0;
+}