xref: /netbsd-src/crypto/external/cpl/trousers/dist/src/tcs/ps/ps_utils.c (revision 6d322f2f4598f0d8a138f10ea648ec4fabe41f8b)
1 /*
2  * Licensed Materials - Property of IBM
3  *
4  * trousers - An open source TCG Software Stack
5  *
6  * (C) Copyright International Business Machines Corp. 2004
7  *
8  */
9 
10 
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #if defined(HAVE_BYTEORDER_H)
17 #include <sys/byteorder.h>
18 #elif defined(HTOLE_DEFINED)
19 #ifdef __NetBSD__
20 #include <sys/endian.h>
21 #else
22 #include <endian.h>
23 #endif
24 #define LE_16 htole16
25 #define LE_32 htole32
26 #define LE_64 htole64
27 #else
28 #define LE_16(x) (x)
29 #define LE_32(x) (x)
30 #define LE_64(x) (x)
31 #endif
32 #include <fcntl.h>
33 #include <string.h>
34 #include <limits.h>
35 #include <assert.h>
36 #include <errno.h>
37 
38 #include "trousers/tss.h"
39 #include "trousers_types.h"
40 #include "tcs_int_literals.h"
41 #include "tcsps.h"
42 #include "tcs_tsp.h"
43 #include "tcs_utils.h"
44 #include "tcslog.h"
45 
46 struct key_disk_cache *key_disk_cache_head = NULL;
47 
48 
49 #ifdef SOLARIS
50 TSS_RESULT
51 #else
52 inline TSS_RESULT
53 #endif
54 read_data(int fd, void *data, UINT32 size)
55 {
56 	int rc;
57 
58 	rc = read(fd, data, size);
59 	if (rc == -1) {
60 		LogError("read of %d bytes: %s", size, strerror(errno));
61 		return TCSERR(TSS_E_INTERNAL_ERROR);
62 	} else if ((unsigned)rc != size) {
63 		LogError("read of %d bytes (only %d read)", size, rc);
64 		return TCSERR(TSS_E_INTERNAL_ERROR);
65 	}
66 
67 	return TSS_SUCCESS;
68 }
69 
70 
71 #ifdef SOLARIS
72 TSS_RESULT
73 #else
74 inline TSS_RESULT
75 #endif
76 write_data(int fd, void *data, UINT32 size)
77 {
78 	int rc;
79 
80 	rc = write(fd, data, size);
81 	if (rc == -1) {
82 		LogError("write of %d bytes: %s", size, strerror(errno));
83 		return TCSERR(TSS_E_INTERNAL_ERROR);
84 	} else if ((unsigned)rc != size) {
85 		LogError("write of %d bytes (only %d written)", size, rc);
86 		return TCSERR(TSS_E_INTERNAL_ERROR);
87 	}
88 
89 	return TSS_SUCCESS;
90 }
91 
92 /*
93  * called by write_key_init to find the next available location in the PS file to
94  * write a new key to.
95  */
96 int
97 find_write_offset(UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size)
98 {
99 	struct key_disk_cache *tmp;
100 	unsigned int offset;
101 
102 	MUTEX_LOCK(disk_cache_lock);
103 
104 	tmp = key_disk_cache_head;
105 	while (tmp) {
106 		/* if we find a deleted key of the right size, return its offset */
107 		if (!(tmp->flags & CACHE_FLAG_VALID) &&
108 		    tmp->pub_data_size == pub_data_size &&
109 		    tmp->blob_size == blob_size &&
110 		    tmp->vendor_data_size == vendor_data_size) {
111 			offset = tmp->offset;
112 			MUTEX_UNLOCK(disk_cache_lock);
113 			return offset;
114 		}
115 		tmp = tmp->next;
116 	}
117 
118 	MUTEX_UNLOCK(disk_cache_lock);
119 
120 	/* no correctly sized holes */
121 	return -1;
122 }
123 
124 /*
125  * move the file pointer to the point where the next key can be written and return
126  * that offset
127  */
128 int
129 write_key_init(int fd, UINT32 pub_data_size, UINT32 blob_size, UINT32 vendor_data_size)
130 {
131 	UINT32 num_keys;
132 	BYTE version;
133 	int rc, offset;
134 
135 	/* seek to the PS version */
136 	rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET);
137 	if (rc == ((off_t) - 1)) {
138 		LogError("lseek: %s", strerror(errno));
139 		return -1;
140 	}
141 
142 	/* go to NUM_KEYS */
143 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
144 	if (rc == ((off_t) - 1)) {
145 		LogError("lseek: %s", strerror(errno));
146 		return -1;
147 	}
148 
149 	/* read the number of keys */
150 	rc = read(fd, &num_keys, sizeof(UINT32));
151 	num_keys = LE_32(num_keys);
152 	if (rc == -1) {
153 		LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
154 		return -1;
155 	} else if (rc == 0) {
156 		/* This is the first key being written */
157 		num_keys = 1;
158 		version = 1;
159 
160 		/* seek to the PS version */
161 		rc = lseek(fd, TSSPS_VERSION_OFFSET, SEEK_SET);
162 		if (rc == ((off_t) - 1)) {
163 			LogError("lseek: %s", strerror(errno));
164 			return -1;
165 		}
166 
167 		/* write out the version info byte */
168 		if ((rc = write_data(fd, &version, sizeof(BYTE)))) {
169 			LogError("%s", __FUNCTION__);
170 			return rc;
171 		}
172 
173 		rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
174 		if (rc == ((off_t) - 1)) {
175 			LogError("lseek: %s", strerror(errno));
176 			return -1;
177 		}
178 
179                 num_keys = LE_32(num_keys);
180 		if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) {
181 			LogError("%s", __FUNCTION__);
182 			return rc;
183 		}
184 
185 		/* return the offset */
186 		return (TSSPS_NUM_KEYS_OFFSET + sizeof(UINT32));
187 	}
188 
189 	/* if there is a hole in the file we can write to, find it */
190 	offset = find_write_offset(pub_data_size, blob_size, vendor_data_size);
191 
192 	if (offset != -1) {
193 		/* we found a hole, seek to it and don't increment the # of keys on disk */
194 		rc = lseek(fd, offset, SEEK_SET);
195 	} else {
196 		/* we didn't find a hole, increment the number of keys on disk and seek
197 		 * to the end of the file
198 		 */
199 		num_keys++;
200 
201 		/* go to the beginning */
202 		rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
203 		if (rc == ((off_t) - 1)) {
204 			LogError("lseek: %s", strerror(errno));
205 			return -1;
206 		}
207                 num_keys = LE_32(num_keys);
208 		if ((rc = write_data(fd, &num_keys, sizeof(UINT32)))) {
209 			LogError("%s", __FUNCTION__);
210 			return rc;
211 		}
212 
213 		rc = lseek(fd, 0, SEEK_END);
214 	}
215 	if (rc == ((off_t) - 1)) {
216 		LogError("lseek: %s", strerror(errno));
217 		return -1;
218 	}
219 
220 	/* lseek returns the number of bytes of offset from the beginning of the file */
221 	return rc;
222 }
223 
224 /*
225  * add a new cache entry for a written key
226  */
227 TSS_RESULT
228 cache_key(UINT32 offset, UINT16 flags,
229 		TSS_UUID *uuid, TSS_UUID *parent_uuid,
230 		UINT16 pub_data_size, UINT32 blob_size,
231 		UINT32 vendor_data_size)
232 {
233 	struct key_disk_cache *tmp;
234 
235 	MUTEX_LOCK(disk_cache_lock);
236 
237 	tmp = key_disk_cache_head;
238 
239 	for (; tmp; tmp = tmp->next) {
240 		/* reuse an invalidated key cache entry */
241 		if (!(tmp->flags & CACHE_FLAG_VALID))
242 			goto fill_cache_entry;
243 	}
244 
245 	tmp = malloc(sizeof(struct key_disk_cache));
246 	if (tmp == NULL) {
247 		LogError("malloc of %zd bytes failed.", sizeof(struct key_disk_cache));
248 		MUTEX_UNLOCK(disk_cache_lock);
249 		return TCSERR(TSS_E_OUTOFMEMORY);
250 	}
251 	tmp->next = key_disk_cache_head;
252 	key_disk_cache_head = tmp;
253 
254 fill_cache_entry:
255 	tmp->offset = offset;
256 #ifdef TSS_DEBUG
257 	if (offset == 0)
258 		LogDebug("Storing key with file offset==0!!!");
259 #endif
260 	tmp->flags = flags;
261 	tmp->blob_size = blob_size;
262 	tmp->pub_data_size = pub_data_size;
263 	tmp->vendor_data_size = vendor_data_size;
264 	memcpy(&tmp->uuid, uuid, sizeof(TSS_UUID));
265 	memcpy(&tmp->parent_uuid, parent_uuid, sizeof(TSS_UUID));
266 
267 	MUTEX_UNLOCK(disk_cache_lock);
268 	return TSS_SUCCESS;
269 }
270 
271 /*
272  * read into the PS file and return the number of keys
273  */
274 int
275 get_num_keys_in_file(int fd)
276 {
277 	UINT32 num_keys;
278 	int rc;
279 
280 	/* go to the number of keys */
281 	rc = lseek(fd, TSSPS_NUM_KEYS_OFFSET, SEEK_SET);
282 	if (rc == ((off_t) - 1)) {
283 		LogError("lseek: %s", strerror(errno));
284 		return 0;
285 	}
286 
287 	rc = read(fd, &num_keys, sizeof(UINT32));
288 	if (rc < 0) {
289 		LogError("read of %zd bytes: %s", sizeof(UINT32), strerror(errno));
290 		return 0;
291 	} else if ((unsigned)rc < sizeof(UINT32)) {
292 		num_keys = 0;
293 	}
294         num_keys = LE_32(num_keys);
295 
296 	return num_keys;
297 }
298 
299 /*
300  * count the number of valid keys in the cache
301  */
302 int
303 get_num_keys()
304 {
305 	int num_keys = 0;
306 	struct key_disk_cache *tmp;
307 
308 	MUTEX_LOCK(disk_cache_lock);
309 
310 	tmp = key_disk_cache_head;
311 
312 	for (; tmp; tmp = tmp->next) {
313 		if (tmp->flags & CACHE_FLAG_VALID)
314 			num_keys++;
315 	}
316 
317 	MUTEX_UNLOCK(disk_cache_lock);
318 	return num_keys;
319 }
320 
321 /*
322  * disk store format:
323  *
324  * TrouSerS 0.2.0 and before:
325  * Version 0:                  cached?
326  * [UINT32   num_keys_on_disk]
327  * [TSS_UUID uuid0           ] yes
328  * [TSS_UUID uuid_parent0    ] yes
329  * [UINT16   pub_data_size0  ] yes
330  * [UINT16   blob_size0      ] yes
331  * [UINT16   cache_flags0    ] yes
332  * [BYTE[]   pub_data0       ]
333  * [BYTE[]   blob0           ]
334  * [...]
335  *
336  * TrouSerS 0.2.1+
337  * Version 1:                  cached?
338  * [BYTE     PS version = '\1']
339  * [UINT32   num_keys_on_disk ]
340  * [TSS_UUID uuid0            ] yes
341  * [TSS_UUID uuid_parent0     ] yes
342  * [UINT16   pub_data_size0   ] yes
343  * [UINT16   blob_size0       ] yes
344  * [UINT32   vendor_data_size0] yes
345  * [UINT16   cache_flags0     ] yes
346  * [BYTE[]   pub_data0        ]
347  * [BYTE[]   blob0            ]
348  * [BYTE[]   vendor_data0     ]
349  * [...]
350  *
351  */
352 /*
353  * read the PS file pointed to by fd and create a cache based on it
354  */
355 int
356 init_disk_cache(int fd)
357 {
358 	UINT32 num_keys = get_num_keys_in_file(fd);
359 	UINT16 i;
360 	UINT64 tmp_offset;
361 	int rc = 0, offset;
362 	struct key_disk_cache *tmp, *prev = NULL;
363 	BYTE srk_blob[2048];
364 	TSS_KEY srk_key;
365 #ifdef TSS_DEBUG
366 	int valid_keys = 0;
367 #endif
368 
369 	MUTEX_LOCK(disk_cache_lock);
370 
371 	if (num_keys == 0) {
372 		key_disk_cache_head = NULL;
373 		MUTEX_UNLOCK(disk_cache_lock);
374 		return 0;
375 	} else {
376 		key_disk_cache_head = tmp = calloc(1, sizeof(struct key_disk_cache));
377 		if (tmp == NULL) {
378 			LogError("malloc of %zd bytes failed.",
379 						sizeof(struct key_disk_cache));
380 			rc = -1;
381 			goto err_exit;
382 		}
383 	}
384 
385 	/* make sure the file pointer is where we expect, just after the number
386 	 * of keys on disk at the head of the file
387 	 */
388 	offset = lseek(fd, TSSPS_KEYS_OFFSET, SEEK_SET);
389 	if (offset == ((off_t) - 1)) {
390 		LogError("lseek: %s", strerror(errno));
391 		rc = -1;
392 		goto err_exit;
393 	}
394 
395 	for (i=0; i<num_keys; i++) {
396 		offset = lseek(fd, 0, SEEK_CUR);
397 		if (offset == ((off_t) - 1)) {
398 			LogError("lseek: %s", strerror(errno));
399 			rc = -1;
400 			goto err_exit;
401 		}
402 		tmp->offset = offset;
403 #ifdef TSS_DEBUG
404 		if (offset == 0)
405 			LogDebug("Storing key with file offset==0!!!");
406 #endif
407 		/* read UUID */
408 		if ((rc = read_data(fd, (void *)&tmp->uuid, sizeof(TSS_UUID)))) {
409 			LogError("%s", __FUNCTION__);
410 			goto err_exit;
411 		}
412 
413 		/* read parent UUID */
414 		if ((rc = read_data(fd, (void *)&tmp->parent_uuid, sizeof(TSS_UUID)))) {
415 			LogError("%s", __FUNCTION__);
416 			goto err_exit;
417 		}
418 
419 		/* pub data size */
420 		if ((rc = read_data(fd, &tmp->pub_data_size, sizeof(UINT16)))) {
421 			LogError("%s", __FUNCTION__);
422 			goto err_exit;
423 		}
424                 tmp->pub_data_size = LE_16(tmp->pub_data_size);
425 
426 		DBG_ASSERT(tmp->pub_data_size <= 2048 && tmp->pub_data_size > 0);
427 
428 		/* blob size */
429 		if ((rc = read_data(fd, &tmp->blob_size, sizeof(UINT16)))) {
430 			LogError("%s", __FUNCTION__);
431 			goto err_exit;
432 		}
433                 tmp->blob_size = LE_16(tmp->blob_size);
434 		DBG_ASSERT(tmp->blob_size <= 4096 && tmp->blob_size > 0);
435 
436 		/* vendor data size */
437 		if ((rc = read_data(fd, &tmp->vendor_data_size, sizeof(UINT32)))) {
438 			LogError("%s", __FUNCTION__);
439 			goto err_exit;
440 		}
441                 tmp->vendor_data_size = LE_32(tmp->vendor_data_size);
442 
443 		/* cache flags */
444 		if ((rc = read_data(fd, &tmp->flags, sizeof(UINT16)))) {
445 			LogError("%s", __FUNCTION__);
446 			goto err_exit;
447 		}
448                 tmp->flags = LE_16(tmp->flags);
449 
450 #ifdef TSS_DEBUG
451 		if (tmp->flags & CACHE_FLAG_VALID)
452 			valid_keys++;
453 #endif
454 		/* fast forward over the pub key */
455 		offset = lseek(fd, tmp->pub_data_size, SEEK_CUR);
456 		if (offset == ((off_t) - 1)) {
457 			LogError("lseek: %s", strerror(errno));
458 			rc = -1;
459 			goto err_exit;
460 		}
461 
462 		/* if this is the SRK, load it into memory, since its already loaded in
463 		 * the chip */
464 		if (!memcmp(&SRK_UUID, &tmp->uuid, sizeof(TSS_UUID))) {
465 			/* read SRK blob from disk */
466 			if ((rc = read_data(fd, srk_blob, tmp->blob_size))) {
467 				LogError("%s", __FUNCTION__);
468 				goto err_exit;
469 			}
470 
471 			tmp_offset = 0;
472 			if ((rc = UnloadBlob_TSS_KEY(&tmp_offset, srk_blob, &srk_key)))
473 				goto err_exit;
474 			/* add to the mem cache */
475 			if ((rc = mc_add_entry_init(SRK_TPM_HANDLE, SRK_TPM_HANDLE, &srk_key,
476 						    &SRK_UUID))) {
477 				LogError("Error adding SRK to mem cache.");
478 				destroy_key_refs(&srk_key);
479 				goto err_exit;
480 			}
481 			destroy_key_refs(&srk_key);
482 		} else {
483 			/* fast forward over the blob */
484 			offset = lseek(fd, tmp->blob_size, SEEK_CUR);
485 			if (offset == ((off_t) - 1)) {
486 				LogError("lseek: %s", strerror(errno));
487 				rc = -1;
488 				goto err_exit;
489 			}
490 
491 			/* fast forward over the vendor data */
492 			offset = lseek(fd, tmp->vendor_data_size, SEEK_CUR);
493 			if (offset == ((off_t) - 1)) {
494 				LogError("lseek: %s", strerror(errno));
495 				rc = -1;
496 				goto err_exit;
497 			}
498 		}
499 
500 		tmp->next = calloc(1, sizeof(struct key_disk_cache));
501 		if (tmp->next == NULL) {
502 			LogError("malloc of %zd bytes failed.",
503 					sizeof(struct key_disk_cache));
504 			rc = -1;
505 			goto err_exit;
506 		}
507 		prev = tmp;
508 		tmp = tmp->next;
509 	}
510 
511 	/* delete the dangling, unfilled cache entry */
512 	free(tmp);
513 	prev->next = NULL;
514 	rc = 0;
515 	LogDebug("%s: found %d valid key(s) on disk.\n", __FUNCTION__, valid_keys);
516 
517 err_exit:
518 	MUTEX_UNLOCK(disk_cache_lock);
519 	return rc;
520 }
521 
522 int
523 close_disk_cache(int fd)
524 {
525 	struct key_disk_cache *tmp, *tmp_next;
526 
527 	if (key_disk_cache_head == NULL)
528 		return 0;
529 
530 	MUTEX_LOCK(disk_cache_lock);
531 	tmp = key_disk_cache_head;
532 
533 	do {
534 		tmp_next = tmp->next;
535 		free(tmp);
536 		tmp = tmp_next;
537 	} while (tmp);
538 
539 	MUTEX_UNLOCK(disk_cache_lock);
540 
541 	return 0;
542 }
543