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