ikev1: Handle queued TRANSACTION messages only after processing replies
[strongswan.git] / src / libimcv / pts / pts_ima_event_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_event_list.h"
17
18 #include <utils/debug.h>
19 #include <crypto/hashers/hasher.h>
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <errno.h>
26
27 typedef struct private_pts_ima_event_list_t private_pts_ima_event_list_t;
28 typedef struct event_entry_t event_entry_t;
29
30 #define IMA_TYPE_LEN 3
31 #define IMA_NG_TYPE_LEN 6
32 #define IMA_TYPE_LEN_MAX 10
33 #define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
34
35 /**
36 * Private data of a pts_ima_event_list_t object.
37 *
38 */
39 struct private_pts_ima_event_list_t {
40
41 /**
42 * Public pts_ima_event_list_t interface.
43 */
44 pts_ima_event_list_t public;
45
46 /**
47 * List of BIOS measurement entries
48 */
49 linked_list_t *list;
50
51 /**
52 * Time when IMA runtime file measurements were taken
53 */
54 time_t creation_time;
55
56 };
57
58 /**
59 * Linux IMA runtime file measurement entry
60 */
61 struct event_entry_t {
62
63 /**
64 * SHA1 measurement hash
65 */
66 chunk_t measurement;
67
68 /**
69 * IMA-NG hash algorithm name or NULL
70 */
71 char *algo;
72
73 /**
74 * IMA-NG eventname or IMA filename
75 */
76 char *name;
77 };
78
79 /**
80 * Free an ima_event_t object
81 */
82 static void free_event_entry(event_entry_t *this)
83 {
84 free(this->measurement.ptr);
85 free(this->algo);
86 free(this->name);
87 free(this);
88 }
89
90 METHOD(pts_ima_event_list_t, get_time, time_t,
91 private_pts_ima_event_list_t *this)
92 {
93 return this->creation_time;
94 }
95
96 METHOD(pts_ima_event_list_t, get_count, int,
97 private_pts_ima_event_list_t *this)
98 {
99 return this->list->get_count(this->list);
100 }
101
102 METHOD(pts_ima_event_list_t, get_next, status_t,
103 private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo,
104 char **name)
105 {
106 event_entry_t *entry;
107 status_t status;
108
109 status = this->list->remove_first(this->list, (void**)&entry);
110 *measurement = entry->measurement;
111 *algo = entry->algo;
112 *name = entry->name;
113 free(entry);
114
115 return status;
116 }
117
118 METHOD(pts_ima_event_list_t, destroy, void,
119 private_pts_ima_event_list_t *this)
120 {
121 this->list->destroy_function(this->list, (void *)free_event_entry);
122 free(this);
123 }
124
125 /**
126 * See header
127 */
128 pts_ima_event_list_t* pts_ima_event_list_create(char *file)
129 {
130 private_pts_ima_event_list_t *this;
131 event_entry_t *entry;
132 uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
133 char type[IMA_TYPE_LEN_MAX];
134 char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
135 char *pos, *error = "";
136 struct stat st;
137 ssize_t res;
138 bool ima_ng;
139 int fd;
140
141 fd = open(file, O_RDONLY);
142 if (fd == -1)
143 {
144 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
145 return NULL;
146 }
147
148 if (fstat(fd, &st) == -1)
149 {
150 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
151 strerror(errno));
152 close(fd);
153 return NULL;
154 }
155
156 INIT(this,
157 .public = {
158 .get_time = _get_time,
159 .get_count = _get_count,
160 .get_next = _get_next,
161 .destroy = _destroy,
162 },
163 .creation_time = st.st_ctime,
164 .list = linked_list_create(),
165 );
166
167 while (TRUE)
168 {
169 /* read 32 bit PCR number in host order */
170 res = read(fd, &pcr, 4);
171
172 /* exit if no more measurement data is available */
173 if (res == 0)
174 {
175 DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
176 file, this->list->get_count(this->list));
177 close(fd);
178 return &this->public;
179 }
180
181 /* create and initialize new IMA entry */
182 entry = malloc_thing(event_entry_t);
183 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
184 entry->algo = NULL;
185 entry->name = NULL;
186
187 if (res != 4 || pcr != IMA_PCR)
188 {
189 error = "invalid IMA PCR field";
190 break;
191 }
192
193 /* read 20 byte SHA-1 measurement digest */
194 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
195 {
196 error = "invalid SHA-1 digest field";
197 break;
198 }
199
200 /* read 32 bit length of IMA type string in host order */
201 if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
202 {
203 error = "invalid IMA type field length";
204 break;
205 }
206
207 /* read and interpret IMA type string */
208 if (read(fd, type, type_len) != type_len)
209 {
210 error = "invalid IMA type field";
211 break;
212 }
213 if (type_len == IMA_NG_TYPE_LEN &&
214 memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
215 {
216 ima_ng = TRUE;
217 }
218 else if (type_len == IMA_TYPE_LEN &&
219 memeq(type, "ima", IMA_TYPE_LEN))
220 {
221 ima_ng = FALSE;
222 }
223 else
224 {
225 error = "unknown IMA type";
226 break;
227 }
228
229 if (ima_ng)
230 {
231 /* read the 32 bit length of the event data in host order */
232 if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
233 {
234 error = "invalid event data field length";
235 break;
236 }
237
238 /* read the 32 bit length of the algo_digest string in host order */
239 if (read(fd, &algo_digest_len, 4) != 4 ||
240 algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
241 eventdata_len < 4 + algo_digest_len + 4)
242 {
243 error = "invalid digest_with_algo field length";
244 break;
245 }
246
247 /* read the IMA algo_digest string */
248 if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
249 {
250 error = "invalid digest_with_algo field";
251 break;
252 }
253
254 /* extract the hash algorithm name */
255 pos = memchr(algo_digest, '\0', algo_digest_len);
256 if (!pos)
257 {
258 error = "no algo field";
259 break;
260 }
261 algo_len = pos - algo_digest + 1;
262
263 if (algo_len > IMA_ALGO_LEN_MAX ||
264 algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
265 {
266 error = "invalid algo field";
267 break;
268 }
269
270 /* copy and store the hash algorithm name */
271 entry->algo = malloc(algo_len);
272 memcpy(entry->algo, algo_digest, algo_len);
273
274 /* read the 32 bit length of the event name in host order */
275 if (read(fd, &name_len, 4) != 4 ||
276 eventdata_len != 4 + algo_digest_len + 4 + name_len)
277 {
278 error = "invalid filename field length";
279 break;
280 }
281
282 /* allocate memory for the file name */
283 entry->name = malloc(name_len);
284
285 /* read file name */
286 if (read(fd, entry->name, name_len) != name_len)
287 {
288 error = "invalid filename field";
289 break;
290 }
291 }
292 else
293 {
294 /* skip SHA-1 digest of the file content */
295 if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
296 {
297 break;
298 }
299
300 /* read the 32 bit length of the file name in host order */
301 if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX)
302 {
303 error = "invalid filename field length";
304 break;
305 }
306
307 /* allocate memory for the file name */
308 entry->name = malloc(name_len + 1);
309
310 /* read file name */
311 if (read(fd, entry->name, name_len) != name_len)
312 {
313 error = "invalid eventname field";
314 break;
315 }
316
317 /* terminate the file name with a nul character */
318 entry->name[name_len] = '\0';
319 }
320
321 this->list->insert_last(this->list, entry);
322 }
323
324 DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
325 free_event_entry(entry);
326 close(fd);
327 destroy(this);
328
329 return NULL;
330 }