Annotation of embedaddon/strongswan/src/libimcv/pts/pts_ima_event_list.c, revision 1.1.1.2
1.1 misho 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
1.1.1.2 ! misho 34: #define IMA_FILENAME_LEN_MAX 255
! 35:
! 36:
1.1 misho 37:
38: /**
39: * Private data of a pts_ima_event_list_t object.
40: *
41: */
42: struct private_pts_ima_event_list_t {
43:
44: /**
45: * Public pts_ima_event_list_t interface.
46: */
47: pts_ima_event_list_t public;
48:
49: /**
50: * List of BIOS measurement entries
51: */
52: linked_list_t *list;
53:
54: /**
55: * Time when IMA runtime file measurements were taken
56: */
57: time_t creation_time;
58:
59: };
60:
61: /**
62: * Linux IMA runtime file measurement entry
63: */
64: struct event_entry_t {
65:
66: /**
1.1.1.2 ! misho 67: * Special IMA measurement hash
1.1 misho 68: */
69: chunk_t measurement;
70:
71: /**
72: * IMA-NG hash algorithm name or NULL
73: */
74: char *algo;
75:
76: /**
77: * IMA-NG eventname or IMA filename
78: */
79: char *name;
80: };
81:
82: /**
83: * Free an ima_event_t object
84: */
85: static void free_event_entry(event_entry_t *this)
86: {
87: free(this->measurement.ptr);
88: free(this->algo);
89: free(this->name);
90: free(this);
91: }
92:
93: METHOD(pts_ima_event_list_t, get_time, time_t,
94: private_pts_ima_event_list_t *this)
95: {
96: return this->creation_time;
97: }
98:
99: METHOD(pts_ima_event_list_t, get_count, int,
100: private_pts_ima_event_list_t *this)
101: {
102: return this->list->get_count(this->list);
103: }
104:
105: METHOD(pts_ima_event_list_t, get_next, status_t,
106: private_pts_ima_event_list_t *this, chunk_t *measurement, char **algo,
107: char **name)
108: {
109: event_entry_t *entry;
110: status_t status;
111:
112: status = this->list->remove_first(this->list, (void**)&entry);
113: *measurement = entry->measurement;
114: *algo = entry->algo;
115: *name = entry->name;
116: free(entry);
117:
118: return status;
119: }
120:
121: METHOD(pts_ima_event_list_t, destroy, void,
122: private_pts_ima_event_list_t *this)
123: {
124: this->list->destroy_function(this->list, (void *)free_event_entry);
125: free(this);
126: }
127:
128: /**
129: * See header
130: */
1.1.1.2 ! misho 131: pts_ima_event_list_t* pts_ima_event_list_create(char *file,
! 132: pts_meas_algorithms_t pcr_algo, bool pcr_padding)
1.1 misho 133: {
134: private_pts_ima_event_list_t *this;
135: event_entry_t *entry;
1.1.1.2 ! misho 136: chunk_t digest;
1.1 misho 137: uint32_t pcr, type_len, name_len, eventdata_len, algo_digest_len, algo_len;
1.1.1.2 ! misho 138: size_t hash_size;
1.1 misho 139: char type[IMA_TYPE_LEN_MAX];
140: char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
141: char *pos, *error = "";
142: struct stat st;
143: ssize_t res;
144: bool ima_ng;
145: int fd;
146:
147: fd = open(file, O_RDONLY);
148: if (fd == -1)
149: {
150: DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
151: return NULL;
152: }
153:
154: if (fstat(fd, &st) == -1)
155: {
156: DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
157: strerror(errno));
158: close(fd);
159: return NULL;
160: }
161:
162: INIT(this,
163: .public = {
164: .get_time = _get_time,
165: .get_count = _get_count,
166: .get_next = _get_next,
167: .destroy = _destroy,
168: },
169: .creation_time = st.st_ctime,
170: .list = linked_list_create(),
171: );
172:
1.1.1.2 ! misho 173: hash_size = pts_meas_algo_hash_size(pcr_algo);
! 174:
1.1 misho 175: while (TRUE)
176: {
177: /* read 32 bit PCR number in host order */
178: res = read(fd, &pcr, 4);
179:
180: /* exit if no more measurement data is available */
181: if (res == 0)
182: {
183: DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
184: file, this->list->get_count(this->list));
185: close(fd);
1.1.1.2 ! misho 186:
1.1 misho 187: return &this->public;
188: }
189:
190: /* create and initialize new IMA entry */
191: entry = malloc_thing(event_entry_t);
1.1.1.2 ! misho 192: entry->measurement = chunk_alloc(hash_size);
1.1 misho 193: entry->algo = NULL;
194: entry->name = NULL;
195:
196: if (res != 4 || pcr != IMA_PCR)
197: {
198: error = "invalid IMA PCR field";
199: break;
200: }
201:
1.1.1.2 ! misho 202: if (pcr_padding)
! 203: {
! 204: memset(entry->measurement.ptr, 0x00, hash_size);
! 205: }
! 206:
! 207: /* read 20 byte SHA-1 IMA measurement digest */
1.1 misho 208: if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
209: {
210: error = "invalid SHA-1 digest field";
211: break;
212: }
213:
214: /* read 32 bit length of IMA type string in host order */
215: if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
216: {
217: error = "invalid IMA type field length";
218: break;
219: }
220:
221: /* read and interpret IMA type string */
222: if (read(fd, type, type_len) != type_len)
223: {
224: error = "invalid IMA type field";
225: break;
226: }
227: if (type_len == IMA_NG_TYPE_LEN &&
228: memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
229: {
230: ima_ng = TRUE;
231: }
232: else if (type_len == IMA_TYPE_LEN &&
233: memeq(type, "ima", IMA_TYPE_LEN))
234: {
235: ima_ng = FALSE;
236: }
237: else
238: {
239: error = "unknown IMA type";
240: break;
241: }
242:
243: if (ima_ng)
244: {
245: /* read the 32 bit length of the event data in host order */
246: if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
247: {
248: error = "invalid event data field length";
249: break;
250: }
251:
252: /* read the 32 bit length of the algo_digest string in host order */
253: if (read(fd, &algo_digest_len, 4) != 4 ||
254: algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
255: eventdata_len < 4 + algo_digest_len + 4)
256: {
257: error = "invalid digest_with_algo field length";
258: break;
259: }
260:
261: /* read the IMA algo_digest string */
262: if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
263: {
264: error = "invalid digest_with_algo field";
265: break;
266: }
267:
268: /* extract the hash algorithm name */
269: pos = memchr(algo_digest, '\0', algo_digest_len);
270: if (!pos)
271: {
272: error = "no algo field";
273: break;
274: }
275: algo_len = pos - algo_digest + 1;
276:
277: if (algo_len > IMA_ALGO_LEN_MAX ||
278: algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
279: {
280: error = "invalid algo field";
281: break;
282: }
283:
284: /* copy and store the hash algorithm name */
285: entry->algo = malloc(algo_len);
286: memcpy(entry->algo, algo_digest, algo_len);
287:
1.1.1.2 ! misho 288: /* extract the digest */
! 289: digest = chunk_create(pos + 1, algo_digest_len - algo_len);
! 290:
1.1 misho 291: /* read the 32 bit length of the event name in host order */
292: if (read(fd, &name_len, 4) != 4 ||
293: eventdata_len != 4 + algo_digest_len + 4 + name_len)
294: {
295: error = "invalid filename field length";
296: break;
297: }
298:
299: /* allocate memory for the file name */
300: entry->name = malloc(name_len);
301:
302: /* read file name */
303: if (read(fd, entry->name, name_len) != name_len)
304: {
305: error = "invalid filename field";
306: break;
307: }
1.1.1.2 ! misho 308:
! 309: /* re-compute IMA measurement digest for non-SHA1 hash algorithms */
! 310: if (pcr_algo != PTS_MEAS_ALGO_SHA1 && !pcr_padding)
! 311: {
! 312: if (!pts_ima_event_hash(digest, entry->algo, entry->name,
! 313: pcr_algo, entry->measurement.ptr))
! 314: {
! 315: break;
! 316: }
! 317:
! 318: }
1.1 misho 319: }
320: else
321: {
322: /* skip SHA-1 digest of the file content */
323: if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
324: {
325: break;
326: }
327:
328: /* read the 32 bit length of the file name in host order */
329: if (read(fd, &name_len, 4) != 4 || name_len == UINT32_MAX)
330: {
331: error = "invalid filename field length";
332: break;
333: }
334:
335: /* allocate memory for the file name */
336: entry->name = malloc(name_len + 1);
337:
338: /* read file name */
339: if (read(fd, entry->name, name_len) != name_len)
340: {
341: error = "invalid eventname field";
342: break;
343: }
344:
345: /* terminate the file name with a nul character */
346: entry->name[name_len] = '\0';
347: }
348:
349: this->list->insert_last(this->list, entry);
350: }
351:
352: DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
353: free_event_entry(entry);
354: close(fd);
355: destroy(this);
356:
357: return NULL;
358: }
1.1.1.2 ! misho 359:
! 360: /**
! 361: * See header
! 362: */
! 363: bool pts_ima_event_hash(chunk_t digest, char *ima_algo, char *ima_name,
! 364: pts_meas_algorithms_t pcr_algo, char *hash_buf)
! 365: {
! 366: hash_algorithm_t hash_alg;
! 367: hasher_t *hasher;
! 368: bool success;
! 369:
! 370: hash_alg = pts_meas_algo_to_hash(pcr_algo);
! 371: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
! 372: if (!hasher)
! 373: {
! 374: DBG1(DBG_PTS, "%N hasher could not be created",
! 375: hash_algorithm_short_names, hash_alg);
! 376: return FALSE;
! 377: }
! 378:
! 379: if (ima_algo)
! 380: {
! 381: uint32_t ad_len, n_len;
! 382: chunk_t algo_name, event_name, algo_digest_len, name_len;
! 383:
! 384: /* IMA-NG hash */
! 385: algo_name = chunk_create(ima_algo, strlen(ima_algo) + 1);
! 386: event_name = chunk_create(ima_name, strlen(ima_name) + 1);
! 387:
! 388: ad_len = htole32(algo_name.len + digest.len);
! 389: algo_digest_len = chunk_create((uint8_t*)&ad_len, sizeof(ad_len));
! 390:
! 391: n_len = htole32(event_name.len);
! 392: name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
! 393:
! 394: success = hasher->get_hash(hasher, algo_digest_len, NULL) &&
! 395: hasher->get_hash(hasher, algo_name, NULL) &&
! 396: hasher->get_hash(hasher, digest, NULL) &&
! 397: hasher->get_hash(hasher, name_len, NULL) &&
! 398: hasher->get_hash(hasher, event_name, hash_buf);
! 399: }
! 400: else
! 401: {
! 402: u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
! 403: chunk_t file_name;
! 404:
! 405: /* IMA legacy hash */
! 406: memset(filename_buffer, 0, sizeof(filename_buffer));
! 407: strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX);
! 408: file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
! 409:
! 410: success = hasher->get_hash(hasher, digest, NULL) &&
! 411: hasher->get_hash(hasher, file_name, hash_buf);
! 412: }
! 413: hasher->destroy(hasher);
! 414:
! 415: return success;
! 416: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>