#include <pen/pen.h>
#include <debug.h>
-#include <utils/linked_list.h>
#include <credentials/credential_manager.h>
/* IMV definitions */
static credential_manager_t *pts_credmgr;
/**
- * List of id's for the files that are requested for measurement
- */
-static linked_list_t *requested_files;
-
-/**
* see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
*/
TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
break;
}
- requested_files = linked_list_create();
while (enumerator->enumerate(enumerator, &id, &type, &pathname))
{
is_directory = (type != 0);
delimiter, pathname);
attr->set_noskip_flag(attr, TRUE);
msg->add_attribute(msg, attr);
- requested_files->insert_last(requested_files, (void*)id);
+
+ attestation_state->add_requested_file(attestation_state, id, type);
}
enumerator->destroy(enumerator);
}
/**
+ * String matching function with boolean return value
+ * Used to remove an item from linked list of strings
+ */
+static bool string_cmp(char *a, char *b)
+{
+ return (strcmp(a,b) == 0) ? TRUE : FALSE;
+}
+
+/**
* see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
*/
TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
request_id, file_count, (file_count == 1) ? "":"s");
- if (!pts_db->is_directory(pts_db, request_id, &is_directory))
+ if (!attestation_state->is_request_dir(attestation_state, request_id, &is_directory))
{
- DBG1(DBG_IMV, "file entry with request id:%d not found", request_id);
+ DBG1(DBG_IMV, "received measurement with id: %d was not requested", request_id);
+ fatal_error = TRUE;
break;
}
-
if (!is_directory)
{
- requested_files->remove(requested_files, (void*)request_id, NULL);
+ attestation_state->remove_requested_file(attestation_state, request_id);
}
else
{
e = pts_db->create_files_in_dir_enumerator(pts_db, request_id);
while (e->enumerate(e, &file))
{
- files_in_dir_with_meas->insert_last(files_in_dir_with_meas, file);
- DBG3(DBG_IMV, "expecting measurement for: %s with request_id: %d", file, request_id);
+ char *file_copy = (char *)malloc(strlen(file) * sizeof(char));
+ strcpy(file_copy, file);
+
+ files_in_dir_with_meas->insert_last(files_in_dir_with_meas, file_copy);
+ DBG3(DBG_IMV, "expecting measurement for: %s with request_id: %d", file_copy, request_id);
}
+ e->destroy(e);
}
e_meas = measurements->create_enumerator(measurements);
while (e_meas->enumerate(e_meas, &filename, &measurement))
{
- enumerator_t *e;
- chunk_t db_measurement;
-
- e = (is_directory) ? pts_db->create_dir_meas_enumerator(pts_db,
- platform_info, request_id, filename, algo) :
- pts_db->create_file_meas_enumerator(pts_db,
- platform_info, request_id, algo);
- if (!e)
- {
- DBG1(DBG_IMV, " database enumerator failed");
- continue;
- }
- if (!e->enumerate(e, &db_measurement))
- {
- DBG2(DBG_IMV, " measurement for '%s' not found"
- " in database", filename);
- e->destroy(e);
- continue;
- }
- if (chunk_equals(db_measurement, measurement))
- {
- DBG2(DBG_IMV, " %#B for '%s' is ok",
- &measurement, filename);
- }
- else
+ bool hash_matched;
+
+ hash_matched = pts_db->check_measurement(pts_db,
+ measurement, platform_info,
+ request_id, filename, algo, is_directory);
+ if (!hash_matched)
{
- DBG1(DBG_IMV, " %#B for '%s' does not match %#B",
- &measurement, filename, &db_measurement);
measurement_error = TRUE;
}
-
- if (is_directory)
- {
+
+ if (is_directory &&
files_in_dir_with_meas->remove(files_in_dir_with_meas,
- filename, (bool (*)(void*,void*))strcmp);
+ filename, (bool (*)(void*,void*))string_cmp))
+ {
+ DBG3(DBG_IMV, "Removed %s from expected files list", filename);
}
- e->destroy(e);
}
if (is_directory &&
!files_in_dir_with_meas->get_count(files_in_dir_with_meas))
{
- requested_files->remove(requested_files, (void*)request_id, NULL);
+ attestation_state->remove_requested_file(attestation_state, request_id);
+ DBG3(DBG_IMV, "Received all expected files measured for request: %d", request_id);
}
- files_in_dir_with_meas->destroy(files_in_dir_with_meas);
+ files_in_dir_with_meas->destroy_function(files_in_dir_with_meas, free);
e_meas->destroy(e_meas);
+
break;
}
pa_tnc_msg->destroy(pa_tnc_msg);
-
if (fatal_error)
{
state->set_recommendation(state,
if (attestation_state->get_handshake_state(attestation_state) &
IMV_ATTESTATION_STATE_END)
- {
- if (measurement_error || requested_files->get_count(requested_files))
+ {
+ if (measurement_error || attestation_state->get_requests_count(attestation_state))
{
enumerator_t *e;
int request;
- e = requested_files->create_enumerator(requested_files);
+ e = attestation_state->create_requests_enumerator(attestation_state);
while (e->enumerate(e, &request))
{
DBG1(DBG_IMV, "measurement/s not received for requests: %d", request);
}
-
e->destroy(e);
+
state->set_recommendation(state,
TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
}
DESTROY_IF(pts_db);
pts_credmgr->destroy(pts_credmgr);
- requested_files->destroy(requested_files);
imv_attestation->destroy(imv_attestation);
imv_attestation = NULL;
*/
pts_t *pts;
+ /**
+ * Requested files and directories
+ */
+ linked_list_t *requested_files;
+
};
typedef struct entry_t entry_t;
private_imv_attestation_state_t *this)
{
this->pts->destroy(this->pts);
+ this->requested_files->destroy_function(this->requested_files, free);
free(this);
}
return this->pts;
}
+METHOD(imv_attestation_state_t, create_requests_enumerator, enumerator_t*,
+ private_imv_attestation_state_t *this)
+{
+ enumerator_t *e;
+ e = this->requested_files->create_enumerator(this->requested_files);
+ return e;
+}
+
+METHOD(imv_attestation_state_t, get_requests_count, int,
+ private_imv_attestation_state_t *this)
+{
+ return this->requested_files->get_count(this->requested_files);
+}
+
+
+METHOD(imv_attestation_state_t, add_requested_file, void,
+ private_imv_attestation_state_t *this, int request_id, int is_dir)
+{
+ file_request_t *entry;
+
+ entry = malloc_thing(file_request_t);
+ entry->request_id = request_id;
+ entry->is_dir = is_dir;
+ this->requested_files->insert_last(this->requested_files, entry);
+}
+
+/**
+ * Comparison function to match an file request entry with its request_id
+ */
+static bool request_match(file_request_t *current_list_item, int request_id)
+{
+ return (current_list_item->request_id == request_id);
+}
+
+METHOD(imv_attestation_state_t, remove_requested_file, bool,
+ private_imv_attestation_state_t *this, int request_id)
+{
+ file_request_t *entry;
+
+ if (this->requested_files->find_first(this->requested_files,
+ (linked_list_match_t)request_match, (void**)&entry, request_id) != SUCCESS)
+ {
+ DBG1(DBG_IMV, "request entry with id: %d not found", request_id);
+ return FALSE;
+ }
+
+ this->requested_files->remove(this->requested_files, entry, NULL);
+ return TRUE;
+}
+
+METHOD(imv_attestation_state_t, is_request_dir, bool,
+ private_imv_attestation_state_t *this, int request_id, bool *is_dir)
+{
+ file_request_t *entry;
+
+ if (this->requested_files->find_first(this->requested_files,
+ (linked_list_match_t)request_match, (void**)&entry, request_id) != SUCCESS)
+ {
+ DBG1(DBG_IMV, "request entry with id: %d not found", request_id);
+ return FALSE;
+ }
+
+ *is_dir = (entry->is_dir);
+ return TRUE;
+}
+
+
/**
* Described in header.
*/
.get_handshake_state = _get_handshake_state,
.set_handshake_state = _set_handshake_state,
.get_pts = _get_pts,
+ .create_requests_enumerator = _create_requests_enumerator,
+ .get_requests_count = _get_requests_count,
+ .add_requested_file = _add_requested_file,
+ .remove_requested_file = _remove_requested_file,
+ .is_request_dir = _is_request_dir,
},
.connection_id = connection_id,
.state = TNC_CONNECTION_STATE_CREATE,
.rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
.eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.pts = pts_create(FALSE),
+ .requested_files = linked_list_create(),
);
platform_info = lib->settings->get_str(lib->settings,
#include <imv/imv_state.h>
#include <tcg/pts/pts.h>
#include <library.h>
+#include <utils/linked_list.h>
typedef struct imv_attestation_state_t imv_attestation_state_t;
typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t;
+typedef struct file_request_t file_request_t;
/**
* IMV Attestation Handshake States (state machine)
};
/**
+ * Defines an structure to hold requested file/directory
+ */
+struct file_request_t {
+ int request_id;
+ int is_dir;
+};
+
+/**
* Internal state of an imv_attestation_t connection instance
*/
struct imv_attestation_state_t {
*/
pts_t* (*get_pts)(imv_attestation_state_t *this);
+ /**
+ * Add an entry to list of requested files/directories
+ *
+ * @param request_id unique request id
+ * @param is_dir 0 for file and 1 for directory
+ */
+ void (*add_requested_file)(imv_attestation_state_t *this, int request_id, int is_dir);
+
+ /**
+ * Creates enumerator over the list of requested file/directories
+ *
+ * @return enumerator over requested files/directories list
+ */
+ enumerator_t* (*create_requests_enumerator)(imv_attestation_state_t *this);
+
+ /**
+ * Returns number of entries in the list of requested file/directories
+ *
+ * @return number of entries in the list of requested file/directories
+ */
+ int (*get_requests_count)(imv_attestation_state_t *this);
+
+ /**
+ * Removes an entry with matching request_id from list of requested files/directories
+ *
+ * @param request_id unique request id
+ * @return TRUE if request entry found, FALSE otherwise
+ */
+ bool (*remove_requested_file)(imv_attestation_state_t *this, int request_id);
+
+ /**
+ * Returns TRUE if entry with given ID is directory and FALSE otherwise
+ *
+ * @param request_id unique request id
+ * @return TRUE if request entry found, FALSE otherwise
+ */
+ bool (*is_request_dir)(imv_attestation_state_t *this, int request_id, bool *is_dir);
};
/**
return e;
}
-METHOD(pts_database_t, is_directory, bool,
- private_pts_database_t *this, int id, bool *is_directory)
-{
- enumerator_t *e;
- int is_dir;
-
- /* look for a entry in files table with matching id */
- e = this->db->query(this->db,
- "SELECT f.type FROM files AS f "
- "WHERE f.id = ?",
- DB_INT, id, DB_INT);
-
- if (!e)
- {
- DBG1(DBG_TNC, "database enumerator failed", id);
- return FALSE;
- }
- if (!e->enumerate(e, &is_dir))
- {
- e->destroy(e);
- DBG1(DBG_TNC, "file entry with given id:%d not found", id);
- return FALSE;
- }
-
- *is_directory = (is_dir == 1) ? TRUE : FALSE;
- return TRUE;
-}
-
-
METHOD(pts_database_t, create_files_in_dir_enumerator, enumerator_t*,
private_pts_database_t *this, int id)
{
return e;
}
-METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*,
- private_pts_database_t *this, char *product, int id, pts_meas_algorithms_t algorithm)
+METHOD(pts_database_t, check_measurement, bool,
+ private_pts_database_t *this, chunk_t received_hash, char *product, int id, char *file_name, pts_meas_algorithms_t algorithm, bool is_dir)
{
enumerator_t *e;
+ chunk_t db_measurement;
+
+ /* look for all entries belonging to a product, file and directory in file_hashes table */
- /* look for all entries belonging to a product and file in file_hashes table */
- e = this->db->query(this->db,
+ e = (is_dir) ? this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON fh.file = f.id "
"JOIN products AS p ON fh.product = p.id "
- "WHERE p.name = ? AND f.id = ? AND fh.algo = ?",
- DB_TEXT, product, DB_INT, id, DB_INT, algorithm, DB_BLOB);
- return e;
-}
-
-METHOD(pts_database_t, create_dir_meas_enumerator, enumerator_t*,
- private_pts_database_t *this, char *product, int id, char *file_name, pts_meas_algorithms_t algorithm)
-{
- enumerator_t *e;
-
- /* look for all entries belonging to a product, file and directory in file_hashes table */
- e = this->db->query(this->db,
+ "WHERE f.path = ? AND p.name = ? AND fh.directory = ? AND fh.algo = ?",
+ DB_TEXT, file_name, DB_TEXT, product, DB_INT, id, DB_INT, algorithm, DB_BLOB) :
+
+ this->db->query(this->db,
"SELECT fh.hash FROM file_hashes AS fh "
"JOIN files AS f ON fh.file = f.id "
"JOIN products AS p ON fh.product = p.id "
- "WHERE f.path = ? AND p.name = ? AND fh.directory = ? AND fh.algo = ?",
- DB_TEXT, file_name, DB_TEXT, product, DB_INT, id, DB_INT, algorithm, DB_BLOB);
- return e;
+ "WHERE p.name = ? AND f.id = ? AND fh.algo = ?",
+ DB_TEXT, product, DB_INT, id, DB_INT, algorithm, DB_BLOB);
+
+ if (!e)
+ {
+ DBG1(DBG_TNC, " database enumerator failed");
+ return FALSE;
+ }
+ if (!e->enumerate(e, &db_measurement))
+ {
+ DBG2(DBG_TNC, " measurement for '%s' not found"
+ " in database", file_name);
+ e->destroy(e);
+ /* Ignore the measurements for which we do not have the hash saved in database */
+ return TRUE;
+ }
+ if (chunk_equals(db_measurement, received_hash))
+ {
+ DBG2(DBG_TNC, " %#B for '%s' is ok",
+ &received_hash, file_name);
+ return TRUE;
+ }
+
+ DBG1(DBG_IMV, " %#B for '%s' does not match %#B",
+ &received_hash, file_name, &db_measurement);
+ return FALSE;
}
+
METHOD(pts_database_t, destroy, void,
private_pts_database_t *this)
{
INIT(this,
.public = {
.create_file_enumerator = _create_file_enumerator,
- .is_directory = _is_directory,
.create_files_in_dir_enumerator = _create_files_in_dir_enumerator,
- .create_file_meas_enumerator = _create_file_meas_enumerator,
- .create_dir_meas_enumerator = _create_dir_meas_enumerator,
+ .check_measurement = _check_measurement,
.destroy = _destroy,
},
.db = lib->db->create(lib->db, uri),
enumerator_t* (*create_file_enumerator)(pts_database_t *this, char *product);
/**
- * Get if file with given id is directory
- *
- * @id primary key in files table
- * @is_directory TRUE if entry with given ID has type of directory
- * @return TRUE if query is not failed
- */
- bool (*is_directory)(pts_database_t *this, int id, bool *is_directory);
-
- /**
* Get Enumerator over files in a given directory with measurements
*
* @id primary key in files table, directory column in file_hashes table
enumerator_t* (*create_files_in_dir_enumerator)(pts_database_t *this, int id);
/**
- * Get Hash measurement of a file with given id and hashing algorithm type
- *
- * @product software product (os, vpn client, etc.)
- * @id primary key in files table
- * @algorithm measurement algorithm type
- * @return enumerator over all measurements matching a given release
- */
- enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, char *product,
- int id, pts_meas_algorithms_t algorithm);
- /**
* Get Hash measurement of a file in a folder with given id and hashing algorithm type
*
+ * @received_hash measurement of a file to match with database entry
* @product software product (os, vpn client, etc.)
* @id primary key in files table
- * @file_name path in files table
+ * @file_name path in files table, obligatory for the files in directory
* @algorithm measurement algorithm type
+ * @is_dir TRUE if file is requested as content in a directory
* @return enumerator over all measurements matching a given release
*/
- enumerator_t* (*create_dir_meas_enumerator)(pts_database_t *this, char *product,
- int id, char *file_name, pts_meas_algorithms_t algorithm);
+ bool (*check_measurement)(pts_database_t *this, chunk_t received_hash,
+ char *product, int id, char *file_name, pts_meas_algorithms_t algorithm, bool is_dir);
/**
/**
* Creates an pts_database_t object
*
- * @param ur database uri
+ * @param uri database uri
*/
pts_database_t* pts_database_create(char *uri);