#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
/**
* 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
*
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-#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;
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,
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;
}
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;
}
* 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);
/**
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+#define PA_TNC_RESERVED 0x000000
+
/**
* Private data of a pa_tnc_msg_t object.
*
{
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 */
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;
#define PA_TNC_VERSION 0x01
#define PA_TNC_HEADER_SIZE 8
-#define PA_TNC_RESERVED 0x000000
-
-
#include "pa_tnc_attr.h"
#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>
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;
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;
}
}
{
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
{
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)
{
#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>
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,
}
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*,
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);
}
.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,
* 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,
},
.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;
}
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
* 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.
* @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_ @}*/
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)
{
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
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)
{
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
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)
{
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},
.set_noskip_flag = _set_noskip_flag,
.build = _build,
.process = _process,
+ .add_segment = _add_segment,
.get_ref = _get_ref,
.destroy = _destroy,
},