42f86a03334837587d10d38ff28df4515d9a91cc
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_ima.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 "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 <utils/debug.h>
24 #include <crypto/hashers/hasher.h>
25 #include <pen/pen.h>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32
33 #define SECURITY_DIR "/sys/kernel/security/"
34 #define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements"
35 #define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements"
36 #define IMA_PCR 10
37 #define IMA_TYPE_LEN 3
38 #define IMA_NG_TYPE_LEN 6
39 #define IMA_TYPE_LEN_MAX 10
40 #define IMA_ALGO_LEN_MIN 5
41 #define IMA_ALGO_LEN_MAX 8
42 #define IMA_ALGO_DIGEST_LEN_MAX IMA_ALGO_LEN_MAX + HASH_SIZE_SHA512
43 #define IMA_FILENAME_LEN_MAX 255
44
45 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
46 typedef struct bios_entry_t bios_entry_t;
47 typedef struct ima_entry_t ima_entry_t;
48 typedef enum ima_state_t ima_state_t;
49
50 enum ima_state_t {
51 IMA_STATE_INIT,
52 IMA_STATE_BIOS,
53 IMA_STATE_BOOT_AGGREGATE,
54 IMA_STATE_RUNTIME,
55 IMA_STATE_END
56 };
57
58 /**
59 * Private data of a pts_ita_comp_ima_t object.
60 *
61 */
62 struct pts_ita_comp_ima_t {
63
64 /**
65 * Public pts_component_t interface.
66 */
67 pts_component_t public;
68
69 /**
70 * Component Functional Name
71 */
72 pts_comp_func_name_t *name;
73
74 /**
75 * Sub-component depth
76 */
77 uint32_t depth;
78
79 /**
80 * PTS measurement database
81 */
82 pts_database_t *pts_db;
83
84 /**
85 * Primary key for AIK database entry
86 */
87 int aik_id;
88
89 /**
90 * Primary key for IMA BIOS Component Functional Name database entry
91 */
92 int bios_cid;
93
94 /**
95 * Primary key for IMA Runtime Component Functional Name database entry
96 */
97 int ima_cid;
98
99 /**
100 * Component is registering IMA BIOS measurements
101 */
102 bool is_bios_registering;
103
104 /**
105 * Component is registering IMA boot aggregate measurement
106 */
107 bool is_ima_registering;
108
109 /**
110 * Measurement sequence number
111 */
112 int seq_no;
113
114 /**
115 * Expected IMA BIOS measurement count
116 */
117 int bios_count;
118
119 /**
120 * IMA BIOS measurements
121 */
122 linked_list_t *bios_list;
123
124 /**
125 * IMA runtime file measurements
126 */
127 linked_list_t *ima_list;
128
129 /**
130 * Whether to send pcr_before and pcr_after info
131 */
132 bool pcr_info;
133
134 /**
135 * IMA measurement time
136 */
137 time_t measurement_time;
138
139 /**
140 * IMA state machine
141 */
142 ima_state_t state;
143
144 /**
145 * Total number of component measurements
146 */
147 int count;
148
149 /**
150 * Number of successful component measurements
151 */
152 int count_ok;
153
154 /**
155 * Number of unknown component measurements
156 */
157 int count_unknown;
158
159 /**
160 * Number of differing component measurements
161 */
162 int count_differ;
163
164 /**
165 * Number of failed component measurements
166 */
167 int count_failed;
168
169 /**
170 * Reference count
171 */
172 refcount_t ref;
173
174 };
175
176 /**
177 * Linux IMA BIOS measurement entry
178 */
179 struct bios_entry_t {
180
181 /**
182 * PCR register
183 */
184 uint32_t pcr;
185
186 /**
187 * SHA1 measurement hash
188 */
189 chunk_t measurement;
190 };
191
192 /**
193 * Linux IMA runtime file measurement entry
194 */
195 struct ima_entry_t {
196
197 /**
198 * SHA1 measurement hash
199 */
200 chunk_t measurement;
201
202 /**
203 * IMA-NG hash algorithm name or NULL
204 */
205 char *algo;
206
207 /**
208 * IMA-NG eventname or IMA filename
209 */
210 char *filename;
211 };
212
213 /**
214 * Free a bios_entry_t object
215 */
216 static void free_bios_entry(bios_entry_t *this)
217 {
218 free(this->measurement.ptr);
219 free(this);
220 }
221
222 /**
223 * Free an ima_entry_t object
224 */
225 static void free_ima_entry(ima_entry_t *this)
226 {
227 free(this->measurement.ptr);
228 free(this->algo);
229 free(this->filename);
230 free(this);
231 }
232
233 /**
234 * Load a PCR measurement file and determine the creation date
235 */
236 static bool load_bios_measurements(char *file, linked_list_t *list,
237 time_t *created)
238 {
239 uint32_t pcr, num, len;
240 bios_entry_t *entry;
241 struct stat st;
242 ssize_t res;
243 int fd;
244
245 fd = open(file, O_RDONLY);
246 if (fd == -1)
247 {
248 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
249 return FALSE;
250 }
251
252 if (fstat(fd, &st) == -1)
253 {
254 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
255 strerror(errno));
256 close(fd);
257 return FALSE;
258 }
259 *created = st.st_ctime;
260
261 while (TRUE)
262 {
263 res = read(fd, &pcr, 4);
264 if (res == 0)
265 {
266 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
267 file, list->get_count(list));
268 close(fd);
269 return TRUE;
270 }
271
272 entry = malloc_thing(bios_entry_t);
273 entry->pcr = pcr;
274 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
275
276 if (res != 4)
277 {
278 break;
279 }
280 if (read(fd, &num, 4) != 4)
281 {
282 break;
283 }
284 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
285 {
286 break;
287 }
288 if (read(fd, &len, 4) != 4)
289 {
290 break;
291 }
292 if (lseek(fd, len, SEEK_CUR) == -1)
293 {
294 break;
295 }
296 list->insert_last(list, entry);
297 }
298
299 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file,
300 strerror(errno));
301 free_bios_entry(entry);
302 close(fd);
303 return FALSE;
304 }
305
306 /**
307 * Load an IMA runtime measurement file and determine the creation and
308 * update dates
309 */
310 static bool load_runtime_measurements(char *file, linked_list_t *list,
311 time_t *created)
312 {
313 ima_entry_t *entry;
314 uint32_t pcr, type_len, filename_len;
315 uint32_t eventdata_len, algo_digest_len, algo_len;
316 bool ima_ng;
317 char type[IMA_TYPE_LEN_MAX];
318 char algo_digest[IMA_ALGO_DIGEST_LEN_MAX];
319 char *pos, *error = "";
320 struct stat st;
321 ssize_t res;
322 int fd;
323
324 fd = open(file, O_RDONLY);
325 if (fd == -1)
326 {
327 DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno));
328 return TRUE;
329 }
330
331 if (fstat(fd, &st) == -1)
332 {
333 DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file,
334 strerror(errno));
335 close(fd);
336 return FALSE;
337 }
338 *created = st.st_ctime;
339
340 while (TRUE)
341 {
342 /* read 32 bit PCR number in host order */
343 res = read(fd, &pcr, 4);
344
345 /* exit if no more measurement data is available */
346 if (res == 0)
347 {
348 DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)",
349 file, list->get_count(list));
350 close(fd);
351 return TRUE;
352 }
353
354 /* create and initialize new IMA entry */
355 entry = malloc_thing(ima_entry_t);
356 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
357 entry->algo = NULL;
358 entry->filename = NULL;
359
360 if (res != 4 || pcr != IMA_PCR)
361 {
362 error = "invalid IMA PCR field";
363 break;
364 }
365
366 /* read 20 byte SHA-1 measurement digest */
367 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
368 {
369 error = "invalid SHA-1 digest field";
370 break;
371 }
372
373 /* read 32 bit length of IMA type string in host order */
374 if (read(fd, &type_len, 4) != 4 || type_len > IMA_TYPE_LEN_MAX)
375 {
376 error = "invalid IMA type field length";
377 break;
378 }
379
380 /* read and interpret IMA type string */
381 if (read(fd, type, type_len) != type_len)
382 {
383 error = "invalid IMA type field";
384 break;
385 }
386 if (type_len == IMA_NG_TYPE_LEN &&
387 memeq(type, "ima-ng", IMA_NG_TYPE_LEN))
388 {
389 ima_ng = TRUE;
390 }
391 else if (type_len == IMA_TYPE_LEN &&
392 memeq(type, "ima", IMA_TYPE_LEN))
393 {
394 ima_ng = FALSE;
395 }
396 else
397 {
398 error = "unknown IMA type";
399 break;
400 }
401
402 if (ima_ng)
403 {
404 /* read the 32 bit length of the event data in host order */
405 if (read(fd, &eventdata_len, 4) != 4 || eventdata_len < 4)
406 {
407 error = "invalid event data field length";
408 break;
409 }
410
411 /* read the 32 bit length of the algo_digest string in host order */
412 if (read(fd, &algo_digest_len, 4) != 4 ||
413 algo_digest_len > IMA_ALGO_DIGEST_LEN_MAX ||
414 eventdata_len < 4 + algo_digest_len + 4)
415 {
416 error = "invalid digest_with_algo field length";
417 break;
418 }
419
420 /* read the IMA algo_digest string */
421 if (read(fd, algo_digest, algo_digest_len) != algo_digest_len)
422 {
423 error = "invalid digest_with_algo field";
424 break;
425 }
426
427 /* extract the hash algorithm name */
428 pos = strchr(algo_digest, '\0');
429 if (!pos)
430 {
431 error = "no algo field";
432 break;
433 }
434 algo_len = pos - algo_digest + 1;
435
436 if (algo_len > IMA_ALGO_LEN_MAX ||
437 algo_len < IMA_ALGO_LEN_MIN || *(pos - 1) != ':')
438 {
439 error = "invalid algo field";
440 break;
441 }
442
443 /* copy and store the hash algorithm name */
444 entry->algo = malloc(algo_len);
445 memcpy(entry->algo, algo_digest, algo_len);
446
447 /* read the 32 bit length of the file name in host order */
448 if (read(fd, &filename_len, 4) != 4 ||
449 eventdata_len != 4 + algo_digest_len + 4 + filename_len)
450 {
451 error = "invalid filename field length";
452 break;
453 }
454
455 /* allocate memory for the file name */
456 entry->filename = malloc(filename_len);
457
458 /* read file name */
459 if (read(fd, entry->filename, filename_len) != filename_len)
460 {
461 error = "invalid filename field";
462 break;
463 }
464 }
465 else
466 {
467 /* skip SHA-1 digest of the file content */
468 if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1)
469 {
470 break;
471 }
472
473 /* read the 32 bit length of the file name in host order */
474 if (read(fd, &filename_len, 4) != 4)
475 {
476 error = "invalid filename field length";
477 break;
478 }
479
480 /* allocate memory for the file name */
481 entry->filename = malloc(filename_len + 1);
482
483 /* read file name */
484 if (read(fd, entry->filename, filename_len) != filename_len)
485 {
486 error = "invalid filename field";
487 break;
488 }
489
490 /* terminate the file name with a nul character */
491 entry->filename[filename_len] = '\0';
492 }
493
494 list->insert_last(list, entry);
495 }
496
497 DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", file, error);
498 free_ima_entry(entry);
499 close(fd);
500 return FALSE;
501 }
502
503 /**
504 * Extend measurement into PCR and create evidence
505 */
506 static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
507 uint8_t qualifier, pts_pcr_t *pcrs,
508 uint32_t pcr, chunk_t measurement)
509 {
510 size_t pcr_len;
511 pts_pcr_transform_t pcr_transform;
512 pts_meas_algorithms_t hash_algo;
513 pts_comp_func_name_t *name;
514 pts_comp_evidence_t *evidence;
515 chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty;
516
517 hash_algo = PTS_MEAS_ALGO_SHA1;
518 pcr_len = HASH_SIZE_SHA1;
519 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
520
521 if (this->pcr_info)
522 {
523 pcr_before = chunk_clone(pcrs->get(pcrs, pcr));
524 }
525 pcr_after = pcrs->extend(pcrs, pcr, measurement);
526 if (!pcr_after.ptr)
527 {
528 free(pcr_before.ptr);
529 return NULL;
530 }
531 name = this->name->clone(this->name);
532 name->set_qualifier(name, qualifier);
533 evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo,
534 pcr_transform, this->measurement_time, measurement);
535 if (this->pcr_info)
536 {
537 pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
538 evidence->set_pcr_info(evidence, pcr_before, pcr_after);
539 }
540 return evidence;
541 }
542
543 /**
544 * Generate an IMA or IMA-NG hash from an event digest and event name
545 *
546 * @param digest event digest
547 * @param ima_algo hash algorithm string ("sha1:", "sha256:", etc.)
548 * @param ima_name event name
549 * @param little_endian endianness of client platform
550 * @param algo hash algorithm used by TPM
551 * @param hash_buf hash value to be compared with TPM measurement
552 */
553 static bool ima_hash(chunk_t digest, char *ima_algo, char *ima_name,
554 bool little_endian, pts_meas_algorithms_t algo,
555 char *hash_buf)
556 {
557 hash_algorithm_t hash_alg;
558 hasher_t *hasher;
559 bool success;
560
561 hash_alg = pts_meas_algo_to_hash(algo);
562 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
563 if (!hasher)
564 {
565 DBG1(DBG_PTS, "%N hasher could not be created",
566 hash_algorithm_short_names, hash_alg);
567 return FALSE;
568 }
569
570 if (ima_algo)
571 {
572 uint32_t d_len, n_len;
573 chunk_t algo_name, event_name, digest_len, name_len;
574
575 /* IMA-NG hash */
576 algo_name = chunk_create(ima_algo, strlen(ima_algo) + 1);
577 event_name = chunk_create(ima_name, strlen(ima_name) + 1);
578
579 d_len = algo_name.len + digest.len;
580 digest_len = chunk_create((uint8_t*)&d_len, sizeof(d_len));
581 /* TODO handle endianness of both client and server platforms */
582
583 n_len = event_name.len;
584 name_len = chunk_create((uint8_t*)&n_len, sizeof(n_len));
585 /* TODO handle endianness of both client and server platforms */
586
587 success = hasher->get_hash(hasher, digest_len, NULL) &&
588 hasher->get_hash(hasher, algo_name, NULL) &&
589 hasher->get_hash(hasher, digest, NULL) &&
590 hasher->get_hash(hasher, name_len, NULL) &&
591 hasher->get_hash(hasher, event_name, hash_buf);
592 }
593 else
594 {
595 u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1];
596 chunk_t file_name;
597
598 /* IMA legacy hash */
599 memset(filename_buffer, 0, sizeof(filename_buffer));
600 strncpy(filename_buffer, ima_name, IMA_FILENAME_LEN_MAX);
601 file_name = chunk_create (filename_buffer, sizeof(filename_buffer));
602
603 success = hasher->get_hash(hasher, digest, NULL) &&
604 hasher->get_hash(hasher, file_name, hash_buf);
605 }
606 hasher->destroy(hasher);
607
608 return success;
609 }
610
611 /**
612 * Compute and check boot aggregate value by hashing PCR0 to PCR7
613 */
614 static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement,
615 char *algo)
616 {
617 u_char pcr_buffer[HASH_SIZE_SHA1];
618 chunk_t boot_aggregate;
619 hasher_t *hasher;
620 uint32_t i;
621 bool success, pcr_ok = TRUE;
622
623 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
624 if (!hasher)
625 {
626 DBG1(DBG_PTS, "%N hasher could not be created",
627 hash_algorithm_short_names, HASH_SHA1);
628 return FALSE;
629 }
630 for (i = 0; i < 8 && pcr_ok; i++)
631 {
632 pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL);
633 }
634 if (pcr_ok)
635 {
636 pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer);
637 }
638 hasher->destroy(hasher);
639
640 if (pcr_ok)
641 {
642 boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer));
643
644 /* TODO handle endianness of client platform */
645 pcr_ok = ima_hash(boot_aggregate, algo, "boot_aggregate",
646 TRUE, PTS_MEAS_ALGO_SHA1, pcr_buffer);
647 }
648 if (pcr_ok)
649 {
650 success = chunk_equals(boot_aggregate, measurement);
651 DBG1(DBG_PTS, "boot aggregate value is %scorrect",
652 success ? "":"in");
653 return success;
654 }
655 else
656 {
657 DBG1(DBG_PTS, "failed to compute boot aggregate value");
658 return FALSE;
659 }
660 }
661
662 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
663 pts_ita_comp_ima_t *this)
664 {
665 return this->name;
666 }
667
668 METHOD(pts_component_t, get_evidence_flags, uint8_t,
669 pts_ita_comp_ima_t *this)
670 {
671 return PTS_REQ_FUNC_COMP_EVID_PCR;
672 }
673
674 METHOD(pts_component_t, get_depth, uint32_t,
675 pts_ita_comp_ima_t *this)
676 {
677 return this->depth;
678 }
679
680 METHOD(pts_component_t, measure, status_t,
681 pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
682 pts_comp_evidence_t **evidence)
683 {
684 bios_entry_t *bios_entry;
685 ima_entry_t *ima_entry;
686 pts_pcr_t *pcrs;
687 pts_comp_evidence_t *evid = NULL;
688 size_t algo_len, name_len;
689 char *uri;
690 status_t status;
691
692 pcrs = pts->get_pcrs(pts);
693
694 if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
695 PTS_ITA_QUALIFIER_TYPE_TRUSTED))
696 {
697 switch (this->state)
698 {
699 case IMA_STATE_INIT:
700 if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS,
701 this->bios_list, &this->measurement_time))
702 {
703 return FAILED;
704 }
705 this->bios_count = this->bios_list->get_count(this->bios_list);
706 this->state = IMA_STATE_BIOS;
707 /* fall through to next state */
708 case IMA_STATE_BIOS:
709 status = this->bios_list->remove_first(this->bios_list,
710 (void**)&bios_entry);
711 if (status != SUCCESS)
712 {
713 DBG1(DBG_PTS, "could not retrieve bios measurement entry");
714 return status;
715 }
716 evid = extend_pcr(this, qualifier, pcrs, bios_entry->pcr,
717 bios_entry->measurement);
718 free(bios_entry);
719
720 this->state = this->bios_list->get_count(this->bios_list) ?
721 IMA_STATE_BIOS : IMA_STATE_INIT;
722 break;
723 default:
724 return FAILED;
725 }
726 }
727 else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
728 PTS_ITA_QUALIFIER_TYPE_OS))
729 {
730 switch (this->state)
731 {
732 case IMA_STATE_INIT:
733 if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS,
734 this->ima_list, &this->measurement_time))
735 {
736 return FAILED;
737 }
738 this->state = IMA_STATE_BOOT_AGGREGATE;
739 /* fall through to next state */
740 case IMA_STATE_BOOT_AGGREGATE:
741 case IMA_STATE_RUNTIME:
742 status = this->ima_list->remove_first(this->ima_list,
743 (void**)&ima_entry);
744 if (status != SUCCESS)
745 {
746 DBG1(DBG_PTS, "could not retrieve ima measurement entry");
747 return status;
748 }
749 if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
750 {
751 if (!check_boot_aggregate(pcrs, ima_entry->measurement,
752 ima_entry->algo))
753 {
754 return FAILED;
755 }
756 }
757 evid = extend_pcr(this, qualifier, pcrs, IMA_PCR,
758 ima_entry->measurement);
759 if (evid)
760 {
761 if (ima_entry->algo)
762 {
763 algo_len = strlen(ima_entry->algo);
764 name_len = strlen(ima_entry->filename);
765 uri = malloc(algo_len + name_len + 1);
766 memcpy(uri, ima_entry->algo, algo_len);
767 strcpy(uri + algo_len, ima_entry->filename);
768 }
769 else
770 {
771 uri = strdup(ima_entry->filename);
772 }
773 evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
774 uri);
775 free(uri);
776 }
777 free(ima_entry->filename);
778 free(ima_entry->algo);
779 free(ima_entry);
780
781 this->state = this->ima_list->get_count(this->ima_list) ?
782 IMA_STATE_RUNTIME : IMA_STATE_END;
783 break;
784 default:
785 return FAILED;
786 }
787 }
788 else
789 {
790 DBG1(DBG_PTS, "unsupported functional component name qualifier");
791 return FAILED;
792 }
793
794 *evidence = evid;
795 if (!evid)
796 {
797 return FAILED;
798 }
799
800 return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ?
801 SUCCESS : NEED_MORE;
802 }
803
804 /**
805 * Parse a validation URI of the form <hash algorithm>:<event name>
806 * into its components
807 */
808 static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
809 char **ima_name, char **ima_algo, char *algo_buf)
810 {
811 pts_meas_algorithms_t hash_algo;
812 char *uri, *pos, *algo, *name;
813
814 evidence->get_validation(evidence, &uri);
815
816 /* IMA-NG format? */
817 pos = strchr(uri, ':');
818 if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX)
819 {
820 memset(algo_buf, '\0', IMA_ALGO_LEN_MAX);
821 memcpy(algo_buf, uri, pos - uri + 1);
822 algo = algo_buf;
823 name = pos + 1;
824
825 if (streq(algo, "sha1:") || streq(algo, ":"))
826 {
827 hash_algo = PTS_MEAS_ALGO_SHA1;
828 }
829 else if (streq(algo, "sha256:"))
830 {
831 hash_algo = PTS_MEAS_ALGO_SHA256;
832 }
833 else if (streq(algo, "sha384:"))
834 {
835 hash_algo = PTS_MEAS_ALGO_SHA384;
836 }
837 else
838 {
839 hash_algo = PTS_MEAS_ALGO_NONE;
840 }
841 }
842 else
843 {
844 algo = NULL;
845 name = uri;
846 hash_algo = PTS_MEAS_ALGO_SHA1;
847 }
848
849 if (ima_name)
850 {
851 *ima_name = name;
852 }
853 if (ima_algo)
854 {
855 *ima_algo = algo;
856 }
857
858 return hash_algo;
859 }
860
861 METHOD(pts_component_t, verify, status_t,
862 pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
863 pts_comp_evidence_t *evidence)
864 {
865 bool has_pcr_info;
866 uint32_t pcr;
867 pts_meas_algorithms_t algo;
868 pts_pcr_transform_t transform;
869 pts_pcr_t *pcrs;
870 time_t measurement_time;
871 chunk_t measurement, pcr_before, pcr_after;
872 status_t status;
873
874 this->aik_id = pts->get_aik_id(pts);
875 pcrs = pts->get_pcrs(pts);
876 measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
877 &measurement_time);
878
879 if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
880 PTS_ITA_QUALIFIER_TYPE_TRUSTED))
881 {
882 switch (this->state)
883 {
884 case IMA_STATE_INIT:
885 this->name->set_qualifier(this->name, qualifier);
886 status = this->pts_db->get_comp_measurement_count(this->pts_db,
887 this->name, this->aik_id, algo,
888 &this->bios_cid, &this->bios_count);
889 this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
890 if (status != SUCCESS)
891 {
892 return status;
893 }
894
895 if (this->bios_count)
896 {
897 DBG1(DBG_PTS, "checking %d BIOS evidence measurements",
898 this->bios_count);
899 }
900 else
901 {
902 DBG1(DBG_PTS, "registering BIOS evidence measurements");
903 this->is_bios_registering = TRUE;
904 }
905
906 this->state = IMA_STATE_BIOS;
907 /* fall through to next state */
908 case IMA_STATE_BIOS:
909 if (this->is_bios_registering)
910 {
911 status = this->pts_db->insert_comp_measurement(this->pts_db,
912 measurement, this->bios_cid, this->aik_id,
913 ++this->seq_no, pcr, algo);
914 if (status != SUCCESS)
915 {
916 return status;
917 }
918 this->bios_count = this->seq_no + 1;
919 }
920 else
921 {
922 status = this->pts_db->check_comp_measurement(this->pts_db,
923 measurement, this->bios_cid, this->aik_id,
924 ++this->seq_no, pcr, algo);
925 if (status == FAILED)
926 {
927 return status;
928 }
929 }
930 break;
931 default:
932 return FAILED;
933 }
934 }
935 else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
936 PTS_ITA_QUALIFIER_TYPE_OS))
937 {
938 int ima_count;
939 char *ima_algo, *ima_name;
940 char algo_buf[IMA_ALGO_LEN_MAX];
941 pts_meas_algorithms_t hash_algo;
942
943 hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo,
944 algo_buf);
945
946 switch (this->state)
947 {
948 case IMA_STATE_BIOS:
949 this->state = IMA_STATE_RUNTIME;
950
951 if (!streq(ima_name, "boot_aggregate"))
952 {
953 DBG1(DBG_PTS, "ima: name must be 'boot_aggregate' "
954 "but is '%s'", ima_name);
955 return FAILED;
956 }
957 if (hash_algo != PTS_MEAS_ALGO_SHA1)
958 {
959 DBG1(DBG_PTS, "ima: boot_aggregate algorithm must be %N "
960 "but is %N",
961 pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1,
962 pts_meas_algorithm_names, hash_algo);
963 return FAILED;
964 }
965 if (!check_boot_aggregate(pcrs, measurement, ima_algo))
966 {
967 return FAILED;
968 }
969 this->state = IMA_STATE_INIT;
970 /* fall through to next state */
971 case IMA_STATE_INIT:
972 this->name->set_qualifier(this->name, qualifier);
973 status = this->pts_db->get_comp_measurement_count(this->pts_db,
974 this->name, this->aik_id, algo,
975 &this->ima_cid, &ima_count);
976 this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
977 if (status != SUCCESS)
978 {
979 return status;
980 }
981
982 if (ima_count)
983 {
984 DBG1(DBG_PTS, "checking boot aggregate evidence "
985 "measurement");
986 status = this->pts_db->check_comp_measurement(this->pts_db,
987 measurement, this->ima_cid,
988 this->aik_id, 1, pcr, algo);
989 }
990 else
991 {
992 DBG1(DBG_PTS, "registering boot aggregate evidence "
993 "measurement");
994 this->is_ima_registering = TRUE;
995 status = this->pts_db->insert_comp_measurement(this->pts_db,
996 measurement, this->ima_cid,
997 this->aik_id, 1, pcr, algo);
998 }
999 this->state = IMA_STATE_RUNTIME;
1000
1001 if (status != SUCCESS)
1002 {
1003 return status;
1004 }
1005 break;
1006 case IMA_STATE_RUNTIME:
1007 {
1008 status_t status = NOT_FOUND;
1009 uint8_t hash_buf[HASH_SIZE_SHA512];
1010 chunk_t digest, hash;
1011 enumerator_t *e;
1012
1013 this->count++;
1014 if (evidence->get_validation(evidence, NULL) !=
1015 PTS_COMP_EVID_VALIDATION_PASSED)
1016 {
1017 DBG1(DBG_PTS, "evidence validation failed");
1018 this->count_failed++;
1019 return FAILED;
1020 }
1021 hash = chunk_create(hash_buf, pts_meas_algo_hash_size(algo));
1022
1023 e = this->pts_db->create_file_meas_enumerator(this->pts_db,
1024 pts->get_platform_id(pts),
1025 hash_algo, ima_name);
1026 if (e)
1027 {
1028 while (e->enumerate(e, &digest))
1029 {
1030 if (!ima_hash(digest, ima_algo, ima_name,
1031 FALSE, algo, hash_buf))
1032 {
1033 status = FAILED;
1034 break;
1035 }
1036 if (chunk_equals(measurement, hash))
1037 {
1038 status = SUCCESS;
1039 break;
1040 }
1041 else
1042 {
1043 status = VERIFY_ERROR;
1044 }
1045 }
1046 e->destroy(e);
1047 }
1048 else
1049 {
1050 status = FAILED;
1051 }
1052
1053 switch (status)
1054 {
1055 case SUCCESS:
1056 DBG3(DBG_PTS, "%#B for '%s' is ok",
1057 &measurement, ima_name);
1058 this->count_ok++;
1059 break;
1060 case NOT_FOUND:
1061 DBG2(DBG_PTS, "%#B for '%s' not found",
1062 &measurement, ima_name);
1063 this->count_unknown++;
1064 break;
1065 case VERIFY_ERROR:
1066 DBG1(DBG_PTS, "%#B for '%s' differs",
1067 &measurement, ima_name);
1068 this->count_differ++;
1069 break;
1070 case FAILED:
1071 default:
1072 DBG1(DBG_PTS, "%#B for '%s' failed",
1073 &measurement, ima_name);
1074 this->count_failed++;
1075 }
1076 break;
1077 }
1078 default:
1079 return FAILED;
1080 }
1081 }
1082 else
1083 {
1084 DBG1(DBG_PTS, "unsupported functional component name qualifier");
1085 return FAILED;
1086 }
1087
1088 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
1089 if (has_pcr_info)
1090 {
1091 if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr)))
1092 {
1093 DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
1094 pcr);
1095 }
1096 if (pcrs->set(pcrs, pcr, pcr_after))
1097 {
1098 return status;
1099 }
1100 }
1101 else
1102 {
1103 pcr_after = pcrs->extend(pcrs, pcr, measurement);
1104 if (pcr_after.ptr)
1105 {
1106 return status;
1107 }
1108 }
1109 return FAILED;
1110 }
1111
1112 METHOD(pts_component_t, finalize, bool,
1113 pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result)
1114 {
1115 char result_buf[BUF_LEN];
1116 char *pos = result_buf;
1117 size_t len = BUF_LEN;
1118 int written;
1119 bool success = TRUE;
1120
1121 this->name->set_qualifier(this->name, qualifier);
1122
1123 if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
1124 PTS_ITA_QUALIFIER_TYPE_TRUSTED))
1125 {
1126 /* finalize BIOS measurements */
1127 if (this->is_bios_registering)
1128 {
1129 /* close registration */
1130 this->is_bios_registering = FALSE;
1131
1132 snprintf(pos, len, "registered %d BIOS evidence measurements",
1133 this->seq_no);
1134 }
1135 else if (this->seq_no < this->bios_count)
1136 {
1137 snprintf(pos, len, "%d of %d BIOS evidence measurements missing",
1138 this->bios_count - this->seq_no, this->bios_count);
1139 success = FALSE;
1140 }
1141 else
1142 {
1143 snprintf(pos, len, "%d BIOS evidence measurements are ok",
1144 this->bios_count);
1145 }
1146 }
1147 else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
1148 PTS_ITA_QUALIFIER_TYPE_OS))
1149 {
1150 /* finalize IMA file measurements */
1151 if (this->is_ima_registering)
1152 {
1153 /* close registration */
1154 this->is_ima_registering = FALSE;
1155
1156 written = snprintf(pos, len, "registered IMA boot aggregate "
1157 "evidence measurement; ");
1158 pos += written;
1159 len -= written;
1160 }
1161 if (this->count)
1162 {
1163 snprintf(pos, len, "processed %d IMA file evidence measurements: "
1164 "%d ok, %d unknown, %d differ, %d failed",
1165 this->count, this->count_ok, this->count_unknown,
1166 this->count_differ, this->count_failed);
1167 }
1168 else
1169 {
1170 snprintf(pos, len, "no IMA file evidence measurements");
1171 success = FALSE;
1172 }
1173 }
1174 else
1175 {
1176 snprintf(pos, len, "unsupported functional component name qualifier");
1177 success = FALSE;
1178 }
1179 this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
1180
1181 DBG1(DBG_PTS, "%s", result_buf);
1182 result->write_data(result, chunk_from_str(result_buf));
1183
1184 return success;
1185 }
1186
1187 METHOD(pts_component_t, get_ref, pts_component_t*,
1188 pts_ita_comp_ima_t *this)
1189 {
1190 ref_get(&this->ref);
1191 return &this->public;
1192 }
1193
1194 METHOD(pts_component_t, destroy, void,
1195 pts_ita_comp_ima_t *this)
1196 {
1197 int count;
1198
1199 if (ref_put(&this->ref))
1200 {
1201
1202 if (this->is_bios_registering)
1203 {
1204 count = this->pts_db->delete_comp_measurements(this->pts_db,
1205 this->bios_cid, this->aik_id);
1206 DBG1(DBG_PTS, "deleted %d registered BIOS evidence measurements",
1207 count);
1208 }
1209 if (this->is_ima_registering)
1210 {
1211 count = this->pts_db->delete_comp_measurements(this->pts_db,
1212 this->ima_cid, this->aik_id);
1213 DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
1214 "measurement");
1215 }
1216 this->bios_list->destroy_function(this->bios_list,
1217 (void *)free_bios_entry);
1218 this->ima_list->destroy_function(this->ima_list,
1219 (void *)free_ima_entry);
1220 this->name->destroy(this->name);
1221
1222 free(this);
1223 }
1224 }
1225
1226 /**
1227 * See header
1228 */
1229 pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
1230 pts_database_t *pts_db)
1231 {
1232 pts_ita_comp_ima_t *this;
1233
1234 INIT(this,
1235 .public = {
1236 .get_comp_func_name = _get_comp_func_name,
1237 .get_evidence_flags = _get_evidence_flags,
1238 .get_depth = _get_depth,
1239 .measure = _measure,
1240 .verify = _verify,
1241 .finalize = _finalize,
1242 .get_ref = _get_ref,
1243 .destroy = _destroy,
1244 },
1245 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
1246 PTS_QUALIFIER_UNKNOWN),
1247 .depth = depth,
1248 .pts_db = pts_db,
1249 .bios_list = linked_list_create(),
1250 .ima_list = linked_list_create(),
1251 .pcr_info = lib->settings->get_bool(lib->settings,
1252 "%s.plugins.imc-attestation.pcr_info", TRUE, lib->ns),
1253 .ref = 1,
1254 );
1255
1256 return &this->public;
1257 }
1258