Implemented add_segment method for PA-TNC attributes
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 1 Oct 2014 21:11:30 +0000 (23:11 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 5 Oct 2014 10:55:38 +0000 (12:55 +0200)
src/libimcv/pa_tnc/pa_tnc_attr.h
src/libimcv/pa_tnc/pa_tnc_attr_manager.c
src/libimcv/pa_tnc/pa_tnc_attr_manager.h
src/libimcv/pa_tnc/pa_tnc_msg.c
src/libimcv/pa_tnc/pa_tnc_msg.h
src/libimcv/seg/seg_contract.c
src/libimcv/seg/seg_env.c
src/libimcv/seg/seg_env.h
src/libimcv/tcg/swid/tcg_swid_attr_req.c
src/libimcv/tcg/swid/tcg_swid_attr_tag_id_inv.c
src/libimcv/tcg/swid/tcg_swid_attr_tag_inv.c

index a529669..be0bef3 100644 (file)
@@ -26,6 +26,7 @@ typedef struct pa_tnc_attr_t pa_tnc_attr_t;
 #include <library.h>
 #include <pen/pen.h>
 
+#define PA_TNC_ATTR_INFO_SIZE           8
 #define PA_TNC_ATTR_HEADER_SIZE                12
 
 #define PA_TNC_ATTR_FLAG_NONE          0x00
@@ -73,12 +74,19 @@ struct pa_tnc_attr_t {
        /**
         * Process the value of an PA-TNC attribute to extract its parameters
         *
-        * @param                                       relative error offset within attribute body
+        * @param offset                        relative error offset within attribute body
         * @return                                      result status
         */
        status_t (*process)(pa_tnc_attr_t *this, uint32_t *offset);
 
        /**
+        * Add a data segment to an attribute allowing incremental processing
+        *
+        * @param segment                       data segment to be appended
+        */
+       void (*add_segment)(pa_tnc_attr_t *this, chunk_t segment);
+
+       /**
         * Get a new reference to the PA-TNC attribute
         *
         * @return                      this, with an increased refcount
index 71f294d..2d914f4 100644 (file)
@@ -120,14 +120,12 @@ METHOD(pa_tnc_attr_manager_t, get_names, enum_name_t*,
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
-#define PA_TNC_ATTR_INFO_SIZE                  8
-
 METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*,
-       private_pa_tnc_attr_manager_t *this, bio_reader_t *reader, uint32_t *offset,
-       chunk_t msg_info, pa_tnc_attr_t **error)
+       private_pa_tnc_attr_manager_t *this, bio_reader_t *reader, bool segmented,
+       uint32_t *offset, chunk_t msg_info, pa_tnc_attr_t **error)
 {
        uint8_t flags;
-       uint32_t type, length, attr_offset;
+       uint32_t type, length, value_len;
        chunk_t value;
        ietf_attr_pa_tnc_error_t *error_attr;
        pen_t vendor_id;
@@ -177,8 +175,9 @@ METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*,
                return NULL;
        }
        length -= PA_TNC_ATTR_HEADER_SIZE;
+       value_len = segmented ? reader->remaining(reader) : length;
 
-       if (!reader->read_data(reader, length, &value))
+       if (!reader->read_data(reader, value_len, &value))
        {
                DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
                *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
@@ -220,7 +219,7 @@ METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*,
                if (!(flags & PA_TNC_ATTR_FLAG_NOSKIP))
                {
                        DBG1(DBG_TNC, "skipping unsupported PA-TNC attribute");
-                       offset += length;
+                       (*offset) += PA_TNC_ATTR_HEADER_SIZE + length;
                        return NULL;
                }
 
@@ -232,21 +231,7 @@ METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*,
                error_attr->set_unsupported_attr(error_attr, flags, unsupported_type);
                return NULL;
        }
-       if (attr->process(attr, &attr_offset) != SUCCESS)
-       {
-               attr->destroy(attr);
-               attr = NULL;
-               if (vendor_id == PEN_IETF && type == IETF_ATTR_PA_TNC_ERROR)
-               {
-                       /* error while processing a PA-TNC error attribute - abort */
-                       return NULL;
-               }
-               error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
-               *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
-                                       msg_info, *offset + PA_TNC_ATTR_HEADER_SIZE + attr_offset);
-               return NULL;
-       }
-       (*offset) += length;
+       (*offset) += PA_TNC_ATTR_HEADER_SIZE;
 
        return attr;
 }
index c38face..048ad19 100644 (file)
@@ -66,13 +66,14 @@ struct pa_tnc_attr_manager_t {
         * Create and pre-parse a PA-TNC attribute object from data
         *
         * @param reader                PA-TNC attribute as encoded data
+        * @param segmented             TRUE if attribute is segmented
         * @param offset                Offset in bytes where an error has been found
         * @param msg_info              Message info added to an error attribute
         * @param error                 Error attribute if an error occurred
         * @return                              PA-TNC attribute object if supported, NULL else
         */
        pa_tnc_attr_t* (*create)(pa_tnc_attr_manager_t *this, bio_reader_t *reader,
-                                                        uint32_t *offset, chunk_t msg_info,
+                                                        bool segmented, uint32_t *offset, chunk_t msg_info,
                                                         pa_tnc_attr_t **error);
 
        /**
index 5a0afcd..d9b4417 100644 (file)
@@ -37,6 +37,8 @@ typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t;
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
 
+#define PA_TNC_RESERVED                0x000000
+
 /**
  * Private data of a pa_tnc_msg_t object.
  *
@@ -187,8 +189,10 @@ METHOD(pa_tnc_msg_t, process, status_t,
 {
        bio_reader_t *reader;
        pa_tnc_attr_t *attr, *error;
+       pen_type_t attr_type;
+       chunk_t attr_value;
        uint8_t version;
-       uint32_t reserved, offset;
+       uint32_t reserved, offset, attr_offset;
        pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER };
 
        /* process message header */
@@ -219,15 +223,32 @@ METHOD(pa_tnc_msg_t, process, status_t,
        while (reader->remaining(reader) > 0)
        {
                attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
-                                                       reader, &offset, this->encoding, &error);
-               if (error)
+                                                       reader, FALSE, &offset, this->encoding, &error);
+               if (!attr)
                {
                        goto err;
                }
-               if (attr)
+               attr_value = attr->get_value(attr);
+               attr_type  = attr->get_type(attr);
+
+               if (attr->process(attr, &attr_offset) != SUCCESS)
                {
-                       this->attributes->insert_last(this->attributes, attr);
+                       attr->destroy(attr);
+
+                       if (attr_type.vendor_id == PEN_IETF &&
+                               attr_type.type == IETF_ATTR_PA_TNC_ERROR)
+                       {
+                               /* suppress error while processing a PA-TNC error attribute */
+                               offset += attr_value.len;
+                               continue;
+                       }
+                       error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+                       error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+                                                                       this->encoding, offset + attr_offset);
+                       goto err;
                }
+               offset += attr_value.len;
+               this->attributes->insert_last(this->attributes, attr);
        }
        reader->destroy(reader);
        return SUCCESS;
index a336908..57ff1a0 100644 (file)
@@ -25,9 +25,6 @@ typedef struct pa_tnc_msg_t pa_tnc_msg_t;
 
 #define PA_TNC_VERSION         0x01
 #define PA_TNC_HEADER_SIZE     8
-#define PA_TNC_RESERVED                0x000000
-
-
 
 #include "pa_tnc_attr.h"
 
index 38e954d..df25e64 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "seg_contract.h"
 #include "seg_env.h"
+#include "ietf/ietf_attr_pa_tnc_error.h"
 #include "tcg/seg/tcg_seg_attr_seg_env.h"
 
 #include <utils/debug.h>
@@ -195,9 +196,10 @@ METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
        tcg_seg_attr_seg_env_t *seg_env_attr;
        seg_env_t *current, *seg_env = NULL;
        pa_tnc_attr_t *base_attr;
+       pen_type_t error_code;
        uint32_t base_attr_id;
        uint8_t flags;
-       chunk_t segment_data;
+       chunk_t segment_data, msg_info;
        enumerator_t *enumerator;
 
        seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
@@ -212,10 +214,7 @@ METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
                if (current->get_base_attr_id(current) == base_attr_id)
                {
                        seg_env = current;
-                       if (!(*more))
-                       {
-                               this->seg_envs->remove_at(this->seg_envs, enumerator);
-                       }
+                       this->seg_envs->remove_at(this->seg_envs, enumerator);
                        break;
                }
        }
@@ -227,13 +226,17 @@ METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
                {
                        DBG1(DBG_TNC, "base attribute ID %d is already in use",
                                                   base_attr_id);
+                       this->seg_envs->insert_last(this->seg_envs, seg_env);
                        return NULL;
                }
                DBG2(DBG_TNC, "received first segment for base attribute ID %d "
                                          "(%d bytes)", base_attr_id, segment_data.len);
                seg_env = seg_env_create_from_data(base_attr_id, segment_data,
-                                                                                  this->max_seg_size);
-               this->seg_envs->insert_last(this->seg_envs, seg_env);
+                                                                                  this->max_seg_size, error);
+               if (!seg_env)
+               {
+                       return NULL;
+               }
        }
        else
        {
@@ -245,19 +248,36 @@ METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
                DBG2(DBG_TNC, "received %s segment for base attribute ID %d "
                                          "(%d bytes)", (*more) ? "next" : "last", base_attr_id,
                                           segment_data.len);
-               seg_env->add_segment(seg_env, segment_data);
+               if (!seg_env->add_segment(seg_env, segment_data, error))
+               {
+                       seg_env->destroy(seg_env);
+                       return NULL;
+               }
        }
+       base_attr = seg_env->get_base_attr(seg_env);
+
        if (*more)
        {
-               return NULL;
+               /* reinsert into list since more segments are to come */
+               this->seg_envs->insert_last(this->seg_envs, seg_env);
+       }
+       else
+       {
+               /* added the last segment */
+               if (!base_attr)
+               {
+                       /* base attribute waits for more data */
+                       DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
+                       msg_info = seg_env->get_base_attr_info(seg_env);
+                       error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+                       *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+                                                                               msg_info, PA_TNC_ATTR_INFO_SIZE);
+               }
+               seg_env->destroy(seg_env);
        }
-       base_attr = seg_env->get_base_attr(seg_env, error);
-       seg_env->destroy(seg_env);
-
        return base_attr;
 }
 
-
 METHOD(seg_contract_t, is_issuer, bool,
        private_seg_contract_t *this)
 {
index 1ec8a36..b961589 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "imcv.h"
 #include "pa_tnc/pa_tnc_msg.h"
+#include "ietf/ietf_attr_pa_tnc_error.h"
 #include "tcg/seg/tcg_seg_attr_seg_env.h"
 
 #include <utils/debug.h>
@@ -48,20 +49,25 @@ struct private_seg_env_t {
        pa_tnc_attr_t *base_attr;
 
        /**
-        * Maximum PA-TNC attribute segment size
+        * Base Attribute Info to be used for PA-TNC error messages
         */
-       uint32_t max_seg_size;
+       u_char base_attr_info[8];
 
        /**
-        * TRUE if attribute is assembled from data
+        * Base Attribute needs more segment data
         */
-       bool from_data;
+       bool need_more;
 
        /**
-        * Remaining attribute data to be sent or received data being accumulated
+        * Pointer to remaining attribute data to be sent
         */
        chunk_t data;
 
+       /**
+        * Maximum PA-TNC attribute segment size
+        */
+       uint32_t max_seg_size;
+
 };
 
 METHOD(seg_env_t, get_base_attr_id, uint32_t,
@@ -71,33 +77,15 @@ METHOD(seg_env_t, get_base_attr_id, uint32_t,
 }
 
 METHOD(seg_env_t, get_base_attr, pa_tnc_attr_t*,
-       private_seg_env_t *this, pa_tnc_attr_t** error)
+       private_seg_env_t *this)
 {
-       *error = NULL;
+       return this->need_more ? NULL : this->base_attr->get_ref(this->base_attr);
+}
 
-       if (!this->base_attr)
-       {
-               bio_writer_t *writer;
-               bio_reader_t *reader;
-               chunk_t msg_info;
-               uint32_t offset = 0;
-
-               writer = bio_writer_create(8);
-               writer->write_uint8 (writer, PA_TNC_VERSION);
-               writer->write_uint24(writer, PA_TNC_RESERVED);
-               writer->write_uint8 (writer, BASE_ATTR_ID_PREFIX);
-               writer->write_uint24(writer, this->base_attr_id);
-               msg_info = writer->extract_buf(writer);
-               writer->destroy(writer);
-
-               reader = bio_reader_create(this->data);
-               this->base_attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
-                                                                               reader, &offset, msg_info, error);
-               chunk_free(&msg_info);
-               reader->destroy(reader);
-       }
-               
-       return this->base_attr ? this->base_attr->get_ref(this->base_attr) : NULL;
+METHOD(seg_env_t, get_base_attr_info, chunk_t,
+       private_seg_env_t *this)
+{
+       return chunk_create(this->base_attr_info, 8);
 }
 
 METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
@@ -175,19 +163,44 @@ METHOD(seg_env_t, next_segment, pa_tnc_attr_t*,
        return seg_env_attr;
 }
 
-METHOD(seg_env_t, add_segment, void,
-       private_seg_env_t *this, chunk_t segment_data)
+METHOD(seg_env_t, add_segment, bool,
+       private_seg_env_t *this, chunk_t segment, pa_tnc_attr_t **error)
 {
-       this->data = chunk_cat("mc", this->data, segment_data);
+       pen_type_t type, error_code;
+       uint32_t attr_offset;
+       chunk_t msg_info;
+       status_t status;
+
+       /* not all attributes might have implemented the add_segment method */
+       if (!this->base_attr->add_segment)
+       {
+               return FALSE;
+       }
+       this->base_attr->add_segment(this->base_attr, segment);
+       status = this->base_attr->process(this->base_attr, &attr_offset);
+
+       if (status != SUCCESS && status != NEED_MORE)
+       {
+               type = this->base_attr->get_type(this->base_attr);
+               if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
+               {
+                       /* error while processing a PA-TNC error attribute - abort */
+                       return FALSE;
+               }
+               error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+               msg_info = get_base_attr_info(this);
+               *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+                                       msg_info, PA_TNC_ATTR_HEADER_SIZE + attr_offset);
+               return FALSE;
+       }
+       this->need_more = (status == NEED_MORE);
+
+       return TRUE;
 }
 
 METHOD(seg_env_t, destroy, void,
        private_seg_env_t *this)
 {
-       if (this->from_data)
-       {
-               chunk_free(&this->data);
-       }
        DESTROY_IF(this->base_attr);
        free(this);
 }
@@ -218,6 +231,7 @@ seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
                .public = {
                        .get_base_attr_id = _get_base_attr_id,
                        .get_base_attr = _get_base_attr,
+                       .get_base_attr_info = _get_base_attr_info,
                        .first_segment = _first_segment,
                        .next_segment = _next_segment,
                        .add_segment = _add_segment,
@@ -236,14 +250,20 @@ seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
  * See header
  */
 seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
-                                                                       uint32_t max_seg_size)
+                                                                       uint32_t max_seg_size, pa_tnc_attr_t** error)
 {
        private_seg_env_t *this;
+       pen_type_t type, error_code;
+       bio_reader_t *reader;
+       chunk_t msg_info;
+       uint32_t offset = 0, attr_offset;
+       status_t status;
 
        INIT(this,
                .public = {
                        .get_base_attr_id = _get_base_attr_id,
                        .get_base_attr = _get_base_attr,
+                       .get_base_attr_info = _get_base_attr_info,
                        .first_segment = _first_segment,
                        .next_segment = _next_segment,
                        .add_segment = _add_segment,
@@ -251,10 +271,41 @@ seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
                },
                .base_attr_id = base_attr_id,
                .max_seg_size = max_seg_size,
-               .data = chunk_clone(data),
-               .from_data = TRUE,
        );
 
+       /* create info field to be used by PA-TNC error messages */
+       memset(this->base_attr_info, 0xff, 4);
+       htoun32(this->base_attr_info + 4, base_attr_id);
+       msg_info = get_base_attr_info(this);
+
+       /* extract from base attribute segment from data */
+       reader = bio_reader_create(data);
+       this->base_attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
+                                                                        reader, TRUE, &offset, msg_info, error);
+       reader->destroy(reader);
+
+       if (!this->base_attr)
+       {
+               destroy(this);
+               return NULL;
+       }
+       status = this->base_attr->process(this->base_attr, &attr_offset);
+
+       if (status != SUCCESS && status != NEED_MORE)
+       {
+               type = this->base_attr->get_type(this->base_attr);
+               if (!(type.vendor_id == PEN_IETF &&
+                         type.type == IETF_ATTR_PA_TNC_ERROR))
+               {
+                       error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
+                       *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
+                                               msg_info, PA_TNC_ATTR_HEADER_SIZE + attr_offset);
+               }
+               destroy(this);
+               return NULL;
+       }
+       this->need_more = (status == NEED_MORE);
+
        return &this->public;
 }
 
index 0dcefdd..dd057ae 100644 (file)
@@ -50,12 +50,18 @@ struct seg_env_t {
        uint32_t (*get_base_attr_id)(seg_env_t *this);
 
        /**
-        * Get Base Attribute
+        * Get Base Attribute if it contains processed [incremental] data
         *
-        * @param error                 Error attribute if an error occurred or NULL
         * @return                              Base Attribute (must be destroyed) or NULL
         */
-       pa_tnc_attr_t* (*get_base_attr)(seg_env_t *this, pa_tnc_attr_t **error);
+       pa_tnc_attr_t* (*get_base_attr)(seg_env_t *this);
+
+       /**
+        * Base Attribute Info to be used by PA-TNC error messages
+        *
+        * @return                              Message info string
+        */
+       chunk_t (*get_base_attr_info)(seg_env_t *this);
 
        /**
         * Generate the first segment envelope of the base attribute
@@ -76,8 +82,11 @@ struct seg_env_t {
         * Generate the first segment envelope of the base attribute
         *
         * @param segment               Attribute segment to be added
+        * @param error                 Error attribute if a parsing error occurred
+        * return                               TRUE if segment was successfully added
         */
-       void (*add_segment)(seg_env_t *this, chunk_t segment);
+       bool (*add_segment)(seg_env_t *this, chunk_t segment,
+                                               pa_tnc_attr_t** error);
 
        /**
         * Destroys a seg_env_t object.
@@ -101,8 +110,10 @@ seg_env_t* seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr,
  * @param base_attr_id         Base Attribute ID
  * @param data                         First attribute segment
  * @param max_seg_size         Maximum segment size
+ * @param error                                Error attribute if a parsing error occurred
  */
 seg_env_t* seg_env_create_from_data(uint32_t base_attr_id, chunk_t data,
-                                                                       uint32_t max_seg_size);
+                                                                       uint32_t max_seg_size,
+                                                                       pa_tnc_attr_t** error);
 
 #endif /** SEG_ENV_H_ @}*/
index 35254cc..5612427 100644 (file)
@@ -220,6 +220,12 @@ METHOD(pa_tnc_attr_t, process, status_t,
        return SUCCESS;
 }
 
+METHOD(pa_tnc_attr_t, add_segment, void,
+       private_tcg_swid_attr_req_t *this, chunk_t segment)
+{
+       this->value = chunk_cat("mc", this->value, segment);
+}
+
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
        private_tcg_swid_attr_req_t *this)
 {
@@ -285,6 +291,7 @@ pa_tnc_attr_t *tcg_swid_attr_req_create(u_int8_t flags, u_int32_t request_id,
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },
@@ -321,6 +328,7 @@ pa_tnc_attr_t *tcg_swid_attr_req_create_from_data(size_t length, chunk_t data)
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },
index 6e9ebd4..4d1316c 100644 (file)
@@ -224,6 +224,12 @@ METHOD(pa_tnc_attr_t, process, status_t,
        return SUCCESS;
 }
 
+METHOD(pa_tnc_attr_t, add_segment, void,
+       private_tcg_swid_attr_tag_id_inv_t *this, chunk_t segment)
+{
+       this->value = chunk_cat("mc", this->value, segment);
+}
+
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
        private_tcg_swid_attr_tag_id_inv_t *this)
 {
@@ -288,6 +294,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create(uint32_t request_id,
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },
@@ -325,6 +332,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_id_inv_create_from_data(size_t length,
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },
index 5923f56..f616967 100644 (file)
@@ -213,6 +213,12 @@ METHOD(pa_tnc_attr_t, process, status_t,
        return SUCCESS;
 }
 
+METHOD(pa_tnc_attr_t, add_segment, void,
+       private_tcg_swid_attr_tag_inv_t *this, chunk_t segment)
+{
+       this->value = chunk_cat("mc", this->value, segment);
+}
+
 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
        private_tcg_swid_attr_tag_inv_t *this)
 {
@@ -276,6 +282,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_inv_create(uint32_t request_id,
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },
@@ -312,6 +319,7 @@ pa_tnc_attr_t *tcg_swid_attr_tag_inv_create_from_data(size_t length,
                                .set_noskip_flag = _set_noskip_flag,
                                .build = _build,
                                .process = _process,
+                               .add_segment = _add_segment,
                                .get_ref = _get_ref,
                                .destroy = _destroy,
                        },