refactored measurement verification
This commit is contained in:
@@ -488,13 +488,10 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
|
|||||||
int file_count;
|
int file_count;
|
||||||
pts_meas_algorithms_t algo;
|
pts_meas_algorithms_t algo;
|
||||||
pts_file_meas_t *measurements;
|
pts_file_meas_t *measurements;
|
||||||
chunk_t measurement;
|
char *platform_info;
|
||||||
char *platform_info, *filename;
|
enumerator_t *e_hash;
|
||||||
enumerator_t *e_meas;
|
|
||||||
bool is_dir;
|
bool is_dir;
|
||||||
linked_list_t *files_in_dir_with_meas;
|
|
||||||
|
|
||||||
files_in_dir_with_meas = linked_list_create();
|
|
||||||
platform_info = pts->get_platform_info(pts);
|
platform_info = pts->get_platform_info(pts);
|
||||||
if (!pts_db || !platform_info)
|
if (!pts_db || !platform_info)
|
||||||
{
|
{
|
||||||
@@ -516,51 +513,16 @@ TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
|
|||||||
DBG1(DBG_IMV, " no entry found for this request");
|
DBG1(DBG_IMV, " no entry found for this request");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (is_dir)
|
|
||||||
|
/* check hashes from database against measurements */
|
||||||
|
e_hash = pts_db->create_hash_enumerator(pts_db,
|
||||||
|
platform_info, algo, request_id, is_dir);
|
||||||
|
if (!measurements->verify(measurements, e_hash, is_dir))
|
||||||
{
|
{
|
||||||
enumerator_t *e;
|
DBG1(DBG_IMV, " measurement error occured");
|
||||||
char *file;
|
measurement_error = TRUE;
|
||||||
|
|
||||||
e = pts_db->create_files_in_dir_enumerator(pts_db, request_id);
|
|
||||||
while (e->enumerate(e, &file))
|
|
||||||
{
|
|
||||||
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_hash->destroy(e_hash);
|
||||||
e_meas = measurements->create_enumerator(measurements);
|
|
||||||
while (e_meas->enumerate(e_meas, &filename, &measurement))
|
|
||||||
{
|
|
||||||
bool hash_match;
|
|
||||||
|
|
||||||
hash_match = pts_db->check_measurement(pts_db, measurement,
|
|
||||||
platform_info, request_id, filename, algo, is_dir);
|
|
||||||
|
|
||||||
if (!hash_match)
|
|
||||||
{
|
|
||||||
measurement_error = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_dir && files_in_dir_with_meas->remove(files_in_dir_with_meas,
|
|
||||||
filename, (bool (*)(void*,void*))string_equals))
|
|
||||||
{
|
|
||||||
DBG3(DBG_IMV, "Removed %s from expected files list", filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_dir &&
|
|
||||||
!files_in_dir_with_meas->get_count(files_in_dir_with_meas))
|
|
||||||
{
|
|
||||||
DBG3(DBG_IMV, "recevied all expected file measurements for request: %d", request_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
files_in_dir_with_meas->destroy_function(files_in_dir_with_meas, free);
|
|
||||||
e_meas->destroy(e_meas);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,68 +54,33 @@ METHOD(pts_database_t, create_file_enumerator, enumerator_t*,
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(pts_database_t, create_files_in_dir_enumerator, enumerator_t*,
|
METHOD(pts_database_t, create_hash_enumerator, enumerator_t*,
|
||||||
private_pts_database_t *this, int id)
|
private_pts_database_t *this, char *product, pts_meas_algorithms_t algo,
|
||||||
|
int id, bool is_dir)
|
||||||
{
|
{
|
||||||
enumerator_t *e;
|
enumerator_t *e;
|
||||||
|
|
||||||
/* look for all entries in file_hashes belonging to a same directory*/
|
if (is_dir)
|
||||||
e = this->db->query(this->db,
|
{
|
||||||
"SELECT DISTINCT f.path FROM files AS f "
|
e = this->db->query(this->db,
|
||||||
"JOIN file_hashes AS fh ON f.id = fh.file "
|
"SELECT f.path, fh.hash FROM file_hashes AS fh "
|
||||||
"WHERE fh.directory = ?",
|
"JOIN files AS f ON fh.file = f.id "
|
||||||
DB_INT, id, DB_TEXT);
|
"JOIN products AS p ON fh.product = p.id "
|
||||||
|
"WHERE p.name = ? AND fh.directory = ? AND fh.algo = ?",
|
||||||
|
DB_TEXT, product, DB_INT, id, DB_INT, algo, DB_TEXT, DB_BLOB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e = this->db->query(this->db,
|
||||||
|
"SELECT f.path, 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 fh.file = ? AND fh.algo = ?",
|
||||||
|
DB_TEXT, product, DB_INT, id, DB_INT, algo, DB_TEXT, DB_BLOB);
|
||||||
|
}
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
|
||||||
|
|
||||||
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 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 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,
|
METHOD(pts_database_t, destroy, void,
|
||||||
private_pts_database_t *this)
|
private_pts_database_t *this)
|
||||||
{
|
{
|
||||||
@@ -133,8 +98,7 @@ pts_database_t *pts_database_create(char *uri)
|
|||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.create_file_enumerator = _create_file_enumerator,
|
.create_file_enumerator = _create_file_enumerator,
|
||||||
.create_files_in_dir_enumerator = _create_files_in_dir_enumerator,
|
.create_hash_enumerator = _create_hash_enumerator,
|
||||||
.check_measurement = _check_measurement,
|
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.db = lib->db->create(lib->db, uri),
|
.db = lib->db->create(lib->db, uri),
|
||||||
|
|||||||
@@ -35,33 +35,23 @@ struct pts_database_t {
|
|||||||
/**
|
/**
|
||||||
* Get files to be measured by PTS
|
* Get files to be measured by PTS
|
||||||
*
|
*
|
||||||
* @product software product (os, vpn client, etc.)
|
* @param product software product (os, vpn client, etc.)
|
||||||
* @return enumerator over all files matching a given release
|
* @return enumerator over all matching files
|
||||||
*/
|
*/
|
||||||
enumerator_t* (*create_file_enumerator)(pts_database_t *this, char *product);
|
enumerator_t* (*create_file_enumerator)(pts_database_t *this, char *product);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Enumerator over files in a given directory with measurements
|
* Get stored measurement hash for single file or directory entries
|
||||||
*
|
*
|
||||||
* @id primary key in files table, directory column in file_hashes table
|
* @param product software product (os, vpn client, etc.)
|
||||||
* @return enumerator over all measurements matching a given release
|
* @param algo hash algorithm used for measurement
|
||||||
|
* @param id primary key of measured file/directory
|
||||||
|
* @param is_dir TRUE if directory was measured
|
||||||
|
* @return enumerator over all matching measurement hashes
|
||||||
*/
|
*/
|
||||||
enumerator_t* (*create_files_in_dir_enumerator)(pts_database_t *this, int id);
|
enumerator_t* (*create_hash_enumerator)(pts_database_t *this, char *product,
|
||||||
|
pts_meas_algorithms_t algo,
|
||||||
/**
|
int id, bool is_dir);
|
||||||
* 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, 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
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys a pts_database_t object.
|
* Destroys a pts_database_t object.
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "pts_file_meas.h"
|
#include "pts_file_meas.h"
|
||||||
|
|
||||||
#include <utils/linked_list.h>
|
#include <utils/linked_list.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
typedef struct private_pts_file_meas_t private_pts_file_meas_t;
|
typedef struct private_pts_file_meas_t private_pts_file_meas_t;
|
||||||
|
|
||||||
@@ -106,6 +107,52 @@ METHOD(pts_file_meas_t, create_enumerator, enumerator_t*,
|
|||||||
(void*)entry_filter, NULL, NULL);
|
(void*)entry_filter, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(pts_file_meas_t, verify, bool,
|
||||||
|
private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir)
|
||||||
|
{
|
||||||
|
char *filename;
|
||||||
|
chunk_t measurement;
|
||||||
|
entry_t *entry;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bool found, success = TRUE;
|
||||||
|
|
||||||
|
while (e_hash->enumerate(e_hash, &filename, &measurement))
|
||||||
|
{
|
||||||
|
found = FALSE;
|
||||||
|
|
||||||
|
enumerator = this->list->create_enumerator(this->list);
|
||||||
|
while (enumerator->enumerate(enumerator, &entry))
|
||||||
|
{
|
||||||
|
if (!is_dir || streq(filename, entry->filename))
|
||||||
|
{
|
||||||
|
found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
DBG1(DBG_TNC, " no measurement found for '%s'", filename);
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
if (chunk_equals(measurement, entry->measurement))
|
||||||
|
{
|
||||||
|
DBG2(DBG_TNC, " %#B for '%s' is ok", &measurement, filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_TNC, " %#B for '%s' is incorrect", &measurement, filename);
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
if (!is_dir)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(pts_file_meas_t, destroy, void,
|
METHOD(pts_file_meas_t, destroy, void,
|
||||||
private_pts_file_meas_t *this)
|
private_pts_file_meas_t *this)
|
||||||
{
|
{
|
||||||
@@ -126,6 +173,7 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id)
|
|||||||
.get_file_count = _get_file_count,
|
.get_file_count = _get_file_count,
|
||||||
.add = _add,
|
.add = _add,
|
||||||
.create_enumerator = _create_enumerator,
|
.create_enumerator = _create_enumerator,
|
||||||
|
.verify = _verify,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.request_id = request_id,
|
.request_id = request_id,
|
||||||
|
|||||||
@@ -53,12 +53,21 @@ struct pts_file_meas_t {
|
|||||||
void (*add)(pts_file_meas_t *this, char *filename, chunk_t measurement);
|
void (*add)(pts_file_meas_t *this, char *filename, chunk_t measurement);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a PTS File Measurement enumerator
|
* Create a PTS File Measurement enumerator
|
||||||
*
|
*
|
||||||
* @return Enumerator returning filename and measurement
|
* @return Enumerator returning filename and measurement
|
||||||
*/
|
*/
|
||||||
enumerator_t* (*create_enumerator)(pts_file_meas_t *this);
|
enumerator_t* (*create_enumerator)(pts_file_meas_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify stored hashes against PTS File Measurements
|
||||||
|
*
|
||||||
|
* @param e_hash Hash enumerator
|
||||||
|
* @paraem is_dir TRUE for directory contents hashes
|
||||||
|
* @return TRUE if all hashes match a measurement
|
||||||
|
*/
|
||||||
|
bool (*verify)(pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys a pts_file_meas_t object.
|
* Destroys a pts_file_meas_t object.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user