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