File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libimcv / pts / components / ita / ita_comp_ima.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:20:08 2021 UTC (3 years, 5 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, HEAD
strongswan 5.9.2

    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>