Request missing SWID tags in a directed PA-TNC message
[strongswan.git] / src / libimcv / pts / pts_ima_bios_list.c
1 /*
2 * Copyright (C) 2011-2014 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pts_ima_bios_list.h"
17
18 #include <utils/debug.h>
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25
26 typedef struct private_pts_ima_bios_list_t private_pts_ima_bios_list_t;
27 typedef struct bios_entry_t bios_entry_t;
28 typedef enum event_type_t event_type_t;
29
30 enum event_type_t {
31 /* BIOS Events (TCG PC Client Specification for Conventional BIOS 1.21) */
32 EV_PREBOOT_CERT = 0x00000000,
33 EV_POST_CODE = 0x00000001,
34 EV_UNUSED = 0x00000002,
35 EV_NO_ACTION = 0x00000003,
36 EV_SEPARATOR = 0x00000004,
37 EV_ACTION = 0x00000005,
38 EV_EVENT_TAG = 0x00000006,
39 EV_S_CRTM_CONTENTS = 0x00000007,
40 EV_S_CRTM_VERSION = 0x00000008,
41 EV_CPU_MICROCODE = 0x00000009,
42 EV_PLATFORM_CONFIG_FLAGS = 0x0000000A,
43 EV_TABLE_OF_DEVICES = 0x0000000B,
44 EV_COMPACT_HASH = 0x0000000C,
45 EV_IPL = 0x0000000D,
46 EV_IPL_PARTITION_DATA = 0x0000000E,
47 EV_NONHOST_CODE = 0x0000000F,
48 EV_NONHOST_CONFIG = 0x00000010,
49 EV_NONHOST_INFO = 0x00000011,
50 EV_OMIT_BOOT_DEVICE_EVENTS = 0x00000012,
51
52 /* EFI Events (TCG EFI Platform Specification 1.22) */
53 EV_EFI_EVENT_BASE = 0x80000000,
54 EV_EFI_VARIABLE_DRIVER_CONFIG = 0x80000001,
55 EV_EFI_VARIABLE_BOOT = 0x80000002,
56 EV_EFI_BOOT_SERVICES_APPLICATION = 0x80000003,
57 EV_EFI_BOOT_SERVICES_DRIVER = 0x80000004,
58 EV_EFI_RUNTIME_SERVICES_DRIVER = 0x80000005,
59 EV_EFI_GPT_EVENT = 0x80000006,
60 EV_EFI_ACTION = 0x80000007,
61 EV_EFI_PLATFORM_FIRMWARE_BLOB = 0x80000008,
62 EV_EFI_HANDOFF_TABLES = 0x80000009,
63
64 EV_EFI_VARIABLE_AUTHORITY = 0x800000E0
65 };
66
67 ENUM_BEGIN(event_type_names, EV_PREBOOT_CERT, EV_OMIT_BOOT_DEVICE_EVENTS,
68 "Preboot Cert",
69 "POST Code",
70 "Unused",
71 "No Action",
72 "Separator",
73 "Action",
74 "Event Tag",
75 "S-CRTM Contents",
76 "S-CRTM Version",
77 "CPU Microcode",
78 "Platform Config Flags",
79 "Table of Devices",
80 "Compact Hash",
81 "IPL",
82 "IPL Partition Data",
83 "Nonhost Code",
84 "Nonhost Config",
85 "Nonhost Info",
86 "Omit Boot Device Events"
87 );
88
89 ENUM_NEXT(event_type_names, EV_EFI_EVENT_BASE, EV_EFI_HANDOFF_TABLES,
90 EV_OMIT_BOOT_DEVICE_EVENTS,
91 "EFI Event Base",
92 "EFI Variable Driver Config",
93 "EFI Variable Boot",
94 "EFI Boot Services Application",
95 "EFI Boot Services Driver",
96 "EFI Runtime Services Driver",
97 "EFI GPT Event",
98 "EFI Action",
99 "EFI Platform Firmware Blob",
100 "EFI Handoff Tables"
101 );
102 ENUM_NEXT(event_type_names, EV_EFI_VARIABLE_AUTHORITY, EV_EFI_VARIABLE_AUTHORITY,
103 EV_EFI_HANDOFF_TABLES,
104 "EFI Variable Authority"
105 );
106 ENUM_END(event_type_names, EV_EFI_VARIABLE_AUTHORITY);
107
108 /**
109 * Private data of a pts_ima_bios_list_t object.
110 *
111 */
112 struct private_pts_ima_bios_list_t {
113
114 /**
115 * Public pts_ima_bios_list_t interface.
116 */
117 pts_ima_bios_list_t public;
118
119 /**
120 * List of BIOS measurement entries
121 */
122 linked_list_t *list;
123
124 /**
125 * Time when BIOS measurements were taken
126 */
127 time_t creation_time;
128
129 };
130
131 /**
132 * Linux IMA BIOS measurement entry
133 */
134 struct bios_entry_t {
135
136 /**
137 * PCR register
138 */
139 uint32_t pcr;
140
141 /**
142 * SHA1 measurement hash
143 */
144 chunk_t measurement;
145 };
146
147 /**
148 * Free a bios_entry_t object
149 */
150 static void free_bios_entry(bios_entry_t *this)
151 {
152 free(this->measurement.ptr);
153 free(this);
154 }
155
156 METHOD(pts_ima_bios_list_t, get_time, time_t,
157 private_pts_ima_bios_list_t *this)
158 {
159 return this->creation_time;
160 }
161
162 METHOD(pts_ima_bios_list_t, get_count, int,
163 private_pts_ima_bios_list_t *this)
164 {
165 return this->list->get_count(this->list);
166 }
167
168 METHOD(pts_ima_bios_list_t, get_next, status_t,
169 private_pts_ima_bios_list_t *this, uint32_t *pcr, chunk_t *measurement)
170 {
171 bios_entry_t *entry;
172 status_t status;
173
174 status = this->list->remove_first(this->list, (void**)&entry);
175 *pcr = entry->pcr;
176 *measurement = entry->measurement;
177 free(entry);
178
179 return status;
180 }
181
182 METHOD(pts_ima_bios_list_t, destroy, void,
183 private_pts_ima_bios_list_t *this)
184 {
185 this->list->destroy_function(this->list, (void *)free_bios_entry);
186 free(this);
187 }
188
189 /**
190 * See header
191 */
192 pts_ima_bios_list_t* pts_ima_bios_list_create(char *file)
193 {
194 private_pts_ima_bios_list_t *this;
195 uint32_t pcr, event_type, event_len, seek_len;
196 uint32_t buf_len = 2048;
197 uint8_t event_buf[buf_len];
198 chunk_t event;
199 bios_entry_t *entry;
200 struct stat st;
201 ssize_t res;
202 int fd;
203
204 fd = open(file, O_RDONLY);
205 if (fd == -1)
206 {
207 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
208 return NULL;
209 }
210
211 if (fstat(fd, &st) == -1)
212 {
213 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
214 strerror(errno));
215 close(fd);
216 return FALSE;
217 }
218
219 INIT(this,
220 .public = {
221 .get_time = _get_time,
222 .get_count = _get_count,
223 .get_next = _get_next,
224 .destroy = _destroy,
225 },
226 .creation_time = st.st_ctime,
227 .list = linked_list_create(),
228 );
229
230 DBG2(DBG_PTS, "PCR Event Type (Size)");
231 while (TRUE)
232 {
233 res = read(fd, &pcr, 4);
234 if (res == 0)
235 {
236 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
237 file, this->list->get_count(this->list));
238 close(fd);
239 return &this->public;
240 }
241
242 entry = malloc_thing(bios_entry_t);
243 entry->pcr = pcr;
244 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
245
246 if (res != 4)
247 {
248 break;
249 }
250 if (read(fd, &event_type, 4) != 4)
251 {
252 break;
253 }
254 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
255 {
256 break;
257 }
258 if (read(fd, &event_len, 4) != 4)
259 {
260 break;
261 }
262 DBG2(DBG_PTS, "%2u %N (%u bytes)", pcr, event_type_names, event_type,
263 event_len);
264
265 seek_len = (event_len > buf_len) ? event_len - buf_len : 0;
266 event_len -= seek_len;
267
268 if (read(fd, event_buf, event_len) != event_len)
269 {
270 break;
271 }
272 event = chunk_create(event_buf, event_len);
273 DBG3(DBG_PTS,"%B", &event);
274
275 if (event_type == EV_ACTION || event_type == EV_EFI_ACTION)
276 {
277 DBG2(DBG_PTS, " '%.*s'", event_len, event_buf);
278 }
279
280 if (seek_len > 0 && lseek(fd, seek_len, SEEK_CUR) == -1)
281 {
282 break;
283 }
284 this->list->insert_last(this->list, entry);
285 }
286
287 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
288 strerror(errno));
289 free_bios_entry(entry);
290 close(fd);
291 destroy(this);
292
293 return NULL;
294 }