Fixed the implemention of the IF-M segmentation protocol
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 18 Aug 2015 18:25:26 +0000 (20:25 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 18 Aug 2015 19:24:26 +0000 (21:24 +0200)
The first segment only fit if the segmentation envelope attribute
was preceded by a Max Attribute Size Response attribute. The
improved implementation fills up the first PA-TNC message with
the first segment up to the maximum message size.

13 files changed:
src/libimcv/imc/imc_msg.c
src/libimcv/imv/imv_msg.c
src/libimcv/pa_tnc/pa_tnc_msg.c
src/libimcv/pa_tnc/pa_tnc_msg.h
src/libimcv/plugins/imc_swid/imc_swid.c
src/libimcv/plugins/imv_attestation/imv_attestation_agent.c
src/libimcv/plugins/imv_os/imv_os_agent.c
src/libimcv/plugins/imv_swid/imv_swid_agent.c
src/libimcv/seg/seg_contract.c
src/libimcv/seg/seg_contract.h
src/libimcv/seg/seg_env.c
src/libimcv/seg/seg_env.h
src/libimcv/suites/test_imcv_seg.c

index 83337cf..9e12e29 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -108,6 +108,7 @@ METHOD(imc_msg_t, send_, TNC_Result,
        pa_tnc_attr_t *attr;
        TNC_UInt32 msg_flags;
        TNC_MessageType msg_type;
+       size_t max_msg_len, min_seg_attr_len, space_left;
        bool attr_added, oversize;
        chunk_t msg;
        seg_contract_t *contract;
@@ -120,23 +121,37 @@ METHOD(imc_msg_t, send_, TNC_Result,
        contract = contracts->get_contract(contracts, this->msg_type,
                                                                           FALSE, this->dst_id);
 
+       /* Retrieve maximum allowed PA-TNC message size if set */
+       max_msg_len = this->state->get_max_msg_len(this->state);
+
+       /* Minimum size needed for Segmentation Envelope Attribute */
+       min_seg_attr_len = PA_TNC_ATTR_HEADER_SIZE + TCG_SEG_ATTR_SEG_ENV_HEADER +
+                                          PA_TNC_ATTR_HEADER_SIZE;
+
        while (this->attr_list->get_count(this->attr_list))
        {
-               pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state));
+               pa_tnc_msg = pa_tnc_msg_create(max_msg_len);
                attr_added = FALSE;
 
                enumerator = this->attr_list->create_enumerator(this->attr_list);
                while (enumerator->enumerate(enumerator, &attr))
                {
+                       space_left = pa_tnc_msg->get_space(pa_tnc_msg);
+
                        if (contract && contract->check_size(contract, attr, &oversize))
                        {
                                if (oversize)
                                {
-                                       /* TODO generate SWID error msg */
+                                       /* TODO handle oversized attributes */
+                               }
+                               else if (max_msg_len == 0 || space_left >= min_seg_attr_len)
+                               {
+                                       attr = contract->first_segment(contract, attr, space_left);
                                }
                                else
                                {
-                                       attr = contract->first_segment(contract, attr);
+                                       /* segment attribute in next iteration */
+                                       break;
                                }
                        }
                        if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
@@ -147,11 +162,12 @@ METHOD(imc_msg_t, send_, TNC_Result,
                        {
                                if (attr_added)
                                {
+                                       /* there might be space for attribute in next iteration */
                                        break;
                                }
                                else
                                {
-                                       DBG1(DBG_IMC, "PA-TNC attribute too large to send, deleted");
+                                       DBG1(DBG_IMV, "PA-TNC attribute too large to send, deleted");
                                        attr->destroy(attr);
                                }
                        }
@@ -341,9 +357,7 @@ METHOD(imc_msg_t, receive, TNC_Result,
                                my_max_seg_size = this->state->get_max_msg_len(this->state)
                                                                        - PA_TNC_HEADER_SIZE
                                                                        - PA_TNC_ATTR_HEADER_SIZE
-                                                                       - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                                       - PA_TNC_ATTR_HEADER_SIZE
-                                                                       - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                                       - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
                                /* If segmentation is possible select lower segment size */
                                if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION &&
index fdf6332..039124c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2014 Andreas Steffen
+ * Copyright (C) 2012-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -125,6 +125,7 @@ METHOD(imv_msg_t, send_, TNC_Result,
        pa_tnc_attr_t *attr;
        TNC_UInt32 msg_flags;
        TNC_MessageType msg_type;
+       size_t max_msg_len, min_seg_attr_len, space_left;
        bool attr_added, oversize;
        chunk_t msg;
        seg_contract_t *contract;
@@ -137,23 +138,37 @@ METHOD(imv_msg_t, send_, TNC_Result,
        contract = contracts->get_contract(contracts, this->msg_type,
                                                                           FALSE, this->dst_id);
 
+       /* Retrieve maximum allowed PA-TNC message size if set */
+       max_msg_len = this->state->get_max_msg_len(this->state);
+
+       /* Minimum size needed for Segmentation Envelope Attribute */
+       min_seg_attr_len = PA_TNC_ATTR_HEADER_SIZE + TCG_SEG_ATTR_SEG_ENV_HEADER +
+                                          PA_TNC_ATTR_HEADER_SIZE;
+
        while (this->attr_list->get_count(this->attr_list))
        {
-               pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state));
+               pa_tnc_msg = pa_tnc_msg_create(max_msg_len);
                attr_added = FALSE;
 
                enumerator = this->attr_list->create_enumerator(this->attr_list);
                while (enumerator->enumerate(enumerator, &attr))
                {
+                       space_left = pa_tnc_msg->get_space(pa_tnc_msg);
+
                        if (contract && contract->check_size(contract, attr, &oversize))
                        {
                                if (oversize)
                                {
-                                       /* TODO generate SWID error msg */
+                                       /* TODO handle oversized attributes */
+                               }
+                               else if (max_msg_len == 0 || space_left >= min_seg_attr_len)
+                               {
+                                       attr = contract->first_segment(contract, attr, space_left);
                                }
                                else
                                {
-                                       attr = contract->first_segment(contract, attr);
+                                       /* segment attribute in next iteration */
+                                       break;
                                }
                        }
                        if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
@@ -164,6 +179,7 @@ METHOD(imv_msg_t, send_, TNC_Result,
                        {
                                if (attr_added)
                                {
+                                       /* there might be space for attribute in next iteration */
                                        break;
                                }
                                else
@@ -377,9 +393,7 @@ METHOD(imv_msg_t, receive, TNC_Result,
                                my_max_seg_size = this->state->get_max_msg_len(this->state)
                                                                        - PA_TNC_HEADER_SIZE
                                                                        - PA_TNC_ATTR_HEADER_SIZE
-                                                                       - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                                       - PA_TNC_ATTR_HEADER_SIZE
-                                                                       - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                                       - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
                                /* If segmentation is possible select lower segment size */
                                if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION &&
index ea4dee9..17c649d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -92,6 +92,12 @@ METHOD(pa_tnc_msg_t, get_encoding, chunk_t,
        return this->encoding;
 }
 
+METHOD(pa_tnc_msg_t, get_space, size_t,
+       private_pa_tnc_msg_t *this)
+{
+       return this->max_msg_len ? this->max_msg_len - this->msg_len : 0;
+}
+
 METHOD(pa_tnc_msg_t, add_attribute, bool,
        private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr)
 {
@@ -389,6 +395,7 @@ pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len)
        INIT(this,
                .public = {
                        .get_encoding = _get_encoding,
+                       .get_space = _get_space,
                        .add_attribute = _add_attribute,
                        .build = _build,
                        .process = _process,
@@ -416,6 +423,7 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
        INIT(this,
                .public = {
                        .get_encoding = _get_encoding,
+                       .get_space = _get_space,
                        .add_attribute = _add_attribute,
                        .build = _build,
                        .process = _process,
index 57ff1a0..3be3020 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -44,6 +44,13 @@ struct pa_tnc_msg_t {
        chunk_t (*get_encoding)(pa_tnc_msg_t *this);
 
        /**
+        * Get the remaining space in octets left in the PA-TNC message
+        *
+        * @return                                      remaining space or 0 if max_msg_len is not set
+        */
+       size_t (*get_space)(pa_tnc_msg_t *this);
+
+       /**
         * Add a PA-TNC attribute
         *
         * @param attr                          PA-TNC attribute to be addedd
index 40f352a..0dcb9af 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -134,9 +134,7 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
        /* Determine maximum PA-TNC attribute segment size */
        max_seg_size = state->get_max_msg_len(state) - PA_TNC_HEADER_SIZE
                                                                                                 - PA_TNC_ATTR_HEADER_SIZE
-                                                                                                - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                                                                - PA_TNC_ATTR_HEADER_SIZE
-                                                                                                - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                                                                - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
        /* Announce support of PA-TNC segmentation to IMV */
        contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size,
index 8e37368..9656306 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2011-2012 Sansar Choinyambuu
- * Copyright (C) 2011-2014 Andreas Steffen
+ * Copyright (C) 2011-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -484,9 +484,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                max_seg_size = state->get_max_msg_len(state)
                                                                - PA_TNC_HEADER_SIZE
                                                                - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                               - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
                /* Announce support of PA-TNC segmentation to IMC */
                contract = seg_contract_create(msg_types[0], max_attr_size,
index f0b1936..5eefb51 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -542,9 +542,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                max_seg_size = state->get_max_msg_len(state)
                                                                - PA_TNC_HEADER_SIZE 
                                                                - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                               - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
                /* Announce support of PA-TNC segmentation to IMC */
                contract = seg_contract_create(msg_types[0], max_attr_size,
index 5bebf32..6d32783 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2014 Andreas Steffen
+ * Copyright (C) 2013-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -446,9 +446,7 @@ METHOD(imv_agent_if_t, batch_ending, TNC_Result,
                                max_seg_size = state->get_max_msg_len(state)
                                                                - PA_TNC_HEADER_SIZE 
                                                                - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER
-                                                               - PA_TNC_ATTR_HEADER_SIZE
-                                                               - TCG_SEG_ATTR_MAX_SIZE_SIZE;
+                                                               - TCG_SEG_ATTR_SEG_ENV_HEADER;
 
                                /* Announce support of PA-TNC segmentation to IMC */
                                contract = seg_contract_create(msg_types[0], max_attr_size,
index 7db702a..41aed58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -148,7 +148,7 @@ METHOD(seg_contract_t, check_size, bool,
 }
 
 METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
-       private_seg_contract_t *this, pa_tnc_attr_t *attr)
+       private_seg_contract_t *this, pa_tnc_attr_t *attr, size_t max_attr_len)
 {
        seg_env_t *seg_env;
 
@@ -160,7 +160,7 @@ METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
        }
        this->seg_envs->insert_last(this->seg_envs, seg_env);
 
-       return seg_env->first_segment(seg_env);
+       return seg_env->first_segment(seg_env, max_attr_len);
 }
 
 METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
index 23676a9..afbf309 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -78,9 +78,11 @@ struct seg_contract_t {
         * Generate first segment of a PA-TNC attribute according to the contract
         *
         * @param attr                  PA-TNC attribute to be segmented
+        * @param max_attr_len  Maximum size of first segment envelope attribute
         * @return                              First segment envelope attribute
         */
-       pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr);
+       pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr,
+                                                                       size_t max_attr_len);
 
        /**
         * Generate next segment of a PA-TNC attribute according to the contract
index f384192..8d0f760 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -89,14 +89,21 @@ METHOD(seg_env_t, get_base_attr_info, chunk_t,
 }
 
 METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
-       private_seg_env_t *this)
+       private_seg_env_t *this, size_t max_attr_len)
 {
        pa_tnc_attr_t *seg_env_attr;
        bio_writer_t *writer;
        pen_type_t type;
        chunk_t segment_data, value;
+       size_t seg_size;
        uint8_t flags, seg_env_flags;
 
+       /* compute size of first segment */
+       seg_size = max_attr_len ? min(this->max_seg_size,
+                                                                 max_attr_len - PA_TNC_ATTR_HEADER_SIZE
+                                                                                          - TCG_SEG_ATTR_SEG_ENV_HEADER)
+                                                       : this->max_seg_size;
+
        /* get components of base attribute header and data */
        flags = this->base_attr->get_noskip_flag(this->base_attr) ?
                                PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE;
@@ -104,7 +111,7 @@ METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
 
        /* attribute data going into the first segment */
        segment_data = this->data;
-       segment_data.len = this->max_seg_size - PA_TNC_ATTR_HEADER_SIZE;
+       segment_data.len = seg_size - PA_TNC_ATTR_HEADER_SIZE;
 
        /* build encoding of the base attribute header and first segment data */
        writer = bio_writer_create(this->max_seg_size);
@@ -118,7 +125,7 @@ METHOD(seg_env_t, first_segment, pa_tnc_attr_t*,
        this->data = chunk_skip(this->data, segment_data.len);
 
        DBG2(DBG_TNC, "creating first segment for base attribute ID %d (%d bytes)",
-                this->base_attr_id, this->max_seg_size);
+                this->base_attr_id, seg_size);
 
        seg_env_flags = SEG_ENV_FLAG_START | SEG_ENV_FLAG_MORE;
        seg_env_attr = tcg_seg_attr_seg_env_create(value, seg_env_flags,
index 611f9a9..5f21236 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Andreas Steffen
+ * Copyright (C) 2014-2015 Andreas Steffen
  * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -66,9 +66,10 @@ struct seg_env_t {
        /**
         * Generate the first segment envelope of the base attribute
         *
+        * @param max_attr_len  Maximum size of first attribute segment envelope
         * @return                              First attribute segment envelope
         */
-       pa_tnc_attr_t* (*first_segment)(seg_env_t *this);
+       pa_tnc_attr_t* (*first_segment)(seg_env_t *this, size_t max_attr_len);
 
        /**
         * Generate the next segment envelope of the base attribute
index 8b51eda..5245be9 100644 (file)
@@ -42,7 +42,7 @@ static struct {
        { 24, 1, 24 },
        { 25, 1, 23 },
        { 47, 1,  1 },
-       { 48, 0,  0 },  
+       { 48, 0,  0 },
 };
 
 static char command[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -87,7 +87,7 @@ START_TEST(test_imcv_seg_env)
                        if (n == 0)
                        {
                                /* create first segment */
-                               attr = seg_env->first_segment(seg_env);
+                               attr = seg_env->first_segment(seg_env, 0);
                        
                                seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
                                segment = seg_env_attr->get_segment(seg_env_attr, &flags);
@@ -168,8 +168,9 @@ START_TEST(test_imcv_seg_env_special)
        pen_type_t type;
        seg_env_t *seg_env;
        chunk_t segment, value;
+       uint32_t max_attr_len = 60;
        uint32_t max_seg_size = 47;
-       uint32_t last_seg_size = 1;
+       uint32_t last_seg_size = 4;
        uint32_t offset = 12;
 
        base_attr = ita_attr_command_create(command);
@@ -179,7 +180,7 @@ START_TEST(test_imcv_seg_env_special)
        base_attr->set_noskip_flag(base_attr, TRUE);
 
        seg_env = seg_env_create(id, base_attr, max_seg_size);
-       attr = seg_env->first_segment(seg_env);
+       attr = seg_env->first_segment(seg_env, max_attr_len);
        attr->destroy(attr);
 
        /* don't return last segment indicator */
@@ -306,7 +307,7 @@ START_TEST(test_imcv_seg_contract)
        contract_r = seg_contract_create(msg_type, max_attr_size, max_seg_size,
                                                                         FALSE, issuer_id, TRUE);
        attr = contract_r->first_segment(contract_r,
-                                                                        base_attr_r->get_ref(base_attr_r));
+                                                                        base_attr_r->get_ref(base_attr_r), 0);
 
        if (seg_env_tests[_i].next_segs == 0)
        {
@@ -422,8 +423,8 @@ START_TEST(test_imcv_seg_contract_special)
        ck_assert(!oversize);
 
        /* get first segment of each base attribute */
-       attr1_f = contract_r->first_segment(contract_r, base_attr1_r->get_ref(base_attr1_r));
-       attr2_f = contract_r->first_segment(contract_r, base_attr2_r->get_ref(base_attr2_r));
+       attr1_f = contract_r->first_segment(contract_r, base_attr1_r->get_ref(base_attr1_r), 0);
+       attr2_f = contract_r->first_segment(contract_r, base_attr2_r->get_ref(base_attr2_r), 0);
        ck_assert(attr1_f);
        ck_assert(attr2_f);
        seg_env_attr1 = (tcg_seg_attr_seg_env_t*)attr1_f;