b1a8b861a41605f3d2d4e25d45adc9cd48d27380
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_ima.c
1 /*
2 * Copyright (C) 2011-2012 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 "ita_comp_ima.h"
17 #include "ita_comp_func_name.h"
18
19 #include "libpts.h"
20 #include "pts/pts_pcr.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 SECURITY_DIR "/sys/kernel/security/"
33 #define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
34 #define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
35 #define IMA_PCR 10
36 #define IMA_TYPE_LEN 3
37 #define IMA_FILENAME_LEN_MAX 255
38
39 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
40 typedef struct bios_entry_t bios_entry_t;
41 typedef struct ima_entry_t ima_entry_t;
42 typedef enum ima_state_t ima_state_t;
43
44 enum ima_state_t {
45 IMA_STATE_INIT,
46 IMA_STATE_BIOS,
47 IMA_STATE_BOOT_AGGREGATE,
48 IMA_STATE_RUNTIME,
49 IMA_STATE_END
50 };
51
52 /**
53 * Private data of a pts_ita_comp_ima_t object.
54 *
55 */
56 struct pts_ita_comp_ima_t {
57
58 /**
59 * Public pts_component_t interface.
60 */
61 pts_component_t public;
62
63 /**
64 * Component Functional Name
65 */
66 pts_comp_func_name_t *name;
67
68 /**
69 * AIK keyid
70 */
71 chunk_t keyid;
72
73 /**
74 * Sub-component depth
75 */
76 u_int32_t depth;
77
78 /**
79 * PTS measurement database
80 */
81 pts_database_t *pts_db;
82
83 /**
84 * Primary key for Component Functional Name database entry
85 */
86 int cid;
87
88 /**
89 * Primary key for AIK database entry
90 */
91 int kid;
92
93 /**
94 * Component is registering measurements
95 */
96 bool is_registering;
97
98 /**
99 * Measurement sequence number
100 */
101 int seq_no;
102
103 /**
104 * Expected IMA BIOS measurement count
105 */
106 int bios_count;
107
108 /**
109 * IMA BIOS measurements
110 */
111 linked_list_t *bios_list;
112
113 /**
114 * IMA runtime file measurements
115 */
116 linked_list_t *ima_list;
117
118 /**
119 * Whether to send pcr_before and pcr_after info
120 */
121 bool pcr_info;
122
123 /**
124 * IMA measurement time
125 */
126 time_t measurement_time;
127
128 /**
129 * IMA state machine
130 */
131 ima_state_t state;
132
133 /**
134 * Total number of component measurements
135 */
136 int count;
137
138 /**
139 * Number of successful component measurements
140 */
141 int count_ok;
142
143 /**
144 * Number of unknown component measurements
145 */
146 int count_unknown;
147
148 /**
149 * Number of differing component measurements
150 */
151 int count_differ;
152
153 /**
154 * Number of failed component measurements
155 */
156 int count_failed;
157
158 };
159
160 /**
161 * Linux IMA BIOS measurement entry
162 */
163 struct bios_entry_t {
164
165 /**
166 * PCR register
167 */
168 u_int32_t pcr;
169
170 /**
171 * SHA1 measurement hash
172 */
173 chunk_t measurement;
174 };
175
176 /**
177 * Linux IMA runtime file measurement entry
178 */
179 struct ima_entry_t {
180
181 /**
182 * SHA1 measurement hash
183 */
184 chunk_t measurement;
185
186 /**
187 * SHA1 file measurement thash
188 */
189 chunk_t file_measurement;
190
191 /**
192 * absolute path of executable files or basename of dynamic libraries
193 */
194 char *filename;
195 };
196
197 /**
198 * Free a bios_entry_t object
199 */
200 static void free_bios_entry(bios_entry_t *this)
201 {
202 free(this->measurement.ptr);
203 free(this);
204 }
205
206 /**
207 * Free an ima_entry_t object
208 */
209 static void free_ima_entry(ima_entry_t *this)
210 {
211 free(this->measurement.ptr);
212 free(this->file_measurement.ptr);
213 free(this->filename);
214 free(this);
215 }
216
217 /**
218 * Load a PCR measurement file and determine the creation date
219 */
220 static bool load_bios_measurements(char *file, linked_list_t *list,
221 time_t *created)
222 {
223 u_int32_t pcr, num, len;
224 bios_entry_t *entry;
225 struct stat st;
226 ssize_t res;
227 int fd;
228
229 fd = open(file, O_RDONLY);
230 if (fd == -1)
231 {
232 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
233 return FALSE;
234 }
235
236 if (fstat(fd, &st) == -1)
237 {
238 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
239 strerror(errno));
240 close(fd);
241 return FALSE;
242 }
243 *created = st.st_ctime;
244
245 while (TRUE)
246 {
247 res = read(fd, &pcr, 4);
248 if (res == 0)
249 {
250 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
251 file, list->get_count(list));
252 close(fd);
253 return TRUE;
254 }
255
256 entry = malloc_thing(bios_entry_t);
257 entry->pcr = pcr;
258 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
259
260 if (res != 4)
261 {
262 break;
263 }
264 if (read(fd, &num, 4) != 4)
265 {
266 break;
267 }
268 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
269 {
270 break;
271 }
272 if (read(fd, &len, 4) != 4)
273 {
274 break;
275 }
276 if (lseek(fd, len, SEEK_CUR) == -1)
277 {
278 break;
279 }
280 list->insert_last(list, entry);
281 }
282
283 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
284 strerror(errno));
285 close(fd);
286 return FALSE;
287 }
288
289 /**
290 * Load an IMA runtime measurement file and determine the creation and
291 * update dates
292 */
293 static bool load_runtime_measurements(char *file, linked_list_t *list,
294 time_t *created)
295 {
296 u_int32_t pcr, len;
297 ima_entry_t *entry;
298 char type[IMA_TYPE_LEN];
299 struct stat st;
300 ssize_t res;
301 int fd;
302
303 fd = open(file, O_RDONLY);
304 if (fd == -1)
305 {
306 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
307 return TRUE;
308 }
309
310 if (fstat(fd, &st) == -1)
311 {
312 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
313 strerror(errno));
314 close(fd);
315 return FALSE;
316 }
317 *created = st.st_ctime;
318
319 while (TRUE)
320 {
321 res = read(fd, &pcr, 4);
322 if (res == 0)
323 {
324 DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
325 file, list->get_count(list));
326 close(fd);
327 return TRUE;
328 }
329
330 entry = malloc_thing(ima_entry_t);
331 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
332 entry->file_measurement = chunk_alloc(HASH_SIZE_SHA1);
333 entry->filename = NULL;
334
335 if (res != 4 || pcr != IMA_PCR)
336 {
337 break;
338 }
339 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
340 {
341 break;
342 }
343 if (read(fd, &len, 4) != 4 || len != IMA_TYPE_LEN)
344 {
345 break;
346 }
347 if (read(fd, type, IMA_TYPE_LEN) != IMA_TYPE_LEN ||
348 memcmp(type, "ima", IMA_TYPE_LEN))
349 {
350 break;
351 }
352 if (read(fd, entry->file_measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
353 {
354 break;
355 }
356 if (read(fd, &len, 4) != 4)
357 {
358 break;
359 }
360 entry->filename = malloc(len + 1);
361 if (read(fd, entry->filename, len) != len)
362 {
363 break;
364 }
365 entry->filename[len] = '\0';
366
367 list->insert_last(list, entry);
368 }
369
370 DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s",
371 file, strerror(errno));
372 close(fd);
373 return FALSE;
374 }
375
376 /**
377 * Extend measurement into PCR an create evidence
378 */
379 static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, pts_pcr_t *pcrs,
380 u_int32_t pcr, chunk_t measurement)
381 {
382 size_t pcr_len;
383 pts_pcr_transform_t pcr_transform;
384 pts_meas_algorithms_t hash_algo;
385 pts_comp_evidence_t *evidence;
386 chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty;
387
388 hash_algo = PTS_MEAS_ALGO_SHA1;
389 pcr_len = HASH_SIZE_SHA1;
390 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
391
392 if (this->pcr_info)
393 {
394 pcr_before = chunk_clone(pcrs->get(pcrs, pcr));
395 }
396 pcr_after = pcrs->extend(pcrs, pcr, measurement);
397 if (!pcr_after.ptr)
398 {
399 free(pcr_before.ptr);
400 return NULL;
401 }
402 evidence = pts_comp_evidence_create(this->name->clone(this->name),
403 this->depth, pcr, hash_algo, pcr_transform,
404 this->measurement_time, measurement);
405 if (this->pcr_info)
406 {
407 pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
408 evidence->set_pcr_info(evidence, pcr_before, pcr_after);
409 }
410 return evidence;
411 }
412
413 /**
414 * Compute and check boot aggregate value by hashing PCR0 to PCR7
415 */
416 static void check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement)
417 {
418 u_int32_t i;
419 u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
420 u_char pcr_buffer[HASH_SIZE_SHA1];
421 chunk_t file_name, boot_aggregate;
422 hasher_t *hasher;
423 bool pcr_ok = TRUE;
424
425 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
426 if (!hasher)
427 {
428 DBG1(DBG_PTS, "%N hasher could not be created",
429 hash_algorithm_short_names, HASH_SHA1);
430 }
431 for (i = 0; i < 8 && pcr_ok; i++)
432 {
433 pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL);
434 }
435 if (pcr_ok)
436 {
437 boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
438 memset(filename_buffer, 0, sizeof(filename_buffer));
439 strcpy(filename_buffer, "boot_aggregate");
440 file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
441
442 pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer) &&
443 hasher->get_hash(hasher, boot_aggregate, NULL) &&
444 hasher->get_hash(hasher, file_name, boot_aggregate.ptr);
445 }
446 hasher->destroy(hasher);
447
448 if (pcr_ok)
449 {
450 DBG1(DBG_PTS, "boot aggregate value is %scorrect",
451 chunk_equals(boot_aggregate, measurement) ? "":"in");
452 }
453 else
454 {
455 DBG1(DBG_PTS, "failed to compute boot aggregate value");
456 }
457 }
458
459 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
460 pts_ita_comp_ima_t *this)
461 {
462 return this->name;
463 }
464
465 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
466 pts_ita_comp_ima_t *this)
467 {
468 return PTS_REQ_FUNC_COMP_EVID_PCR;
469 }
470
471 METHOD(pts_component_t, get_depth, u_int32_t,
472 pts_ita_comp_ima_t *this)
473 {
474 return this->depth;
475 }
476
477 METHOD(pts_component_t, measure, status_t,
478 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
479 {
480 bios_entry_t *bios_entry;
481 ima_entry_t *ima_entry;
482 pts_pcr_t *pcrs;
483 pts_comp_evidence_t *evid = NULL;
484 status_t status;
485
486 pcrs = pts->get_pcrs(pts);
487
488 switch (this->state)
489 {
490 case IMA_STATE_INIT:
491 if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS, this->bios_list,
492 &this->measurement_time))
493 {
494 return FAILED;
495 }
496 this->state = IMA_STATE_BIOS;
497 /* fall through to next state */
498 case IMA_STATE_BIOS:
499 status = this->bios_list->remove_first(this->bios_list,
500 (void**)&bios_entry);
501 if (status != SUCCESS)
502 {
503 DBG1(DBG_PTS, "could not retrieve bios measurement entry");
504 return status;
505 }
506 evid = extend_pcr(this, pcrs, bios_entry->pcr,
507 bios_entry->measurement);
508 free(bios_entry);
509
510 /* break if still some BIOS measurements are left */
511 if (this->bios_list->get_count(this->bios_list))
512 {
513 break;
514 }
515
516 /* check if IMA runtime measurements are enabled */
517 if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS,
518 this->ima_list, &this->measurement_time))
519 {
520 return FAILED;
521 }
522
523 this->state = this->ima_list->get_count(this->ima_list) ?
524 IMA_STATE_BOOT_AGGREGATE : IMA_STATE_END;
525 break;
526 case IMA_STATE_BOOT_AGGREGATE:
527 case IMA_STATE_RUNTIME:
528 status = this->ima_list->remove_first(this->ima_list,
529 (void**)&ima_entry);
530 if (status != SUCCESS)
531 {
532 DBG1(DBG_PTS, "could not retrieve ima measurement entry");
533 return status;
534 }
535 if (this->state == IMA_STATE_BOOT_AGGREGATE)
536 {
537 check_boot_aggregate(pcrs, ima_entry->measurement);
538 }
539
540 evid = extend_pcr(this, pcrs, IMA_PCR, ima_entry->measurement);
541 if (evid)
542 {
543 evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
544 ima_entry->filename);
545 }
546 free(ima_entry->file_measurement.ptr);
547 free(ima_entry->filename);
548 free(ima_entry);
549
550 this->state = this->ima_list->get_count(this->ima_list) ?
551 IMA_STATE_RUNTIME : IMA_STATE_END;
552 break;
553 case IMA_STATE_END:
554 break;
555 }
556
557 *evidence = evid;
558 return evid ? ((this->state == IMA_STATE_END) ? SUCCESS : NEED_MORE) :
559 FAILED;
560 }
561
562 METHOD(pts_component_t, verify, status_t,
563 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
564 {
565 bool has_pcr_info;
566 u_int32_t extended_pcr, vid, name;
567 enum_name_t *names;
568 pts_meas_algorithms_t algo;
569 pts_pcr_transform_t transform;
570 pts_pcr_t *pcrs;
571 time_t measurement_time;
572 chunk_t measurement, pcr_before, pcr_after;
573 status_t status;
574 char *uri;
575
576 pcrs = pts->get_pcrs(pts);
577 measurement = evidence->get_measurement(evidence, &extended_pcr,
578 &algo, &transform, &measurement_time);
579
580 switch (this->state)
581 {
582 case IMA_STATE_INIT:
583 if (!pts->get_aik_keyid(pts, &this->keyid))
584 {
585 return FAILED;
586 }
587 this->keyid = chunk_clone(this->keyid);
588
589 if (!this->pts_db)
590 {
591 DBG1(DBG_PTS, "pts database not available");
592 return FAILED;
593 }
594 status = this->pts_db->get_comp_measurement_count(this->pts_db,
595 this->name, this->keyid, algo,
596 &this->cid, &this->kid, &this->bios_count);
597 if (status != SUCCESS)
598 {
599 return status;
600 }
601 vid = this->name->get_vendor_id(this->name);
602 name = this->name->get_name(this->name);
603 names = pts_components->get_comp_func_names(pts_components, vid);
604
605 if (this->bios_count)
606 {
607 DBG1(DBG_PTS, "checking %d %N '%N' BIOS evidence measurements",
608 this->bios_count, pen_names, vid, names, name);
609 }
610 else
611 {
612 DBG1(DBG_PTS, "registering %N '%N' BIOS evidence measurements",
613 pen_names, vid, names, name);
614 this->is_registering = TRUE;
615 }
616 this->state = IMA_STATE_BIOS;
617 /* fall through to next state */
618 case IMA_STATE_BIOS:
619 if (extended_pcr != IMA_PCR)
620 {
621 if (this->is_registering)
622 {
623 status = this->pts_db->insert_comp_measurement(this->pts_db,
624 measurement, this->cid, this->kid,
625 ++this->seq_no, extended_pcr, algo);
626 if (status != SUCCESS)
627 {
628 return status;
629 }
630 this->bios_count = this->seq_no + 1;
631 }
632 else
633 {
634 status = this->pts_db->check_comp_measurement(this->pts_db,
635 measurement, this->cid, this->kid,
636 ++this->seq_no, extended_pcr, algo);
637 if (status != SUCCESS)
638 {
639 return status;
640 }
641 }
642 break;
643 }
644 this->state = IMA_STATE_BOOT_AGGREGATE;
645 /* fall through to next state */
646 case IMA_STATE_BOOT_AGGREGATE:
647 check_boot_aggregate(pcrs, measurement);
648 this->state = IMA_STATE_RUNTIME;
649 break;
650 case IMA_STATE_RUNTIME:
651 this->count++;
652 if (evidence->get_validation(evidence, &uri) !=
653 PTS_COMP_EVID_VALIDATION_PASSED)
654 {
655 DBG1(DBG_PTS, "policy URI could no be retrieved");
656 this->count_failed++;
657 return FAILED;
658 }
659 status = this->pts_db->check_file_measurement(this->pts_db,
660 pts->get_platform_info(pts),
661 PTS_MEAS_ALGO_SHA1_IMA,
662 measurement, uri);
663 switch (status)
664 {
665 case SUCCESS:
666 DBG3(DBG_PTS, "%#B for '%s' is ok", &measurement, uri);
667 this->count_ok++;
668 break;
669 case NOT_FOUND:
670 DBG2(DBG_PTS, "%#B for '%s' not found", &measurement, uri);
671 this->count_unknown++;
672 break;
673 case VERIFY_ERROR:
674 DBG1(DBG_PTS, "%#B for '%s' differs", &measurement, uri);
675 this->count_differ++;
676 break;
677 case FAILED:
678 default:
679 DBG1(DBG_PTS, "%#B for '%s' failed", &measurement, uri);
680 this->count_failed++;
681 }
682
683 break;
684 case IMA_STATE_END:
685 break;
686 }
687
688 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
689 if (has_pcr_info)
690 {
691 if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
692 {
693 DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
694 extended_pcr);
695 }
696 if (pcrs->set(pcrs, extended_pcr, pcr_after))
697 {
698 return SUCCESS;
699 }
700 }
701 else
702 {
703 pcr_after = pcrs->extend(pcrs, extended_pcr, measurement);
704 if (pcr_after.ptr)
705 {
706 return SUCCESS;
707 }
708 }
709 return FAILED;
710 }
711
712 METHOD(pts_component_t, finalize, bool,
713 pts_ita_comp_ima_t *this)
714 {
715 u_int32_t vid, name;
716 enum_name_t *names;
717
718 vid = this->name->get_vendor_id(this->name);
719 name = this->name->get_name(this->name);
720 names = pts_components->get_comp_func_names(pts_components, vid);
721
722 if (this->is_registering)
723 {
724 /* close registration */
725 this->is_registering = FALSE;
726
727 DBG1(DBG_PTS, "registered %d %N '%N' BIOS evidence measurements",
728 this->seq_no, pen_names, vid, names, name);
729 }
730 else if (this->seq_no < this->bios_count)
731 {
732 DBG1(DBG_PTS, "%d of %d %N '%N' BIOS evidence measurements missing",
733 this->bios_count - this->seq_no, this->bios_count,
734 pen_names, vid, names, name);
735 return FALSE;
736 }
737
738 /* finalize IMA file measurements */
739 if (this->count)
740 {
741 DBG1(DBG_PTS, "processed %d %N '%N' file evidence measurements: "
742 "%d ok, %d unknown, %d differ, %d failed",
743 this->count, pen_names, vid, names, name,
744 this->count_ok, this->count_unknown, this->count_differ,
745 this->count_failed);
746
747 return !this->count_differ && !this->count_failed;
748 }
749
750 return TRUE;
751 }
752
753 METHOD(pts_component_t, destroy, void,
754 pts_ita_comp_ima_t *this)
755 {
756 int count;
757 u_int32_t vid, name;
758 enum_name_t *names;
759
760 if (this->is_registering)
761 {
762 count = this->pts_db->delete_comp_measurements(this->pts_db,
763 this->cid, this->kid);
764 vid = this->name->get_vendor_id(this->name);
765 name = this->name->get_name(this->name);
766 names = pts_components->get_comp_func_names(pts_components, vid);
767 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
768 "evidence measurements", count, pen_names, vid, names, name);
769 }
770 this->bios_list->destroy_function(this->bios_list, (void *)free_bios_entry);
771 this->ima_list->destroy_function(this->ima_list, (void *)free_ima_entry);
772 this->name->destroy(this->name);
773 free(this->keyid.ptr);
774 free(this);
775 }
776
777 /**
778 * See header
779 */
780 pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
781 pts_database_t *pts_db)
782 {
783 pts_ita_comp_ima_t *this;
784
785 INIT(this,
786 .public = {
787 .get_comp_func_name = _get_comp_func_name,
788 .get_evidence_flags = _get_evidence_flags,
789 .get_depth = _get_depth,
790 .measure = _measure,
791 .verify = _verify,
792 .finalize = _finalize,
793 .destroy = _destroy,
794 },
795 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
796 qualifier),
797 .depth = depth,
798 .pts_db = pts_db,
799 .bios_list = linked_list_create(),
800 .ima_list = linked_list_create(),
801 .pcr_info = lib->settings->get_bool(lib->settings,
802 "libimcv.plugins.imc-attestation.pcr_info", TRUE),
803 );
804
805 return &this->public;
806 }
807