Merge branch 'ikev1-clean' into ikev1-master
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_ima.c
1 /*
2 * Copyright (C) 2011 Andreas Steffen
3 *
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "ita_comp_ima.h"
18 #include "ita_comp_func_name.h"
19
20 #include "libpts.h"
21 #include "pts/components/pts_component.h"
22
23 #include <debug.h>
24 #include <pen/pen.h>
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 #define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
33 #define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
34 #define IMA_PCR_MAX 16
35
36 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
37
38 /**
39 * Private data of a pts_ita_comp_ima_t object.
40 *
41 */
42 struct pts_ita_comp_ima_t {
43
44 /**
45 * Public pts_component_t interface.
46 */
47 pts_component_t public;
48
49 /**
50 * Component Functional Name
51 */
52 pts_comp_func_name_t *name;
53
54 /**
55 * AIK keyid
56 */
57 chunk_t keyid;
58
59 /**
60 * Sub-component depth
61 */
62 u_int32_t depth;
63
64 /**
65 * PTS measurement database
66 */
67 pts_database_t *pts_db;
68
69 /**
70 * Primary key for Component Functional Name database entry
71 */
72 int cid;
73
74 /**
75 * Primary key for AIK database entry
76 */
77 int kid;
78
79 /**
80 * Component is registering measurements
81 */
82 bool is_registering;
83
84 /**
85 * IMA BIOS measurement time
86 */
87 time_t bios_measurement_time;
88
89 /**
90 * IMA BIOS measurements
91 */
92 linked_list_t *list;
93
94 /**
95 * Expected measurement count
96 */
97 int count;
98
99 /**
100 * Measurement sequence number
101 */
102 int seq_no;
103
104 /**
105 * Shadow PCR registers
106 */
107 chunk_t pcrs[IMA_PCR_MAX];
108 };
109
110 typedef struct entry_t entry_t;
111
112 /**
113 * Linux IMA measurement entry
114 */
115 struct entry_t {
116
117 /**
118 * PCR register
119 */
120 u_int32_t pcr;
121
122 /**
123 * SHA1 measurement hash
124 */
125 chunk_t measurement;
126 };
127
128 /**
129 * Free an entry_t object
130 */
131 static void free_entry(entry_t *this)
132 {
133 free(this->measurement.ptr);
134 free(this);
135 }
136
137 /**
138 * Load a PCR measurement file and determine the creation date
139 */
140 static bool load_measurements(char *file, linked_list_t *list, time_t *created)
141 {
142 u_int32_t pcr, num, len;
143 entry_t *entry;
144 struct stat st;
145 ssize_t res;
146 int fd;
147
148 fd = open(file, O_RDONLY);
149 if (fd == -1)
150 {
151 DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno));
152 return FALSE;
153 }
154
155 if (fstat(fd, &st) == -1)
156 {
157 DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file,
158 strerror(errno));
159 close(fd);
160 return FALSE;
161 }
162 *created = st.st_ctime;
163
164 while (TRUE)
165 {
166 res = read(fd, &pcr, 4);
167 if (res == 0)
168 {
169 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
170 file, list->get_count(list));
171 close(fd);
172 return TRUE;
173 }
174
175 entry = malloc_thing(entry_t);
176 entry->pcr = pcr;
177 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
178
179 if (res != 4)
180 {
181 break;
182 }
183 if (read(fd, &num, 4) != 4)
184 {
185 break;
186 }
187 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
188 {
189 break;
190 }
191 if (read(fd, &len, 4) != 4)
192 {
193 break;
194 }
195 if (lseek(fd, len, SEEK_CUR) == -1)
196 {
197 break;
198 }
199 list->insert_last(list, entry);
200 }
201
202 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s",
203 file, strerror(errno));
204 close(fd);
205 return FALSE;
206 }
207
208 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
209 pts_ita_comp_ima_t *this)
210 {
211 return this->name;
212 }
213
214 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
215 pts_ita_comp_ima_t *this)
216 {
217 return PTS_REQ_FUNC_COMP_EVID_PCR;
218 }
219
220 METHOD(pts_component_t, get_depth, u_int32_t,
221 pts_ita_comp_ima_t *this)
222 {
223 return this->depth;
224 }
225
226 METHOD(pts_component_t, measure, status_t,
227 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
228 {
229 pts_comp_evidence_t *evid;
230 chunk_t pcr_before, pcr_after;
231 pts_pcr_transform_t pcr_transform;
232 pts_meas_algorithms_t hash_algo;
233 size_t pcr_len;
234 entry_t *entry;
235 hasher_t *hasher;
236
237 hash_algo = PTS_MEAS_ALGO_SHA1;
238 pcr_len = pts->get_pcr_len(pts);
239 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
240
241 if (this->list->get_count(this->list) == 0)
242 {
243 if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list,
244 &this->bios_measurement_time))
245 {
246 return FAILED;
247 }
248 }
249
250 if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS)
251 {
252 DBG1(DBG_PTS, "could not retrieve measurement entry");
253 return FAILED;
254 }
255
256 pcr_before = chunk_clone(this->pcrs[entry->pcr]);
257
258 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
259 hasher->get_hash(hasher, pcr_before, NULL);
260 hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr);
261 hasher->destroy(hasher);
262
263 pcr_after = chunk_clone(this->pcrs[entry->pcr]);
264
265 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
266 this->depth, entry->pcr, hash_algo, pcr_transform,
267 this->bios_measurement_time, entry->measurement);
268 evid->set_pcr_info(evid, pcr_before, pcr_after);
269
270 free(entry);
271
272 return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS;
273 }
274
275 METHOD(pts_component_t, verify, status_t,
276 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
277 {
278 bool has_pcr_info;
279 u_int32_t extended_pcr, vid, name;
280 enum_name_t *names;
281 pts_meas_algorithms_t algo;
282 pts_pcr_transform_t transform;
283 time_t measurement_time;
284 chunk_t measurement, pcr_before, pcr_after;
285
286 measurement = evidence->get_measurement(evidence, &extended_pcr,
287 &algo, &transform, &measurement_time);
288
289 if (!this->keyid.ptr)
290 {
291 if (!pts->get_aik_keyid(pts, &this->keyid))
292 {
293 return FAILED;
294 }
295 this->keyid = chunk_clone(this->keyid);
296
297 if (!this->pts_db)
298 {
299 DBG1(DBG_PTS, "pts database not available");
300 return FAILED;
301 }
302 if (this->pts_db->get_comp_measurement_count(this->pts_db,
303 this->name, this->keyid, algo,
304 &this->cid, &this->kid, &this->count) != SUCCESS)
305 {
306 return FAILED;
307 }
308 vid = this->name->get_vendor_id(this->name);
309 name = this->name->get_name(this->name);
310 names = pts_components->get_comp_func_names(pts_components, vid);
311
312 if (this->count)
313 {
314 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
315 "measurements", this->count, pen_names, vid, names, name);
316 }
317 else
318 {
319 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
320 "measurements", pen_names, vid, names, name);
321 this->is_registering = TRUE;
322 }
323 }
324
325 if (this->is_registering)
326 {
327 if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
328 this->cid, this->kid, ++this->seq_no,
329 extended_pcr, algo) != SUCCESS)
330 {
331 return FAILED;
332 }
333 this->count = this->seq_no + 1;
334 }
335 else
336 {
337 if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
338 this->cid, this->kid, ++this->seq_no,
339 extended_pcr, algo) != SUCCESS)
340 {
341 return FAILED;
342 }
343 }
344
345 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
346 if (has_pcr_info)
347 {
348 if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
349 {
350 return FAILED;
351 }
352 }
353
354 return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
355 }
356
357 METHOD(pts_component_t, check_off_registrations, bool,
358 pts_ita_comp_ima_t *this)
359 {
360 u_int32_t vid, name;
361 enum_name_t *names;
362
363 if (!this->is_registering)
364 {
365 return FALSE;
366 }
367
368 /* Finalize registration */
369 this->is_registering = FALSE;
370
371 vid = this->name->get_vendor_id(this->name);
372 name = this->name->get_name(this->name);
373 names = pts_components->get_comp_func_names(pts_components, vid);
374 DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
375 "measurements", this->seq_no, pen_names, vid, names, name);
376 return TRUE;
377 }
378
379 METHOD(pts_component_t, destroy, void,
380 pts_ita_comp_ima_t *this)
381 {
382 int i, count;
383 u_int32_t vid, name;
384 enum_name_t *names;
385
386 for (i = 0; i < IMA_PCR_MAX; i++)
387 {
388 free(this->pcrs[i].ptr);
389 }
390 if (this->is_registering)
391 {
392 count = this->pts_db->delete_comp_measurements(this->pts_db,
393 this->cid, this->kid);
394 vid = this->name->get_vendor_id(this->name);
395 name = this->name->get_name(this->name);
396 names = pts_components->get_comp_func_names(pts_components, vid);
397 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
398 "evidence measurements", count, pen_names, vid, names, name);
399 }
400 this->list->destroy_function(this->list, (void *)free_entry);
401 this->name->destroy(this->name);
402 free(this->keyid.ptr);
403 free(this);
404 }
405
406 /**
407 * See header
408 */
409 pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
410 pts_database_t *pts_db)
411 {
412 pts_ita_comp_ima_t *this;
413 int i;
414
415 INIT(this,
416 .public = {
417 .get_comp_func_name = _get_comp_func_name,
418 .get_evidence_flags = _get_evidence_flags,
419 .get_depth = _get_depth,
420 .measure = _measure,
421 .verify = _verify,
422 .check_off_registrations = _check_off_registrations,
423 .destroy = _destroy,
424 },
425 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
426 qualifier),
427 .depth = depth,
428 .pts_db = pts_db,
429 .list = linked_list_create(),
430 );
431
432 for (i = 0; i < IMA_PCR_MAX; i++)
433 {
434 this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1);
435 memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1);
436 }
437 return &this->public;
438 }
439