summaryrefslogtreecommitdiff
path: root/src/tcs/ps/tcsps.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcs/ps/tcsps.c')
-rw-r--r--src/tcs/ps/tcsps.c784
1 files changed, 784 insertions, 0 deletions
diff --git a/src/tcs/ps/tcsps.c b/src/tcs/ps/tcsps.c
new file mode 100644
index 0000000..0d55608
--- /dev/null
+++ b/src/tcs/ps/tcsps.c
@@ -0,0 +1,784 @@
+
+/*
+ * Licensed Materials - Property of IBM
+ *
+ * trousers - An open source TCG Software Stack
+ *
+ * (C) Copyright International Business Machines Corp. 2004-2006
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.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 <assert.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include "trousers/tss.h"
+#include "trousers_types.h"
+#include "tcsps.h"
+#include "tcs_tsp.h"
+#include "tcs_utils.h"
+#include "capabilities.h"
+#include "tcslog.h"
+#include "tcsd_wrap.h"
+#include "tcsd.h"
+
+int system_ps_fd = -1;
+MUTEX_DECLARE(disk_cache_lock);
+
+static struct flock fl;
+
+int
+get_file()
+{
+ int rc;
+ /* check the global file handle first. If it exists, lock it and return */
+ if (system_ps_fd != -1) {
+ int rc = 0;
+
+ fl.l_type = F_WRLCK;
+ if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
+ LogError("failed to get system PS lock: %s", strerror(errno));
+ return -1;
+ }
+
+ return system_ps_fd;
+ }
+
+ /* open and lock the file */
+ system_ps_fd = open(tcsd_options.system_ps_file, O_CREAT|O_RDWR, 0600);
+ if (system_ps_fd < 0) {
+ LogError("system PS: open() of %s failed: %s",
+ tcsd_options.system_ps_file, strerror(errno));
+ return -1;
+ }
+
+ fl.l_type = F_WRLCK;
+ if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
+ LogError("failed to get system PS lock of file %s: %s",
+ tcsd_options.system_ps_file, strerror(errno));
+ return -1;
+ }
+
+ return system_ps_fd;
+}
+
+int
+put_file(int fd)
+{
+ int rc = 0;
+ /* release the file lock */
+
+ fl.l_type = F_UNLCK;
+ if ((rc = fcntl(fd, F_SETLKW, &fl))) {
+ LogError("failed to unlock system PS file: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ return rc;
+}
+
+void
+close_file(int fd)
+{
+ close(fd);
+ system_ps_fd = -1;
+}
+
+TSS_RESULT
+psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid)
+{
+ int rc;
+ UINT32 file_offset = 0;
+ struct key_disk_cache *tmp;
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* jump to the location of the parent uuid */
+ file_offset = TSSPS_PARENT_UUID_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return -1;
+ }
+
+ if ((rc = read_data(fd, ret_uuid, sizeof(TSS_UUID)))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+ }
+ MUTEX_UNLOCK(disk_cache_lock);
+ /* key not found */
+ return -2;
+}
+
+/*
+ * return a key blob from PS given a uuid
+ */
+TSS_RESULT
+psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *ret_buffer, UINT16 *ret_buffer_size)
+{
+ int rc;
+ UINT32 file_offset = 0;
+ struct key_disk_cache *tmp;
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* jump to the location of the key blob */
+ file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* we found the key; file ptr is pointing at the blob */
+ if (*ret_buffer_size < tmp->blob_size) {
+ /* not enough room */
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_FAIL);
+ }
+
+ if ((rc = read_data(fd, ret_buffer, tmp->blob_size))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+ *ret_buffer_size = tmp->blob_size;
+ LogDebugUnrollKey(ret_buffer);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+ }
+ MUTEX_UNLOCK(disk_cache_lock);
+ /* key not found */
+ return TCSERR(TSS_E_FAIL);
+}
+
+/*
+ * return a key blob from PS given its cache entry. The disk cache must be
+ * locked by the caller.
+ */
+TSS_RESULT
+psfile_get_key_by_cache_entry(int fd, struct key_disk_cache *c, BYTE *ret_buffer,
+ UINT16 *ret_buffer_size)
+{
+ int rc;
+ UINT32 file_offset = 0;
+
+ /* jump to the location of the key blob */
+ file_offset = TSSPS_BLOB_DATA_OFFSET(c);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* we found the key; file ptr is pointing at the blob */
+ if (*ret_buffer_size < c->blob_size) {
+ /* not enough room */
+ LogError("%s: Buf size too small. Needed %d bytes, passed %d", __FUNCTION__,
+ c->blob_size, *ret_buffer_size);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ if ((rc = read_data(fd, ret_buffer, c->blob_size))) {
+ LogError("%s: error reading %d bytes", __FUNCTION__, c->blob_size);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ *ret_buffer_size = c->blob_size;
+
+ return TSS_SUCCESS;
+}
+
+/*
+ * return the vendor data from PS given its cache entry. The disk cache must be
+ * locked by the caller.
+ */
+TSS_RESULT
+psfile_get_vendor_data(int fd, struct key_disk_cache *c, UINT32 *size, BYTE **data)
+{
+ int rc;
+ UINT32 file_offset;
+
+ /* jump to the location of the data */
+ file_offset = TSSPS_VENDOR_DATA_OFFSET(c);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ if ((*data = malloc(c->vendor_data_size)) == NULL) {
+ LogError("malloc of %u bytes failed", c->vendor_data_size);
+ return TCSERR(TSS_E_OUTOFMEMORY);
+ }
+
+ if ((rc = read_data(fd, *data, c->vendor_data_size))) {
+ LogError("%s: error reading %u bytes", __FUNCTION__, c->vendor_data_size);
+ free(*data);
+ *data = NULL;
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ *size = c->vendor_data_size;
+
+ return TSS_SUCCESS;
+}
+
+TSS_RESULT
+psfile_get_ps_type_by_uuid(int fd, TSS_UUID *uuid, UINT32 *ret_ps_type)
+{
+ struct key_disk_cache *tmp;
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) ||
+ !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ if (tmp->flags & CACHE_FLAG_PARENT_PS_SYSTEM) {
+ *ret_ps_type = TSS_PS_TYPE_SYSTEM;
+ goto done;
+ } else
+ break;
+ }
+
+ *ret_ps_type = TSS_PS_TYPE_USER;
+done:
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+}
+
+TSS_RESULT
+psfile_is_pub_registered(int fd, TCPA_STORE_PUBKEY *pub, TSS_BOOL *is_reg)
+{
+ int rc;
+ UINT32 file_offset = 0;
+ struct key_disk_cache *tmp;
+ char tmp_buffer[2048];
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ /* if the key is of the wrong size or is invalid, try the next one */
+ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* we have a valid key with the same key size as the one we're looking for.
+ * grab the pub key data off disk and compare it. */
+
+ /* jump to the location of the public key */
+ file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ DBG_ASSERT(tmp->pub_data_size < 2048);
+
+ /* read in the key */
+ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+
+ /* do the compare */
+ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* the key matches, copy the uuid out */
+ *is_reg = TRUE;
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+ }
+ MUTEX_UNLOCK(disk_cache_lock);
+ /* key not found */
+ *is_reg = FALSE;
+ return TSS_SUCCESS;
+}
+
+
+TSS_RESULT
+psfile_get_uuid_by_pub(int fd, TCPA_STORE_PUBKEY *pub, TSS_UUID **ret_uuid)
+{
+ int rc;
+ UINT32 file_offset = 0;
+ struct key_disk_cache *tmp;
+ char tmp_buffer[2048];
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ /* if the key is of the wrong size or is invalid, try the next one */
+ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* we have a valid key with the same key size as the one we're looking for.
+ * grab the pub key data off disk and compare it. */
+
+ /* jump to the location of the public key */
+ file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ DBG_ASSERT(tmp->pub_data_size < 2048);
+
+ if (tmp->pub_data_size > sizeof(tmp_buffer)) {
+ LogError("Source buffer size too big! Size: %d",
+ tmp->pub_data_size);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ /* read in the key */
+ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+
+ /* do the compare */
+ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ *ret_uuid = (TSS_UUID *)malloc(sizeof(TSS_UUID));
+ if (*ret_uuid == NULL) {
+ LogError("malloc of %zd bytes failed.", sizeof(TSS_UUID));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_OUTOFMEMORY);
+ }
+
+ /* the key matches, copy the uuid out */
+ memcpy(*ret_uuid, &tmp->uuid, sizeof(TSS_UUID));
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TSS_SUCCESS;
+ }
+ MUTEX_UNLOCK(disk_cache_lock);
+ /* key not found */
+ return TCSERR(TSS_E_PS_KEY_NOTFOUND);
+}
+
+TSS_RESULT
+psfile_get_key_by_pub(int fd, TCPA_STORE_PUBKEY *pub, UINT32 *size, BYTE **ret_key)
+{
+ int rc;
+ UINT32 file_offset = 0;
+ struct key_disk_cache *tmp;
+ BYTE tmp_buffer[4096];
+
+ MUTEX_LOCK(disk_cache_lock);
+ tmp = key_disk_cache_head;
+
+ while (tmp) {
+ /* if the key is of the wrong size or is invalid, try the next one */
+ if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* we have a valid key with the same key size as the one we're looking for.
+ * grab the pub key data off disk and compare it. */
+
+ /* jump to the location of the public key */
+ file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ DBG_ASSERT(tmp->pub_data_size < 2048);
+ if (tmp->pub_data_size > sizeof(tmp_buffer)) {
+ LogError("Source buffer size too big! Size: %d",
+ tmp->pub_data_size);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* read in the key */
+ if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+
+ /* do the compare */
+ if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
+ tmp = tmp->next;
+ continue;
+ }
+
+ /* jump to the location of the key blob */
+ file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
+
+ rc = lseek(fd, file_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ DBG_ASSERT(tmp->blob_size < 4096);
+ if (tmp->blob_size > sizeof(tmp_buffer)) {
+ LogError("Blob size greater than 4096! Size: %d",
+ tmp->blob_size);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* read in the key blob */
+ if ((rc = read_data(fd, tmp_buffer, tmp->blob_size))) {
+ LogError("%s", __FUNCTION__);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+
+ *ret_key = malloc(tmp->blob_size);
+ if (*ret_key == NULL) {
+ LogError("malloc of %d bytes failed.", tmp->blob_size);
+ MUTEX_UNLOCK(disk_cache_lock);
+ return TCSERR(TSS_E_OUTOFMEMORY);
+ }
+
+ memcpy(*ret_key, tmp_buffer, tmp->blob_size);
+ *size = tmp->blob_size;
+
+ MUTEX_UNLOCK(disk_cache_lock);
+ return rc;
+ }
+ MUTEX_UNLOCK(disk_cache_lock);
+ /* key not found */
+ return -2;
+}
+
+/*
+ * 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 ]
+ * [...]
+ *
+ */
+TSS_RESULT
+psfile_write_key(int fd,
+ TSS_UUID *uuid,
+ TSS_UUID *parent_uuid,
+ UINT32 *parent_ps,
+ BYTE *vendor_data,
+ UINT32 vendor_size,
+ BYTE *key_blob,
+ UINT16 key_blob_size)
+{
+ TSS_KEY key;
+ UINT16 pub_key_size, cache_flags = CACHE_FLAG_VALID;
+ UINT64 offset;
+ int rc = 0;
+
+ /* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */
+ if (*parent_ps == TSS_PS_TYPE_SYSTEM)
+ cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM;
+
+ /* Unload the blob to get the public key */
+ offset = 0;
+ if ((rc = UnloadBlob_TSS_KEY(&offset, key_blob, &key)))
+ return rc;
+
+ pub_key_size = key.pubKey.keyLength;
+
+ if ((rc = write_key_init(fd, pub_key_size, key_blob_size, vendor_size)) < 0)
+ goto done;
+
+ /* offset now holds the number of bytes from the beginning of the file
+ * the key will be stored at
+ */
+ offset = rc;
+
+#ifdef TSS_DEBUG
+ if (offset == 0)
+ LogDebug("ERROR: key being written with offset 0!!");
+#endif
+
+ /* [TSS_UUID uuid0 ] yes */
+ if ((rc = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+
+ /* [TSS_UUID uuid_parent0 ] yes */
+ if ((rc = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+
+ /* [UINT16 pub_data_size0 ] yes */
+ pub_key_size = LE_16(pub_key_size);
+ if ((rc = write_data(fd, &pub_key_size, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+ /* Swap it back for later */
+ pub_key_size = LE_16(pub_key_size);
+
+ /* [UINT16 blob_size0 ] yes */
+ key_blob_size = LE_16(key_blob_size);
+ if ((rc = write_data(fd, &key_blob_size, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+ /* Swap it back for later */
+ key_blob_size = LE_16(key_blob_size);
+
+ /* [UINT32 vendor_data_size0 ] yes */
+ vendor_size = LE_32(vendor_size);
+ if ((rc = write_data(fd, &vendor_size, sizeof(UINT32)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+ /* Swap it back for later */
+ vendor_size = LE_32(vendor_size);
+
+ /* [UINT16 cache_flags0 ] yes */
+ cache_flags = LE_16(cache_flags);
+ if ((rc = write_data(fd, &cache_flags, sizeof(UINT16)))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+ /* Swap it back for later */
+ cache_flags = LE_16(cache_flags);
+
+ /* [BYTE[] pub_data0 ] no */
+ if ((rc = write_data(fd, (void *)key.pubKey.key, pub_key_size))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+
+ /* [BYTE[] blob0 ] no */
+ if ((rc = write_data(fd, (void *)key_blob, key_blob_size))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+
+ /* [BYTE[] vendor_data0 ] no */
+ if (vendor_size > 0) {
+ if ((rc = write_data(fd, (void *)vendor_data, vendor_size))) {
+ LogError("%s", __FUNCTION__);
+ goto done;
+ }
+ }
+
+ if ((rc = cache_key((UINT32)offset, cache_flags, uuid, parent_uuid, pub_key_size,
+ key_blob_size, vendor_size)))
+ goto done;
+done:
+ destroy_key_refs(&key);
+
+ return rc;
+}
+
+TSS_RESULT
+psfile_remove_key(int fd, struct key_disk_cache *c)
+{
+ TSS_RESULT result;
+ UINT32 head_offset = 0, tail_offset, num_keys;
+ BYTE buf[4096];
+ struct stat stat_buf;
+ int rc, size = 0;
+
+ if ((rc = fstat(fd, &stat_buf)) != 0) {
+ LogError("fstat: %s", strerror(errno));
+ return TSS_E_INTERNAL_ERROR;
+ }
+
+ /* head_offset is the offset the beginning of the key */
+ head_offset = TSSPS_UUID_OFFSET(c);
+
+ /* tail_offset is the offset the beginning of the next key */
+ tail_offset = TSSPS_VENDOR_DATA_OFFSET(c) + c->vendor_data_size;
+
+ rc = lseek(fd, tail_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* read in from tail, write out to head to fill the gap */
+ while ((rc = read(fd, buf, sizeof(buf))) > 0) {
+ size = rc;
+ tail_offset += size;
+
+ /* set the file pointer to where we want to write */
+ rc = lseek(fd, head_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* write the data */
+ if ((result = write_data(fd, (void *)buf, size))) {
+ LogError("%s", __FUNCTION__);
+ return result;
+ }
+ head_offset += size;
+
+ /* set the file pointer to where we want to read in the next
+ * loop */
+ rc = lseek(fd, tail_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+ }
+
+ if (rc < 0) {
+ LogError("read: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* set the file pointer to where we want to write */
+ rc = lseek(fd, head_offset, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* head_offset now contains a pointer to where we want to truncate the
+ * file. Zero out the old tail end of the file and truncate it. */
+
+ memset(buf, 0, sizeof(buf));
+
+ /* Zero out the old tail end of the file */
+ if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) {
+ LogError("%s", __FUNCTION__);
+ return result;
+ }
+
+ if ((rc = ftruncate(fd, head_offset)) < 0) {
+ LogError("ftruncate: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* we succeeded in removing a key from the disk. Decrement the number
+ * of keys in the file */
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ rc = read(fd, &num_keys, sizeof(UINT32));
+ num_keys = LE_32(num_keys);
+ if (rc != sizeof(UINT32)) {
+ LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
+ if (rc == ((off_t) - 1)) {
+ LogError("lseek: %s", strerror(errno));
+ return TCSERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ /* decrement, then write back out to disk */
+ num_keys--;
+
+ num_keys = LE_32(num_keys);
+ if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) {
+ LogError("%s", __FUNCTION__);
+ return result;
+ }
+
+ return TSS_SUCCESS;
+}