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 <pwd.h>
18 #include <sys/types.h>
19 #include <sys/file.h>
20 #include <sys/stat.h>
21 #include <assert.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <netdb.h>
25 #if defined (HAVE_BYTEORDER_H)
26 #include <sys/byteorder.h>
27 #elif defined (HTOLE_DEFINED)
28 
29 #ifndef __APPLE__
30 #include <endian.h>
31 #else
32 #include "portable_endian.h"
33 #endif
34 
35 #define LE_16 htole16
36 #define LE_32 htole32
37 #define LE_64 htole64
38 #else
39 #define LE_16(x) (x)
40 #define LE_32(x) (x)
41 #define LE_64(x) (x)
42 #endif
43 
44 #include "trousers/tss.h"
45 #include "trousers/trousers.h"
46 #include "trousers_types.h"
47 #include "tcs_tsp.h"
48 #include "spi_utils.h"
49 #include "tspps.h"
50 #include "tsplog.h"
51 
52 static int user_ps_fd = -1;
53 static MUTEX_DECLARE_INIT(user_ps_lock);
54 #if (defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__))
55 static MUTEX_DECLARE_INIT(user_ps_path);
56 #endif
57 static struct flock fl;
58 
59 
60 /*
61  * Determine the default path to the persistent storage file and create it if it doesn't exist.
62  */
63 TSS_RESULT
get_user_ps_path(char ** file)64 get_user_ps_path(char **file)
65 {
66 	TSS_RESULT result;
67 	char *file_name = NULL, *home_dir = NULL;
68 	struct passwd *pwp;
69 #if (defined (__linux) || defined (linux) || defined(__GLIBC__))
70 	struct passwd pw;
71 #endif
72 	struct stat stat_buf;
73 	char buf[PASSWD_BUFSIZE];
74 	uid_t euid;
75 	int rc;
76 
77 	if ((file_name = getenv("TSS_USER_PS_FILE"))) {
78 		*file = strdup(file_name);
79 		return (*file) ? TSS_SUCCESS : TSPERR(TSS_E_OUTOFMEMORY);
80 	}
81 #if (defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__))
82 	MUTEX_LOCK(user_ps_path);
83 #endif
84 
85 	euid = geteuid();
86 
87 #if defined (SOLARIS)
88 	/*
89          * Solaris keeps user PS in a local directory instead of
90          * in the user's home directory, which may be shared
91          * by multiple systems.
92          *
93          * The directory path on Solaris is /var/tpm/userps/[EUID]/
94          */
95         rc = snprintf(buf, sizeof (buf), "%s/%d", TSS_USER_PS_DIR, euid);
96 #else
97 	setpwent();
98 	while (1) {
99 #if (defined (__linux) || defined (linux) || defined(__GLIBC__))
100 		rc = getpwent_r(&pw, buf, PASSWD_BUFSIZE, &pwp);
101 		if (rc) {
102 			LogDebugFn("USER PS: Error getting path to home directory: getpwent_r: %s",
103 				   strerror(rc));
104 			endpwent();
105 			return TSPERR(TSS_E_INTERNAL_ERROR);
106 		}
107 
108 #elif (defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__))
109 		if ((pwp = getpwent()) == NULL) {
110 			LogDebugFn("USER PS: Error getting path to home directory: getpwent: %s",
111                                    strerror(rc));
112 			endpwent();
113 			MUTEX_UNLOCK(user_ps_path);
114 			return TSPERR(TSS_E_INTERNAL_ERROR);
115 		}
116 #endif
117 		if (euid == pwp->pw_uid) {
118                         home_dir = strdup(pwp->pw_dir);
119                         break;
120                 }
121         }
122         endpwent();
123 
124 	if (!home_dir)
125 		return TSPERR(TSS_E_OUTOFMEMORY);
126 
127 	/* Tack on TSS_USER_PS_DIR and see if it exists */
128 	rc = snprintf(buf, sizeof (buf), "%s/%s", home_dir, TSS_USER_PS_DIR);
129 #endif /* SOLARIS */
130 	if (rc == sizeof (buf)) {
131 		LogDebugFn("USER PS: Path to file too long! (> %d bytes)", PASSWD_BUFSIZE);
132 		result = TSPERR(TSS_E_INTERNAL_ERROR);
133 		goto done;
134 	}
135 
136 	errno = 0;
137 	if ((rc = stat(buf, &stat_buf)) == -1) {
138 		if (errno == ENOENT) {
139 			errno = 0;
140 			/* Create the user's ps directory if it is not there. */
141 			if ((rc = mkdir(buf, 0700)) == -1) {
142 				LogDebugFn("USER PS: Error creating dir: %s: %s", buf,
143 					   strerror(errno));
144 				result = TSPERR(TSS_E_INTERNAL_ERROR);
145 				goto done;
146 			}
147 		} else {
148 			LogDebugFn("USER PS: Error stating dir: %s: %s", buf, strerror(errno));
149 			result = TSPERR(TSS_E_INTERNAL_ERROR);
150 			goto done;
151 		}
152 	}
153 
154 	/* Directory exists or has been created, return the path to the file */
155 #if defined (SOLARIS)
156 	rc = snprintf(buf, sizeof (buf), "%s/%d/%s", TSS_USER_PS_DIR, euid,
157 		      TSS_USER_PS_FILE);
158 #else
159 	rc = snprintf(buf, sizeof (buf), "%s/%s/%s", home_dir, TSS_USER_PS_DIR,
160 		      TSS_USER_PS_FILE);
161 #endif
162 	if (rc == sizeof (buf)) {
163 		LogDebugFn("USER PS: Path to file too long! (> %zd bytes)", sizeof (buf));
164 	} else
165 		*file = strdup(buf);
166 
167 	result = (*file) ? TSS_SUCCESS : TSPERR(TSS_E_OUTOFMEMORY);
168 done:
169 	free(home_dir);
170 	return result;
171 }
172 
173 TSS_RESULT
get_file(int * fd)174 get_file(int *fd)
175 {
176 	TSS_RESULT result;
177 	int rc = 0;
178 	char *file_name = NULL;
179 
180 	MUTEX_LOCK(user_ps_lock);
181 
182 	/* check the global file handle first.  If it exists, lock it and return */
183 	if (user_ps_fd != -1) {
184 		fl.l_type = F_WRLCK;
185 		if ((rc = fcntl(user_ps_fd, F_SETLKW, &fl))) {
186 			LogDebug("USER PS: failed to lock file: %s", strerror(errno));
187 			MUTEX_UNLOCK(user_ps_lock);
188 			return TSPERR(TSS_E_INTERNAL_ERROR);
189 		}
190 		*fd = user_ps_fd;
191 		return TSS_SUCCESS;
192 	}
193 
194 	/* open and lock the file */
195 	if ((result = get_user_ps_path(&file_name))) {
196 		LogDebugFn("USER PS: error getting file path");
197 		MUTEX_UNLOCK(user_ps_lock);
198 		return result;
199 	}
200 
201 	user_ps_fd = open(file_name, O_CREAT|O_RDWR, 0600);
202 	if (user_ps_fd < 0) {
203 		LogDebug("USER PS: open of %s failed: %s", file_name, strerror(errno));
204 		free(file_name);
205 		MUTEX_UNLOCK(user_ps_lock);
206 		return TSPERR(TSS_E_INTERNAL_ERROR);
207 	}
208 	fl.l_type = F_WRLCK;
209 	if ((rc = fcntl(user_ps_fd, F_SETLKW, &fl))) {
210 		LogDebug("USER PS: failed to get lock of %s: %s", file_name, strerror(errno));
211 		free(file_name);
212 		close(user_ps_fd);
213 		user_ps_fd = -1;
214 		MUTEX_UNLOCK(user_ps_lock);
215 		return TSPERR(TSS_E_INTERNAL_ERROR);
216 	}
217 
218 	*fd = user_ps_fd;
219 	free(file_name);
220 	return TSS_SUCCESS;
221 }
222 
223 int
put_file(int fd)224 put_file(int fd)
225 {
226 	int rc = 0;
227 
228 	fsync(fd);
229 
230 	/* release the file lock */
231 	fl.l_type = F_UNLCK;
232 	if ((rc = fcntl(fd, F_SETLKW, &fl))) {
233 		LogDebug("USER PS: failed to unlock file: %s", strerror(errno));
234 		rc = -1;
235 	}
236 
237 	MUTEX_UNLOCK(user_ps_lock);
238 	return rc;
239 }
240 
241 void
psfile_close(int fd)242 psfile_close(int fd)
243 {
244 	close(fd);
245 	user_ps_fd = -1;
246 	MUTEX_UNLOCK(user_ps_lock);
247 }
248 
249 TSS_RESULT
psfile_is_key_registered(int fd,TSS_UUID * uuid,TSS_BOOL * answer)250 psfile_is_key_registered(int fd, TSS_UUID *uuid, TSS_BOOL *answer)
251 {
252         TSS_RESULT result;
253         struct key_disk_cache tmp;
254 
255 	if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp)) == TSS_SUCCESS)
256 		*answer = TRUE;
257 	else if (result == (TSS_E_PS_KEY_NOTFOUND | TSS_LAYER_TSP))
258 		*answer = FALSE;
259         else
260                 return result;
261 
262         return TSS_SUCCESS;
263 }
264 
265 TSS_RESULT
psfile_get_parent_uuid_by_uuid(int fd,TSS_UUID * uuid,TSS_UUID * ret_uuid)266 psfile_get_parent_uuid_by_uuid(int fd, TSS_UUID *uuid, TSS_UUID *ret_uuid)
267 {
268 	TSS_RESULT result;
269         struct key_disk_cache tmp;
270 
271 	if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp)))
272 		return result;
273 
274 	memcpy(ret_uuid, &tmp.parent_uuid, sizeof(TSS_UUID));
275 
276         return TSS_SUCCESS;
277 }
278 
279 TSS_RESULT
psfile_get_parent_ps_type(int fd,TSS_UUID * uuid,UINT32 * type)280 psfile_get_parent_ps_type(int fd, TSS_UUID *uuid, UINT32 *type)
281 {
282 	TSS_RESULT result;
283         struct key_disk_cache tmp;
284 
285 	if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp)))
286 		return result;
287 
288 	if (tmp.flags & CACHE_FLAG_PARENT_PS_SYSTEM)
289 		*type = TSS_PS_TYPE_SYSTEM;
290 	else
291 		*type = TSS_PS_TYPE_USER;
292 
293         return TSS_SUCCESS;
294 }
295 
296 /*
297  * return a key struct from PS given a uuid
298  */
299 TSS_RESULT
psfile_get_key_by_uuid(int fd,TSS_UUID * uuid,BYTE * key)300 psfile_get_key_by_uuid(int fd, TSS_UUID *uuid, BYTE *key)
301 {
302         int rc;
303 	TSS_RESULT result;
304         off_t file_offset;
305         struct key_disk_cache tmp;
306 	BYTE buf[4096];
307 
308 	if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &tmp)))
309 		return result;
310 
311 	/* jump to the location of the key blob */
312 	file_offset = TSSPS_BLOB_DATA_OFFSET(&tmp);
313 
314 	rc = lseek(fd, file_offset, SEEK_SET);
315 	if (rc == ((off_t)-1)) {
316 		LogDebugFn("lseek: %s", strerror(errno));
317 		return TSPERR(TSS_E_INTERNAL_ERROR);
318 	}
319 
320 	if (tmp.blob_size > 4096) {
321 		LogError("Blob size greater than 4096! Size:  %d",
322 			  tmp.blob_size);
323 		return TSPERR(TSS_E_INTERNAL_ERROR);
324 	}
325 	if ((rc = read_data(fd, buf, tmp.blob_size))) {
326 		LogDebugFn("Blob read from disk failed.");
327 		return rc;
328 	}
329 
330 	memcpy(key, buf, tmp.blob_size);
331 	return TSS_SUCCESS;
332 }
333 
334 /*
335  * return a key struct from PS given a public key
336  */
337 TSS_RESULT
psfile_get_key_by_pub(int fd,TSS_UUID * uuid,UINT32 pub_size,BYTE * pub,BYTE * key)338 psfile_get_key_by_pub(int fd, TSS_UUID *uuid, UINT32 pub_size, BYTE *pub, BYTE *key)
339 {
340         int rc;
341 	TSS_RESULT result;
342         off_t file_offset;
343         struct key_disk_cache tmp;
344 	BYTE buf[4096];
345 
346 	if ((result = psfile_get_cache_entry_by_pub(fd, pub_size, pub, &tmp)))
347 		return result;
348 
349 	/* jump to the location of the key blob */
350 	file_offset = TSSPS_BLOB_DATA_OFFSET(&tmp);
351 
352 	rc = lseek(fd, file_offset, SEEK_SET);
353 	if (rc == ((off_t)-1)) {
354 		LogDebugFn("lseek: %s", strerror(errno));
355 		return TSPERR(TSS_E_INTERNAL_ERROR);
356 	}
357 
358 	if (tmp.blob_size > 4096) {
359 		LogError("Blob size greater than 4096! Size:  %d",
360 			  tmp.blob_size);
361 		return TSPERR(TSS_E_INTERNAL_ERROR);
362 	}
363 
364 	if ((result = read_data(fd, buf, tmp.blob_size))) {
365 		LogDebugFn("Blob read from disk failed.");
366 		return result;
367 	}
368 
369 	memcpy(key, buf, tmp.blob_size);
370 	memcpy(uuid, &tmp.uuid, sizeof(TSS_UUID));
371 
372 	return TSS_SUCCESS;
373 }
374 
375 TSS_RESULT
psfile_get_uuid_by_pub(int fd,UINT32 pub_size,BYTE * pub,TSS_UUID * uuid)376 psfile_get_uuid_by_pub(int fd, UINT32 pub_size, BYTE *pub, TSS_UUID *uuid)
377 {
378 	TSS_RESULT result;
379         struct key_disk_cache tmp;
380 
381 	if ((result = psfile_get_cache_entry_by_pub(fd, pub_size, pub, &tmp)))
382 		return result;
383 
384 	memcpy(uuid, &tmp.uuid, sizeof(TSS_UUID));
385 
386         return TSS_SUCCESS;
387 }
388 
389 TSS_RESULT
psfile_change_num_keys(int fd,BYTE increment)390 psfile_change_num_keys(int fd, BYTE increment)
391 {
392 	int rc;
393 	TSS_RESULT result;
394 	UINT32 num_keys;
395 
396 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
397 	if (rc == ((off_t)-1)) {
398 		LogDebug("lseek: %s", strerror(errno));
399 		return TSPERR(TSS_E_INTERNAL_ERROR);
400 	}
401 
402 	rc = read(fd, &num_keys, sizeof(UINT32));
403 	if (rc != sizeof(UINT32)) {
404 		LogDebug("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
405 		return TSPERR(TSS_E_INTERNAL_ERROR);
406 	}
407 	num_keys = LE_32(num_keys);
408 
409 	if (increment)
410 		num_keys++;
411 	else
412 		num_keys--;
413 
414 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
415 	if (rc == ((off_t)-1)) {
416 		LogDebug("lseek: %s", strerror(errno));
417 		return TSPERR(TSS_E_INTERNAL_ERROR);
418 	}
419 
420 	num_keys = LE_32(num_keys);
421 	if ((result = write_data(fd, (void *)&num_keys, sizeof(UINT32)))) {
422 		LogDebug("%s", __FUNCTION__);
423 		return result;
424 	}
425 
426 	return TSS_SUCCESS;
427 }
428 
429 /* Write the initial header (number of keys and PS version) to initialize a new file */
430 TSS_RESULT
psfile_write_key_header(int fd)431 psfile_write_key_header(int fd)
432 {
433 	int rc;
434 	TSS_RESULT result;
435 	UINT32 i;
436 
437 	rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET);
438 	if (rc == ((off_t)-1)) {
439 		LogDebug("lseek: %s", strerror(errno));
440 		return TSPERR(TSS_E_INTERNAL_ERROR);
441 	}
442 
443 	i = TSSPS_VERSION;
444         if ((result = write_data(fd, &i, sizeof(BYTE)))) {
445 		LogDebug("%s", __FUNCTION__);
446 		return result;
447 	}
448 
449 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
450 	if (rc == ((off_t)-1)) {
451 		LogDebug("lseek: %s", strerror(errno));
452 		return TSPERR(TSS_E_INTERNAL_ERROR);
453 	}
454 
455 	i = 0;
456         if ((result = write_data(fd, &i, sizeof(UINT32)))) {
457 		LogDebug("%s", __FUNCTION__);
458 		return result;
459 	}
460 
461 	return TSS_SUCCESS;
462 }
463 
464 /*
465  * disk store format:
466  *
467  * TrouSerS 0.2.1+
468  * Version 1:                  cached?
469  * [BYTE     PS version = '\1']
470  * [UINT32   num_keys_on_disk ]
471  * [TSS_UUID uuid0            ] yes
472  * [TSS_UUID uuid_parent0     ] yes
473  * [UINT16   pub_data_size0   ] yes
474  * [UINT16   blob_size0       ] yes
475  * [UINT32   vendor_data_size0] yes
476  * [UINT16   cache_flags0     ] yes
477  * [BYTE[]   pub_data0        ]
478  * [BYTE[]   blob0            ]
479  * [BYTE[]   vendor_data0     ]
480  * [...]
481  *
482  */
483 TSS_RESULT
psfile_write_key(int fd,TSS_UUID * uuid,TSS_UUID * parent_uuid,UINT32 parent_ps,BYTE * key_blob,UINT16 key_blob_size)484 psfile_write_key(int fd,
485 		 TSS_UUID *uuid,
486 		 TSS_UUID *parent_uuid,
487 		 UINT32 parent_ps,
488 		 BYTE *key_blob,
489 		 UINT16 key_blob_size)
490 {
491 	TSS_RESULT result;
492 	TSS_KEY key;
493 	UINT32 zero = 0;
494 	UINT64 offset;
495 	UINT16 pub_key_size, cache_flags = 0;
496 	struct stat stat_buf;
497 	int rc, file_offset;
498 
499 	/* leaving the cache flag for parent ps type as 0 implies TSS_PS_TYPE_USER */
500 	if (parent_ps == TSS_PS_TYPE_SYSTEM)
501 		cache_flags |= CACHE_FLAG_PARENT_PS_SYSTEM;
502 
503 	if ((rc = fstat(fd, &stat_buf)) == -1) {
504 		LogDebugFn("stat failed: %s", strerror(errno));
505 		return TSPERR(TSS_E_INTERNAL_ERROR);
506 	}
507 
508 	file_offset = stat_buf.st_size;
509 
510 	if (file_offset < (int)TSSPS_KEYS_OFFSET) {
511 		if ((result = psfile_write_key_header(fd)))
512 			return result;
513 		file_offset = TSSPS_KEYS_OFFSET;
514 	}
515 
516 	rc = lseek(fd, file_offset, SEEK_SET);
517 	if (rc == ((off_t)-1)) {
518 		LogDebug("lseek: %s", strerror(errno));
519 		return TSPERR(TSS_E_INTERNAL_ERROR);
520 	}
521 
522 	/* Unload the blob to get the public key */
523 	offset = 0;
524 	if ((result = UnloadBlob_TSS_KEY(&offset, key_blob, &key)))
525 		return result;
526 
527 	pub_key_size = key.pubKey.keyLength;
528 
529 	/* [TSS_UUID uuid0           ] yes */
530         if ((result = write_data(fd, (void *)uuid, sizeof(TSS_UUID)))) {
531 		LogDebug("%s", __FUNCTION__);
532 		goto done;
533 	}
534 
535 	/* [TSS_UUID uuid_parent0    ] yes */
536         if ((result = write_data(fd, (void *)parent_uuid, sizeof(TSS_UUID)))) {
537 		LogDebug("%s", __FUNCTION__);
538 		goto done;
539 	}
540 
541 	/* [UINT16   pub_data_size0  ] yes */
542 	pub_key_size = LE_16(pub_key_size);
543         if ((result = write_data(fd, &pub_key_size, sizeof(UINT16)))) {
544 		LogDebug("%s", __FUNCTION__);
545 		goto done;
546 	}
547 	pub_key_size = LE_16(pub_key_size);
548 
549 	/* [UINT16   blob_size0      ] yes */
550 	key_blob_size = LE_16(key_blob_size);
551         if ((result = write_data(fd, &key_blob_size, sizeof(UINT16)))) {
552 		LogDebug("%s", __FUNCTION__);
553 		goto done;
554 	}
555 	key_blob_size = LE_16(key_blob_size);
556 
557 	/* [UINT32   vendor_data_size0 ] yes */
558         if ((result = write_data(fd, &zero, sizeof(UINT32)))) {
559 		LogDebug("%s", __FUNCTION__);
560 		goto done;
561 	}
562 
563 	/* [UINT16   cache_flags0    ] yes */
564 	cache_flags = LE_16(cache_flags);
565         if ((result = write_data(fd, &cache_flags, sizeof(UINT16)))) {
566 		LogDebug("%s", __FUNCTION__);
567 		goto done;
568 	}
569 	cache_flags = LE_16(cache_flags);
570 
571 	/* [BYTE[]   pub_data0       ] no */
572         if ((result = write_data(fd, (void *)key.pubKey.key, pub_key_size))) {
573 		LogDebug("%s", __FUNCTION__);
574 		goto done;
575 	}
576 
577 	/* [BYTE[]   blob0           ] no */
578         if ((result = write_data(fd, (void *)key_blob, key_blob_size))) {
579 		LogDebug("%s", __FUNCTION__);
580 		goto done;
581 	}
582 
583 	if ((result = psfile_change_num_keys(fd, TSS_PSFILE_INCREMENT_NUM_KEYS))) {
584 		LogDebug("%s", __FUNCTION__);
585 		goto done;
586 	}
587 
588 done:
589 	free_key_refs(&key);
590         return result;
591 }
592 
593 TSS_RESULT
psfile_remove_key(int fd,TSS_UUID * uuid)594 psfile_remove_key(int fd, TSS_UUID *uuid)
595 {
596         TSS_RESULT result;
597         UINT32 head_offset = 0, tail_offset;
598 	int rc, size = 0;
599 	struct key_disk_cache c;
600 	BYTE buf[4096];
601 
602 	if ((result = psfile_get_cache_entry_by_uuid(fd, uuid, &c)))
603 		return result;
604 
605 	/* head_offset is the offset the beginning of the key */
606 	head_offset = TSSPS_UUID_OFFSET(&c);
607 
608 	/* tail_offset is the offset the beginning of the next key */
609 	tail_offset = TSSPS_VENDOR_DATA_OFFSET(&c) + c.vendor_data_size;
610 
611 	rc = lseek(fd, tail_offset, SEEK_SET);
612 	if (rc == ((off_t)-1)) {
613 		LogDebug("lseek: %s", strerror(errno));
614 		return TSPERR(TSS_E_INTERNAL_ERROR);
615 	}
616 
617 	/* read in from tail, write out to head to fill the gap */
618 	while ((rc = read(fd, buf, sizeof(buf))) > 0) {
619 		size = rc;
620 		tail_offset += size;
621 
622 		/* set the file pointer to where we want to write */
623 		rc = lseek(fd, head_offset, SEEK_SET);
624 		if (rc == ((off_t)-1)) {
625 			LogDebug("lseek: %s", strerror(errno));
626 			return TSPERR(TSS_E_INTERNAL_ERROR);
627 		}
628 
629 		/* write the data */
630 		if ((result = write_data(fd, (void *)buf, size))) {
631 			LogDebug("%s", __FUNCTION__);
632 			return result;
633 		}
634 		head_offset += size;
635 
636 		/* set the file pointer to where we want to read in the next
637 		 * loop */
638 		rc = lseek(fd, tail_offset, SEEK_SET);
639 		if (rc == ((off_t)-1)) {
640 			LogDebug("lseek: %s", strerror(errno));
641 			return TSPERR(TSS_E_INTERNAL_ERROR);
642 		}
643 	}
644 
645 	if (rc < 0) {
646 		LogDebug("read: %s", strerror(errno));
647 		return TSPERR(TSS_E_INTERNAL_ERROR);
648 	}
649 
650 	/* set the file pointer to where we want to write */
651 	rc = lseek(fd, head_offset, SEEK_SET);
652 	if (rc == ((off_t)-1)) {
653 		LogDebug("lseek: %s", strerror(errno));
654 		return TSPERR(TSS_E_INTERNAL_ERROR);
655 	}
656 
657 	/* head_offset now contains a pointer to where we want to truncate the
658 	 * file. Zero out the old tail end of the file and truncate it. */
659 
660 	__tspi_memset(buf, 0, sizeof(buf));
661 
662 	/* Zero out the old tail end of the file */
663 	if ((result = write_data(fd, (void *)buf, tail_offset - head_offset))) {
664 		LogDebug("%s", __FUNCTION__);
665 		return result;
666 	}
667 
668 	if ((rc = ftruncate(fd, head_offset)) < 0) {
669 		LogDebug("ftruncate: %s", strerror(errno));
670 		return TSPERR(TSS_E_INTERNAL_ERROR);
671 	}
672 
673 	/* we succeeded in removing a key from the disk. Decrement the number
674 	 * of keys in the file */
675 	if ((result = psfile_change_num_keys(fd, TSS_PSFILE_DECREMENT_NUM_KEYS)))
676 		return result;
677 
678 	return TSS_SUCCESS;
679 }
680 
681 TSS_RESULT
psfile_get_all_cache_entries(int fd,UINT32 * size,struct key_disk_cache ** c)682 psfile_get_all_cache_entries(int fd, UINT32 *size, struct key_disk_cache **c)
683 {
684 	UINT32 i, num_keys = psfile_get_num_keys(fd);
685 	int offset;
686 	TSS_RESULT result;
687 	struct key_disk_cache *tmp = NULL;
688 
689 	if (num_keys == 0) {
690 		*size = 0;
691 		*c = NULL;
692 		return TSS_SUCCESS;
693 	}
694 
695 	/* make sure the file pointer is where we expect, just after the number
696 	 * of keys on disk at the head of the file
697 	 */
698 	offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET);
699 	if (offset == ((off_t)-1)) {
700 		LogDebug("lseek: %s", strerror(errno));
701 		return TSPERR(TSS_E_INTERNAL_ERROR);
702 	}
703 
704 	if ((tmp = malloc(num_keys * sizeof(struct key_disk_cache))) == NULL) {
705 		LogDebug("malloc of %zu bytes failed.", num_keys * sizeof(struct key_disk_cache));
706 		return TSPERR(TSS_E_OUTOFMEMORY);
707 	}
708 
709 	for (i = 0; i < num_keys; i++) {
710 		offset = lseek(fd, 0, SEEK_CUR);
711 		if (offset == ((off_t)-1)) {
712 			LogDebug("lseek: %s", strerror(errno));
713 			result = TSPERR(TSS_E_INTERNAL_ERROR);
714 			goto err_exit;
715 		}
716 		tmp[i].offset = offset;
717 
718 		/* read UUID */
719 		if ((result = read_data(fd, &tmp[i].uuid, sizeof(TSS_UUID)))) {
720 			LogDebug("%s", __FUNCTION__);
721 			goto err_exit;
722 		}
723 
724 		/* read parent UUID */
725 		if ((result = read_data(fd, &tmp[i].parent_uuid, sizeof(TSS_UUID)))) {
726 			LogDebug("%s", __FUNCTION__);
727 			goto err_exit;
728 		}
729 
730 		/* pub data size */
731 		if ((result = read_data(fd, &tmp[i].pub_data_size, sizeof(UINT16)))) {
732 			LogDebug("%s", __FUNCTION__);
733 			goto err_exit;
734 		}
735 		tmp[i].pub_data_size = LE_16(tmp[i].pub_data_size);
736 
737 		DBG_ASSERT(tmp[i].pub_data_size <= 2048);
738 
739 		/* blob size */
740 		if ((result = read_data(fd, &tmp[i].blob_size, sizeof(UINT16)))) {
741 			LogDebug("%s", __FUNCTION__);
742 			goto err_exit;
743 		}
744 		tmp[i].blob_size = LE_16(tmp[i].blob_size);
745 
746 		DBG_ASSERT(tmp[i].blob_size <= 4096);
747 
748 		/* vendor data size */
749 		if ((result = read_data(fd, &tmp[i].vendor_data_size, sizeof(UINT32)))) {
750 			LogDebug("%s", __FUNCTION__);
751 			goto err_exit;
752 		}
753 		tmp[i].vendor_data_size = LE_32(tmp[i].vendor_data_size);
754 
755 		/* cache flags */
756 		if ((result = read_data(fd, &tmp[i].flags, sizeof(UINT16)))) {
757 			LogDebug("%s", __FUNCTION__);
758 			goto err_exit;
759 		}
760 		tmp[i].flags = LE_16(tmp[i].flags);
761 
762 		/* fast forward over the pub key */
763 		offset = lseek(fd, tmp[i].pub_data_size, SEEK_CUR);
764 		if (offset == ((off_t)-1)) {
765 			LogDebug("lseek: %s", strerror(errno));
766 			result = TSPERR(TSS_E_INTERNAL_ERROR);
767 			goto err_exit;
768 		}
769 
770 		/* fast forward over the blob */
771 		offset = lseek(fd, tmp[i].blob_size, SEEK_CUR);
772 		if (offset == ((off_t)-1)) {
773 			LogDebug("lseek: %s", strerror(errno));
774 			result = TSPERR(TSS_E_INTERNAL_ERROR);
775 			goto err_exit;
776 		}
777 
778 		/* ignore vendor data for user ps */
779 	}
780 
781 	*size = num_keys;
782 	*c = tmp;
783 
784 	return TSS_SUCCESS;
785 
786 err_exit:
787 	free(tmp);
788 	return result;
789 }
790 
791 TSS_RESULT
copy_key_info(int fd,TSS_KM_KEYINFO * ki,struct key_disk_cache * c)792 copy_key_info(int fd, TSS_KM_KEYINFO *ki, struct key_disk_cache *c)
793 {
794 	TSS_KEY key;
795 	BYTE blob[4096];
796 	UINT64 offset;
797 	TSS_RESULT result;
798 	off_t off;
799 
800 	/* Set the file pointer to the offset that the key blob is at */
801 	off = lseek(fd, TSSPS_BLOB_DATA_OFFSET(c), SEEK_SET);
802 	if (off == ((off_t)-1)) {
803 		LogDebug("lseek: %s", strerror(errno));
804 		return TSPERR(TSS_E_INTERNAL_ERROR);
805 	}
806 
807 	/* Read in the key blob */
808 	if ((result = read_data(fd, (void *)blob, c->blob_size))) {
809 		LogDebug("%s", __FUNCTION__);
810 		return result;
811 	}
812 
813 	/* Expand the blob into a useable form */
814 	offset = 0;
815 	if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
816 		return result;
817 
818 	if (key.hdr.key12.tag == TPM_TAG_KEY12) {
819 		ki->versionInfo.bMajor = TSS_SPEC_MAJOR;
820 		ki->versionInfo.bMinor = TSS_SPEC_MINOR;
821 		ki->versionInfo.bRevMajor = 0;
822 		ki->versionInfo.bRevMinor = 0;
823 	} else
824 		memcpy(&ki->versionInfo, &key.hdr.key11.ver, sizeof(TSS_VERSION));
825 	memcpy(&ki->keyUUID, &c->uuid, sizeof(TSS_UUID));
826 	memcpy(&ki->parentKeyUUID, &c->parent_uuid, sizeof(TSS_UUID));
827 	ki->bAuthDataUsage = key.authDataUsage;
828 
829 	free_key_refs(&key);
830 
831 	return TSS_SUCCESS;
832 }
833 
834 TSS_RESULT
copy_key_info2(int fd,TSS_KM_KEYINFO2 * ki,struct key_disk_cache * c)835 copy_key_info2(int fd, TSS_KM_KEYINFO2 *ki, struct key_disk_cache *c)
836 {
837 	TSS_KEY key;
838 	BYTE blob[4096];
839 	UINT64 offset;
840 	TSS_RESULT result;
841 	off_t off;
842 
843 	/* Set the file pointer to the offset that the key blob is at */
844 	off = lseek(fd, TSSPS_BLOB_DATA_OFFSET(c), SEEK_SET);
845 	if (off == ((off_t)-1)) {
846 		LogDebug("lseek: %s", strerror(errno));
847 		return TSPERR(TSS_E_INTERNAL_ERROR);
848 	}
849 
850 	/* Read in the key blob */
851 	if ((result = read_data(fd, (void *)blob, c->blob_size))) {
852 		LogDebug("%s", __FUNCTION__);
853 		return result;
854 	}
855 
856 	/* Expand the blob into a useable form */
857 	offset = 0;
858 	if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
859 		return result;
860 
861 	if (key.hdr.key12.tag == TPM_TAG_KEY12) {
862 		ki->versionInfo.bMajor = TSS_SPEC_MAJOR;
863 		ki->versionInfo.bMinor = TSS_SPEC_MINOR;
864 		ki->versionInfo.bRevMajor = 0;
865 		ki->versionInfo.bRevMinor = 0;
866 	} else
867 		memcpy(&ki->versionInfo, &key.hdr.key11.ver, sizeof(TSS_VERSION));
868 	memcpy(&ki->keyUUID, &c->uuid, sizeof(TSS_UUID));
869 	memcpy(&ki->parentKeyUUID, &c->parent_uuid, sizeof(TSS_UUID));
870 
871 	/* CHECK: fill the two new fields of TSS_KM_KEYINFO2 */
872 	ki->persistentStorageType = TSS_PS_TYPE_USER;
873 	ki->persistentStorageTypeParent = c->flags & CACHE_FLAG_PARENT_PS_SYSTEM ?
874 					  TSS_PS_TYPE_SYSTEM : TSS_PS_TYPE_USER;
875 
876 	ki->bAuthDataUsage = key.authDataUsage;
877 
878 	free_key_refs(&key);
879 
880 	return TSS_SUCCESS;
881 }
882 
883 
884 TSS_RESULT
psfile_get_registered_keys(int fd,TSS_UUID * uuid,TSS_UUID * tcs_uuid,UINT32 * size,TSS_KM_KEYINFO ** keys)885 psfile_get_registered_keys(int fd,
886 			   TSS_UUID *uuid,
887 			   TSS_UUID *tcs_uuid,
888 			   UINT32 *size,
889 			   TSS_KM_KEYINFO **keys)
890 {
891 	TSS_RESULT result;
892 	struct key_disk_cache *cache_entries;
893 	UINT32 cache_size, i, j;
894 	TSS_KM_KEYINFO *keyinfos = NULL;
895 	TSS_UUID *find_uuid;
896 
897         if ((result = psfile_get_all_cache_entries(fd, &cache_size, &cache_entries)))
898                 return result;
899 
900 	if (cache_size == 0) {
901 		if (uuid)
902 			return TSPERR(TSS_E_PS_KEY_NOTFOUND);
903 		else {
904 			*size = 0;
905 			*keys = NULL;
906 			return TSS_SUCCESS;
907 		}
908 	}
909 
910         if (uuid) {
911 		find_uuid = uuid;
912 		j = 0;
913 
914 restart_search:
915 		/* Search for the requested UUID.  When found, allocate new space for it, copy
916 		 * it in, then change the uuid to be searched for it its parent and start over. */
917 		for (i = 0; i < cache_size; i++) {
918 			if (!memcmp(&cache_entries[i].uuid, find_uuid, sizeof(TSS_UUID))) {
919 				if (!(keyinfos = realloc(keyinfos,
920 							 (j+1) * sizeof(TSS_KM_KEYINFO)))) {
921 					free(cache_entries);
922 					free(keyinfos);
923 					return TSPERR(TSS_E_OUTOFMEMORY);
924 				}
925 				__tspi_memset(&keyinfos[j], 0, sizeof(TSS_KM_KEYINFO));
926 
927 				if ((result = copy_key_info(fd, &keyinfos[j], &cache_entries[i]))) {
928 					free(cache_entries);
929 					free(keyinfos);
930 					return result;
931 				}
932 
933 				find_uuid = &keyinfos[j].parentKeyUUID;
934 				j++;
935 				goto restart_search;
936 			}
937 		}
938 
939 		/* Searching for keys in the user PS will always lead us up to some key in the
940 		 * system PS. Return that key's uuid so that the upper layers can call down to TCS
941 		 * to search for it. */
942 		memcpy(tcs_uuid, find_uuid, sizeof(TSS_UUID));
943 
944 		*size = j;
945         } else {
946 		if ((keyinfos = calloc(cache_size, sizeof(TSS_KM_KEYINFO))) == NULL) {
947 			LogDebug("malloc of %zu bytes failed.",
948 				 cache_size * sizeof(TSS_KM_KEYINFO));
949 			free(cache_entries);
950 			return TSPERR(TSS_E_OUTOFMEMORY);
951 		}
952 
953                 for (i = 0; i < cache_size; i++) {
954 			if ((result = copy_key_info(fd, &keyinfos[i], &cache_entries[i]))) {
955 				free(cache_entries);
956 				free(keyinfos);
957 				return result;
958 			}
959                 }
960 
961 		*size = cache_size;
962         }
963 
964 	free(cache_entries);
965 
966 	*keys = keyinfos;
967 
968 	return TSS_SUCCESS;
969 }
970 
971 TSS_RESULT
psfile_get_registered_keys2(int fd,TSS_UUID * uuid,TSS_UUID * tcs_uuid,UINT32 * size,TSS_KM_KEYINFO2 ** keys)972 psfile_get_registered_keys2(int fd,
973 			   TSS_UUID *uuid,
974 			   TSS_UUID *tcs_uuid,
975 			   UINT32 *size,
976 			   TSS_KM_KEYINFO2 **keys)
977 {
978 	TSS_RESULT result;
979 	struct key_disk_cache *cache_entries;
980 	UINT32 cache_size, i, j;
981 	TSS_KM_KEYINFO2 *keyinfos = NULL;
982 	TSS_UUID *find_uuid;
983 
984         if ((result = psfile_get_all_cache_entries(fd, &cache_size, &cache_entries)))
985                 return result;
986 
987 	if (cache_size == 0) {
988 		if (uuid)
989 			return TSPERR(TSS_E_PS_KEY_NOTFOUND);
990 		else {
991 			*size = 0;
992 			*keys = NULL;
993 			return TSS_SUCCESS;
994 		}
995 	}
996 
997 	if (uuid) {
998 		find_uuid = uuid;
999 		j = 0;
1000 
1001 		restart_search:
1002 			/* Search for the requested UUID.  When found, allocate new space for it, copy
1003 			 * it in, then change the uuid to be searched for it its parent and start over. */
1004 			for (i = 0; i < cache_size; i++) {
1005 				/*Return 0 if normal finish*/
1006 				if (!memcmp(&cache_entries[i].uuid, find_uuid, sizeof(TSS_UUID))) {
1007 					if (!(keyinfos = realloc(keyinfos,
1008 							(j+1) * sizeof(TSS_KM_KEYINFO2)))) {
1009 						free(cache_entries);
1010 						free(keyinfos);
1011 						return TSPERR(TSS_E_OUTOFMEMORY);
1012 					}
1013 					/* Here the key UUID is found and needs to be copied for the array*/
1014 					/* Initializes the keyinfos with 0's*/
1015 					__tspi_memset(&keyinfos[j], 0, sizeof(TSS_KM_KEYINFO2));
1016 
1017 					if ((result = copy_key_info2(fd, &keyinfos[j], &cache_entries[i]))) {
1018 						free(cache_entries);
1019 						free(keyinfos);
1020 						return result;
1021 					}
1022 
1023 					find_uuid = &keyinfos[j].parentKeyUUID;
1024 					j++;
1025 					goto restart_search;
1026 				}
1027 			}
1028 
1029 		/* Searching for keys in the user PS will always lead us up to some key in the
1030 		 * system PS. Return that key's uuid so that the upper layers can call down to TCS
1031 		 * to search for it. */
1032 		memcpy(tcs_uuid, find_uuid, sizeof(TSS_UUID));
1033 
1034 		*size = j;
1035 	} else {
1036 		if ((keyinfos = calloc(cache_size, sizeof(TSS_KM_KEYINFO2))) == NULL) {
1037 			LogDebug("malloc of %zu bytes failed.",
1038 					cache_size * sizeof(TSS_KM_KEYINFO2));
1039 			free(cache_entries);
1040 			return TSPERR(TSS_E_OUTOFMEMORY);
1041 		}
1042 
1043 		for (i = 0; i < cache_size; i++) {
1044 			if ((result = copy_key_info2(fd, &keyinfos[i], &cache_entries[i]))) {
1045 				free(cache_entries);
1046 				free(keyinfos);
1047 				return result;
1048 			}
1049 		}
1050 
1051 		*size = cache_size;
1052 	}
1053 
1054 	free(cache_entries);
1055 
1056 	*keys = keyinfos;
1057 
1058 	return TSS_SUCCESS;
1059 }
1060 
1061 /*
1062  * read into the PS file and return the number of keys
1063  */
1064 UINT32
psfile_get_num_keys(int fd)1065 psfile_get_num_keys(int fd)
1066 {
1067 	UINT32 num_keys;
1068 	int rc;
1069 
1070 	/* go to the number of keys */
1071 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
1072 	if (rc == ((off_t)-1)) {
1073 		LogDebug("lseek: %s", strerror(errno));
1074 		return 0;
1075 	}
1076 
1077 	rc = read(fd, &num_keys, sizeof(UINT32));
1078 	if (rc < 0) {
1079 		LogDebug("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
1080 		return 0;
1081 	} else if ((unsigned)rc < sizeof(UINT32)) {
1082 		num_keys = 0;
1083 	}
1084 
1085 	/* The system PS file is written in little-endian */
1086 	num_keys = LE_32(num_keys);
1087 	return num_keys;
1088 }
1089 
1090 /*
1091  * disk store format:
1092  *
1093  * TrouSerS 0.2.1+
1094  * Version 1:                  cached?
1095  * [BYTE     PS version = '\1']
1096  * [UINT32   num_keys_on_disk ]
1097  * [TSS_UUID uuid0            ] yes
1098  * [TSS_UUID uuid_parent0     ] yes
1099  * [UINT16   pub_data_size0   ] yes
1100  * [UINT16   blob_size0       ] yes
1101  * [UINT32   vendor_data_size0] yes
1102  * [UINT16   cache_flags0     ] yes
1103  * [BYTE[]   pub_data0        ]
1104  * [BYTE[]   blob0            ]
1105  * [BYTE[]   vendor_data0     ]
1106  * [...]
1107  *
1108  */
1109 TSS_RESULT
psfile_get_cache_entry_by_uuid(int fd,TSS_UUID * uuid,struct key_disk_cache * c)1110 psfile_get_cache_entry_by_uuid(int fd, TSS_UUID *uuid, struct key_disk_cache *c)
1111 {
1112 	UINT32 i, num_keys = psfile_get_num_keys(fd);
1113 	int offset;
1114 	TSS_RESULT result;
1115 	BYTE found = 0;
1116 
1117 	if (num_keys == 0)
1118 		return TSPERR(TSS_E_PS_KEY_NOTFOUND);
1119 
1120 	/* make sure the file pointer is where we expect, just after the number
1121 	 * of keys on disk at the head of the file
1122 	 */
1123 	offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET);
1124 	if (offset == ((off_t)-1)) {
1125 		LogDebug("lseek: %s", strerror(errno));
1126 		return TSPERR(TSS_E_INTERNAL_ERROR);
1127 	}
1128 
1129 	for (i = 0; i < num_keys && !found; i++) {
1130 		offset = lseek(fd, 0, SEEK_CUR);
1131 		if (offset == ((off_t)-1)) {
1132 			LogDebug("lseek: %s", strerror(errno));
1133 			return TSPERR(TSS_E_INTERNAL_ERROR);
1134 		}
1135 		c->offset = offset;
1136 
1137 		/* read UUID */
1138 		if ((result = read_data(fd, (void *)&c->uuid, sizeof(TSS_UUID)))) {
1139 			LogDebug("%s", __FUNCTION__);
1140 			return result;
1141 		}
1142 
1143 		if (!memcmp(&c->uuid, uuid, sizeof(TSS_UUID))) {
1144 			found = 1;
1145 
1146 			/* read parent UUID */
1147 			if ((result = read_data(fd, (void *)&c->parent_uuid, sizeof(TSS_UUID)))) {
1148 				LogDebug("%s", __FUNCTION__);
1149 				return result;
1150 			}
1151 		} else {
1152 			/* fast forward over the parent UUID */
1153 			offset = lseek(fd, sizeof(TSS_UUID), SEEK_CUR);
1154 			if (offset == ((off_t)-1)) {
1155 				LogDebug("lseek: %s", strerror(errno));
1156 				return TSPERR(TSS_E_INTERNAL_ERROR);
1157 			}
1158 		}
1159 
1160 		/* pub data size */
1161 		if ((result = read_data(fd, &c->pub_data_size, sizeof(UINT16)))) {
1162 			LogDebug("%s", __FUNCTION__);
1163 			return result;
1164 		}
1165 		c->pub_data_size = LE_16(c->pub_data_size);
1166 		DBG_ASSERT(c->pub_data_size <= 2048 && c->pub_data_size > 0);
1167 
1168 		/* blob size */
1169 		if ((result = read_data(fd, &c->blob_size, sizeof(UINT16)))) {
1170 			LogDebug("%s", __FUNCTION__);
1171 			return result;
1172 		}
1173 		c->blob_size = LE_16(c->blob_size);
1174 		DBG_ASSERT(c->blob_size <= 4096 && c->blob_size > 0);
1175 
1176 		/* vendor data size */
1177 		if ((result = read_data(fd, &c->vendor_data_size, sizeof(UINT32)))) {
1178 			LogDebug("%s", __FUNCTION__);
1179 			return result;
1180 		}
1181 		c->vendor_data_size = LE_32(c->vendor_data_size);
1182 
1183 		/* cache flags */
1184 		if ((result = read_data(fd, &c->flags, sizeof(UINT16)))) {
1185 			LogDebug("%s", __FUNCTION__);
1186 			return result;
1187 		}
1188 		c->flags = LE_16(c->flags);
1189 
1190 		/* fast forward over the pub key */
1191 		offset = lseek(fd, c->pub_data_size, SEEK_CUR);
1192 		if (offset == ((off_t)-1)) {
1193 			LogDebug("lseek: %s", strerror(errno));
1194 			return TSPERR(TSS_E_INTERNAL_ERROR);
1195 		}
1196 
1197 		/* fast forward over the blob */
1198 		offset = lseek(fd, c->blob_size, SEEK_CUR);
1199 		if (offset == ((off_t)-1)) {
1200 			LogDebug("lseek: %s", strerror(errno));
1201 			return TSPERR(TSS_E_INTERNAL_ERROR);
1202 		}
1203 
1204 		/* ignore vendor data in user ps */
1205 	}
1206 
1207 	return found ? TSS_SUCCESS : TSPERR(TSS_E_PS_KEY_NOTFOUND);
1208 }
1209 
1210 TSS_RESULT
psfile_get_cache_entry_by_pub(int fd,UINT32 pub_size,BYTE * pub,struct key_disk_cache * c)1211 psfile_get_cache_entry_by_pub(int fd, UINT32 pub_size, BYTE *pub, struct key_disk_cache *c)
1212 {
1213 	BYTE blob[2048];
1214 	UINT32 i, num_keys = psfile_get_num_keys(fd);
1215 	int offset;
1216 	TSS_RESULT result;
1217 
1218 	if (num_keys == 0)
1219 		return TSPERR(TSS_E_PS_KEY_NOTFOUND);
1220 
1221 	/* make sure the file pointer is where we expect, just after the number
1222 	 * of keys on disk at the head of the file
1223 	 */
1224 	offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET);
1225 	if (offset == ((off_t)-1)) {
1226 		LogDebug("lseek: %s", strerror(errno));
1227 		return TSPERR(TSS_E_INTERNAL_ERROR);
1228 	}
1229 
1230 	for (i = 0; i < num_keys; i++) {
1231 		offset = lseek(fd, 0, SEEK_CUR);
1232 		if (offset == ((off_t)-1)) {
1233 			LogDebug("lseek: %s", strerror(errno));
1234 			return TSPERR(TSS_E_INTERNAL_ERROR);
1235 		}
1236 		c->offset = offset;
1237 
1238 		/* read UUID */
1239 		if ((result = read_data(fd, (void *)&c->uuid, sizeof(TSS_UUID)))) {
1240 			LogDebug("%s", __FUNCTION__);
1241 			return result;
1242 		}
1243 
1244 		/* read parent UUID */
1245 		if ((result = read_data(fd, (void *)&c->parent_uuid, sizeof(TSS_UUID)))) {
1246 			LogDebug("%s", __FUNCTION__);
1247 			return result;
1248 		}
1249 
1250 		/* pub data size */
1251 		if ((result = read_data(fd, &c->pub_data_size, sizeof(UINT16)))) {
1252 			LogDebug("%s", __FUNCTION__);
1253 			return result;
1254 		}
1255 
1256 		c->pub_data_size = LE_16(c->pub_data_size);
1257 		DBG_ASSERT(c->pub_data_size <= 2048 && c->pub_data_size > 0);
1258 
1259 		/* blob size */
1260 		if ((result = read_data(fd, &c->blob_size, sizeof(UINT16)))) {
1261 			LogDebug("%s", __FUNCTION__);
1262 			return result;
1263 		}
1264 
1265 		c->blob_size = LE_16(c->blob_size);
1266 		DBG_ASSERT(c->blob_size <= 4096 && c->blob_size > 0);
1267 
1268 		/* vendor data size */
1269 		if ((result = read_data(fd, &c->vendor_data_size, sizeof(UINT32)))) {
1270 			LogDebug("%s", __FUNCTION__);
1271 			return result;
1272 		}
1273 		c->vendor_data_size = LE_32(c->vendor_data_size);
1274 
1275 		/* cache flags */
1276 		if ((result = read_data(fd, &c->flags, sizeof(UINT16)))) {
1277 			LogDebug("%s", __FUNCTION__);
1278 			return result;
1279 		}
1280 		c->flags = LE_16(c->flags);
1281 
1282 		if (c->pub_data_size == pub_size) {
1283 			/* read in the pub key */
1284 			if ((result = read_data(fd, blob, c->pub_data_size))) {
1285 				LogDebug("%s", __FUNCTION__);
1286 				return result;
1287 			}
1288 
1289 			if (!memcmp(blob, pub, pub_size))
1290 				break;
1291 		}
1292 
1293 		/* fast forward over the blob */
1294 		offset = lseek(fd, c->blob_size, SEEK_CUR);
1295 		if (offset == ((off_t)-1)) {
1296 			LogDebug("lseek: %s", strerror(errno));
1297 			return TSPERR(TSS_E_INTERNAL_ERROR);
1298 		}
1299 
1300 		/* ignore vendor data */
1301 	}
1302 
1303 	return TSS_SUCCESS;
1304 }
1305