From: Andreas Steffen Date: Mon, 16 Jul 2012 07:53:32 +0000 (+0200) Subject: ipsec attest now can measure all files in a directory X-Git-Tag: 5.0.1~377 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0f236aacb5ae9908ccecd6a87cb755e3e534f194;p=thirdparty%2Fstrongswan.git ipsec attest now can measure all files in a directory --- diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.c b/src/libpts/plugins/imc_attestation/imc_attestation_process.c index d5ff07f3d8..edaaa570f0 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation_process.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.c @@ -254,8 +254,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, DBG2(DBG_IMC, "measurement request %d for %s '%s'", request_id, is_directory ? "directory" : "file", pathname); - measurements = pts->do_measurements(pts, request_id, - pathname, is_directory); + measurements = pts_file_meas_create_from_path(request_id, + pathname, is_directory, TRUE, + pts->get_meas_algorithm(pts)); if (!measurements) { /* TODO handle error codes from measurements */ diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c index 518ec7a60d..ffea7c2e5d 100644 --- a/src/libpts/plugins/imv_attestation/attest.c +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -131,9 +131,11 @@ static void do_args(int argc, char *argv[]) { "directory", required_argument, NULL, 'D' }, { "dir", required_argument, NULL, 'D' }, { "file", required_argument, NULL, 'F' }, + { "ima", no_argument, NULL, 'I' }, { "key", required_argument, NULL, 'K' }, { "owner", required_argument, NULL, 'O' }, { "product", required_argument, NULL, 'P' }, + { "relative", no_argument, NULL, 'R' }, { "sha1", no_argument, NULL, '1' }, { "sha256", no_argument, NULL, '2' }, { "sha384", no_argument, NULL, '3' }, @@ -232,6 +234,9 @@ static void do_args(int argc, char *argv[]) exit(EXIT_FAILURE); } continue; + case 'I': + attest->set_ima(attest); + continue; case 'K': { chunk_t aik; @@ -252,6 +257,9 @@ static void do_args(int argc, char *argv[]) exit(EXIT_FAILURE); } continue; + case 'R': + attest->set_relative(attest); + continue; case '1': attest->set_algo(attest, PTS_MEAS_ALGO_SHA1); continue; diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c index 213c72e7cb..64cc4b98d4 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.c +++ b/src/libpts/plugins/imv_attestation/attest_db.c @@ -16,8 +16,11 @@ #include "attest_db.h" #include "libpts.h" +#include "pts/pts_file_meas.h" #include "pts/components/pts_comp_func_name.h" +#include + typedef struct private_attest_db_t private_attest_db_t; /** @@ -105,6 +108,16 @@ struct private_attest_db_t { */ bool product_set; + /** + * TRUE if relative filenames are to be used + */ + bool relative; + + /** + * TRUE if IMA-specific SHA-1 template hash be computed + */ + bool ima; + /** * File measurement hash algorithm */ @@ -252,6 +265,7 @@ METHOD(attest_db_t, set_directory, bool, private_attest_db_t *this, char *dir, bool create) { enumerator_t *e; + size_t len; if (this->dir_set) { @@ -259,6 +273,13 @@ METHOD(attest_db_t, set_directory, bool, return FALSE; } free(this->dir); + + /* remove trailing '/' character */ + len = strlen(dir); + if (len && dir[len-1] == '/') + { + dir[len-1] = '\0'; + } this->dir = strdup(dir); e = this->db->query(this->db, @@ -568,6 +589,18 @@ METHOD(attest_db_t, set_algo, void, this->algo = algo; } +METHOD(attest_db_t, set_ima, void, + private_attest_db_t *this) +{ + this->ima = TRUE; +} + +METHOD(attest_db_t, set_relative, void, + private_attest_db_t *this) +{ + this->relative = TRUE; +} + METHOD(attest_db_t, set_owner, void, private_attest_db_t *this, char *owner) { @@ -603,7 +636,7 @@ METHOD(attest_db_t, list_components, void, while (e->enumerate(e, &cid, &vid, &name, &qualifier)) { cfn = pts_comp_func_name_create(vid, name, qualifier); - printf("%3d: %s\n", cid, print_cfn(cfn)); + printf("%4d: %s\n", cid, print_cfn(cfn)); cfn->destroy(cfn); count++; } @@ -637,7 +670,7 @@ METHOD(attest_db_t, list_keys, void, { while (e->enumerate(e, &kid, &keyid, &owner)) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); count++; } e->destroy(e); @@ -652,7 +685,7 @@ METHOD(attest_db_t, list_keys, void, { while (e->enumerate(e, &kid, &keyid, &owner)) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); count++; } e->destroy(e); @@ -687,7 +720,7 @@ METHOD(attest_db_t, list_files, void, while (e->enumerate(e, &fid, &type, &file, &meas, &meta)) { type = (type < 0 || type > 2) ? 0 : type; - printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ", + printf("%4d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ", file_type[type], file); count++; } @@ -705,7 +738,7 @@ METHOD(attest_db_t, list_files, void, while (e->enumerate(e, &fid, &type, &file)) { type = (type < 0 || type > 2) ? 0 : type; - printf("%3d: %s %s\n", fid, file_type[type], file); + printf("%4d: %s %s\n", fid, file_type[type], file); count++; } e->destroy(e); @@ -739,7 +772,7 @@ METHOD(attest_db_t, list_products, void, { while (e->enumerate(e, &pid, &product, &meas, &meta)) { - printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", + printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", product); count++; } @@ -755,7 +788,7 @@ METHOD(attest_db_t, list_products, void, { while (e->enumerate(e, &pid, &product)) { - printf("%3d: %s\n", pid, product); + printf("%4d: %s\n", pid, product); count++; } e->destroy(e); @@ -826,11 +859,11 @@ METHOD(attest_db_t, list_hashes, void, { if (this->fid != fid_old) { - printf("%3d: %s%s%s\n", this->fid, this->dir, + printf("%4d: %s%s%s\n", this->fid, this->dir, slash(this->dir, this->file) ? "/" : "", this->file); fid_old = this->fid; } - printf(" %#B\n", &hash); + printf(" %#B\n", &hash); count++; } e->destroy(e); @@ -860,12 +893,12 @@ METHOD(attest_db_t, list_hashes, void, { get_directory(this, did, &dir); } - printf("%3d: %s%s%s\n", fid, + printf("%4d: %s%s%s\n", fid, dir, slash(dir, file) ? "/" : "", file); fid_old = fid; did_old = did; } - printf(" %#B\n", &hash); + printf(" %#B\n", &hash); count++; } e->destroy(e); @@ -922,11 +955,11 @@ METHOD(attest_db_t, list_hashes, void, get_directory(this, did, &dir); did_old = did; } - printf("%3d: %s%s%s\n", fid, + printf("%4d: %s%s%s\n", fid, dir, slash(dir, file) ? "/" : "", file); fid_old = fid; } - printf(" %#B '%s'\n", &hash, product); + printf(" %#B '%s'\n", &hash, product); count++; } e->destroy(e); @@ -964,7 +997,7 @@ METHOD(attest_db_t, list_measurements, void, { if (this->kid != kid_old) { - printf("%3d: %#B '%s'\n", this->kid, &this->key, owner); + printf("%4d: %#B '%s'\n", this->kid, &this->key, owner); kid_old = this->kid; } printf("%5d %02d %#B\n", seq_no, pcr, &hash); @@ -993,7 +1026,7 @@ METHOD(attest_db_t, list_measurements, void, { if (kid != kid_old) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); kid_old = kid; } printf("%5d %02d %#B\n", seq_no, pcr, &hash); @@ -1026,7 +1059,7 @@ METHOD(attest_db_t, list_measurements, void, if (cid != cid_old) { cfn = pts_comp_func_name_create(vid, name, qualifier); - printf("%3d: %s\n", cid, print_cfn(cfn)); + printf("%4d: %s\n", cid, print_cfn(cfn)); cfn->destroy(cfn); cid_old = cid; } @@ -1047,6 +1080,7 @@ METHOD(attest_db_t, add, bool, { bool success = FALSE; + /* add key/component pair */ if (this->kid && this->cid) { success = this->db->execute(this->db, NULL, @@ -1056,6 +1090,104 @@ METHOD(attest_db_t, add, bool, printf("key/component pair (%d/%d) %sinserted into database\n", this->kid, this->cid, success ? "" : "could not be "); } + + /* add directory or file measurement for a given product */ + if ((this->did || this->fid) && this->pid) + { + char *pathname, *filename, *label; + pts_file_meas_t *measurements; + chunk_t measurement, hash; + int fid, did, files_added = 0, hashes_added = 0; + enumerator_t *enumerator, *e; + + pathname = this->did ? this->dir : this->file; + measurements = pts_file_meas_create_from_path(0, pathname, this->did, + this->relative, this->algo); + if (!measurements) + { + return FALSE; + } + if (this->fid && this->relative) + { + set_directory(this, dirname(pathname), TRUE); + } + did = this->relative ? this->did : 0; + + enumerator = measurements->create_enumerator(measurements); + while (enumerator->enumerate(enumerator, &filename, &measurement)) + { + /* retrieve or create filename */ + label = "could not be created"; + + e = this->db->query(this->db, + "SELECT id FROM files WHERE path = ?", + DB_TEXT, filename, DB_INT); + if (!e) + { + printf("files query failed\n"); + break; + } + if (e->enumerate(e, &fid)) + { + label = "exists"; + } + else + { + if (this->db->execute(this->db, &fid, + "INSERT INTO files (type, path) VALUES (0, ?)", + DB_TEXT, filename) == 1) + { + label = "created"; + files_added++; + } + } + e->destroy(e); + + printf("%4d: %s - %s\n", fid, filename, label); + + /* retrieve or create file hash */ + label = "could not be created"; + + e = this->db->query(this->db, + "SELECT hash FROM file_hashes " + "WHERE algo = ? AND file = ? AND directory = ? AND product = ?", + DB_INT, this->algo, DB_INT, fid, DB_INT, did, DB_INT, this->pid, + DB_BLOB); + if (!e) + { + printf("file_hashes query failed\n"); + break; + } + if (e->enumerate(e, &hash)) + { + label = chunk_equals(measurement, hash) ? + "exists and equals" : "exists and differs"; + } + else + { + if (this->db->execute(this->db, NULL, + "INSERT INTO file_hashes " + "(file, directory, product, algo, hash) " + "VALUES (?, ?, ?, ?, ?)", + DB_INT, fid, DB_INT, did, DB_INT, this->pid, + DB_INT, this->algo, DB_BLOB, measurement) == 1) + { + label = "created"; + hashes_added++; + } + } + e->destroy(e); + + printf(" %#B - %s\n", &measurement, label); + } + enumerator->destroy(enumerator); + + printf("%d measurements, added %d new files and %d new file hashes\n", + measurements->get_file_count(measurements), + files_added, hashes_added); + measurements->destroy(measurements); + success = TRUE; + } return success; } @@ -1173,6 +1305,8 @@ attest_db_t *attest_db_create(char *uri) .set_product = _set_product, .set_pid = _set_pid, .set_algo = _set_algo, + .set_ima = _set_ima, + .set_relative = _set_relative, .set_owner = _set_owner, .list_products = _list_products, .list_files = _list_files, diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h index 9c9a9dcba2..4e7991a3d9 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.h +++ b/src/libpts/plugins/imv_attestation/attest_db.h @@ -125,6 +125,16 @@ struct attest_db_t { */ void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo); + /** + * Set that the IMA-specific SHA-1 template hash be computed + */ + void (*set_ima)(attest_db_t *this); + + /** + * Set that relative filenames are to be used + */ + void (*set_relative)(attest_db_t *this); + /** * Set owner [user/host] of an AIK * diff --git a/src/libpts/plugins/imv_attestation/data.sql b/src/libpts/plugins/imv_attestation/data.sql index a42245c7e5..e014711b25 100644 --- a/src/libpts/plugins/imv_attestation/data.sql +++ b/src/libpts/plugins/imv_attestation/data.sql @@ -89,7 +89,7 @@ INSERT INTO files ( INSERT INTO files ( type, path ) VALUES ( - 1, '/lib/xtables/' + 1, '/lib/xtables' ); INSERT INTO files ( diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index 3c42366e2e..4ee20b4bb4 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -23,12 +23,13 @@ #include #include +#include #include #include +#include +#include #include -#define PTS_BUF_SIZE 4096 - /** * Maximum number of PCR's of TPM, TPM Spec 1.2 */ @@ -486,54 +487,6 @@ METHOD(pts_t, get_aik_keyid, bool, return success; } -METHOD(pts_t, hash_file, bool, - private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash) -{ - u_char buffer[PTS_BUF_SIZE]; - FILE *file; - int bytes_read; - - file = fopen(pathname, "rb"); - if (!file) - { - DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname, - strerror(errno)); - return FALSE; - } - while (TRUE) - { - bytes_read = fread(buffer, 1, sizeof(buffer), file); - if (bytes_read > 0) - { - hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL); - } - else - { - hasher->get_hash(hasher, chunk_empty, hash); - break; - } - } - fclose(file); - - return TRUE; -} - -/** - * Get the relative filename of a fully qualified file pathname - */ -static char* get_filename(char *pathname) -{ - char *pos, *filename; - - pos = filename = pathname; - while (pos && *(++pos) != '\0') - { - filename = pos; - pos = strchr(filename, '/'); - } - return filename; -} - METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path, pts_error_code_t *error_code) { @@ -565,82 +518,6 @@ METHOD(pts_t, is_path_valid, bool, return TRUE; } -METHOD(pts_t, do_measurements, pts_file_meas_t*, - private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory) -{ - hasher_t *hasher; - hash_algorithm_t hash_alg; - u_char hash[HASH_SIZE_SHA384]; - chunk_t measurement; - pts_file_meas_t *measurements; - - /* Create a hasher */ - hash_alg = pts_meas_algo_to_hash(this->algorithm); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - if (!hasher) - { - DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); - return NULL; - } - - /* Create a measurement object */ - measurements = pts_file_meas_create(request_id); - - /* Link the hash to the measurement and set the measurement length */ - measurement = chunk_create(hash, hasher->get_hash_size(hasher)); - - if (is_directory) - { - enumerator_t *enumerator; - char *rel_name, *abs_name; - struct stat st; - - enumerator = enumerator_create_directory(pathname); - if (!enumerator) - { - DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname, - strerror(errno)); - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) - { - /* measure regular files only */ - if (S_ISREG(st.st_mode) && *rel_name != '.') - { - if (!hash_file(this, hasher, abs_name, hash)) - { - enumerator->destroy(enumerator); - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - DBG2(DBG_PTS, " %#B for '%s'", &measurement, rel_name); - measurements->add(measurements, rel_name, measurement); - } - } - enumerator->destroy(enumerator); - } - else - { - char *filename; - - if (!hash_file(this, hasher, pathname, hash)) - { - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - filename = get_filename(pathname); - DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); - measurements->add(measurements, filename, measurement); - } - hasher->destroy(hasher); - - return measurements; -} - /** * Obtain statistical information describing a file */ @@ -748,7 +625,7 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*, metadata->destroy(metadata); return NULL; } - entry->filename = strdup(get_filename(pathname)); + entry->filename = strdup(basename(pathname)); metadata->add(metadata, entry); } @@ -1499,8 +1376,6 @@ pts_t *pts_create(bool is_imc) .set_aik = _set_aik, .get_aik_keyid = _get_aik_keyid, .is_path_valid = _is_path_valid, - .hash_file = _hash_file, - .do_measurements = _do_measurements, .get_metadata = _get_metadata, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h index 212acb02ad..c35f686872 100644 --- a/src/libpts/pts/pts.h +++ b/src/libpts/pts/pts.h @@ -229,35 +229,14 @@ struct pts_t { */ bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code); - /** - * Compute a hash over a file - * @param hasher Hasher to be used - * @param pathname Absolute path of a file - * @param hash Buffer to keep hash output - * @return TRUE if path is valid and hashing succeeded - */ - bool (*hash_file)(pts_t *this, hasher_t *hasher, char *pathname, u_char *hash); - - /** - * Do PTS File Measurements - * - * @param request_id ID of PTS File Measurement Request - * @param pathname Absolute pathname of file to be measured - * @param is_directory TRUE if directory contents are measured - * @return PTS File Measurements of NULL if FAILED - */ - pts_file_meas_t* (*do_measurements)(pts_t *this, u_int16_t request_id, - char *pathname, bool is_directory); - /** * Obtain file metadata * * @param pathname Absolute pathname of file/directory - * @param is_directory TRUE if directory contents are requested + * @param is_dir TRUE if directory contents are requested * @return PTS File Metadata or NULL if FAILED */ - pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, - bool is_directory); + pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir); /** * Reads given PCR value and returns it diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c index 8db3ea93f8..32d50c92c7 100644 --- a/src/libpts/pts/pts_file_meas.c +++ b/src/libpts/pts/pts_file_meas.c @@ -18,6 +18,10 @@ #include #include +#include +#include +#include + typedef struct private_pts_file_meas_t private_pts_file_meas_t; /** @@ -201,3 +205,131 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id) return &this->public; } +/** + * Hash a file with a given absolute pathname + */ +static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash) +{ + u_char buffer[4096]; + size_t bytes_read; + FILE *file; + + file = fopen(pathname, "rb"); + if (!file) + { + DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname, + strerror(errno)); + return FALSE; + } + while (TRUE) + { + bytes_read = fread(buffer, 1, sizeof(buffer), file); + if (bytes_read > 0) + { + hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL); + } + else + { + hasher->get_hash(hasher, chunk_empty, hash); + break; + } + } + fclose(file); + + return TRUE; +} + +/** + * See header + */ +pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id, + char *pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg) +{ + private_pts_file_meas_t *this; + hash_algorithm_t hash_alg; + hasher_t *hasher; + u_char hash[HASH_SIZE_SHA384]; + chunk_t measurement; + char* filename; + bool success = TRUE; + + /* Create a hasher and a hash measurement buffer */ + hash_alg = pts_meas_algo_to_hash(alg); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher) + { + DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); + return NULL; + } + measurement = chunk_create(hash, hasher->get_hash_size(hasher)); + + INIT(this, + .public = { + .get_request_id = _get_request_id, + .get_file_count = _get_file_count, + .add = _add, + .create_enumerator = _create_enumerator, + .insert = _insert, + .verify = _verify, + .destroy = _destroy, + }, + .request_id = request_id, + .list = linked_list_create(), + ); + + if (is_dir) + { + enumerator_t *enumerator; + char *rel_name, *abs_name; + struct stat st; + + enumerator = enumerator_create_directory(pathname); + if (!enumerator) + { + DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname, + strerror(errno)); + success = FALSE; + goto end; + } + while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) + { + /* measure regular files only */ + if (S_ISREG(st.st_mode) && *rel_name != '.') + { + if (!hash_file(hasher, abs_name, hash)) + { + success = FALSE; + break; + } + filename = use_rel_name ? rel_name : abs_name; + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + } + } + enumerator->destroy(enumerator); + } + else + { + if (!hash_file(hasher, pathname, hash)) + { + success = FALSE; + goto end; + } + filename = use_rel_name ? basename(pathname) : pathname; + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + } + +end: + hasher->destroy(hasher); + if (success) + { + return &this->public; + } + else + { + destroy(this); + return NULL; + } +} diff --git a/src/libpts/pts/pts_file_meas.h b/src/libpts/pts/pts_file_meas.h index 9b197e736f..817cb547a3 100644 --- a/src/libpts/pts/pts_file_meas.h +++ b/src/libpts/pts/pts_file_meas.h @@ -93,4 +93,17 @@ struct pts_file_meas_t { */ pts_file_meas_t* pts_file_meas_create(u_int16_t request_id); +/** + * Creates a pts_file_meas_t object measuring a file/directory + * + * @param request_id ID of PTS File Measurement Request + * @param pathname Absolute file or directory pathname + * @param is_dir TRUE if directory path + * @param use_rel_name TRUE if relative filenames are to be used + * @param alg PTS hash measurement algorithm to be used + */ +pts_file_meas_t* pts_file_meas_create_from_path(u_int16_t request_id, + char* pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg); + #endif /** PTS_FILE_MEAS_H_ @}*/