Implemented SWID REST API
authorAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 23 May 2014 13:21:38 +0000 (15:21 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 31 May 2014 18:37:55 +0000 (20:37 +0200)
src/libpts/plugins/imv_swid/Makefile.am
src/libpts/plugins/imv_swid/imv_swid_agent.c
src/libpts/plugins/imv_swid/imv_swid_rest.c [new file with mode: 0644]
src/libpts/plugins/imv_swid/imv_swid_rest.h [new file with mode: 0644]
src/libpts/plugins/imv_swid/imv_swid_state.c
src/libpts/plugins/imv_swid/imv_swid_state.h

index 29c05e0..fc4350f 100644 (file)
@@ -12,10 +12,12 @@ imcv_LTLIBRARIES = imv-swid.la
 imv_swid_la_LIBADD = \
        $(top_builddir)/src/libimcv/libimcv.la \
        $(top_builddir)/src/libpts/libpts.la \
-       $(top_builddir)/src/libstrongswan/libstrongswan.la
+       $(top_builddir)/src/libstrongswan/libstrongswan.la \
+       -ljson
 
 imv_swid_la_SOURCES = \
        imv_swid.c imv_swid_state.h imv_swid_state.c \
-       imv_swid_agent.h imv_swid_agent.c
+       imv_swid_agent.h imv_swid_agent.c \
+       imv_swid_rest.h imv_swid_rest.c
 
 imv_swid_la_LDFLAGS = -module -avoid-version -no-undefined
index fdf1dcf..f5a343a 100644 (file)
  * for more details.
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
+
 #include "imv_swid_agent.h"
 #include "imv_swid_state.h"
+#include "imv_swid_rest.h"
 
 #include "libpts.h"
 #include "swid/swid_error.h"
@@ -67,6 +71,11 @@ struct private_imv_swid_agent_t {
         */
        imv_agent_t *agent;
 
+       /**
+        * REST API to strongTNC manager
+        */
+       imv_swid_rest_t *rest_api;
+
 };
 
 METHOD(imv_agent_if_t, bind_functions, TNC_Result,
@@ -101,7 +110,6 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
 {
        imv_swid_state_t *swid_state;
        imv_msg_t *out_msg;
-       imv_session_t *session;
        enumerator_t *enumerator;
        pa_tnc_attr_t *attr;
        TNC_Result result;
@@ -115,20 +123,15 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
        }
 
        swid_state = (imv_swid_state_t*)state;
-       session = state->get_session(state);
 
        /* analyze PA-TNC attributes */
        enumerator = in_msg->create_attribute_enumerator(in_msg);
        while (enumerator->enumerate(enumerator, &attr))
        {
-               pen_type_t type;
-               uint32_t request_id, last_eid, eid_epoch;
+               uint32_t request_id = 0, last_eid, eid_epoch;
                swid_inventory_t *inventory;
-               int tag_count;
-               char *tag_item;
-               imv_workitem_t *workitem, *found = NULL;
-               enumerator_t *et, *ew;
-               
+               pen_type_t type;
+
                type = attr->get_type(attr);
 
                if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
@@ -137,7 +140,7 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
                        pen_type_t error_code;
                        chunk_t msg_info, description;
                        bio_reader_t *reader;
-                       uint32_t request_id = 0, max_attr_size;
+                       uint32_t max_attr_size;
                        bool success;
 
                        error_attr = (ietf_attr_pa_tnc_error_t*)attr;
@@ -200,8 +203,7 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
                        case TCG_SWID_TAG_ID_INVENTORY:
                        {
                                tcg_swid_attr_tag_id_inv_t *attr_cast;
-                               swid_tag_id_t *tag_id;
-                               chunk_t tag_creator, unique_sw_id;
+                               int tag_id_count;
 
                                state->set_action_flags(state, IMV_SWID_ATTR_TAG_ID_INV);
 
@@ -209,26 +211,21 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
                                request_id = attr_cast->get_request_id(attr_cast);
                                last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
                                inventory = attr_cast->get_inventory(attr_cast);
-                               tag_item = "tag ID";
-                               DBG2(DBG_IMV, "received SWID %s inventory for request %d "
-                                                         "at eid %d of epoch 0x%08x", tag_item,
-                                                          request_id, last_eid, eid_epoch);
+                               tag_id_count = inventory->get_count(inventory);
+
+                               DBG2(DBG_IMV, "received SWID tag ID inventory with %d items "
+                                                         "for request %d at eid %d of epoch 0x%08x",
+                                                          tag_id_count, request_id, last_eid, eid_epoch);
 
-                               et = inventory->create_enumerator(inventory);
-                               while (et->enumerate(et, &tag_id))
+                               if (request_id == swid_state->get_request_id(swid_state))
                                {
-                                       tag_creator = tag_id->get_tag_creator(tag_id);
-                                       unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
-                                       DBG3(DBG_IMV, "  %.*s_%.*s",
-                                                tag_creator.len, tag_creator.ptr,
-                                                unique_sw_id.len, unique_sw_id.ptr);
+                                       swid_state->set_swid_inventory(swid_state, inventory);
+                                       swid_state->set_count(swid_state, tag_id_count, 0);
                                }
-                               et->destroy(et);
-
-                               if (request_id == 0)
+                               else
                                {
-                                       /* TODO handle subscribed messages */
-                                       break;
+                                       DBG1(DBG_IMV, "no workitem found for SWID tag ID inventory "
+                                                                 "with request ID %d", request_id);
                                }
                                break;
                         }
@@ -237,6 +234,10 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
                                tcg_swid_attr_tag_inv_t *attr_cast;
                                swid_tag_t *tag;
                                chunk_t tag_encoding;
+                               json_object *jarray, *jstring;
+                               char *tag_str;
+                               int tag_count;
+                               enumerator_t *e;
 
                                state->set_action_flags(state, IMV_SWID_ATTR_TAG_INV);
 
@@ -244,51 +245,50 @@ static TNC_Result receive_msg(private_imv_swid_agent_t *this,
                                request_id = attr_cast->get_request_id(attr_cast);
                                last_eid = attr_cast->get_last_eid(attr_cast, &eid_epoch);
                                inventory = attr_cast->get_inventory(attr_cast);
-                               tag_item = "tag";
-                               DBG2(DBG_IMV, "received SWID %s inventory for request %d "
-                                                         "at eid %d of epoch 0x%08x", tag_item,
-                                                          request_id, last_eid, eid_epoch);
+                               tag_count = inventory->get_count(inventory);
+
+                               DBG2(DBG_IMV, "received SWID tag inventory with %d items for "
+                                                         "request %d at eid %d of epoch 0x%08x",
+                                                          tag_count, request_id, last_eid, eid_epoch);
 
-                               et = inventory->create_enumerator(inventory);
-                               while (et->enumerate(et, &tag))
+
+                               if (request_id == swid_state->get_request_id(swid_state))
                                {
-                                       tag_encoding = tag->get_encoding(tag);
-                                       DBG3(DBG_IMV, "%.*s", tag_encoding.len, tag_encoding.ptr);
-                               }
-                               et->destroy(et);
+                                       swid_state->set_count(swid_state, 0, tag_count);
 
-                               if (request_id == 0)
+                                       if (this->rest_api)
+                                       {
+                                               jarray = json_object_new_array();
+
+                                               e = inventory->create_enumerator(inventory);
+                                               while (e->enumerate(e, &tag))
+                                               {
+                                                       tag_encoding = tag->get_encoding(tag);
+                                                       tag_str = strndup(tag_encoding.ptr, tag_encoding.len);
+                                                       DBG3(DBG_IMV, "%s", tag_str);
+                                                       jstring = json_object_new_string(tag_str);
+                                                       json_object_array_add(jarray, jstring);
+                                                       free(tag_str);
+                                               }
+                                               e->destroy(e);
+
+                                               if (this->rest_api->post(this->rest_api,
+                                                               "swid/add-tags/", jarray, NULL) != SUCCESS)
+                                               {
+                                                       DBG1(DBG_IMV, "error in REST API add-tags request");
+                                               }
+                                               json_object_put(jarray);
+                                       }
+                               }
+                               else
                                {
-                                       /* TODO handle subscribed messages */
-                                       break;
+                                       DBG1(DBG_IMV, "no workitem found for SWID tag inventory "
+                                                                 "with request ID %d", request_id);
                                }
-                               break;
                        }
                        default:
                                continue;
                 }
-
-               ew = session->create_workitem_enumerator(session);
-               while (ew->enumerate(ew, &workitem))
-               {
-                       if (workitem->get_id(workitem) == request_id)
-                       {
-                               found = workitem;
-                               break;
-                       }
-               }
-               if (found)
-               {
-                       /* accumulate the swid tag [ID] count */
-                       tag_count = inventory->get_count(inventory);
-                       swid_state->set_count(swid_state, tag_count);
-               }
-               else
-               {
-                       DBG1(DBG_IMV, "no workitem found for SWID %s inventory "
-                                                 "with request ID %d", tag_item, request_id);
-               }
-               ew->destroy(ew);
        }
        enumerator->destroy(enumerator);
 
@@ -382,7 +382,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                return TNC_RESULT_SUCCESS;
        }
 
-       /* create an empty out message - we might need it */
+       /* 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]);
 
@@ -403,6 +403,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                return this->agent->provide_recommendation(this->agent, state);
        }
 
+       /* Look for SWID tag workitem and create SWID tag request */
        if (handshake_state == IMV_SWID_STATE_INIT &&
                session->get_policy_started(session))
        {
@@ -431,13 +432,14 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                                        flags |= TCG_SWID_ATTR_REQ_FLAG_C;
                                }
                                request_id = workitem->get_id(workitem);
-
+                               swid_state->set_request_id(swid_state, request_id);
                                attr = tcg_swid_attr_req_create(flags, request_id, 0);
                                out_msg->add_attribute(out_msg, attr);
                                workitem->set_imv_id(workitem, imv_id);
                                no_workitems = FALSE;
                                DBG2(DBG_IMV, "IMV %d issues SWID request %d",
                                                 imv_id, request_id);
+                               break;
                        }
                        enumerator->destroy(enumerator);
 
@@ -462,30 +464,140 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
        {
                TNC_IMV_Evaluation_Result eval;
                TNC_IMV_Action_Recommendation rec;
-               char result_str[BUF_LEN], *tag_item;
-               int tag_count;
-
-               enumerator = session->create_workitem_enumerator(session);
-               while (enumerator->enumerate(enumerator, &workitem))
+               char result_str[BUF_LEN], *error_str = "", *command;
+               char *target, *separator;
+               int tag_id_count, tag_count, i;
+               chunk_t tag_creator, unique_sw_id;
+               json_object *jrequest, *jresponse, *jvalue;
+               tcg_swid_attr_req_t *cast_attr;
+               swid_tag_id_t *tag_id;
+               status_t status = SUCCESS;
+
+               if (this->rest_api)
                {
-                       if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
+                       if (asprintf(&command, "sessions/%d/swid_measurement/",
+                                                session->get_session_id(session, NULL, NULL)) < 0)
                        {
-                               swid_state->get_count(swid_state, &tag_count);
-                               tag_item = (received & IMV_SWID_ATTR_TAG_INV) ? "" : " ID";
-                               snprintf(result_str, BUF_LEN, "received inventory of %d "
-                                               "SWID tag%s%s", tag_count, tag_item,
-                                               (tag_count == 1) ? "" : "s");
-                               session->remove_workitem(session, enumerator);
-
-                               eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
-                               rec = workitem->set_result(workitem, result_str, eval);
-                               state->update_recommendation(state, rec, eval);
-                               imcv_db->finalize_workitem(imcv_db, workitem);
-                               workitem->destroy(workitem);
+                               error_str = "allocation of command string failed";
+                               status = FAILED;
+                       }
+                       else
+                       {
+                               jrequest = swid_state->get_swid_inventory(swid_state);
+                               status = this->rest_api->post(this->rest_api, command,
+                                                                                         jrequest, &jresponse);
+                               if (status == FAILED)
+                               {
+                                       error_str = "error in REST API swid_measurement request";
+                               }
+                               free(command);
+                       }
+               }
+
+               switch (status)
+               {
+                       case SUCCESS:
+                               enumerator = session->create_workitem_enumerator(session);
+                               while (enumerator->enumerate(enumerator, &workitem))
+                               {
+                                       if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
+                                       {
+                                               swid_state->get_count(swid_state, &tag_id_count,
+                                                                                                                 &tag_count);
+                                               snprintf(result_str, BUF_LEN, "received inventory of "
+                                                                "%d SWID tag ID%s and %d SWID tag%s",
+                                                                tag_id_count, (tag_id_count == 1) ? "" : "s",
+                                                                tag_count, (tag_count == 1) ? "" : "s");
+                                               session->remove_workitem(session, enumerator);
+
+                                               eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
+                                               rec = workitem->set_result(workitem, result_str, eval);
+                                               state->update_recommendation(state, rec, eval);
+                                               imcv_db->finalize_workitem(imcv_db, workitem);
+                                               workitem->destroy(workitem);
+                                               break;
+                                       }
+                               }
+                               enumerator->destroy(enumerator);
+                               break;
+                       case NEED_MORE:
+                               if (received & IMV_SWID_ATTR_TAG_INV)
+                               {
+                                       error_str = "not all requested SWID tags were received";
+                                       status = FAILED;
+                                       json_object_put(jresponse);
+                                       break;
+                               }
+                               if (json_object_get_type(jresponse) != json_type_array)
+                               {
+                                       error_str = "response was not a json_array";
+                                       status = FAILED;
+                                       json_object_put(jresponse);
+                                       break;
+                               }
+                               attr = tcg_swid_attr_req_create(TCG_SWID_ATTR_REQ_FLAG_NONE,
+                                                               swid_state->get_request_id(swid_state), 0);
+                               cast_attr = (tcg_swid_attr_req_t*)attr;
+
+                               tag_id_count = json_object_array_length(jresponse);
+                               DBG1(DBG_IMV, "%d SWID tag targets", tag_id_count);
+
+                               for (i = 0; i < tag_id_count; i++)
+                               {
+                                       jvalue = json_object_array_get_idx(jresponse, i);
+                                       if (json_object_get_type(jvalue) != json_type_string)
+                                       {
+                                               error_str = "json_string element expected in json_array";
+                                               status = FAILED;
+                                               json_object_put(jresponse);
+                                               break;
+                                       }
+                                       target = json_object_get_string(jvalue);
+                                       DBG1(DBG_IMV, "  %s", target);
+
+                                       /* Separate target into tag_creator and unique_sw_id */
+                                       separator = strchr(target, '_');
+                                       if (!separator)
+                                       {
+                                               error_str = "separation of regid from "
+                                                                       "unique software ID failed";
+                                               break;
+                                       }
+                                       tag_creator = chunk_create(target, separator - target);
+                                       separator++;
+                                       unique_sw_id = chunk_create(separator, strlen(target) -
+                                                                                               tag_creator.len - 1);
+                                       tag_id = swid_tag_id_create(tag_creator, unique_sw_id,
+                                                                                               chunk_empty);
+                                       cast_attr->add_target(cast_attr, tag_id);
+                               }
+                               json_object_put(jresponse);
+
+                               out_msg->add_attribute(out_msg, attr);
+                               break;
+                       case FAILED:
+                       default:
                                break;
+               }
+
+               if (status == FAILED)
+               {
+                       enumerator = session->create_workitem_enumerator(session);
+                       while (enumerator->enumerate(enumerator, &workitem))
+                       {
+                               if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
+                               {
+                                       session->remove_workitem(session, enumerator);
+                                       eval = TNC_IMV_EVALUATION_RESULT_ERROR;
+                                       rec = workitem->set_result(workitem, error_str, eval);
+                                       state->update_recommendation(state, rec, eval);
+                                       imcv_db->finalize_workitem(imcv_db, workitem);
+                                       workitem->destroy(workitem);
+                                       break;
+                               }
                        }
+                       enumerator->destroy(enumerator);
                }
-               enumerator->destroy(enumerator);
        }
 
        /* finalized all workitems ? */
@@ -528,6 +640,7 @@ METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
 METHOD(imv_agent_if_t, destroy, void,
        private_imv_swid_agent_t *this)
 {
+       DESTROY_IF(this->rest_api);
        this->agent->destroy(this->agent);
        free(this);
        libpts_deinit();
@@ -541,6 +654,7 @@ imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id,
 {
        private_imv_swid_agent_t *this;
        imv_agent_t *agent;
+       char *rest_api_uri;
 
        agent = imv_agent_create(name, msg_types, countof(msg_types), id,
                                                         actual_version);
@@ -562,6 +676,12 @@ imv_agent_if_t *imv_swid_agent_create(const char *name, TNC_IMVID id,
                .agent = agent,
        );
 
+       rest_api_uri = lib->settings->get_str(lib->settings,
+                                               "%s.plugins.imv-swid.rest_api_uri", NULL, lib->ns);
+       if (rest_api_uri)
+       {
+               this->rest_api = imv_swid_rest_create(rest_api_uri);
+       }
        libpts_init();
 
        return &this->public;
diff --git a/src/libpts/plugins/imv_swid/imv_swid_rest.c b/src/libpts/plugins/imv_swid/imv_swid_rest.c
new file mode 100644 (file)
index 0000000..3ad93a3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+
+#include "imv_swid_rest.h"
+
+typedef struct private_imv_swid_rest_t private_imv_swid_rest_t;
+
+/**
+ * Private data of an imv_swid_rest_t object.
+ */
+struct private_imv_swid_rest_t {
+
+       /**
+        * Public members of imv_swid_rest_t
+        */
+       imv_swid_rest_t public;
+
+       /**
+        * URI of REST API
+        */
+       char *uri;
+
+};
+
+#define HTTP_STATUS_CODE_PRECONDITION_FAILED   412
+
+METHOD(imv_swid_rest_t, post, status_t,
+       private_imv_swid_rest_t *this, char *command, json_object *jrequest,
+       json_object **jresponse)
+{
+       struct json_tokener *tokener;
+       chunk_t data, response = chunk_empty;
+       u_int timeout = 30;
+       status_t status;
+       char *uri;
+       int code;
+
+       if (asprintf(&uri, "%s%s",this->uri, command) < 0)
+       {
+               return FAILED;
+       }
+       data = chunk_from_str(json_object_to_json_string(jrequest));
+
+       status = lib->fetcher->fetch(lib->fetcher, uri, &response,
+                               FETCH_TIMEOUT, timeout,
+                               FETCH_REQUEST_DATA, data,
+                               FETCH_REQUEST_TYPE, "application/json; charset=utf-8",
+                               FETCH_REQUEST_HEADER, "Accept: application/json",
+                               FETCH_REQUEST_HEADER, "Expect:",
+                               FETCH_RESPONSE_CODE, &code,
+                               FETCH_END);
+       free(uri);
+
+       if (status == SUCCESS)
+       {
+               return  SUCCESS;
+       }
+       if (code != HTTP_STATUS_CODE_PRECONDITION_FAILED || !response.ptr)
+       {
+               return FAILED;
+       }
+
+       if (jresponse)
+       {
+               /* Parse HTTP response into a JSON object */
+               tokener = json_tokener_new();
+               *jresponse = json_tokener_parse_ex(tokener, response.ptr, response.len);
+               json_tokener_free(tokener);
+       }
+       free(response.ptr);
+
+       return NEED_MORE;
+}
+
+METHOD(imv_swid_rest_t, destroy, void,
+       private_imv_swid_rest_t *this)
+{
+       free(this->uri);
+       free(this);
+}
+
+/**
+ * Described in header.
+ */
+imv_swid_rest_t *imv_swid_rest_create(char *uri)
+{
+       private_imv_swid_rest_t *this;
+
+       INIT(this,
+               .public = {
+                       .post = _post,
+                       .destroy = _destroy,
+               },
+               .uri = strdup(uri),
+       );
+
+       return &this->public;
+}
+
+
diff --git a/src/libpts/plugins/imv_swid/imv_swid_rest.h b/src/libpts/plugins/imv_swid/imv_swid_rest.h
new file mode 100644 (file)
index 0000000..b68f72f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013-2014 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup imv_swid imv_swid
+ * @ingroup libimcv_plugins
+ *
+ * @defgroup imv_swid_rest_t imv_swid_rest
+ * @{ @ingroup imv_swid
+ */
+
+#ifndef IMV_SWID_REST_H_
+#define IMV_SWID_REST_H_
+
+#include <library.h>
+
+#include <json/json.h>
+
+typedef struct imv_swid_rest_t imv_swid_rest_t;
+
+/**
+ * Public REST interface
+ */
+struct imv_swid_rest_t {
+
+       /**
+        * Post a HTTP request including a JSON object
+        *
+        * @param jreq          JSON object in HTTP request
+        * @param jresp         JSON object in HTTP response if NEED_MORE
+        * @return                      Status (SUCCESS, NEED_MORE or FAILED)
+        */
+       status_t (*post)(imv_swid_rest_t *this, char *command, json_object *jreq,
+                                        json_object **jresp);
+
+       /**
+        * Destroy imv_swid_rest_t object
+        */
+       void (*destroy)(imv_swid_rest_t *this);
+
+};
+
+/**
+ * Create an imv_swid_rest_t instance
+ *
+ * @param uri                  REST URI (http://username:password@hostname[:port]/api/)
+ */
+imv_swid_rest_t* imv_swid_rest_create(char *uri);
+
+#endif /** IMV_SWID_REST_H_ @}*/
index 3afeaed..fa8a79c 100644 (file)
  */
 
 #include "imv_swid_state.h"
-#include "imv/imv_lang_string.h"
-#include "imv/imv_reason_string.h"
-#include "imv/imv_remediation_string.h"
+
+#include <imv/imv_lang_string.h>
+#include <imv/imv_reason_string.h>
+#include <imv/imv_remediation_string.h>
+#include <swid/swid_tag_id.h>
 
 #include <tncif_policy.h>
 
@@ -96,9 +98,24 @@ struct private_imv_swid_state_t {
        imv_remediation_string_t *remediation_string;
 
        /**
-        * Number of processed SWID Tags or SWID Tag IDs
+        * SWID Tag Request ID
+        */
+       uint32_t request_id;
+
+       /**
+        * Number of processed SWID Tag IDs
+        */
+       int tag_id_count;
+
+       /**
+        * Number of processed SWID Tags
         */
-       int count;
+       int tag_count;
+
+       /**
+        * JSON array containing an inventory of SWID Tag IDs
+        */
+       json_object *jarray;
 
        /**
         * Angel count
@@ -215,6 +232,7 @@ METHOD(imv_state_t, get_remediation_instructions, bool,
 METHOD(imv_state_t, destroy, void,
        private_imv_swid_state_t *this)
 {
+       json_object_put(this->jarray);
        DESTROY_IF(this->session);
        DESTROY_IF(this->reason_string);
        DESTROY_IF(this->remediation_string);
@@ -233,18 +251,68 @@ METHOD(imv_swid_state_t, get_handshake_state, imv_swid_handshake_state_t,
        return this->handshake_state;
 }
 
+METHOD(imv_swid_state_t, set_request_id, void,
+       private_imv_swid_state_t *this, uint32_t request_id)
+{
+       this->request_id = request_id;
+}
+
+METHOD(imv_swid_state_t, get_request_id, uint32_t,
+       private_imv_swid_state_t *this)
+{
+       return this->request_id;
+}
+
+METHOD(imv_swid_state_t, set_swid_inventory, void,
+    private_imv_swid_state_t *this, swid_inventory_t *inventory)
+{
+       chunk_t tag_creator, unique_sw_id;
+       char software_id[256];
+       json_object *jstring;
+       swid_tag_id_t *tag_id;
+       enumerator_t *enumerator;
+
+       enumerator = inventory->create_enumerator(inventory);
+       while (enumerator->enumerate(enumerator, &tag_id))
+       {
+               /* Construct software ID from tag creator and unique software ID */
+               tag_creator = tag_id->get_tag_creator(tag_id);
+               unique_sw_id = tag_id->get_unique_sw_id(tag_id, NULL);
+               snprintf(software_id, 256, "%.*s_%.*s",
+                                tag_creator.len, tag_creator.ptr,
+                                unique_sw_id.len, unique_sw_id.ptr);
+               DBG3(DBG_IMV, "  %s", software_id);
+
+               /* Add software ID to JSON array */
+               jstring = json_object_new_string(software_id);
+               json_object_array_add(this->jarray, jstring);
+       }
+       enumerator->destroy(enumerator);
+}
+
+METHOD(imv_swid_state_t, get_swid_inventory, json_object*,
+       private_imv_swid_state_t *this)
+{
+       return this->jarray;
+}
+
 METHOD(imv_swid_state_t, set_count, void,
-       private_imv_swid_state_t *this, int count)
+       private_imv_swid_state_t *this, int tag_id_count, int tag_count)
 {
-       this->count           += count;
+       this->tag_id_count += tag_id_count;
+       this->tag_count += tag_count;
 }
 
 METHOD(imv_swid_state_t, get_count, void,
-       private_imv_swid_state_t *this, int *count)
+       private_imv_swid_state_t *this, int *tag_id_count, int *tag_count)
 {
-       if (count)
+       if (tag_id_count)
+       {
+               *tag_id_count = this->tag_id_count;
+       }
+       if (tag_count)
        {
-               *count = this->count;
+               *tag_count = this->tag_count;
        }
 }
 
@@ -290,6 +358,10 @@ imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id)
                        },
                        .set_handshake_state = _set_handshake_state,
                        .get_handshake_state = _get_handshake_state,
+                       .set_request_id = _set_request_id,
+                       .get_request_id = _get_request_id,
+                       .set_swid_inventory = _set_swid_inventory,
+                       .get_swid_inventory = _get_swid_inventory,
                        .set_count = _set_count,
                        .get_count = _get_count,
                        .set_angel_count = _set_angel_count,
@@ -299,6 +371,7 @@ imv_state_t *imv_swid_state_create(TNC_ConnectionID connection_id)
                .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
                .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
                .connection_id = connection_id,
+               .jarray = json_object_new_array(),
        );
 
        return &this->public.interface;
index 8e7cd61..7ffabfd 100644 (file)
 #define IMV_SWID_STATE_H_
 
 #include <imv/imv_state.h>
+#include <swid/swid_inventory.h>
 #include <library.h>
 
+#include <json/json.h>
+
 typedef struct imv_swid_state_t imv_swid_state_t;
 typedef enum imv_swid_handshake_state_t imv_swid_handshake_state_t;
 
@@ -65,30 +68,60 @@ struct imv_swid_state_t {
        imv_swid_handshake_state_t (*get_handshake_state)(imv_swid_state_t *this);
 
        /**
+        * Set the SWID request ID
+        *
+        * @param request_id            SWID request ID to be set
+        */
+       void (*set_request_id)(imv_swid_state_t *this, uint32_t request_id);
+
+       /**
+        * Get the SWID request ID
+        *
+        * @return                                      SWID request ID
+        */
+       uint32_t (*get_request_id)(imv_swid_state_t *this);
+
+    /**
+     * Set or extend the SWID Tag ID inventory in the state
+     *
+     * @param inventory                        SWID Tags ID inventory to be added
+     */
+    void (*set_swid_inventory)(imv_swid_state_t *this, swid_inventory_t *inventory);
+
+   /**
+     * Get the encoding of the complete SWID Tag ID inventory
+     *
+     * @return                        SWID Tags ID inventory as a JSON array
+     */
+    json_object* (*get_swid_inventory)(imv_swid_state_t *this);
+
+       /**
         * Set [or with multiple attributes increment] SWID Tag [ID] counters
         *
-        * @param count                         Number of received SWID Tags or SWID Tag IDs
+        * @param tag_id_count          Number of received SWID Tag IDs
+        * @param tag_count                     Number of received SWID Tags
         */
-       void (*set_count)(imv_swid_state_t *this, int count);
+       void (*set_count)(imv_swid_state_t *this, int tag_id_count, int tag_count);
 
        /**
         * Set [or with multiple attributes increment] SWID Tag [ID] counters
         *
-        * @param count                         Number of received SWID Tags or SWID Tag IDs
+        * @param tag_id_count          Number of received SWID Tag IDs
+        * @param tag_count                     Number of received SWID Tags
         */
-       void (*get_count)(imv_swid_state_t *this, int *count);
+       void (*get_count)(imv_swid_state_t *this, int *tag_id_count, int *tag_count);
 
        /**
         * Increase/Decrease the ITA Angel count
         *
-        * @param start                 TRUE increases and FALSE decreases count by one
+        * @param start                         TRUE increases and FALSE decreases count by one
         */
        void (*set_angel_count)(imv_swid_state_t *this, bool start);
 
        /**
         * Get the ITA Angel count
         *
-        * @return                              ITA Angel count
+        * @return                                      ITA Angel count
         */
        int (*get_angel_count)(imv_swid_state_t *this);