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. 2006
8 *
9 */
10
11/*
12 * biosem.c
13 *
14 * Routines for handling PCR events from the TCG Compliant BIOS
15 *
16 */
17
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <limits.h>
26#include <unistd.h>
27
28#include "trousers/tss.h"
29#include "trousers_types.h"
30#include "tcs_tsp.h"
31#include "tcs_utils.h"
32#include "tcs_int_literals.h"
33#include "capabilities.h"
34#include "tcsps.h"
35#include "tcslog.h"
36#include "tcsem.h"
37
38#ifdef EVLOG_SOURCE_BIOS
39
40struct ext_log_source bios_source = {
41	bios_open,
42	bios_get_entries_by_pcr,
43	bios_get_entry,
44	bios_close
45};
46
47int
48bios_open(void *source, FILE **handle)
49{
50	FILE *fd;
51
52	if ((fd = fopen((char *)source, "r")) == NULL ) {
53		LogError("Error opening BIOS Eventlog file %s: %s", (char *)source,
54			 strerror(errno));
55		return -1;
56	}
57
58	*handle = fd;
59
60	return 0;
61}
62
63TSS_RESULT
64bios_get_entries_by_pcr(FILE *handle, UINT32 pcr_index, UINT32 first,
65			UINT32 *count, TSS_PCR_EVENT **events)
66{
67	char page[BIOS_READ_SIZE];
68	int error_path = 1;
69	UINT32 seen_indices = 0, copied_events = 0, i;
70	struct event_wrapper *list = calloc(1, sizeof(struct event_wrapper));
71	struct event_wrapper *cur = list;
72	TSS_RESULT result = TSS_E_INTERNAL_ERROR;
73	TCG_PCClientPCREventStruc *event = NULL;
74	int num=0;
75
76	if (list == NULL) {
77		LogError("malloc of %zd bytes failed.", sizeof(struct event_wrapper));
78		return TSS_E_OUTOFMEMORY;
79	}
80
81	if (*count == 0) {
82		result = TSS_SUCCESS;
83		goto free_list;
84	}
85
86	while (1) {
87		/* read event header from the file */
88		if ((fread(page, 32, 1, handle)) <= 0) {
89			goto copy_events;
90		}
91
92		event = (TCG_PCClientPCREventStruc *)page;
93
94		/* if the index is the one we're looking for, grab the entry */
95		if (pcr_index == event->pcrIndex) {
96			if (seen_indices >= first) {
97				/* grab this entry */
98				cur->event.rgbPcrValue = malloc(20);
99				if (cur->event.rgbPcrValue == NULL) {
100					LogError("malloc of %d bytes failed.", 20);
101					result = TSS_E_OUTOFMEMORY;
102					goto free_list;
103				}
104
105				cur->event.ulPcrIndex = pcr_index;
106				cur->event.eventType = event->eventType;
107				cur->event.ulPcrValueLength = 20;
108
109				/* copy the SHA1 XXX endianess ignored */
110				memcpy(cur->event.rgbPcrValue, event->digest, 20);
111
112				/* copy the event name XXX endianess ignored */
113				cur->event.ulEventLength = event->eventDataSize;
114
115				if (event->eventDataSize>0) {
116					cur->event.rgbEvent = malloc(event->eventDataSize);
117					if (cur->event.rgbEvent == NULL) {
118						LogError("malloc of %d bytes failed.",
119							 event->eventDataSize);
120						free(cur->event.rgbPcrValue);
121						result = TSS_E_OUTOFMEMORY;
122						goto free_list;
123					}
124					if ((fread(cur->event.rgbEvent,
125						   event->eventDataSize, 1, handle)) <= 0) {
126						LogError("read from event source failed: %s",
127							 strerror(errno));
128						return result;
129					}
130				} else {
131					cur->event.rgbEvent = NULL;
132				}
133
134				copied_events++;
135				if (copied_events == *count)
136					goto copy_events;
137
138				cur->next = calloc(1, sizeof(struct event_wrapper));
139				if (cur->next == NULL) {
140					LogError("malloc of %zd bytes failed.",
141						 sizeof(struct event_wrapper));
142					result = TSS_E_OUTOFMEMORY;
143					goto free_list;
144				}
145				cur = cur->next;
146			} else {
147				/* skip */
148				if (event->eventDataSize > 0)
149					fseek(handle,event->eventDataSize,SEEK_CUR);
150			}
151			seen_indices++;
152		} else {
153			if (event->eventDataSize > 0)
154				fseek(handle,event->eventDataSize,SEEK_CUR);
155			}
156		num++;
157	}
158
159copy_events:
160
161	/* we've copied all the events we need to from this PCR, now
162	 * copy them all into one contiguous memory block
163	 */
164	*events = calloc(copied_events, sizeof(TSS_PCR_EVENT));
165	if (*events == NULL) {
166		LogError("malloc of %zd bytes failed.", copied_events * sizeof(TSS_PCR_EVENT));
167		result = TSS_E_OUTOFMEMORY;
168		goto free_list;
169	}
170
171	cur = list;
172	for (i = 0; i < copied_events; i++) {
173		memcpy(&((*events)[i]), &(cur->event), sizeof(TSS_PCR_EVENT));
174		cur = cur->next;
175	}
176
177	*count = copied_events;
178	/* assume we're in an error path until we get here */
179	error_path = 0;
180	result = TSS_SUCCESS;
181
182free_list:
183	cur = list->next;
184	while (cur != NULL) {
185		if (error_path) {
186			free(cur->event.rgbEvent);
187			free(cur->event.rgbPcrValue);
188		}
189		free(list);
190		list = cur;
191		cur = list->next;
192	}
193	free(list);
194	return result;
195}
196
197TSS_RESULT
198bios_get_entry(FILE *handle, UINT32 pcr_index, UINT32 *num, TSS_PCR_EVENT **ppEvent)
199{
200	char page[BIOS_READ_SIZE];
201	UINT32 seen_indices = 0;
202	TSS_RESULT result = TSS_E_INTERNAL_ERROR;
203	TSS_PCR_EVENT *e = NULL;
204	TCG_PCClientPCREventStruc *event = NULL;
205
206	while (1) {
207		/* read event header from the file */
208		if ((fread(page, 32, 1, handle)) == 0) {
209			goto done;
210		}
211
212		event = (TCG_PCClientPCREventStruc *)page;
213
214		if (pcr_index == event->pcrIndex) {
215			if (ppEvent && !*ppEvent && seen_indices == *num) {
216				*ppEvent = calloc(1, sizeof(TSS_PCR_EVENT));
217				if (*ppEvent == NULL) {
218					LogError("malloc of %zd bytes failed.",
219						 sizeof(TSS_PCR_EVENT));
220					return TSS_E_INTERNAL_ERROR;
221				}
222
223				e = *ppEvent;
224
225				e->rgbPcrValue = malloc(20);
226				if (e->rgbPcrValue == NULL) {
227					LogError("malloc of %d bytes failed.", 20);
228					free(e);
229					e = NULL;
230					break;
231				}
232
233				e->ulPcrIndex = pcr_index;
234				e->eventType = event->eventType;
235				e->ulPcrValueLength = 20;
236
237				/* copy the SHA1 XXX endianess ignored */
238				memcpy(e->rgbPcrValue, event->digest, 20);
239
240				e->ulEventLength = event->eventDataSize;
241
242				if (event->eventDataSize>0) {
243					e->rgbEvent = malloc(e->ulEventLength);
244					if (e->rgbEvent == NULL) {
245						LogError("malloc of %d bytes failed.",
246							 e->ulEventLength);
247						free(e->rgbPcrValue);
248						free(e);
249						e = NULL;
250						break;
251					}
252					if ((fread(e->rgbEvent,
253						   event->eventDataSize,
254						   1, handle)) <= 0) {
255						LogError("read from event source failed: %s",
256							 strerror(errno));
257						return result;
258					}
259				} else {
260					e->rgbEvent = NULL;
261				}
262				result = TSS_SUCCESS;
263
264				break;
265			} else {
266				/* skip */
267				if (event->eventDataSize > 0) {
268					fseek(handle,event->eventDataSize,SEEK_CUR);
269				}
270			}
271			seen_indices++;
272		} else {
273			/* skip */
274			if (event->eventDataSize > 0) {
275				fseek(handle,event->eventDataSize,SEEK_CUR);
276			}
277		}
278	}
279
280done:
281	if (!ppEvent) {
282		*num = seen_indices;
283		result = TSS_SUCCESS;
284	} else if (e == NULL)
285		*ppEvent = NULL;
286
287	return result;
288}
289
290int
291bios_close(FILE *handle)
292{
293	fclose(handle);
294
295	return 0;
296}
297
298#endif
299