Home | History | Annotate | Line # | Download | only in ps
      1 
      2 /*
      3  * Licensed Materials - Property of IBM
      4  *
      5  * trousers - An open source TCG Software Stack
      6  *
      7  * (C) Copyright International Business Machines Corp. 2004-2006
      8  *
      9  */
     10 
     11 
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <unistd.h>
     16 #include <errno.h>
     17 #include <sys/types.h>
     18 #include <sys/file.h>
     19 #include <sys/stat.h>
     20 #if defined (HAVE_BYTEORDER_H)
     21 #include <sys/byteorder.h>
     22 #elif defined (HTOLE_DEFINED)
     23 
     24 #ifndef __APPLE__
     25 #include <endian.h>
     26 #else
     27 #include "portable_endian.h"
     28 #endif
     29 
     30 #define LE_16 htole16
     31 #define LE_32 htole32
     32 #define LE_64 htole64
     33 #else
     34 #define LE_16(x) (x)
     35 #define LE_32(x) (x)
     36 #define LE_64(x) (x)
     37 #endif
     38 #include <assert.h>
     39 #include <fcntl.h>
     40 #include <limits.h>
     41 
     42 #include "trousers/tss.h"
     43 #include "trousers_types.h"
     44 #include "tcsps.h"
     45 #include "tcs_tsp.h"
     46 #include "tcs_utils.h"
     47 #include "capabilities.h"
     48 #include "tcslog.h"
     49 #include "tcsd_wrap.h"
     50 #include "tcsd.h"
     51 
     52 int system_ps_fd = -1;
     53 MUTEX_DECLARE(disk_cache_lock);
     54 
     55 static struct flock fl;
     56 
     57 int
     58 get_file()
     59 {
     60 	int rc;
     61 	/* check the global file handle first.  If it exists, lock it and return */
     62 	if (system_ps_fd != -1) {
     63 		int rc = 0;
     64 
     65 		fl.l_type = F_WRLCK;
     66 		if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
     67 			LogError("failed to get system PS lock: %s", strerror(errno));
     68 			return -1;
     69 		}
     70 
     71 		return system_ps_fd;
     72 	}
     73 
     74 	/* open and lock the file */
     75 	system_ps_fd = open(tcsd_options.system_ps_file, O_CREAT|O_RDWR, 0600);
     76 	if (system_ps_fd < 0) {
     77 		LogError("system PS: open() of %s failed: %s",
     78 				tcsd_options.system_ps_file, strerror(errno));
     79 		return -1;
     80 	}
     81 
     82 	fl.l_type = F_WRLCK;
     83 	if ((rc = fcntl(system_ps_fd, F_SETLKW, &fl))) {
     84 		LogError("failed to get system PS lock of file %s: %s",
     85 			tcsd_options.system_ps_file, strerror(errno));
     86 		return -1;
     87 	}
     88 
     89 	return system_ps_fd;
     90 }
     91 
     92 int
     93 put_file(int fd)
     94 {
     95 	int rc = 0;
     96 	/* release the file lock */
     97 
     98 	fl.l_type = F_UNLCK;
     99 	if ((rc = fcntl(fd, F_SETLKW, &fl))) {
    100 		LogError("failed to unlock system PS file: %s",
    101 			strerror(errno));
    102 		return -1;
    103 	}
    104 
    105 	return rc;
    106 }
    107 
    108 void
    109 close_file(int fd)
    110 {
    111 	close(fd);
    112 	system_ps_fd = -1;
    113 }
    114 
    115 TSS_RESULT
    116 psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid)
    117 {
    118         int rc;
    119         UINT32 file_offset = 0;
    120         struct key_disk_cache *tmp;
    121 
    122         MUTEX_LOCK(disk_cache_lock);
    123         tmp = key_disk_cache_head;
    124 
    125         while (tmp) {
    126                 if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
    127                         tmp = tmp->next;
    128                         continue;
    129                 }
    130 
    131                 /* jump to the location of the parent uuid */
    132                 file_offset = TSSPS_PARENT_UUID_OFFSET(tmp);
    133 
    134                 rc = lseek(fd, file_offset, SEEK_SET);
    135                 if (rc == ((off_t) - 1)) {
    136                         LogError("lseek: %s", strerror(errno));
    137                         MUTEX_UNLOCK(disk_cache_lock);
    138                         return -1;
    139                 }
    140 
    141                 if ((rc = read_data(fd, ret_uuid, sizeof(TSS_UUID)))) {
    142 			LogError("%s", __FUNCTION__);
    143                         MUTEX_UNLOCK(disk_cache_lock);
    144                         return rc;
    145                 }
    146 
    147                 MUTEX_UNLOCK(disk_cache_lock);
    148                 return TSS_SUCCESS;
    149         }
    150         MUTEX_UNLOCK(disk_cache_lock);
    151         /* key not found */
    152         return -2;
    153 }
    154 
    155 /*
    156  * return a key blob from PS given a uuid
    157  */
    158 TSS_RESULT
    159 psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *ret_buffer, UINT16 *ret_buffer_size)
    160 {
    161         int rc;
    162         UINT32 file_offset = 0;
    163         struct key_disk_cache *tmp;
    164 
    165         MUTEX_LOCK(disk_cache_lock);
    166         tmp = key_disk_cache_head;
    167 
    168         while (tmp) {
    169                 if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) || !(tmp->flags & CACHE_FLAG_VALID)) {
    170                         tmp = tmp->next;
    171                         continue;
    172                 }
    173 
    174                 /* jump to the location of the key blob */
    175                 file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
    176 
    177                 rc = lseek(fd, file_offset, SEEK_SET);
    178                 if (rc == ((off_t) - 1)) {
    179                         LogError("lseek: %s", strerror(errno));
    180                         MUTEX_UNLOCK(disk_cache_lock);
    181                         return TCSERR(TSS_E_INTERNAL_ERROR);
    182                 }
    183 
    184                 /* we found the key; file ptr is pointing at the blob */
    185                 if (*ret_buffer_size < tmp->blob_size) {
    186                         /* not enough room */
    187                         MUTEX_UNLOCK(disk_cache_lock);
    188                         return TCSERR(TSS_E_FAIL);
    189                 }
    190 
    191                 if ((rc = read_data(fd, ret_buffer, tmp->blob_size))) {
    192 			LogError("%s", __FUNCTION__);
    193                         MUTEX_UNLOCK(disk_cache_lock);
    194                         return rc;
    195                 }
    196 		*ret_buffer_size = tmp->blob_size;
    197 		LogDebugUnrollKey(ret_buffer);
    198                 MUTEX_UNLOCK(disk_cache_lock);
    199                 return TSS_SUCCESS;
    200         }
    201         MUTEX_UNLOCK(disk_cache_lock);
    202         /* key not found */
    203         return TCSERR(TSS_E_FAIL);
    204 }
    205 
    206 /*
    207  * return a key blob from PS given its cache entry. The disk cache must be
    208  * locked by the caller.
    209  */
    210 TSS_RESULT
    211 psfile_get_key_by_cache_entry(int fd, struct key_disk_cache *c, BYTE *ret_buffer,
    212 			  UINT16 *ret_buffer_size)
    213 {
    214         int rc;
    215         UINT32 file_offset = 0;
    216 
    217 	/* jump to the location of the key blob */
    218 	file_offset = TSSPS_BLOB_DATA_OFFSET(c);
    219 
    220 	rc = lseek(fd, file_offset, SEEK_SET);
    221 	if (rc == ((off_t) - 1)) {
    222 		LogError("lseek: %s", strerror(errno));
    223 		return TCSERR(TSS_E_INTERNAL_ERROR);
    224 	}
    225 
    226 	/* we found the key; file ptr is pointing at the blob */
    227 	if (*ret_buffer_size < c->blob_size) {
    228 		/* not enough room */
    229 		LogError("%s: Buf size too small. Needed %d bytes, passed %d", __FUNCTION__,
    230 				c->blob_size, *ret_buffer_size);
    231 		return TCSERR(TSS_E_INTERNAL_ERROR);
    232 	}
    233 
    234 	if ((rc = read_data(fd, ret_buffer, c->blob_size))) {
    235 		LogError("%s: error reading %d bytes", __FUNCTION__, c->blob_size);
    236 		return TCSERR(TSS_E_INTERNAL_ERROR);
    237 	}
    238 	*ret_buffer_size = c->blob_size;
    239 
    240 	return TSS_SUCCESS;
    241 }
    242 
    243 /*
    244  * return the vendor data from PS given its cache entry. The disk cache must be
    245  * locked by the caller.
    246  */
    247 TSS_RESULT
    248 psfile_get_vendor_data(int fd, struct key_disk_cache *c, UINT32 *size, BYTE **data)
    249 {
    250         int rc;
    251         UINT32 file_offset;
    252 
    253 	/* jump to the location of the data */
    254 	file_offset = TSSPS_VENDOR_DATA_OFFSET(c);
    255 
    256 	rc = lseek(fd, file_offset, SEEK_SET);
    257 	if (rc == ((off_t) - 1)) {
    258 		LogError("lseek: %s", strerror(errno));
    259 		return TCSERR(TSS_E_INTERNAL_ERROR);
    260 	}
    261 
    262 	if ((*data = malloc(c->vendor_data_size)) == NULL) {
    263 		LogError("malloc of %u bytes failed", c->vendor_data_size);
    264 		return TCSERR(TSS_E_OUTOFMEMORY);
    265 	}
    266 
    267 	if ((rc = read_data(fd, *data, c->vendor_data_size))) {
    268 		LogError("%s: error reading %u bytes", __FUNCTION__, c->vendor_data_size);
    269 		free(*data);
    270 		*data = NULL;
    271 		return TCSERR(TSS_E_INTERNAL_ERROR);
    272 	}
    273 	*size = c->vendor_data_size;
    274 
    275 	return TSS_SUCCESS;
    276 }
    277 
    278 TSS_RESULT
    279 psfile_get_ps_type_by_uuid(int fd, TSS_UUID *uuid, UINT32 *ret_ps_type)
    280 {
    281 	struct key_disk_cache *tmp;
    282 
    283 	MUTEX_LOCK(disk_cache_lock);
    284 	tmp = key_disk_cache_head;
    285 
    286         while (tmp) {
    287 		if (memcmp(uuid, &tmp->uuid, sizeof(TSS_UUID)) ||
    288 		    !(tmp->flags & CACHE_FLAG_VALID)) {
    289 			tmp = tmp->next;
    290 			continue;
    291                 }
    292 
    293 		if (tmp->flags & CACHE_FLAG_PARENT_PS_SYSTEM) {
    294 			*ret_ps_type = TSS_PS_TYPE_SYSTEM;
    295 			goto done;
    296 		} else
    297 			break;
    298         }
    299 
    300 	*ret_ps_type = TSS_PS_TYPE_USER;
    301 done:
    302 	MUTEX_UNLOCK(disk_cache_lock);
    303 	return TSS_SUCCESS;
    304 }
    305 
    306 TSS_RESULT
    307 psfile_is_pub_registered(int fd, TCPA_STORE_PUBKEY *pub, TSS_BOOL *is_reg)
    308 {
    309         int rc;
    310         UINT32 file_offset = 0;
    311         struct key_disk_cache *tmp;
    312 	char tmp_buffer[2048];
    313 
    314         MUTEX_LOCK(disk_cache_lock);
    315         tmp = key_disk_cache_head;
    316 
    317         while (tmp) {
    318 		/* if the key is of the wrong size or is invalid, try the next one */
    319                 if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
    320                         tmp = tmp->next;
    321                         continue;
    322                 }
    323 
    324 		/* we have a valid key with the same key size as the one we're looking for.
    325 		 * grab the pub key data off disk and compare it. */
    326 
    327                 /* jump to the location of the public key */
    328                 file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
    329 
    330                 rc = lseek(fd, file_offset, SEEK_SET);
    331                 if (rc == ((off_t) - 1)) {
    332                         LogError("lseek: %s", strerror(errno));
    333                         MUTEX_UNLOCK(disk_cache_lock);
    334                         return TCSERR(TSS_E_INTERNAL_ERROR);
    335                 }
    336 
    337 		DBG_ASSERT(tmp->pub_data_size < 2048);
    338 
    339 		/* read in the key */
    340                 if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
    341 			LogError("%s", __FUNCTION__);
    342                         MUTEX_UNLOCK(disk_cache_lock);
    343                         return rc;
    344                 }
    345 
    346 		/* do the compare */
    347 		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
    348 			tmp = tmp->next;
    349 			continue;
    350 		}
    351 
    352 		/* the key matches, copy the uuid out */
    353 		*is_reg = TRUE;
    354 
    355                 MUTEX_UNLOCK(disk_cache_lock);
    356                 return TSS_SUCCESS;
    357         }
    358         MUTEX_UNLOCK(disk_cache_lock);
    359         /* key not found */
    360 	*is_reg = FALSE;
    361         return TSS_SUCCESS;
    362 }
    363 
    364 
    365 TSS_RESULT
    366 psfile_get_uuid_by_pub(int fd, TCPA_STORE_PUBKEY *pub, TSS_UUID **ret_uuid)
    367 {
    368         int rc;
    369         UINT32 file_offset = 0;
    370         struct key_disk_cache *tmp;
    371 	char tmp_buffer[2048];
    372 
    373         MUTEX_LOCK(disk_cache_lock);
    374         tmp = key_disk_cache_head;
    375 
    376         while (tmp) {
    377 		/* if the key is of the wrong size or is invalid, try the next one */
    378                 if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
    379                         tmp = tmp->next;
    380                         continue;
    381                 }
    382 
    383 		/* we have a valid key with the same key size as the one we're looking for.
    384 		 * grab the pub key data off disk and compare it. */
    385 
    386                 /* jump to the location of the public key */
    387                 file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
    388 
    389                 rc = lseek(fd, file_offset, SEEK_SET);
    390                 if (rc == ((off_t) - 1)) {
    391                         LogError("lseek: %s", strerror(errno));
    392                         MUTEX_UNLOCK(disk_cache_lock);
    393                         return TCSERR(TSS_E_INTERNAL_ERROR);
    394                 }
    395 
    396 		DBG_ASSERT(tmp->pub_data_size < 2048);
    397 
    398 		if (tmp->pub_data_size > sizeof(tmp_buffer)) {
    399 			LogError("Source buffer size too big! Size:  %d",
    400 				 tmp->pub_data_size);
    401 			MUTEX_UNLOCK(disk_cache_lock);
    402 			return TCSERR(TSS_E_INTERNAL_ERROR);
    403 		}
    404 		/* read in the key */
    405                 if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
    406 			LogError("%s", __FUNCTION__);
    407                         MUTEX_UNLOCK(disk_cache_lock);
    408                         return rc;
    409                 }
    410 
    411 		/* do the compare */
    412 		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
    413 			tmp = tmp->next;
    414 			continue;
    415 		}
    416 
    417 		*ret_uuid = (TSS_UUID *)malloc(sizeof(TSS_UUID));
    418 		if (*ret_uuid == NULL) {
    419 			LogError("malloc of %zd bytes failed.", sizeof(TSS_UUID));
    420                         MUTEX_UNLOCK(disk_cache_lock);
    421 			return TCSERR(TSS_E_OUTOFMEMORY);
    422 		}
    423 
    424 		/* the key matches, copy the uuid out */
    425 		memcpy(*ret_uuid, &tmp->uuid, sizeof(TSS_UUID));
    426 
    427                 MUTEX_UNLOCK(disk_cache_lock);
    428                 return TSS_SUCCESS;
    429         }
    430         MUTEX_UNLOCK(disk_cache_lock);
    431         /* key not found */
    432         return TCSERR(TSS_E_PS_KEY_NOTFOUND);
    433 }
    434 
    435 TSS_RESULT
    436 psfile_get_key_by_pub(int fd, TCPA_STORE_PUBKEY *pub, UINT32 *size, BYTE **ret_key)
    437 {
    438         int rc;
    439         UINT32 file_offset = 0;
    440         struct key_disk_cache *tmp;
    441 	BYTE tmp_buffer[4096];
    442 
    443         MUTEX_LOCK(disk_cache_lock);
    444         tmp = key_disk_cache_head;
    445 
    446         while (tmp) {
    447 		/* if the key is of the wrong size or is invalid, try the next one */
    448                 if (pub->keyLength != tmp->pub_data_size || !(tmp->flags & CACHE_FLAG_VALID)) {
    449                         tmp = tmp->next;
    450                         continue;
    451                 }
    452 
    453 		/* we have a valid key with the same key size as the one we're looking for.
    454 		 * grab the pub key data off disk and compare it. */
    455 
    456                 /* jump to the location of the public key */
    457                 file_offset = TSSPS_PUB_DATA_OFFSET(tmp);
    458 
    459                 rc = lseek(fd, file_offset, SEEK_SET);
    460                 if (rc == ((off_t) - 1)) {
    461                         LogError("lseek: %s", strerror(errno));
    462                         MUTEX_UNLOCK(disk_cache_lock);
    463                         return TCSERR(TSS_E_INTERNAL_ERROR);
    464                 }
    465 
    466 		DBG_ASSERT(tmp->pub_data_size < 2048);
    467 		if (tmp->pub_data_size > sizeof(tmp_buffer)) {
    468 			LogError("Source buffer size too big! Size:  %d",
    469 				 tmp->pub_data_size);
    470 			MUTEX_UNLOCK(disk_cache_lock);
    471 			return TCSERR(TSS_E_INTERNAL_ERROR);
    472 		}
    473 
    474 		/* read in the key */
    475                 if ((rc = read_data(fd, tmp_buffer, tmp->pub_data_size))) {
    476 			LogError("%s", __FUNCTION__);
    477                         MUTEX_UNLOCK(disk_cache_lock);
    478                         return rc;
    479                 }
    480 
    481 		/* do the compare */
    482 		if (memcmp(tmp_buffer, pub->key, tmp->pub_data_size)) {
    483 			tmp = tmp->next;
    484 			continue;
    485 		}
    486 
    487                 /* jump to the location of the key blob */
    488                 file_offset = TSSPS_BLOB_DATA_OFFSET(tmp);
    489 
    490                 rc = lseek(fd, file_offset, SEEK_SET);
    491                 if (rc == ((off_t) - 1)) {
    492                         LogError("lseek: %s", strerror(errno));
    493                         MUTEX_UNLOCK(disk_cache_lock);
    494                         return TCSERR(TSS_E_INTERNAL_ERROR);
    495                 }
    496 
    497 		DBG_ASSERT(tmp->blob_size < 4096);
    498 		if (tmp->blob_size > sizeof(tmp_buffer)) {
    499 			LogError("Blob size greater than 4096! Size:  %d",
    500 				 tmp->blob_size);
    501 			MUTEX_UNLOCK(disk_cache_lock);
    502 			return TCSERR(TSS_E_INTERNAL_ERROR);
    503 		}
    504 
    505 		/* read in the key blob */
    506                 if ((rc = read_data(fd, tmp_buffer, tmp->blob_size))) {
    507 			LogError("%s", __FUNCTION__);
    508                         MUTEX_UNLOCK(disk_cache_lock);
    509                         return rc;
    510                 }
    511 
    512 		*ret_key = malloc(tmp->blob_size);
    513 		if (*ret_key == NULL) {
    514 			LogError("malloc of %d bytes failed.", tmp->blob_size);
    515                         MUTEX_UNLOCK(disk_cache_lock);
    516 			return TCSERR(TSS_E_OUTOFMEMORY);
    517 		}
    518 
    519 		memcpy(*ret_key, tmp_buffer, tmp->blob_size);
    520 		*size = tmp->blob_size;
    521 
    522                 MUTEX_UNLOCK(disk_cache_lock);
    523                 return rc;
    524         }
    525         MUTEX_UNLOCK(disk_cache_lock);
    526         /* key not found */
    527         return -2;
    528 }
    529 
    530 /*
    531  * disk store format:
    532  *
    533  * TrouSerS 0.2.0 and before:
    534  * Version 0:                  cached?
    535  * [UINT32   num_keys_on_disk]
    536  * [TSS_UUID uuid0           ] yes
    537  * [TSS_UUID uuid_parent0    ] yes
    538  * [UINT16   pub_data_size0  ] yes
    539  * [UINT16   blob_size0      ] yes
    540  * [UINT16   cache_flags0    ] yes
    541  * [BYTE[]   pub_data0       ]
    542  * [BYTE[]   blob0           ]
    543  * [...]
    544  *
    545  * TrouSerS 0.2.1+
    546  * Version 1:                  cached?
    547  * [BYTE     PS version = '\1']
    548  * [UINT32   num_keys_on_disk ]
    549  * [TSS_UUID uuid0            ] yes
    550  * [TSS_UUID uuid_parent0     ] yes
    551  * [UINT16   pub_data_size0   ] yes
    552  * [UINT16   blob_size0       ] yes
    553  * [UINT32   vendor_data_size0] yes
    554  * [UINT16   cache_flags0     ] yes
    555  * [BYTE[]   pub_data0        ]
    556  * [BYTE[]   blob0            ]
    557  * [BYTE[]   vendor_data0     ]
    558  * [...]
    559  *
    560  */
    561 TSS_RESULT
    562 psfile_write_key(int fd,
    563 		TSS_UUID *uuid,
    564 		TSS_UUID *parent_uuid,
    565 		UINT32 *parent_ps,
    566 		BYTE *vendor_data,
    567 		UINT32 vendor_size,
    568 		BYTE *key_blob,
    569 		UINT16 key_blob_size)
    570 {
    571 	TSS_KEY key;
    572 	UINT16 pub_key_size, cache_flags = CACHE_FLAG_VALID;
    573 	UINT64 offset;
    574 	int rc = 0;
    575 
    576 	/* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */
    577 	if (*parent_ps == TSS_PS_TYPE_SYSTEM)
    578 		cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM;
    579 
    580 	/* Unload the blob to get the public key */
    581 	offset = 0;
    582 	if ((rc = UnloadBlob_TSS_KEY(&offset, key_blob, &key)))
    583 		return rc;
    584 
    585 	pub_key_size = key.pubKey.keyLength;
    586 
    587         if ((rc = write_key_init(fd, pub_key_size, key_blob_size, vendor_size)) < 0)
    588                 goto done;
    589 
    590 	/* offset now holds the number of bytes from the beginning of the file
    591 	 * the key will be stored at
    592 	 */
    593 	offset = rc;
    594 
    595 #ifdef TSS_DEBUG
    596 	if (offset == 0)
    597 		LogDebug("ERROR: key being written with offset 0!!");
    598 #endif
    599 
    600 	/* [TSS_UUID uuid0           ] yes */
    601         if ((rc = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) {
    602 		LogError("%s", __FUNCTION__);
    603                 goto done;
    604 	}
    605 
    606 	/* [TSS_UUID uuid_parent0    ] yes */
    607         if ((rc = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) {
    608 		LogError("%s", __FUNCTION__);
    609                 goto done;
    610 	}
    611 
    612 	/* [UINT16   pub_data_size0  ] yes */
    613 	pub_key_size = LE_16(pub_key_size);
    614         if ((rc = write_data(fd, &pub_key_size, sizeof(UINT16)))) {
    615 		LogError("%s", __FUNCTION__);
    616                 goto done;
    617 	}
    618 	/* Swap it back for later */
    619 	pub_key_size = LE_16(pub_key_size);
    620 
    621 	/* [UINT16   blob_size0      ] yes */
    622 	key_blob_size = LE_16(key_blob_size);
    623         if ((rc = write_data(fd, &key_blob_size, sizeof(UINT16)))) {
    624 		LogError("%s", __FUNCTION__);
    625                 goto done;
    626 	}
    627 	/* Swap it back for later */
    628 	key_blob_size = LE_16(key_blob_size);
    629 
    630 	/* [UINT32   vendor_data_size0 ] yes */
    631 	vendor_size = LE_32(vendor_size);
    632         if ((rc = write_data(fd, &vendor_size, sizeof(UINT32)))) {
    633 		LogError("%s", __FUNCTION__);
    634                 goto done;
    635 	}
    636 	/* Swap it back for later */
    637 	vendor_size = LE_32(vendor_size);
    638 
    639 	/* [UINT16   cache_flags0    ] yes */
    640 	cache_flags = LE_16(cache_flags);
    641         if ((rc = write_data(fd, &cache_flags, sizeof(UINT16)))) {
    642 		LogError("%s", __FUNCTION__);
    643                 goto done;
    644 	}
    645 	/* Swap it back for later */
    646 	cache_flags = LE_16(cache_flags);
    647 
    648 	/* [BYTE[]   pub_data0       ] no */
    649         if ((rc = write_data(fd, (void *)key.pubKey.key, pub_key_size))) {
    650 		LogError("%s", __FUNCTION__);
    651                 goto done;
    652 	}
    653 
    654 	/* [BYTE[]   blob0           ] no */
    655         if ((rc = write_data(fd, (void *)key_blob, key_blob_size))) {
    656 		LogError("%s", __FUNCTION__);
    657                 goto done;
    658 	}
    659 
    660 	/* [BYTE[]   vendor_data0    ] no */
    661 	if (vendor_size > 0) {
    662 		if ((rc = write_data(fd, (void *)vendor_data, vendor_size))) {
    663 			LogError("%s", __FUNCTION__);
    664 			goto done;
    665 		}
    666 	}
    667 
    668 	if ((rc = cache_key((UINT32)offset, cache_flags, uuid, parent_uuid, pub_key_size,
    669 					key_blob_size, vendor_size)))
    670                 goto done;
    671 done:
    672 	destroy_key_refs(&key);
    673 
    674         return rc;
    675 }
    676 
    677 TSS_RESULT
    678 psfile_remove_key(int fd, struct key_disk_cache *c)
    679 {
    680         TSS_RESULT result;
    681         UINT32 head_offset = 0, tail_offset, num_keys;
    682 	BYTE buf[4096];
    683 	struct stat stat_buf;
    684 	int rc, size = 0;
    685 
    686 	if ((rc = fstat(fd, &stat_buf)) != 0) {
    687 		LogError("fstat: %s", strerror(errno));
    688 		return TSS_E_INTERNAL_ERROR;
    689 	}
    690 
    691 	/* head_offset is the offset the beginning of the key */
    692 	head_offset = TSSPS_UUID_OFFSET(c);
    693 
    694 	/* tail_offset is the offset the beginning of the next key */
    695 	tail_offset = TSSPS_VENDOR_DATA_OFFSET(c) + c->vendor_data_size;
    696 
    697 	rc = lseek(fd, tail_offset, SEEK_SET);
    698 	if (rc == ((off_t) - 1)) {
    699 		LogError("lseek: %s", strerror(errno));
    700 		return TCSERR(TSS_E_INTERNAL_ERROR);
    701 	}
    702 
    703 	/* read in from tail, write out to head to fill the gap */
    704 	while ((rc = read(fd, buf, sizeof(buf))) > 0) {
    705 		size = rc;
    706 		tail_offset += size;
    707 
    708 		/* set the file pointer to where we want to write */
    709 		rc = lseek(fd, head_offset, SEEK_SET);
    710 		if (rc == ((off_t) - 1)) {
    711 			LogError("lseek: %s", strerror(errno));
    712 			return TCSERR(TSS_E_INTERNAL_ERROR);
    713 		}
    714 
    715 		/* write the data */
    716 		if ((result = write_data(fd, (void *)buf, size))) {
    717 			LogError("%s", __FUNCTION__);
    718 			return result;
    719 		}
    720 		head_offset += size;
    721 
    722 		/* set the file pointer to where we want to read in the next
    723 		 * loop */
    724 		rc = lseek(fd, tail_offset, SEEK_SET);
    725 		if (rc == ((off_t) - 1)) {
    726 			LogError("lseek: %s", strerror(errno));
    727 			return TCSERR(TSS_E_INTERNAL_ERROR);
    728 		}
    729 	}
    730 
    731 	if (rc < 0) {
    732 		LogError("read: %s", strerror(errno));
    733 		return TCSERR(TSS_E_INTERNAL_ERROR);
    734 	}
    735 
    736 	/* set the file pointer to where we want to write */
    737 	rc = lseek(fd, head_offset, SEEK_SET);
    738 	if (rc == ((off_t) - 1)) {
    739 		LogError("lseek: %s", strerror(errno));
    740 		return TCSERR(TSS_E_INTERNAL_ERROR);
    741 	}
    742 
    743 	/* head_offset now contains a pointer to where we want to truncate the
    744 	 * file. Zero out the old tail end of the file and truncate it. */
    745 
    746 	memset(buf, 0, sizeof(buf));
    747 
    748 	/* Zero out the old tail end of the file */
    749 	if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) {
    750 		LogError("%s", __FUNCTION__);
    751 		return result;
    752 	}
    753 
    754 	if ((rc = ftruncate(fd, head_offset)) < 0) {
    755 		LogError("ftruncate: %s", strerror(errno));
    756 		return TCSERR(TSS_E_INTERNAL_ERROR);
    757 	}
    758 
    759 	/* we succeeded in removing a key from the disk. Decrement the number
    760 	 * of keys in the file */
    761 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
    762 	if (rc == ((off_t) - 1)) {
    763 		LogError("lseek: %s", strerror(errno));
    764 		return TCSERR(TSS_E_INTERNAL_ERROR);
    765 	}
    766 
    767 	rc = read(fd, &num_keys, sizeof(UINT32));
    768 	num_keys = LE_32(num_keys);
    769 	if (rc != sizeof(UINT32)) {
    770 		LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
    771 		return TCSERR(TSS_E_INTERNAL_ERROR);
    772 	}
    773 
    774 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
    775 	if (rc == ((off_t) - 1)) {
    776 		LogError("lseek: %s", strerror(errno));
    777 		return TCSERR(TSS_E_INTERNAL_ERROR);
    778 	}
    779 
    780 	/* decrement, then write back out to disk */
    781 	num_keys--;
    782 
    783 	num_keys = LE_32(num_keys);
    784 	if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) {
    785 		LogError("%s", __FUNCTION__);
    786 		return result;
    787 	}
    788 
    789 	return TSS_SUCCESS;
    790 }
    791