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