From: Andreas Steffen Date: Mon, 10 Jun 2013 11:29:07 +0000 (+0200) Subject: Introduced workitems to Attestation IMV X-Git-Tag: 5.1.0dr1~57 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b1da8368d0ed33cc31410f26444363aa37368cc7;p=thirdparty%2Fstrongswan.git Introduced workitems to Attestation IMV --- diff --git a/src/libimcv/imv/data.sql b/src/libimcv/imv/data.sql index 4df72be8eb..ff00a3a54c 100644 --- a/src/libimcv/imv/data.sql +++ b/src/libimcv/imv/data.sql @@ -262,6 +262,12 @@ INSERT INTO files ( /* 5 */ 'openssl', 8 ); +INSERT INTO files ( /* 6 */ + name, dir +) VALUES ( + 'tnc_config', 2 +); + /* Algorithms */ INSERT INTO algorithms ( @@ -639,15 +645,40 @@ INSERT INTO policies ( /* 7 */ INSERT INTO policies ( /* 8 */ type, name, rec_fail, rec_noresult ) VALUES ( - 9, 'No Open TCP Ports', 1, 1 + 11, 'No Open TCP Ports', 1, 1 ); INSERT INTO policies ( /* 9 */ type, name, rec_fail, rec_noresult ) VALUES ( - 10, 'No Open UDP Ports', 1, 1 + 12, 'No Open UDP Ports', 1, 1 +); + +INSERT INTO policies ( /* 10 */ + type, name, file, rec_fail, rec_noresult +) VALUES ( + 7, 'Metadata of /etc/tnc_config', 6, 0, 0 +); + +INSERT INTO policies ( /* 11 */ + type, name, dir, rec_fail, rec_noresult +) VALUES ( + 8, 'Measure as reference /bin', 1, 0, 0 +); + +INSERT INTO policies ( /* 12 */ + type, name, file, rec_fail, rec_noresult +) VALUES ( + 6, 'Measure /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', 2, 2, 2 ); +INSERT INTO policies ( /* 13 */ + type, name, file, rec_fail, rec_noresult +) VALUES ( + 6, 'Measure /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0', 4, 2, 2 +); + + /* Enforcements */ INSERT INTO enforcements ( @@ -713,13 +744,13 @@ INSERT INTO enforcements ( INSERT INTO enforcements ( policy, group_id, max_age ) VALUES ( - 5, 2, 86400 + 5, 4, 86400 ); INSERT INTO enforcements ( policy, group_id, max_age ) VALUES ( - 6, 2, 86400 + 6, 4, 86400 ); INSERT INTO enforcements ( @@ -788,3 +819,27 @@ INSERT INTO enforcements ( 9, 5, 60 ); +INSERT INTO enforcements ( + policy, group_id, max_age +) VALUES ( + 10, 2, 60 +); + +INSERT INTO enforcements ( + policy, group_id, max_age +) VALUES ( + 11, 2, 86400 +); + +INSERT INTO enforcements ( + policy, group_id, max_age +) VALUES ( + 12, 2, 86400 +); + +INSERT INTO enforcements ( + policy, group_id, max_age +) VALUES ( + 13, 2, 86400 +); + diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index ae20f2b183..435c25a3c2 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -285,6 +285,7 @@ static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id) { enumerator_t *enumerator; imv_state_t *state; + imv_session_t *session; bool found = FALSE; this->connection_lock->write_lock(this->connection_lock); @@ -294,6 +295,11 @@ static bool delete_connection(private_imv_agent_t *this, TNC_ConnectionID id) if (id == state->get_connection_id(state)) { found = TRUE; + session = state->get_session(state); + if (session) + { + imcv_db->remove_session(imcv_db, session); + } state->destroy(state); this->connections->remove_at(this->connections, enumerator); break; @@ -480,7 +486,7 @@ METHOD(imv_agent_t, create_state, TNC_Result, if (imcv_db) { - session = imcv_db->get_session(imcv_db, conn_id, ar_id_type, ar_id_value); + session = imcv_db->add_session(imcv_db, conn_id, ar_id_type, ar_id_value); if (session) { DBG2(DBG_IMV, " assigned session ID %d", diff --git a/src/libimcv/imv/imv_database.c b/src/libimcv/imv/imv_database.c index 1e72b98b0f..6c4ec071a2 100644 --- a/src/libimcv/imv/imv_database.c +++ b/src/libimcv/imv/imv_database.c @@ -59,7 +59,7 @@ struct private_imv_database_t { }; -METHOD(imv_database_t, get_session, imv_session_t*, +METHOD(imv_database_t, add_session, imv_session_t*, private_imv_database_t *this, TNC_ConnectionID conn_id, u_int32_t ar_id_type, chunk_t ar_id_value) { @@ -123,6 +123,26 @@ METHOD(imv_database_t, get_session, imv_session_t*, return session; } +METHOD(imv_database_t, remove_session, void, + private_imv_database_t *this, imv_session_t *session) +{ + enumerator_t *enumerator; + imv_session_t *current; + + this->mutex->lock(this->mutex); + enumerator = this->sessions->create_enumerator(this->sessions); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current == session) + { + this->sessions->remove_at(this->sessions, enumerator); + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + METHOD(imv_database_t, add_product, int, private_imv_database_t *this, imv_session_t *session, char *product) { @@ -204,10 +224,9 @@ METHOD(imv_database_t, policy_script, bool, { imv_workitem_t *workitem; imv_workitem_type_t type; - imv_session_t *current; - int id, session_id, rec_fail, rec_noresult; - enumerator_t *enumerator, *e; - char command[512], resp[128], *last, *argument; + int id, session_id, arg_int, rec_fail, rec_noresult; + enumerator_t *e; + char command[512], resp[128], *last, *arg_str; FILE *shell; session_id = session->get_session_id(session); @@ -250,17 +269,18 @@ METHOD(imv_database_t, policy_script, bool, { /* get workitem list generated by policy manager */ e = this->db->query(this->db, - "SELECT id, type, argument, rec_fail, rec_noresult " - "FROM workitems WHERE session = ?", - DB_INT, session_id, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT); + "SELECT id, type, arg_str, arg_int, rec_fail, rec_noresult " + "FROM workitems WHERE session = ?", DB_INT, session_id, + DB_INT, DB_INT, DB_TEXT, DB_INT,DB_INT, DB_INT); if (!e) { DBG1(DBG_IMV, "no workitem enumerator returned"); return FALSE; } - while (e->enumerate(e, &id, &type, &argument, &rec_fail, &rec_noresult)) + while (e->enumerate(e, &id, &type, &arg_str, &arg_int, &rec_fail, + &rec_noresult)) { - workitem = imv_workitem_create(id, type, argument, rec_fail, + workitem = imv_workitem_create(id, type, arg_str, arg_int, rec_fail, rec_noresult); session->insert_workitem(session, workitem); } @@ -270,20 +290,6 @@ METHOD(imv_database_t, policy_script, bool, } else if (!start && session->get_policy_started(session)) { - /* remove session */ - this->mutex->lock(this->mutex); - enumerator = this->sessions->create_enumerator(this->sessions); - while (enumerator->enumerate(enumerator, ¤t)) - { - if (current == session) - { - this->sessions->remove_at(this->sessions, enumerator); - break; - } - } - enumerator->destroy(enumerator); - this->mutex->unlock(this->mutex); - session->set_policy_started(session, FALSE); } @@ -329,7 +335,8 @@ imv_database_t *imv_database_create(char *uri, char *script) INIT(this, .public = { - .get_session = _get_session, + .add_session = _add_session, + .remove_session = _remove_session, .add_product = _add_product, .add_device = _add_device, .add_recommendation = _add_recommendation, diff --git a/src/libimcv/imv/imv_database.h b/src/libimcv/imv/imv_database.h index 6cab415899..48a3ded9e7 100644 --- a/src/libimcv/imv/imv_database.h +++ b/src/libimcv/imv/imv_database.h @@ -44,10 +44,17 @@ struct imv_database_t { * @param ar_id_value Access Requestor identity value * @return Session associated with TNCCS Connection */ - imv_session_t* (*get_session)(imv_database_t *this, + imv_session_t* (*add_session)(imv_database_t *this, TNC_ConnectionID conn_id, u_int32_t ar_id_type, chunk_t ar_id_value); + /** + * Remove and delete a session + * + * @param session Session + */ + void (*remove_session)(imv_database_t *this, imv_session_t *session); + /** * Add product information string to a session database entry * diff --git a/src/libimcv/imv/imv_policy_manager.c b/src/libimcv/imv/imv_policy_manager.c index 34d177de23..9c08cd53ad 100644 --- a/src/libimcv/imv/imv_policy_manager.c +++ b/src/libimcv/imv/imv_policy_manager.c @@ -25,7 +25,7 @@ /** * global debug output variables */ -static int debug_level = 2; +static int debug_level = 1; static bool stderr_quiet = FALSE; /** @@ -51,7 +51,7 @@ bool policy_start(database_t *db, int session_id) { enumerator_t *e; int id, gid, device_id, product_id, group_id = 0; - int type, rec_fail, rec_noresult; + int type, file, dir, arg_int, rec_fail, rec_noresult; char *argument; /* get session data */ @@ -107,22 +107,41 @@ bool policy_start(database_t *db, int session_id) /* get enforcements for given group */ e = db->query(db, - "SELECT e.id, p.type, p.argument, p.rec_fail, p.rec_noresult " + "SELECT e.id, " + "p.type, p.argument, p.file, p.dir, p.rec_fail, p.rec_noresult " "FROM enforcements AS e JOIN policies as p ON e.policy = p.id " - "WHERE e.group_id = ?", - DB_INT, group_id, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT); + "WHERE e.group_id = ?", DB_INT, group_id, + DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT); if (!e) { return FALSE; } - while (e->enumerate(e, &id, &type, &argument, &rec_fail, &rec_noresult)) + while (e->enumerate(e, &id, &type, &argument, &file, &dir, &rec_fail, + &rec_noresult)) { + /* determine arg_int */ + switch ((imv_workitem_type_t)type) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_FILE_META: + arg_int = file; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + case IMV_WORKITEM_DIR_META: + arg_int = dir; + break; + default: + arg_int = 0; + } + /* insert a workitem */ if (db->execute(db, NULL, - "INSERT INTO workitems (session, enforcement, type, argument, " - "rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?)", + "INSERT INTO workitems (session, enforcement, type, arg_str, " + "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)", DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument, - DB_INT, rec_fail, DB_INT, rec_noresult) != 1) + DB_INT, arg_int, DB_INT, rec_fail, DB_INT, rec_noresult) != 1) { e->destroy(e); fprintf(stderr, "could not insert workitem\n"); @@ -139,7 +158,6 @@ bool policy_stop(database_t *db, int session_id) enumerator_t *e; int rec, policy; char *result; - bool no_worklists = TRUE; e = db->query(db, "SELECT w.rec_final, w.result, e.policy FROM workitems AS w " @@ -150,24 +168,16 @@ bool policy_stop(database_t *db, int session_id) { while (e->enumerate(e, &rec, &result, &policy)) { - no_worklists = FALSE; - - /* insert result */ db->execute(db, NULL, "INSERT INTO results (session, policy, rec, result) " "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy, DB_INT, rec, DB_TEXT, result); } e->destroy(e); - - if (no_worklists) - { - return TRUE; - } } return db->execute(db, NULL, "DELETE FROM workitems WHERE session = ?", - DB_UINT, session_id) > 0; + DB_UINT, session_id) >= 0; } int main(int argc, char *argv[]) @@ -224,6 +234,12 @@ int main(int argc, char *argv[]) /* attach IMV database */ uri = lib->settings->get_str(lib->settings, "libimcv.database", NULL); + if (!uri) + { + fprintf(stderr, "database uri not defined.\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + db = lib->db->create(lib->db, uri); if (!db) { diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index 53df6714ee..791846bb1e 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -79,6 +79,20 @@ struct imv_state_t { */ u_int32_t (*get_max_msg_len)(imv_state_t *this); + /** + * Set flags for completed actions + * + * @param flags Flags to be set + */ + void (*set_action_flags)(imv_state_t *this, u_int32_t flags); + + /** + * Get flags set for completed actions + * + * @return Flags set for completed actions + */ + u_int32_t (*get_action_flags)(imv_state_t *this); + /** * Set Access Requestor ID * diff --git a/src/libimcv/imv/imv_workitem.c b/src/libimcv/imv/imv_workitem.c index 78d7f30856..43af9bf37c 100644 --- a/src/libimcv/imv/imv_workitem.c +++ b/src/libimcv/imv/imv_workitem.c @@ -27,8 +27,10 @@ ENUM(imv_workitem_type_names, IMV_WORKITEM_PACKAGES, IMV_WORKITEM_UDP_SCAN, "PWDEN", "FREFM", "FMEAS", + "FMETA", "DREFM", "DMEAS", + "DMETA", "TCPSC", "UDPSC" ); @@ -62,7 +64,12 @@ struct private_imv_workitem_t { /** * Argument string */ - char *argument; + char *arg_str; + + /** + * Argument integer + */ + int arg_int; /** * Result string @@ -110,10 +117,16 @@ METHOD(imv_workitem_t, get_type, imv_workitem_type_t, return this->type; } -METHOD(imv_workitem_t, get_argument, char*, +METHOD(imv_workitem_t, get_arg_str, char*, + private_imv_workitem_t *this) +{ + return this->arg_str; +} + +METHOD(imv_workitem_t, get_arg_int, int, private_imv_workitem_t *this) { - return this->argument; + return this->arg_int; } METHOD(imv_workitem_t, set_result, TNC_IMV_Action_Recommendation, @@ -135,9 +148,10 @@ METHOD(imv_workitem_t, set_result, TNC_IMV_Action_Recommendation, this->rec_final = this->rec_noresult; break; } - DBG2(DBG_IMV, "workitem %N: %N%s%s", imv_workitem_type_names, this->type, - TNC_IMV_Action_Recommendation_names, this->rec_final, - strlen(result) ? " - " : "", result); + DBG2(DBG_IMV, "IMV %d handled %N workitem %d: %N%s%s", this->imv_id, + imv_workitem_type_names, this->type, this->id, + TNC_IMV_Action_Recommendation_names, this->rec_final, + strlen(result) ? " - " : "", result); return this->rec_final; } @@ -155,7 +169,7 @@ METHOD(imv_workitem_t, get_result, TNC_IMV_Action_Recommendation, METHOD(imv_workitem_t, destroy, void, private_imv_workitem_t *this) { - free(this->argument); + free(this->arg_str); free(this->result); free(this); } @@ -164,7 +178,7 @@ METHOD(imv_workitem_t, destroy, void, * See header */ imv_workitem_t *imv_workitem_create(int id, imv_workitem_type_t type, - char *argument, + char *arg_str, int arg_int, TNC_IMV_Action_Recommendation rec_fail, TNC_IMV_Action_Recommendation rec_noresult) { @@ -176,7 +190,8 @@ imv_workitem_t *imv_workitem_create(int id, imv_workitem_type_t type, .set_imv_id = _set_imv_id, .get_imv_id = _get_imv_id, .get_type = _get_type, - .get_argument = _get_argument, + .get_arg_str = _get_arg_str, + .get_arg_int = _get_arg_int, .set_result = _set_result, .get_result = _get_result, .destroy = _destroy, @@ -184,7 +199,8 @@ imv_workitem_t *imv_workitem_create(int id, imv_workitem_type_t type, .id = id, .imv_id = TNC_IMVID_ANY, .type = type, - .argument = strdup(argument), + .arg_str = arg_str ? strdup(arg_str) : NULL, + .arg_int = arg_int, .rec_fail = rec_fail, .rec_noresult = rec_noresult, .rec_final = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, diff --git a/src/libimcv/imv/imv_workitem.h b/src/libimcv/imv/imv_workitem.h index c803242e7b..80ce3f4534 100644 --- a/src/libimcv/imv/imv_workitem.h +++ b/src/libimcv/imv/imv_workitem.h @@ -36,10 +36,12 @@ enum imv_workitem_type_t { IMV_WORKITEM_DEFAULT_PWD = 4, IMV_WORKITEM_FILE_REF_MEAS = 5, IMV_WORKITEM_FILE_MEAS = 6, - IMV_WORKITEM_DIR_REF_MEAS = 7, - IMV_WORKITEM_DIR_MEAS = 8, - IMV_WORKITEM_TCP_SCAN = 9, - IMV_WORKITEM_UDP_SCAN = 10 + IMV_WORKITEM_FILE_META = 7, + IMV_WORKITEM_DIR_REF_MEAS = 8, + IMV_WORKITEM_DIR_MEAS = 9, + IMV_WORKITEM_DIR_META = 10, + IMV_WORKITEM_TCP_SCAN = 11, + IMV_WORKITEM_UDP_SCAN = 12 }; extern enum_name_t *imv_workitem_type_names; @@ -78,11 +80,18 @@ struct imv_workitem_t { TNC_IMVID (*get_imv_id)(imv_workitem_t *this); /** - * Get argument string + * Get string argument * * @return Argument string */ - char* (*get_argument)(imv_workitem_t *this); + char* (*get_arg_str)(imv_workitem_t *this); + + /** + * Get integer argument + * + * @return Argument integer + */ + int (*get_arg_int)(imv_workitem_t *this); /** * Set result string @@ -114,12 +123,13 @@ struct imv_workitem_t { * * @param id Primary workitem key * @param type Workitem type - * @param argument Argument string + * @param arg_str String argument + * @param arg_int Integer argument * @param rec_fail Recommendation with minor/major non-compliance case * @param rec_noresult Recommendation in don't know/error case */ imv_workitem_t *imv_workitem_create(int id, imv_workitem_type_t type, - char *argument, + char *arg_str, int arg_int, TNC_IMV_Action_Recommendation rec_fail, TNC_IMV_Action_Recommendation rec_noresult); diff --git a/src/libimcv/imv/tables.sql b/src/libimcv/imv/tables.sql index 823a72d3af..aee88943af 100644 --- a/src/libimcv/imv/tables.sql +++ b/src/libimcv/imv/tables.sql @@ -107,7 +107,8 @@ CREATE TABLE workitems ( session integer NOT NULL REFERENCES sessions(id), enforcement integer NOT NULL REFERENCES enforcements(id), type integer NOT NULL, - argument text NOT NULL, + arg_str text, + arg_int INTEGER DEFAULT 0, rec_fail integer NOT NULL, rec_noresult integer NOT NULL, rec_final integer, diff --git a/src/libimcv/plugins/imv_os/imv_os_agent.c b/src/libimcv/plugins/imv_os/imv_os_agent.c index 17c0585f10..86692ed402 100644 --- a/src/libimcv/plugins/imv_os/imv_os_agent.c +++ b/src/libimcv/plugins/imv_os/imv_os_agent.c @@ -184,8 +184,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, ietf_attr_product_info_t *attr_cast; pen_t vendor_id; - os_state->set_received(os_state, - IMV_OS_ATTR_PRODUCT_INFORMATION); + state->set_action_flags(state, + IMV_OS_ATTR_PRODUCT_INFORMATION); attr_cast = (ietf_attr_product_info_t*)attr; os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL); if (vendor_id != PEN_IETF) @@ -205,8 +205,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, { ietf_attr_string_version_t *attr_cast; - os_state->set_received(os_state, - IMV_OS_ATTR_STRING_VERSION); + state->set_action_flags(state, + IMV_OS_ATTR_STRING_VERSION); attr_cast = (ietf_attr_string_version_t*)attr; os_version = attr_cast->get_version(attr_cast, NULL, NULL); if (os_version.len) @@ -221,8 +221,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, ietf_attr_numeric_version_t *attr_cast; u_int32_t major, minor; - os_state->set_received(os_state, - IMV_OS_ATTR_NUMERIC_VERSION); + state->set_action_flags(state, + IMV_OS_ATTR_NUMERIC_VERSION); attr_cast = (ietf_attr_numeric_version_t*)attr; attr_cast->get_version(attr_cast, &major, &minor); DBG1(DBG_IMV, "operating system numeric version is %d.%d", @@ -236,8 +236,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, op_result_t op_result; time_t last_boot; - os_state->set_received(os_state, - IMV_OS_ATTR_OPERATIONAL_STATUS); + state->set_action_flags(state, + IMV_OS_ATTR_OPERATIONAL_STATUS); attr_cast = (ietf_attr_op_status_t*)attr; op_status = attr_cast->get_status(attr_cast); op_result = attr_cast->get_result(attr_cast); @@ -252,8 +252,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, ietf_attr_fwd_enabled_t *attr_cast; os_fwd_status_t fwd_status; - os_state->set_received(os_state, - IMV_OS_ATTR_FORWARDING_ENABLED); + state->set_action_flags(state, + IMV_OS_ATTR_FORWARDING_ENABLED); attr_cast = (ietf_attr_fwd_enabled_t*)attr; fwd_status = attr_cast->get_status(attr_cast); DBG1(DBG_IMV, "IPv4 forwarding is %N", @@ -270,7 +270,7 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, ietf_attr_default_pwd_enabled_t *attr_cast; bool default_pwd_status; - os_state->set_received(os_state, + state->set_action_flags(state, IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED); attr_cast = (ietf_attr_default_pwd_enabled_t*)attr; default_pwd_status = attr_cast->get_status(attr_cast); @@ -289,8 +289,8 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, enumerator_t *e; status_t status; - os_state->set_received(os_state, - IMV_OS_ATTR_INSTALLED_PACKAGES); + state->set_action_flags(state, + IMV_OS_ATTR_INSTALLED_PACKAGES); if (!this->db) { break; @@ -325,7 +325,7 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, char *name; chunk_t value; - os_state->set_received(os_state, IMV_OS_ATTR_SETTINGS); + state->set_action_flags(state, IMV_OS_ATTR_SETTINGS); attr_cast = (ita_attr_settings_t*)attr; e = attr_cast->create_enumerator(attr_cast); @@ -349,7 +349,7 @@ static TNC_Result receive_msg(private_imv_os_agent_t *this, imv_state_t *state, int device_id; chunk_t value; - os_state->set_received(os_state, IMV_OS_ATTR_DEVICE_ID); + state->set_action_flags(state, IMV_OS_ATTR_DEVICE_ID); value = attr->get_value(attr); DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr); @@ -464,7 +464,7 @@ METHOD(imv_agent_if_t, receive_message_long, TNC_Result, /** * Build an IETF Attribute Request attribute for missing attributes */ -static pa_tnc_attr_t* build_attr_request(u_int received) +static pa_tnc_attr_t* build_attr_request(u_int32_t received) { pa_tnc_attr_t *attr; ietf_attr_attr_request_t *attr_cast; @@ -517,7 +517,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, TNC_Result result = TNC_RESULT_SUCCESS; bool no_workitems = TRUE; enumerator_t *enumerator; - u_int received; + u_int32_t received; if (!this->agent->get_state(this->agent, id, &state)) { @@ -525,14 +525,18 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, } os_state = (imv_os_state_t*)state; handshake_state = os_state->get_handshake_state(os_state); - received = os_state->get_received(os_state); + received = state->get_action_flags(state); session = state->get_session(state); imv_id = this->agent->get_id(this->agent); + if (handshake_state == IMV_OS_STATE_END) + { + return TNC_RESULT_SUCCESS; + } + /* create an empty out message - we might need it */ - out_msg = imv_msg_create(this->agent, state, id, - this->agent->get_id(this->agent), - TNC_IMCID_ANY, msg_types[0]); + out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, + msg_types[0]); if (handshake_state == IMV_OS_STATE_INIT) { @@ -627,7 +631,8 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, if (no_workitems) { - DBG2(DBG_IMV, "no workitems generated - no evaluation requested"); + DBG2(DBG_IMV, "IMV %d has no workitems - " + "no evaluation requested", imv_id); state->set_recommendation(state, TNC_IMV_ACTION_RECOMMENDATION_ALLOW, TNC_IMV_EVALUATION_RESULT_DONT_KNOW); @@ -727,6 +732,8 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result, /* finalized all workitems ? */ if (session->get_workitem_count(session, imv_id) == 0) { + os_state->set_handshake_state(os_state, IMV_OS_STATE_END); + result = out_msg->send_assessment(out_msg); out_msg->destroy(out_msg); if (result != TNC_RESULT_SUCCESS) diff --git a/src/libimcv/plugins/imv_os/imv_os_state.c b/src/libimcv/plugins/imv_os/imv_os_state.c index 3cfe6b39c8..4ab8a814c7 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.c +++ b/src/libimcv/plugins/imv_os/imv_os_state.c @@ -64,6 +64,11 @@ struct private_imv_os_state_t { */ u_int32_t max_msg_len; + /** + * Flags set for completed actions + */ + u_int32_t action_flags; + /** * Access Requestor ID Type */ @@ -159,11 +164,6 @@ struct private_imv_os_state_t { */ int count_ok; - /** - * Flags set for received attributes - */ - u_int received_flags; - /** * OS Settings */ @@ -337,6 +337,18 @@ METHOD(imv_state_t, get_max_msg_len, u_int32_t, return this->max_msg_len; } +METHOD(imv_state_t, set_action_flags, void, + private_imv_os_state_t *this, u_int32_t flags) +{ + this->action_flags |= flags; +} + +METHOD(imv_state_t, get_action_flags, u_int32_t, + private_imv_os_state_t *this) +{ + return this->action_flags; +} + METHOD(imv_state_t, set_ar_id, void, private_imv_os_state_t *this, u_int32_t id_type, chunk_t id_value) { @@ -580,18 +592,6 @@ METHOD(imv_os_state_t, get_count, void, } } -METHOD(imv_os_state_t, set_received, void, - private_imv_os_state_t *this, u_int flags) -{ - this->received_flags |= flags; -} - -METHOD(imv_os_state_t, get_received, u_int, - private_imv_os_state_t *this) -{ - return this->received_flags; -} - METHOD(imv_os_state_t, set_device_id, void, private_imv_os_state_t *this, int id) { @@ -660,6 +660,8 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .set_flags = _set_flags, .set_max_msg_len = _set_max_msg_len, .get_max_msg_len = _get_max_msg_len, + .set_action_flags = _set_action_flags, + .get_action_flags = _get_action_flags, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, .set_session = _set_session, @@ -678,8 +680,6 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .get_info = _get_info, .set_count = _set_count, .get_count = _get_count, - .set_received = _set_received, - .get_received = _get_received, .set_device_id = _set_device_id, .get_device_id = _get_device_id, .set_os_settings = _set_os_settings, diff --git a/src/libimcv/plugins/imv_os/imv_os_state.h b/src/libimcv/plugins/imv_os/imv_os_state.h index 9b3cac50a2..3ff482b32d 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.h +++ b/src/libimcv/plugins/imv_os/imv_os_state.h @@ -39,7 +39,8 @@ enum imv_os_handshake_state_t { IMV_OS_STATE_INIT, IMV_OS_STATE_ATTR_REQ, IMV_OS_STATE_POLICY_START, - IMV_OS_STATE_WORKITEMS + IMV_OS_STATE_WORKITEMS, + IMV_OS_STATE_END }; /** @@ -119,20 +120,6 @@ struct imv_os_state_t { void (*get_count)(imv_os_state_t *this, int *count, int *count_update, int *count_blacklist, int *count_ok); - /** - * Set flags for received attributes - * - * @param flags Flags to be set - */ - void (*set_received)(imv_os_state_t *this, u_int flags); - - /** - * Get flags set for received attributes - * - * @return Flags set for received attributes - */ - u_int (*get_received)(imv_os_state_t *this); - /** * Set device ID * diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_agent.c b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c index 7feb980c1d..ba3bbe33ca 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_agent.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_agent.c @@ -34,6 +34,8 @@ #include #include +#include +#include #include @@ -116,31 +118,6 @@ METHOD(imv_agent_if_t, notify_connection_change, TNC_Result, } } -/** - * Build a message to be sent - */ -static TNC_Result send_message(private_imv_attestation_agent_t *this, - imv_state_t *state, imv_msg_t *out_msg) -{ - imv_attestation_state_t *attestation_state; - TNC_Result result; - - attestation_state = (imv_attestation_state_t*)state; - - if (imv_attestation_build(out_msg, attestation_state, - this->supported_algorithms, - this->supported_dh_groups, this->pts_db)) - { - result = out_msg->send(out_msg, TRUE); - } - else - { - result = TNC_RESULT_FATAL; - } - - return result; -} - /** * Process a received message */ @@ -197,8 +174,7 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, DBG1(DBG_IMV, "received TCG-PTS error '%N'", pts_error_code_names, error_code.type); DBG1(DBG_IMV, "error information: %B", &msg_info); - - result = TNC_RESULT_FATAL; + fatal_error = TRUE; } break; } @@ -224,7 +200,7 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, } else if (type.vendor_id == PEN_TCG) { - if (!imv_attestation_process(attr, out_msg, attestation_state, + if (!imv_attestation_process(attr, out_msg, state, this->supported_algorithms, this->supported_dh_groups, this->pts_db, this->pts_credmgr)) { @@ -235,6 +211,10 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, } enumerator->destroy(enumerator); + /** + * The IETF Product Information and String Version attributes + * are supposed to arrive in the same PA-TNC message + */ if (os_name.len && os_version.len) { pts->set_platform_info(pts, os_name, os_version); @@ -256,64 +236,9 @@ static TNC_Result receive_msg(private_imv_attestation_agent_t *this, /* send PA-TNC message with excl flag set */ result = out_msg->send(out_msg, TRUE); - - if (result != TNC_RESULT_SUCCESS) - { - out_msg->destroy(out_msg); - return result; - } - - /* check the IMV state for the next PA-TNC attributes to send */ - result = send_message(this, state, out_msg); - - if (result != TNC_RESULT_SUCCESS) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, - TNC_IMV_EVALUATION_RESULT_ERROR); - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return this->agent->provide_recommendation(this->agent, state); - } - - if (attestation_state->get_handshake_state(attestation_state) == - IMV_ATTESTATION_STATE_END) - { - if (attestation_state->get_file_meas_request_count(attestation_state)) - { - DBG1(DBG_IMV, "failure due to %d pending file measurements", - attestation_state->get_file_meas_request_count(attestation_state)); - attestation_state->set_measurement_error(attestation_state, - IMV_ATTESTATION_ERROR_FILE_MEAS_PEND); - } - if (attestation_state->get_measurement_error(attestation_state)) - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, - TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR); - } - else - { - state->set_recommendation(state, - TNC_IMV_ACTION_RECOMMENDATION_ALLOW, - TNC_IMV_EVALUATION_RESULT_COMPLIANT); - } - result = out_msg->send_assessment(out_msg); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { - return result; - } - return this->agent->provide_recommendation(this->agent, state); - } out_msg->destroy(out_msg); return result; - } METHOD(imv_agent_if_t, receive_message, TNC_Result, @@ -354,24 +279,224 @@ METHOD(imv_agent_if_t, receive_message_long, TNC_Result, in_msg->destroy(in_msg); return result; - } METHOD(imv_agent_if_t, batch_ending, TNC_Result, private_imv_attestation_agent_t *this, TNC_ConnectionID id) { - return TNC_RESULT_SUCCESS; + imv_msg_t *out_msg; + imv_state_t *state; + imv_session_t *session; + imv_attestation_state_t *attestation_state; + TNC_IMVID imv_id; + TNC_Result result = TNC_RESULT_SUCCESS; + pts_t *pts; + char *platform_info; + + if (!this->agent->get_state(this->agent, id, &state)) + { + return TNC_RESULT_FATAL; + } + attestation_state = (imv_attestation_state_t*)state; + pts = attestation_state->get_pts(attestation_state); + platform_info = pts->get_platform_info(pts); + session = state->get_session(state); + imv_id = this->agent->get_id(this->agent); + + /* create an empty out message - we might need it */ + out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY, + msg_types[0]); + + if (platform_info && session && + (state->get_action_flags(state) & IMV_ATTESTATION_FLAG_ALGO) && + !(state->get_action_flags(state) & IMV_ATTESTATION_FLAG_FILE_MEAS)) + { + imv_workitem_t *workitem; + bool is_dir, no_workitems = TRUE; + u_int32_t delimiter = SOLIDUS_UTF; + u_int16_t request_id; + pa_tnc_attr_t *attr; + char *pathname; + enumerator_t *enumerator; + + enumerator = session->create_workitem_enumerator(session); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY) + { + continue; + } + + switch (workitem->get_type(workitem)) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_FILE_META: + is_dir = FALSE; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + case IMV_WORKITEM_DIR_META: + is_dir = TRUE; + break; + default: + continue; + } + + pathname = this->pts_db->get_pathname(this->pts_db, is_dir, + workitem->get_arg_int(workitem)); + if (!pathname) + { + continue; + } + workitem->set_imv_id(workitem, imv_id); + no_workitems = FALSE; + + if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META) + { + TNC_IMV_Action_Recommendation rec; + TNC_IMV_Evaluation_Result eval; + + DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'", + imv_id, is_dir ? "directory" : "file", pathname); + attr = tcg_pts_attr_req_file_meta_create(is_dir, + delimiter, pathname); + /* currently just fire and forget metadata requests */ + eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; + session->remove_workitem(session, enumerator); + rec = workitem->set_result(workitem, "", eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, workitem); + workitem->destroy(workitem); + } + else + { + /* use lower 16 bits of the workitem ID as request ID */ + request_id = workitem->get_id(workitem) & 0xffff; + + DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'", + imv_id, request_id, is_dir ? "directory" : "file", + pathname); + attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id, + delimiter, pathname); + } + free(pathname); + attr->set_noskip_flag(attr, TRUE); + out_msg->add_attribute(out_msg, attr); + } + enumerator->destroy(enumerator); + + /* sent all file and directory measurement and metadata requests */ + state->set_action_flags(state, IMV_ATTESTATION_FLAG_FILE_MEAS); + + if (no_workitems) + { + DBG2(DBG_IMV, "IMV %d has no workitems - " + "no evaluation requested", imv_id); + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_ALLOW, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + } + } + } + + /* check the IMV state for the next PA-TNC attributes to send */ + if (!imv_attestation_build(out_msg, attestation_state, + this->supported_algorithms, + this->supported_dh_groups, this->pts_db)) + { + state->set_recommendation(state, + TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, + TNC_IMV_EVALUATION_RESULT_ERROR); + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* finalized all workitems? */ + if (session && session->get_workitem_count(session, imv_id) == 0 && + attestation_state->get_handshake_state(attestation_state) == + IMV_ATTESTATION_STATE_END) + { + result = out_msg->send_assessment(out_msg); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + return this->agent->provide_recommendation(this->agent, state); + } + + /* send non-empty PA-TNC message with excl flag not set */ + if (out_msg->get_attribute_count(out_msg)) + { + result = out_msg->send(out_msg, FALSE); + } + out_msg->destroy(out_msg); + + return result; } METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result, private_imv_attestation_agent_t *this, TNC_ConnectionID id) { + TNC_IMVID imv_id; imv_state_t *state; + imv_attestation_state_t *attestation_state; + imv_session_t *session; if (!this->agent->get_state(this->agent, id, &state)) { return TNC_RESULT_FATAL; } + attestation_state = (imv_attestation_state_t*)state; + session = state->get_session(state); + imv_id = this->agent->get_id(this->agent); + + if (session) + { + imv_workitem_t *workitem; + enumerator_t *enumerator; + int pending_file_meas = 0; + + enumerator = session->create_workitem_enumerator(session); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &workitem)) + { + if (workitem->get_imv_id(workitem) != imv_id) + { + continue; + } + switch (workitem->get_type(workitem)) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + pending_file_meas++; + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (pending_file_meas) + { + DBG1(DBG_IMV, "failure due to %d pending file measurements", + pending_file_meas); + attestation_state->set_measurement_error(attestation_state, + IMV_ATTESTATION_ERROR_FILE_MEAS_PEND); + } + } + } return this->agent->provide_recommendation(this->agent, state); } @@ -406,7 +531,6 @@ imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id, "libimcv.plugins.imv-attestation.dh_group", "ecp256"); cadir = lib->settings->get_str(lib->settings, "libimcv.plugins.imv-attestation.cadir", NULL); - libpts_init(); INIT(this, .public = { @@ -427,6 +551,8 @@ imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id, .pts_db = pts_database_create(imcv_db), ); + libpts_init(); + if (!this->agent || !pts_meas_algo_probe(&this->supported_algorithms) || !pts_dh_group_probe(&this->supported_dh_groups) || diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.c b/src/libpts/plugins/imv_attestation/imv_attestation_build.c index b4feec7cd4..3e09f72043 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_build.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.c @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include @@ -49,8 +47,7 @@ bool imv_attestation_build(imv_msg_t *out_msg, if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ && !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D)) { - DBG2(DBG_IMV, "PTS-IMC does not support DH Nonce negotiation - " - "advancing to TPM Initialization"); + DBG2(DBG_IMV, "PTS-IMC does not support DH Nonce negotiation"); handshake_state = IMV_ATTESTATION_STATE_TPM_INIT; } @@ -61,9 +58,8 @@ bool imv_attestation_build(imv_msg_t *out_msg, if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT && !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T)) { - DBG2(DBG_IMV, "PTS-IMC made no TPM available - " - "advancing to File Measurements"); - handshake_state = IMV_ATTESTATION_STATE_MEAS; + DBG2(DBG_IMV, "PTS-IMC made no TPM available"); + handshake_state = IMV_ATTESTATION_STATE_END; } switch (handshake_state) @@ -129,83 +125,9 @@ bool imv_attestation_build(imv_msg_t *out_msg, attr->set_noskip_flag(attr, TRUE); out_msg->add_attribute(out_msg, attr); - attestation_state->set_handshake_state(attestation_state, - IMV_ATTESTATION_STATE_MEAS); - break; - } - case IMV_ATTESTATION_STATE_MEAS: - { - enumerator_t *enumerator; - u_int32_t delimiter = SOLIDUS_UTF; - char *platform_info, *pathname; - u_int16_t request_id; - int id, type; - bool is_dir, have_request = FALSE; - attestation_state->set_handshake_state(attestation_state, IMV_ATTESTATION_STATE_COMP_EVID); - - /* Get Platform and OS of the PTS-IMC */ - platform_info = pts->get_platform_info(pts); - - if (!pts_db || !platform_info) - { - DBG1(DBG_IMV, "%s%s%s not available", - (pts_db) ? "" : "pts database", - (!pts_db && !platform_info) ? "and" : "", - (platform_info) ? "" : "platform info"); - break; - } - DBG1(DBG_IMV, "platform is '%s'", platform_info); - - /* Send Request File Metadata attribute */ - enumerator = pts_db->create_file_meta_enumerator(pts_db, - platform_info); - if (!enumerator) - { - break; - } - while (enumerator->enumerate(enumerator, &type, &pathname)) - { - is_dir = (type != 0); - DBG2(DBG_IMV, "metadata request for %s '%s'", - is_dir ? "directory" : "file", pathname); - attr = tcg_pts_attr_req_file_meta_create(is_dir, delimiter, - pathname); - attr->set_noskip_flag(attr, TRUE); - out_msg->add_attribute(out_msg, attr); - have_request = TRUE; - } - enumerator->destroy(enumerator); - - /* Send Request File Measurement attribute */ - enumerator = pts_db->create_file_meas_enumerator(pts_db, - platform_info); - if (!enumerator) - { - break; - } - while (enumerator->enumerate(enumerator, &id, &type, &pathname)) - { - is_dir = (type != 0); - request_id = attestation_state->add_file_meas_request( - attestation_state, id, is_dir); - DBG2(DBG_IMV, "measurement request %d for %s '%s'", - request_id, is_dir ? "directory" : "file", pathname); - attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id, - delimiter, pathname); - attr->set_noskip_flag(attr, TRUE); - out_msg->add_attribute(out_msg, attr); - have_request = TRUE; - } - enumerator->destroy(enumerator); - - /* do we have any file metadata or measurement requests? */ - if (have_request) - { - break; - } - /* fall through to next state */ + break; } case IMV_ATTESTATION_STATE_COMP_EVID: { @@ -304,6 +226,8 @@ bool imv_attestation_build(imv_msg_t *out_msg, } break; case IMV_ATTESTATION_STATE_END: + attestation_state->set_handshake_state(attestation_state, + IMV_ATTESTATION_STATE_END); break; } return TRUE; diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.c b/src/libpts/plugins/imv_attestation/imv_attestation_process.c index 4541075efd..5c00022571 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_process.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen + * Copyright (C) 2011-2013 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,6 +15,7 @@ #include "imv_attestation_process.h" +#include #include #include @@ -35,15 +36,17 @@ #include bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, - imv_attestation_state_t *attestation_state, + imv_state_t *state, pts_meas_algorithms_t supported_algorithms, pts_dh_group_t supported_dh_groups, pts_database_t *pts_db, credential_manager_t *pts_credmgr) { + imv_attestation_state_t *attestation_state; pen_type_t attr_type; pts_t *pts; + attestation_state = (imv_attestation_state_t*)state; pts = attestation_state->get_pts(attestation_state); attr_type = attr->get_type(attr); @@ -73,6 +76,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, return FALSE; } pts->set_meas_algorithm(pts, selected_algorithm); + state->set_action_flags(state, IMV_ATTESTATION_FLAG_ALGO); break; } case TCG_PTS_DH_NONCE_PARAMS_RESP: @@ -190,28 +194,26 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, } case TCG_PTS_FILE_MEAS: { + TNC_IMV_Evaluation_Result eval; + TNC_IMV_Action_Recommendation rec; tcg_pts_attr_file_meas_t *attr_cast; u_int16_t request_id; - int file_count, file_id; + int arg_int, file_count; pts_meas_algorithms_t algo; pts_file_meas_t *measurements; + imv_session_t *session; + imv_workitem_t *workitem, *found = NULL; + imv_workitem_type_t type; char *platform_info; - enumerator_t *e_hash; bool is_dir; + enumerator_t *enumerator; + eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT; + session = state->get_session(state); + algo = pts->get_meas_algorithm(pts); platform_info = pts->get_platform_info(pts); - if (!pts_db || !platform_info) - { - DBG1(DBG_IMV, "%s%s%s not available", - (pts_db) ? "" : "pts database", - (!pts_db && !platform_info) ? "and" : "", - (platform_info) ? "" : "platform info"); - break; - } - attr_cast = (tcg_pts_attr_file_meas_t*)attr; measurements = attr_cast->get_measurements(attr_cast); - algo = pts->get_meas_algorithm(pts); request_id = measurements->get_request_id(measurements); file_count = measurements->get_file_count(measurements); @@ -220,23 +222,94 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, if (request_id) { - if (!attestation_state->check_off_file_meas_request( - attestation_state, request_id, &file_id, &is_dir)) + enumerator = session->create_workitem_enumerator(session); + while (enumerator->enumerate(enumerator, &workitem)) + { + /* request ID consist of lower 16 bits of workitem ID */ + if ((workitem->get_id(workitem) & 0xffff) == request_id) + { + found = workitem; + break; + } + } + + if (!found) { DBG1(DBG_IMV, " no entry found for file measurement " "request %d", request_id); + enumerator->destroy(enumerator); break; } + type = found->get_type(found); + arg_int = found->get_arg_int(found); + + switch (type) + { + default: + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + is_dir = FALSE; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + is_dir = TRUE; + } - /* check hashes from database against measurements */ - e_hash = pts_db->create_file_hash_enumerator(pts_db, - platform_info, algo, file_id, is_dir); - if (!measurements->verify(measurements, e_hash, is_dir)) + switch (type) { - attestation_state->set_measurement_error(attestation_state, + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_DIR_MEAS: + { + enumerator_t *e; + + /* check hashes from database against measurements */ + e = pts_db->create_file_hash_enumerator(pts_db, + platform_info, algo, is_dir, arg_int); + if (!e) + { + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + break; + } + if (!measurements->verify(measurements, e, is_dir)) + { + attestation_state->set_measurement_error( + attestation_state, IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL); + eval = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR; + } + e->destroy(e); + break; + } + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_DIR_REF_MEAS: + { + enumerator_t *e; + char *filename; + chunk_t measurement; + + e = measurements->create_enumerator(measurements); + while (e->enumerate(e, &filename, &measurement)) + { + if (pts_db->add_file_measurement(pts_db, + platform_info, algo, measurement, filename, + is_dir, arg_int) != SUCCESS) + { + eval = TNC_IMV_EVALUATION_RESULT_ERROR; + } + } + e->destroy(e); + break; + } + default: + break; } - e_hash->destroy(e_hash); + + session->remove_workitem(session, enumerator); + enumerator->destroy(enumerator); + rec = found->set_result(found, "", eval); + state->update_recommendation(state, rec, eval); + imcv_db->finalize_workitem(imcv_db, found); + found->destroy(found); } else { diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.h b/src/libpts/plugins/imv_attestation/imv_attestation_process.h index 74e4644b43..af8666b668 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_process.h +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.h @@ -40,7 +40,7 @@ * * @param attr PA-TNC attribute to be processed * @param out_msg PA-TNC message containing error messages - * @param attestation_state attestation state of a given connection + * @param state state of a given connection * @param supported_algorithms supported PTS measurement algorithms * @param supported_dh_groups supported DH groups * @param pts_db PTS configuration database @@ -48,7 +48,7 @@ * @return TRUE if successful */ bool imv_attestation_process(pa_tnc_attr_t *attr, imv_msg_t *out_msg, - imv_attestation_state_t *attestation_state, + imv_state_t *state, pts_meas_algorithms_t supported_algorithms, pts_dh_group_t supported_dh_groups, pts_database_t *pts_db, diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c index 442ffdd034..27b2655f8c 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c @@ -65,6 +65,11 @@ struct private_imv_attestation_state_t { */ u_int32_t max_msg_len; + /** + * Flags set for completed actions + */ + u_int32_t action_flags; + /** * Access Requestor ID Type */ @@ -95,16 +100,6 @@ struct private_imv_attestation_state_t { */ TNC_IMV_Evaluation_Result eval; - /** - * File Measurement Request counter - */ - u_int16_t file_meas_request_counter; - - /** - * List of PTS File/Directory Measurement requests - */ - linked_list_t *file_meas_requests; - /** * List of Functional Components */ @@ -127,15 +122,6 @@ struct private_imv_attestation_state_t { }; -/** - * PTS File/Directory Measurement request entry - */ -struct file_meas_request_t { - u_int16_t id; - int file_id; - bool is_dir; -}; - /** * PTS Functional Component entry */ @@ -233,6 +219,18 @@ METHOD(imv_state_t, get_max_msg_len, u_int32_t, return this->max_msg_len; } +METHOD(imv_state_t, set_action_flags, void, + private_imv_attestation_state_t *this, u_int32_t flags) +{ + this->action_flags |= flags; +} + +METHOD(imv_state_t, get_action_flags, u_int32_t, + private_imv_attestation_state_t *this) +{ + return this->action_flags; +} + METHOD(imv_state_t, set_ar_id, void, private_imv_attestation_state_t *this, u_int32_t id_type, chunk_t id_value) { @@ -345,7 +343,6 @@ METHOD(imv_state_t, destroy, void, { DESTROY_IF(this->session); DESTROY_IF(this->reason_string); - this->file_meas_requests->destroy_function(this->file_meas_requests, free); this->components->destroy_function(this->components, (void *)free_func_comp); this->pts->destroy(this->pts); free(this->ar_id_value.ptr); @@ -371,51 +368,6 @@ METHOD(imv_attestation_state_t, get_pts, pts_t*, return this->pts; } -METHOD(imv_attestation_state_t, add_file_meas_request, u_int16_t, - private_imv_attestation_state_t *this, int file_id, bool is_dir) -{ - file_meas_request_t *request; - - request = malloc_thing(file_meas_request_t); - request->id = ++this->file_meas_request_counter; - request->file_id = file_id; - request->is_dir = is_dir; - this->file_meas_requests->insert_last(this->file_meas_requests, request); - - return this->file_meas_request_counter; -} - -METHOD(imv_attestation_state_t, check_off_file_meas_request, bool, - private_imv_attestation_state_t *this, u_int16_t id, int *file_id, - bool* is_dir) -{ - enumerator_t *enumerator; - file_meas_request_t *request; - bool found = FALSE; - - enumerator = this->file_meas_requests->create_enumerator(this->file_meas_requests); - while (enumerator->enumerate(enumerator, &request)) - { - if (request->id == id) - { - found = TRUE; - *file_id = request->file_id; - *is_dir = request->is_dir; - this->file_meas_requests->remove_at(this->file_meas_requests, enumerator); - free(request); - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -METHOD(imv_attestation_state_t, get_file_meas_request_count, int, - private_imv_attestation_state_t *this) -{ - return this->file_meas_requests->get_count(this->file_meas_requests); -} - METHOD(imv_attestation_state_t, create_component, pts_component_t*, private_imv_attestation_state_t *this, pts_comp_func_name_t *name, u_int32_t depth, pts_database_t *pts_db) @@ -536,6 +488,8 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .set_flags = _set_flags, .set_max_msg_len = _set_max_msg_len, .get_max_msg_len = _get_max_msg_len, + .set_action_flags = _set_action_flags, + .get_action_flags = _get_action_flags, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, .set_session = _set_session, @@ -551,9 +505,6 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .get_handshake_state = _get_handshake_state, .set_handshake_state = _set_handshake_state, .get_pts = _get_pts, - .add_file_meas_request = _add_file_meas_request, - .check_off_file_meas_request = _check_off_file_meas_request, - .get_file_meas_request_count = _get_file_meas_request_count, .create_component = _create_component, .get_component = _get_component, .finalize_components = _finalize_components, @@ -566,7 +517,6 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .handshake_state = IMV_ATTESTATION_STATE_INIT, .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, - .file_meas_requests = linked_list_create(), .components = linked_list_create(), .pts = pts_create(FALSE), ); diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.h b/src/libpts/plugins/imv_attestation/imv_attestation_state.h index ab77d3042c..f798aa0631 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.h +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.h @@ -31,9 +31,18 @@ #include typedef struct imv_attestation_state_t imv_attestation_state_t; +typedef enum imv_attestation_flag_t imv_attestation_flag_t; typedef enum imv_attestation_handshake_state_t imv_attestation_handshake_state_t; typedef enum imv_meas_error_t imv_meas_error_t; +/** + * IMV Attestation Flags set for completed actions + */ +enum imv_attestation_flag_t { + IMV_ATTESTATION_FLAG_ALGO = (1<<0), + IMV_ATTESTATION_FLAG_FILE_MEAS = (1<<1) +}; + /** * IMV Attestation Handshake States (state machine) */ @@ -41,7 +50,6 @@ enum imv_attestation_handshake_state_t { IMV_ATTESTATION_STATE_INIT, IMV_ATTESTATION_STATE_NONCE_REQ, IMV_ATTESTATION_STATE_TPM_INIT, - IMV_ATTESTATION_STATE_MEAS, IMV_ATTESTATION_STATE_COMP_EVID, IMV_ATTESTATION_STATE_EVID_FINAL, IMV_ATTESTATION_STATE_END, @@ -91,34 +99,6 @@ struct imv_attestation_state_t { */ pts_t* (*get_pts)(imv_attestation_state_t *this); - /** - * Add an entry to the list of pending file/directory measurement requests - * - * @param file_id primary key into file table - * @param is_dir TRUE if directory - * @return unique request ID - */ - u_int16_t (*add_file_meas_request)(imv_attestation_state_t *this, - int file_id, bool is_dir); - - /** - * Returns the number of pending file/directory measurement requests - * - * @return number of pending requests - */ - int (*get_file_meas_request_count)(imv_attestation_state_t *this); - - /** - * Check for presence of request_id and if found remove it from the list - * - * @param id unique request ID - * @param file_id primary key into file table - * @param is_dir return TRUE if request was for a directory - * @return TRUE if request ID found, FALSE otherwise - */ - bool (*check_off_file_meas_request)(imv_attestation_state_t *this, - u_int16_t id, int *file_id, bool *is_dir); - /** * Create and add an entry to the list of Functional Components * diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index 561db8686d..905751b0f6 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -13,6 +13,9 @@ * for more details. */ +#define _GNU_SOURCE +#include + #include "pts_database.h" #include @@ -39,60 +42,69 @@ struct private_pts_database_t { }; -METHOD(pts_database_t, create_file_meas_enumerator, enumerator_t*, - private_pts_database_t *this, char *product) +METHOD(pts_database_t, get_pathname, char*, + private_pts_database_t *this, bool is_dir, int id) { enumerator_t *e; + char *path, *name, *pathname; - /* look for all entries belonging to a product in the files table */ - e = this->db->query(this->db, - "SELECT f.id, f.type, f.path FROM files AS f " - "JOIN product_file AS pf ON f.id = pf.file " - "JOIN products AS p ON p.id = pf.product " - "WHERE p.name = ? AND pf.measurement = 1", - DB_TEXT, product, DB_INT, DB_INT, DB_TEXT); - return e; -} - -METHOD(pts_database_t, create_file_meta_enumerator, enumerator_t*, - private_pts_database_t *this, char *product) -{ - enumerator_t *e; + if (is_dir) + { + e = this->db->query(this->db, + "SELECT path FROM directories WHERE id = ?", + DB_INT, id, DB_TEXT); + if (!e || !e->enumerate(e, &path)) + { + pathname = NULL; + } + else + { + pathname = strdup(path); + } + } + else + { + e = this->db->query(this->db, + "SELECT d.path, f.name FROM files AS f " + "JOIN directories AS d ON d.id = f.dir WHERE f.id = ?", + DB_INT, id, DB_TEXT, DB_TEXT); + if (!e || !e->enumerate(e, &path, &name) || + asprintf(&pathname, "%s%s%s", + path, streq(path, "/") ? "" : "/", name) == -1) + { + pathname = NULL; + } + } + DESTROY_IF(e); - /* look for all entries belonging to a product in the files table */ - e = this->db->query(this->db, - "SELECT f.type, f.path FROM files AS f " - "JOIN product_file AS pf ON f.id = pf.file " - "JOIN products AS p ON p.id = pf.product " - "WHERE p.name = ? AND pf.metadata = 1", - DB_TEXT, product, DB_INT, DB_TEXT); - return e; + return pathname; } METHOD(pts_database_t, create_file_hash_enumerator, enumerator_t*, private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, - int id, bool is_dir) + bool is_dir, int id) { enumerator_t *e; if (is_dir) { 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.directory = ? AND fh.algo = ? " - "ORDER BY f.path", - DB_TEXT, product, DB_INT, id, DB_INT, algo, DB_TEXT, DB_BLOB); + "SELECT f.name, fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "JOIN products AS p ON p.id = fh.product " + "JOIN directories as d ON d.id = f.dir " + "WHERE p.name = ? AND fh.algo = ? AND d.id = ? " + "ORDER BY f.name", + DB_TEXT, product, DB_INT, algo, DB_INT, id, 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); + "SELECT f.name, fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "JOIN products AS p ON p.id = fh.product " + "WHERE p.name = ? AND fh.algo = ? AND fh.file = ?", + DB_TEXT, product, DB_INT, algo, DB_INT, id, DB_TEXT, DB_BLOB); } return e; } @@ -121,6 +133,114 @@ METHOD(pts_database_t, check_aik_keyid, status_t, return SUCCESS; } +METHOD(pts_database_t, add_file_measurement, status_t, + private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, + chunk_t measurement, char *filename, bool is_dir, int id) +{ + enumerator_t *e; + char *name; + chunk_t hash_value; + int hash_id, fid, pid = 0; + status_t status = SUCCESS; + + /* get primary key of product string */ + e = this->db->query(this->db, + "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT); + if (e) + { + e->enumerate(e, &pid); + e->destroy(e); + } + if (pid == 0) + { + return FAILED; + } + + if (is_dir) + { + /* does filename entry already exist? */ + e = this->db->query(this->db, + "SELECT id FROM files WHERE name = ? AND dir = ?", + DB_TEXT, filename, DB_INT, id); + if (!e) + { + return FAILED; + } + if (!e->enumerate(e, &fid)) + { + /* create filename entry */ + if (this->db->execute(this->db, &fid, + "INSERT INTO files (name, dir) VALUES (?, ?)", + DB_TEXT, filename, DB_INT, id) != 1) + { + DBG1(DBG_PTS, "could not insert filename into database"); + status = FAILED; + } + } + e->destroy(e); + } + else + { + fid = id; + + /* verify filename */ + e = this->db->query(this->db, + "SELECT name FROM files WHERE id = ?", DB_INT, fid, DB_TEXT); + if (!e) + { + return FAILED; + } + if (!e->enumerate(e, &name) || !streq(name, filename)) + { + DBG1(DBG_PTS, "filename of reference measurement does not match"); + status = FAILED; + } + e->destroy(e); + } + + if (status != SUCCESS) + { + return status; + } + + /* does hash measurement value already exist? */ + e = this->db->query(this->db, + "SELECT fh.id, fh.hash FROM file_hashes AS fh " + "WHERE fh.product = ? AND fh.algo = ? AND fh.file = ?", + DB_INT, pid, DB_INT, algo, DB_INT, fid, DB_INT, DB_BLOB); + if (!e) + { + return FAILED; + } + if (e->enumerate(e, &hash_id, &hash_value)) + { + if (!chunk_equals(measurement, hash_value)) + { + /* update hash measurement value */ + if (this->db->execute(this->db, &hash_id, + "UPDATE file_hashes SET hash = ? WHERE id = ?", + DB_BLOB, measurement, DB_INT, hash_id) != 1) + { + status = FAILED; + } + } + } + else + { + /* insert hash measurement value */ + if (this->db->execute(this->db, &hash_id, + "INSERT INTO file_hashes (file, product, algo, hash) " + "VALUES (?, ?, ?, ?)", DB_INT, fid, DB_INT, pid, + DB_INT, algo, DB_BLOB, measurement) != 1) + { + status = FAILED; + } + } + e->destroy(e); + + return status; +} + METHOD(pts_database_t, check_file_measurement, status_t, private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, chunk_t measurement, char *filename) @@ -325,11 +445,11 @@ pts_database_t *pts_database_create(imv_database_t *imv_db) INIT(this, .public = { - .create_file_meas_enumerator = _create_file_meas_enumerator, - .create_file_meta_enumerator = _create_file_meta_enumerator, + .get_pathname = _get_pathname, .create_comp_evid_enumerator = _create_comp_evid_enumerator, .create_file_hash_enumerator = _create_file_hash_enumerator, .check_aik_keyid = _check_aik_keyid, + .add_file_measurement = _add_file_measurement, .check_file_measurement = _check_file_measurement, .check_comp_measurement = _check_comp_measurement, .insert_comp_measurement = _insert_comp_measurement, diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index 630342129c..eb8aca3469 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -36,35 +36,26 @@ typedef struct pts_database_t pts_database_t; struct pts_database_t { /** - * Get files/directories to be measured by PTS + * Get absolute pathname for file or directory measurement * - * @param product Software product (os, vpn client, etc.) - * @return Enumerator over all matching files/directories + * @param is_dir TRUE if dir, FALSE if file + * @param id Primary key into directories or files table + * @return Absolute pathname as a text string */ - enumerator_t* (*create_file_meas_enumerator)(pts_database_t *this, - char *product); - - /** - * Get files/directories to request metadata of - * - * @param product Software product (os, vpn client, etc.) - * @return Enumerator over all matching files/directories - */ - enumerator_t* (*create_file_meta_enumerator)(pts_database_t *this, - char *product); + char* (*get_pathname)(pts_database_t *this, bool is_dir, int id); /** * Get stored measurement hash for single file or directory entries * * @param product Software product (os, vpn client, etc.) * @param algo Hash algorithm used for measurement - * @param id Primary key of measured file/directory * @param is_dir TRUE if directory was measured + * @param id Primary key of measured file/directory * @return Enumerator over all matching measurement hashes */ enumerator_t* (*create_file_hash_enumerator)(pts_database_t *this, char *product, pts_meas_algorithms_t algo, - int id, bool is_dir); + bool is_dir, int id); /** * Check if an AIK given by its keyid is registered in the database @@ -83,6 +74,22 @@ struct pts_database_t { */ enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid); + /** + * Add PTS file measurement reference value + * + * @param product Software product (os, vpn client, etc.) + * @param algo File measurement hash algorithm used + * @param measurement File measurement hash + * @param filename Optional name of the file to be checked + * @param is_dir TRUE if part of directory measurement + * @param id Primary key into direcories/files table + * @return Status + */ + status_t (*add_file_measurement)(pts_database_t *this, char *product, + pts_meas_algorithms_t algo, + chunk_t measurement, char *filename, + bool is_dir, int id); + /** * Check PTS file measurement against reference stored in database *