1: /*
2: * Copyright (C) 2011-2020 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: #define _GNU_SOURCE
17: #include <stdio.h>
18:
19: #include "ita_comp_ima.h"
20: #include "ita_comp_func_name.h"
21:
22: #include "imcv.h"
23: #include "pts/pts_pcr.h"
24: #include "pts/pts_ima_bios_list.h"
25: #include "pts/pts_ima_event_list.h"
26: #include "pts/components/pts_component.h"
27:
28: #include <utils/debug.h>
29: #include <crypto/hashers/hasher.h>
30: #include <pen/pen.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:
36: typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
37: typedef enum ima_state_t ima_state_t;
38:
39: enum ima_state_t {
40: IMA_STATE_INIT,
41: IMA_STATE_BIOS,
42: IMA_STATE_BOOT_AGGREGATE,
43: IMA_STATE_RUNTIME,
44: IMA_STATE_END
45: };
46:
47: /**
48: * Private data of a pts_ita_comp_ima_t object.
49: *
50: */
51: struct pts_ita_comp_ima_t {
52:
53: /**
54: * Public pts_component_t interface.
55: */
56: pts_component_t public;
57:
58: /**
59: * Component Functional Name
60: */
61: pts_comp_func_name_t *name;
62:
63: /**
64: * Sub-component depth
65: */
66: uint32_t depth;
67:
68: /**
69: * PTS measurement database
70: */
71: pts_database_t *pts_db;
72:
73: /**
74: * Primary key for AIK database entry
75: */
76: int aik_id;
77:
78: /**
79: * Primary key for IMA BIOS Component Functional Name database entry
80: */
81: int bios_cid;
82:
83: /**
84: * Primary key for IMA Runtime Component Functional Name database entry
85: */
86: int ima_cid;
87:
88: /**
89: * Component is registering IMA BIOS measurements
90: */
91: bool is_bios_registering;
92:
93: /**
94: * Component is registering IMA boot aggregate measurement
95: */
96: bool is_ima_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: pts_ima_bios_list_t *bios_list;
112:
113: /**
114: * IMA runtime file measurements
115: */
116: pts_ima_event_list_t *ima_list;
117:
118: /**
119: * Whether to send pcr_before and pcr_after info
120: */
121: bool pcr_info;
122:
123: /**
124: * Whether to pad PCR measurements if matching hash is not available
125: */
126: bool pcr_padding;
127:
128: /**
129: * Creation time of measurement
130: */
131: time_t creation_time;
132:
133: /**
134: * IMA state machine
135: */
136: ima_state_t state;
137:
138: /**
139: * Total number of component measurements
140: */
141: int count;
142:
143: /**
144: * Number of successful component measurements
145: */
146: int count_ok;
147:
148: /**
149: * Number of unknown component measurements
150: */
151: int count_unknown;
152:
153: /**
154: * Number of differing component measurements
155: */
156: int count_differ;
157:
158: /**
159: * Number of failed component measurements
160: */
161: int count_failed;
162:
163: /**
164: * Reference count
165: */
166: refcount_t ref;
167:
168: };
169:
170: /**
171: * Extend measurement into PCR and create evidence
172: */
173: static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this,
174: uint8_t qualifier, pts_pcr_t *pcrs,
175: uint32_t pcr, chunk_t measurement,
176: pts_pcr_transform_t pcr_transform)
177: {
178: pts_meas_algorithms_t pcr_algo;
179: pts_comp_func_name_t *name;
180: pts_comp_evidence_t *evidence;
181: chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty;
182:
183: pcr_algo = pcrs->get_pcr_algo(pcrs);
184:
185: if (this->pcr_info)
186: {
187: pcr_before = chunk_clone(pcrs->get(pcrs, pcr));
188: }
189: pcr_after = pcrs->extend(pcrs, pcr, measurement);
190: if (!pcr_after.ptr)
191: {
192: free(pcr_before.ptr);
193: return NULL;
194: }
195: name = this->name->clone(this->name);
196: name->set_qualifier(name, qualifier);
197: evidence = pts_comp_evidence_create(name, this->depth, pcr, pcr_algo,
198: pcr_transform, this->creation_time, measurement);
199: if (this->pcr_info)
200: {
201: pcr_after =chunk_clone(pcrs->get(pcrs, pcr));
202: evidence->set_pcr_info(evidence, pcr_before, pcr_after);
203: }
204: return evidence;
205: }
206:
207: /**
208: * Compute and check boot aggregate value by hashing PCR0 to PCR7
209: */
210: static bool check_boot_aggregate(pts_pcr_t *pcrs, char *algo, bool pcr_padding,
211: chunk_t boot_aggregate, chunk_t measurement)
212:
213: {
214: chunk_t ba_measurement;
215: uint8_t meas_buffer[HASH_SIZE_SHA512];
216: size_t hash_size;
217: pts_meas_algorithms_t pcr_algo;
218: hash_algorithm_t hash_alg;
219: hasher_t *hasher;
220: uint32_t i, pcr_max;
221: bool success, pcr_ok = TRUE;
222:
223: /* determine PCR hash algorithm and the need for PCR padding */
224: pcr_algo = pcrs->get_pcr_algo(pcrs);
225: if (pcr_algo == PTS_MEAS_ALGO_SHA1)
226: {
227: pcr_padding = FALSE;
228: }
229:
230:
231: /* create hasher for boot aggregate computation */
232: hash_alg = pts_meas_algo_to_hash(pcr_algo);
233: hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
234: if (!hasher)
235: {
236: DBG1(DBG_PTS, "%N hasher could not be created",
237: hash_algorithm_short_names, hash_alg);
238: return FALSE;
239: }
240: hash_size = hasher->get_hash_size(hasher);
241:
242: /* Include PCR8 and PCR9 in boot aggregate with unpadded non-SHA1 hashes */
243: pcr_max = (pcr_algo == PTS_MEAS_ALGO_SHA1 || pcr_padding) ? 7 : 9;
244:
245: /* the boot aggregate hash is computed over PCR0 .. PCR7/PCR9 */
246: for (i = 0; i <= pcr_max && pcr_ok; i++)
247: {
248: pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL);
249: }
250: if (pcr_ok)
251: {
252: pcr_ok = hasher->get_hash(hasher, chunk_empty, boot_aggregate.ptr);
253: }
254: hasher->destroy(hasher);
255:
256:
257: if (pcr_ok)
258: {
259: ba_measurement = chunk_create(meas_buffer, hash_size);
260: if (pcr_padding)
261: {
262: memset(meas_buffer, 0x00, hash_size);
263: pcr_algo = PTS_MEAS_ALGO_SHA1;
264: }
265: pcr_ok = pts_ima_event_hash(boot_aggregate, algo, "boot_aggregate",
266: pcr_algo, meas_buffer);
267: }
268: if (pcr_ok)
269: {
270: success = chunk_equals_const(ba_measurement, measurement);
271: DBG1(DBG_PTS, "boot aggregate computed over PCR0..PCR%d is %scorrect",
272: pcr_max, success ? "":"in");
273: return success;
274: }
275: else
276: {
277: DBG1(DBG_PTS, "failed to compute boot aggregate value");
278: return FALSE;
279: }
280: }
281:
282: METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
283: pts_ita_comp_ima_t *this)
284: {
285: return this->name;
286: }
287:
288: METHOD(pts_component_t, get_evidence_flags, uint8_t,
289: pts_ita_comp_ima_t *this)
290: {
291: return PTS_REQ_FUNC_COMP_EVID_PCR;
292: }
293:
294: METHOD(pts_component_t, get_depth, uint32_t,
295: pts_ita_comp_ima_t *this)
296: {
297: return this->depth;
298: }
299:
300: METHOD(pts_component_t, measure, status_t,
301: pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
302: pts_comp_evidence_t **evidence)
303: {
304: pts_pcr_t *pcrs;
305: pts_meas_algorithms_t pcr_algo;
306: pts_comp_evidence_t *evid = NULL;
307: size_t algo_len, name_len, pcr_size;
308: chunk_t measurement, boot_aggregate;
309: uint8_t pcr_buffer[HASH_SIZE_SHA512];
310: char *uri, *algo, *name;
311: uint32_t pcr;
312: status_t status;
313:
314: pcrs = pts->get_pcrs(pts);
315: if (!pcrs)
316: {
317: return FAILED;
318: }
319: pcr_algo = pcrs->get_pcr_algo(pcrs);
320: pcr_size = pts_meas_algo_hash_size(pcr_algo);
321:
322: if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
323: PTS_ITA_QUALIFIER_TYPE_TRUSTED))
324: {
325: switch (this->state)
326: {
327: case IMA_STATE_INIT:
328: this->bios_list = pts_ima_bios_list_create(pts->get_tpm(pts),
329: IMA_BIOS_MEASUREMENTS, pcr_algo);
330: if (!this->bios_list)
331: {
332: return FAILED;
333: }
334: this->creation_time = this->bios_list->get_time(this->bios_list);
335: this->bios_count = this->bios_list->get_count(this->bios_list);
336: this->state = IMA_STATE_BIOS;
337: /* fall through to next state */
338: case IMA_STATE_BIOS:
339: status = this->bios_list->get_next(this->bios_list, &pcr,
340: &measurement);
341: if (status != SUCCESS)
342: {
343: DBG1(DBG_PTS, "could not retrieve bios measurement entry");
344: return status;
345: }
346: evid = extend_pcr(this, qualifier, pcrs, pcr, measurement,
347: PTS_PCR_TRANSFORM_MATCH);
348:
349: this->state = this->bios_list->get_count(this->bios_list) ?
350: IMA_STATE_BIOS : IMA_STATE_INIT;
351: break;
352: default:
353: return FAILED;
354: }
355: }
356: else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
357: PTS_ITA_QUALIFIER_TYPE_OS))
358: {
359: switch (this->state)
360: {
361: case IMA_STATE_INIT:
362:
363: /* disable padding for SHA1 legacy hash */
364: if (pcr_algo == PTS_MEAS_ALGO_SHA1)
365: {
366: this->pcr_padding = FALSE;
367: }
368:
369: this->ima_list = pts_ima_event_list_create(
370: IMA_RUNTIME_MEASUREMENTS,
371: pcr_algo, this->pcr_padding);
372: if (!this->ima_list)
373: {
374: return FAILED;
375: }
376: this->creation_time = this->ima_list->get_time(this->ima_list);
377: this->count = this->ima_list->get_count(this->ima_list);
378: this->state = IMA_STATE_BOOT_AGGREGATE;
379: /* fall through to next state */
380: case IMA_STATE_BOOT_AGGREGATE:
381: case IMA_STATE_RUNTIME:
382: status = this->ima_list->get_next(this->ima_list, &measurement,
383: &algo, &name);
384: if (status != SUCCESS)
385: {
386: DBG1(DBG_PTS, "could not retrieve ima measurement entry");
387: return status;
388: }
389: if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count)
390: {
391: boot_aggregate = chunk_create(pcr_buffer, pcr_size);
392: if (!check_boot_aggregate(pcrs, algo, this->pcr_padding,
393: boot_aggregate, measurement))
394: {
395: return FAILED;
396: }
397: }
398:
399: evid = extend_pcr(this, qualifier, pcrs, IMA_PCR, measurement,
400: this->pcr_padding ? PTS_PCR_TRANSFORM_SHORT :
401: PTS_PCR_TRANSFORM_MATCH);
402: if (evid)
403: {
404: if (algo)
405: {
406: algo_len = strlen(algo);
407: name_len = strlen(name);
408: uri = malloc(algo_len + name_len + 1);
409: memcpy(uri, algo, algo_len);
410: strcpy(uri + algo_len, name);
411: }
412: else
413: {
414: uri = strdup(name);
415: }
416: evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED,
417: uri);
418: free(uri);
419: }
420: free(name);
421: free(algo);
422:
423: this->state = this->ima_list->get_count(this->ima_list) ?
424: IMA_STATE_RUNTIME : IMA_STATE_END;
425: break;
426: default:
427: return FAILED;
428: }
429: }
430: else
431: {
432: DBG1(DBG_PTS, "unsupported functional component name qualifier");
433: return FAILED;
434: }
435:
436: *evidence = evid;
437: if (!evid)
438: {
439: return FAILED;
440: }
441:
442: return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ?
443: SUCCESS : NEED_MORE;
444: }
445:
446: /**
447: * Parse a validation URI of the form <hash algorithm>:<event name>
448: * into its components
449: */
450: static pts_meas_algorithms_t parse_validation_uri(pts_comp_evidence_t *evidence,
451: char **ima_name, char **ima_algo, char *algo_buf)
452: {
453: pts_meas_algorithms_t hash_algo;
454: char *uri, *pos, *algo, *name;
455:
456: evidence->get_validation(evidence, &uri);
457:
458: /* IMA-NG format? */
459: pos = strchr(uri, ':');
460: if (pos && (pos - uri + 1) < IMA_ALGO_LEN_MAX)
461: {
462: memset(algo_buf, '\0', IMA_ALGO_LEN_MAX);
463: memcpy(algo_buf, uri, pos - uri + 1);
464: algo = algo_buf;
465: name = pos + 1;
466:
467: if (streq(algo, "sha1:") || streq(algo, ":"))
468: {
469: hash_algo = PTS_MEAS_ALGO_SHA1;
470: }
471: else if (streq(algo, "sha256:"))
472: {
473: hash_algo = PTS_MEAS_ALGO_SHA256;
474: }
475: else if (streq(algo, "sha384:"))
476: {
477: hash_algo = PTS_MEAS_ALGO_SHA384;
478: }
479: else
480: {
481: hash_algo = PTS_MEAS_ALGO_NONE;
482: }
483: }
484: else
485: {
486: algo = NULL;
487: name = uri;
488: hash_algo = PTS_MEAS_ALGO_SHA1;
489: }
490:
491: if (ima_name)
492: {
493: *ima_name = name;
494: }
495: if (ima_algo)
496: {
497: *ima_algo = algo;
498: }
499:
500: return hash_algo;
501: }
502:
503: /**
504: * Look up all hashes for a given file and OS in the database and check
505: * if one of them matches the IMA measurement
506: */
507: static status_t verify_ima_measuremnt(pts_t *pts, pts_database_t *pts_db,
508: pts_meas_algorithms_t hash_algo,
509: pts_meas_algorithms_t algo,
510: bool pcr_padding, chunk_t measurement,
511: char* ima_algo, char* ima_name,
512: char *filename)
513: {
514: status_t status = NOT_FOUND;
515: pts_meas_algorithms_t meas_algo;
516: uint8_t *hex_digest_buf;
517: uint8_t digest_buf[HASH_SIZE_SHA512];
518: uint8_t hash_buf[HASH_SIZE_SHA512];
519: size_t hash_size;
520: chunk_t hash, digest, hex_digest;
521: enumerator_t *e;
522:
523: hash_size = pts_meas_algo_hash_size(algo);
524: hash = chunk_create(hash_buf, hash_size);
525:
526: if (pcr_padding)
527: {
528: memset(hash_buf, 0x00, hash_size);
529: meas_algo = PTS_MEAS_ALGO_SHA1;
530: }
531: else
532: {
533: meas_algo = algo;
534: }
535:
536: e = pts_db->create_file_meas_enumerator(pts_db, pts->get_platform_id(pts),
537: hash_algo, filename);
538: if (!e)
539: {
540: return FAILED;
541: }
542:
543: while (e->enumerate(e, &hex_digest_buf))
544: {
545: hex_digest = chunk_from_str(hex_digest_buf);
546: digest = chunk_from_hex(hex_digest, digest_buf);
547:
548: if (!pts_ima_event_hash(digest, ima_algo, ima_name, meas_algo, hash_buf))
549: {
550: status = FAILED;
551: break;
552: }
553: if (chunk_equals_const(measurement, hash))
554: {
555: status = SUCCESS;
556: break;
557: }
558: else
559: {
560: status = VERIFY_ERROR;
561: }
562: }
563: e->destroy(e);
564:
565: return status;
566: }
567:
568: /**
569: * Generate an alternative pathname based on symbolic link info
570: */
571: static char* alternative_pathname(pts_t * pts, char *path)
572: {
573: pts_symlinks_t *symlinks;
574: enumerator_t *enumerator;
575: chunk_t prefix1, prefix2;
576: char *alt_path = NULL;
577: size_t path_len = strlen(path);
578: int ret;
579:
580: symlinks = pts->get_symlinks(pts);
581: if (!symlinks || symlinks->get_count(symlinks) == 0)
582: {
583: return NULL;
584: }
585:
586: enumerator = symlinks->create_enumerator(symlinks);
587: while (enumerator->enumerate(enumerator, &prefix1, &prefix2))
588: {
589: /* replace prefix2 by prefix1*/
590: if (path_len > prefix2.len && path[prefix2.len] == '/' &&
591: memeq(path, prefix2.ptr, prefix2.len))
592: {
593: ret = asprintf(&alt_path, "%.*s%s", (int)prefix1.len, prefix1.ptr,
594: path + prefix2.len);
595: if (ret <= 0)
596: {
597: alt_path = NULL;
598: }
599: break;
600: }
601:
602: /* replace prefix1 by prefix2 */
603: if (path_len > prefix1.len && path[prefix1.len] == '/' &&
604: memeq(path, prefix1.ptr, prefix1.len))
605: {
606: ret = asprintf(&alt_path, "%.*s%s", (int)prefix2.len, prefix2.ptr,
607: path + prefix1.len);
608: if (ret <= 0)
609: {
610: alt_path = NULL;
611: }
612: break;
613: }
614: }
615: enumerator->destroy(enumerator);
616:
617: return alt_path;
618: }
619:
620: METHOD(pts_component_t, verify, status_t,
621: pts_ita_comp_ima_t *this, uint8_t qualifier, pts_t *pts,
622: pts_comp_evidence_t *evidence)
623: {
624: bool has_pcr_info;
625: uint32_t pcr;
626: size_t pcr_size;
627: pts_meas_algorithms_t algo, pcr_algo;
628: pts_pcr_transform_t transform;
629: pts_pcr_t *pcrs;
630: time_t creation_time;
631: chunk_t measurement, pcr_before, pcr_after;
632: status_t status = NOT_FOUND;
633:
634: this->aik_id = pts->get_aik_id(pts);
635:
636:
637: pcrs = pts->get_pcrs(pts);
638: if (!pcrs)
639: {
640: return FAILED;
641: }
642: pcr_algo = pcrs->get_pcr_algo(pcrs);
643: pcr_size = pts_meas_algo_hash_size(pcr_algo);
644:
645: measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform,
646: &creation_time);
647: if (algo != pcr_algo)
648: {
649: DBG1(DBG_PTS, "received %N measurement hash but PCR bank is %N",
650: pts_meas_algorithm_names, algo, pts_meas_algorithm_names, algo);
651: return FAILED;
652: }
653: this->pcr_padding = (transform == PTS_PCR_TRANSFORM_SHORT);
654:
655: if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
656: PTS_ITA_QUALIFIER_TYPE_TRUSTED))
657: {
658: switch (this->state)
659: {
660: case IMA_STATE_INIT:
661: this->name->set_qualifier(this->name, qualifier);
662: status = this->pts_db->get_comp_measurement_count(this->pts_db,
663: this->name, this->aik_id, algo,
664: &this->bios_cid, &this->bios_count);
665: this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
666: if (status != SUCCESS)
667: {
668: return status;
669: }
670:
671: if (this->bios_count)
672: {
673: DBG1(DBG_PTS, "checking %d BIOS evidence measurements",
674: this->bios_count);
675: }
676: else
677: {
678: DBG1(DBG_PTS, "registering BIOS evidence measurements");
679: this->is_bios_registering = TRUE;
680: }
681:
682: this->state = IMA_STATE_BIOS;
683: /* fall through to next state */
684: case IMA_STATE_BIOS:
685: if (this->is_bios_registering)
686: {
687: status = this->pts_db->insert_comp_measurement(this->pts_db,
688: measurement, this->bios_cid, this->aik_id,
689: ++this->seq_no, pcr, algo);
690: if (status != SUCCESS)
691: {
692: return status;
693: }
694: this->bios_count = this->seq_no + 1;
695: }
696: else
697: {
698: status = this->pts_db->check_comp_measurement(this->pts_db,
699: measurement, this->bios_cid, this->aik_id,
700: ++this->seq_no, pcr, algo);
701: if (status == FAILED)
702: {
703: return status;
704: }
705: }
706: break;
707: default:
708: return FAILED;
709: }
710: }
711: else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
712: PTS_ITA_QUALIFIER_TYPE_OS))
713: {
714: int ima_count;
715: char *ima_algo, *ima_name;
716: char algo_buf[IMA_ALGO_LEN_MAX];
717: uint8_t pcr_buffer[HASH_SIZE_SHA512];
718: chunk_t boot_aggregate;
719: pts_meas_algorithms_t hash_algo;
720:
721: hash_algo = parse_validation_uri(evidence, &ima_name, &ima_algo,
722: algo_buf);
723:
724: switch (this->state)
725: {
726: case IMA_STATE_BIOS:
727: this->state = IMA_STATE_RUNTIME;
728:
729: if (!streq(ima_name, "boot_aggregate"))
730: {
731: DBG1(DBG_PTS, "ima: name must be 'boot_aggregate' "
732: "but is '%s'", ima_name);
733: return FAILED;
734: }
735: if (hash_algo != pcr_algo)
736: {
737: DBG1(DBG_PTS, "ima: boot_aggregate algorithm must be %N "
738: "but is %N",
739: pts_meas_algorithm_names, pcr_algo,
740: pts_meas_algorithm_names, hash_algo);
741: return FAILED;
742: }
743: boot_aggregate = chunk_create(pcr_buffer, pcr_size);
744: if (!check_boot_aggregate(pcrs, ima_algo, this->pcr_padding,
745: boot_aggregate, measurement))
746: {
747: return FAILED;
748: }
749: this->state = IMA_STATE_INIT;
750: /* fall through to next state */
751: case IMA_STATE_INIT:
752: this->name->set_qualifier(this->name, qualifier);
753: status = this->pts_db->get_comp_measurement_count(this->pts_db,
754: this->name, this->aik_id, algo,
755: &this->ima_cid, &ima_count);
756: this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
757: if (status != SUCCESS)
758: {
759: return status;
760: }
761:
762: if (ima_count)
763: {
764: DBG1(DBG_PTS, "checking boot aggregate evidence "
765: "measurement");
766: status = this->pts_db->check_comp_measurement(this->pts_db,
767: boot_aggregate, this->ima_cid,
768: this->aik_id, 1, pcr, algo);
769: }
770: else
771: {
772: DBG1(DBG_PTS, "registering boot aggregate evidence "
773: "measurement");
774: this->is_ima_registering = TRUE;
775: status = this->pts_db->insert_comp_measurement(this->pts_db,
776: boot_aggregate, this->ima_cid,
777: this->aik_id, 1, pcr, algo);
778: }
779: this->state = IMA_STATE_RUNTIME;
780:
781: if (status != SUCCESS)
782: {
783: return status;
784: }
785: break;
786: case IMA_STATE_RUNTIME:
787: {
788: this->count++;
789:
790: if (evidence->get_validation(evidence, NULL) !=
791: PTS_COMP_EVID_VALIDATION_PASSED)
792: {
793: DBG1(DBG_PTS, "evidence validation failed");
794: this->count_failed++;
795: return FAILED;
796: }
797:
798: status = verify_ima_measuremnt(pts, this->pts_db,
799: hash_algo, algo,
800: this->pcr_padding, measurement,
801: ima_algo, ima_name, ima_name);
802:
803: if (status == NOT_FOUND || status == VERIFY_ERROR)
804: {
805: status_t alt_status;
806: char *alt_path;
807:
808: alt_path = alternative_pathname(pts, ima_name);
809: if (alt_path)
810: {
811: alt_status = verify_ima_measuremnt(pts, this->pts_db,
812: hash_algo, algo,
813: this->pcr_padding, measurement,
814: ima_algo, ima_name, alt_path);
815: if (alt_status != NOT_FOUND)
816: {
817: status = alt_status;
818: }
819: free(alt_path);
820: }
821: }
822:
823: switch (status)
824: {
825: case SUCCESS:
826: DBG3(DBG_PTS, "%#B for '%s' is ok",
827: &measurement, ima_name);
828: this->count_ok++;
829: break;
830: case NOT_FOUND:
831: DBG2(DBG_PTS, "%#B for '%s' not found",
832: &measurement, ima_name);
833: this->count_unknown++;
834: break;
835: case VERIFY_ERROR:
836: DBG1(DBG_PTS, "%#B for '%s' differs",
837: &measurement, ima_name);
838: this->count_differ++;
839: break;
840: case FAILED:
841: default:
842: DBG1(DBG_PTS, "%#B for '%s' failed",
843: &measurement, ima_name);
844: this->count_failed++;
845: }
846: break;
847: }
848: default:
849: return FAILED;
850: }
851: }
852: else
853: {
854: DBG1(DBG_PTS, "unsupported functional component name qualifier");
855: return FAILED;
856: }
857:
858: has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
859: if (has_pcr_info)
860: {
861: if (!chunk_equals_const(pcr_before, pcrs->get(pcrs, pcr)))
862: {
863: DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
864: pcr);
865: }
866: if (pcrs->set(pcrs, pcr, pcr_after))
867: {
868: return status;
869: }
870: }
871: else
872: {
873: pcr_after = pcrs->extend(pcrs, pcr, measurement);
874: if (pcr_after.ptr)
875: {
876: return status;
877: }
878: }
879: return FAILED;
880: }
881:
882: METHOD(pts_component_t, finalize, bool,
883: pts_ita_comp_ima_t *this, uint8_t qualifier, bio_writer_t *result)
884: {
885: char result_buf[BUF_LEN];
886: char *pos = result_buf;
887: size_t len = BUF_LEN;
888: int written;
889: bool success = TRUE;
890:
891: this->name->set_qualifier(this->name, qualifier);
892:
893: if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
894: PTS_ITA_QUALIFIER_TYPE_TRUSTED))
895: {
896: /* finalize BIOS measurements */
897: if (this->is_bios_registering)
898: {
899: /* close registration */
900: this->is_bios_registering = FALSE;
901:
902: snprintf(pos, len, "registered %d BIOS evidence measurements",
903: this->seq_no);
904: }
905: else if (this->seq_no < this->bios_count)
906: {
907: snprintf(pos, len, "%d of %d BIOS evidence measurements missing",
908: this->bios_count - this->seq_no, this->bios_count);
909: success = FALSE;
910: }
911: else
912: {
913: snprintf(pos, len, "%d BIOS evidence measurements are ok",
914: this->bios_count);
915: }
916: }
917: else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL |
918: PTS_ITA_QUALIFIER_TYPE_OS))
919: {
920: /* finalize IMA file measurements */
921: if (this->is_ima_registering)
922: {
923: /* close registration */
924: this->is_ima_registering = FALSE;
925:
926: written = snprintf(pos, len, "registered IMA boot aggregate "
927: "evidence measurement; ");
928: pos += written;
929: len -= written;
930: }
931: if (this->count)
932: {
933: snprintf(pos, len, "processed %d IMA file evidence measurements: "
934: "%d ok, %d unknown, %d differ, %d failed",
935: this->count, this->count_ok, this->count_unknown,
936: this->count_differ, this->count_failed);
937: }
938: else
939: {
940: snprintf(pos, len, "no IMA file evidence measurements");
941: success = FALSE;
942: }
943: }
944: else
945: {
946: snprintf(pos, len, "unsupported functional component name qualifier");
947: success = FALSE;
948: }
949: this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN);
950:
951: DBG1(DBG_PTS, "%s", result_buf);
952: result->write_data(result, chunk_from_str(result_buf));
953:
954: return success;
955: }
956:
957: METHOD(pts_component_t, get_ref, pts_component_t*,
958: pts_ita_comp_ima_t *this)
959: {
960: ref_get(&this->ref);
961: return &this->public;
962: }
963:
964: METHOD(pts_component_t, destroy, void,
965: pts_ita_comp_ima_t *this)
966: {
967: int count;
968:
969: if (ref_put(&this->ref))
970: {
971:
972: if (this->is_bios_registering)
973: {
974: count = this->pts_db->delete_comp_measurements(this->pts_db,
975: this->bios_cid, this->aik_id);
976: DBG1(DBG_PTS, "deleted %d registered BIOS evidence measurements",
977: count);
978: }
979: if (this->is_ima_registering)
980: {
981: count = this->pts_db->delete_comp_measurements(this->pts_db,
982: this->ima_cid, this->aik_id);
983: DBG1(DBG_PTS, "deleted registered boot aggregate evidence "
984: "measurement");
985: }
986: DESTROY_IF(this->bios_list);
987: DESTROY_IF(this->ima_list);
988: this->name->destroy(this->name);
989:
990: free(this);
991: }
992: }
993:
994: /**
995: * See header
996: */
997: pts_component_t *pts_ita_comp_ima_create(uint32_t depth,
998: pts_database_t *pts_db)
999: {
1000: pts_ita_comp_ima_t *this;
1001:
1002: INIT(this,
1003: .public = {
1004: .get_comp_func_name = _get_comp_func_name,
1005: .get_evidence_flags = _get_evidence_flags,
1006: .get_depth = _get_depth,
1007: .measure = _measure,
1008: .verify = _verify,
1009: .finalize = _finalize,
1010: .get_ref = _get_ref,
1011: .destroy = _destroy,
1012: },
1013: .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
1014: PTS_QUALIFIER_UNKNOWN),
1015: .depth = depth,
1016: .pts_db = pts_db,
1017: .pcr_info = lib->settings->get_bool(lib->settings,
1018: "%s.plugins.imc-attestation.pcr_info", FALSE, lib->ns),
1019: .pcr_padding = lib->settings->get_bool(lib->settings,
1020: "%s.plugins.imc-attestation.pcr_padding", FALSE, lib->ns),
1021: .ref = 1,
1022: );
1023:
1024: return &this->public;
1025: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>