diff options
Diffstat (limited to 'src/libimcv/seg')
-rw-r--r-- | src/libimcv/seg/seg_contract.c | 479 | ||||
-rw-r--r-- | src/libimcv/seg/seg_contract.h | 180 | ||||
-rw-r--r-- | src/libimcv/seg/seg_contract_manager.c | 94 | ||||
-rw-r--r-- | src/libimcv/seg/seg_contract_manager.h | 63 | ||||
-rw-r--r-- | src/libimcv/seg/seg_env.c | 306 | ||||
-rw-r--r-- | src/libimcv/seg/seg_env.h | 119 |
6 files changed, 1241 insertions, 0 deletions
diff --git a/src/libimcv/seg/seg_contract.c b/src/libimcv/seg/seg_contract.c new file mode 100644 index 000000000..7db702a08 --- /dev/null +++ b/src/libimcv/seg/seg_contract.c @@ -0,0 +1,479 @@ +/* + * 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. + */ + +#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> +#include <bio/bio_writer.h> + +#include <tncif_pa_subtypes.h> + +typedef struct private_seg_contract_t private_seg_contract_t; + +/** + * Private data of a seg_contract_t object. + */ +struct private_seg_contract_t { + + /** + * Public seg_contract_t interface. + */ + seg_contract_t public; + + /** + * PA-TNC message type + */ + pen_type_t msg_type; + + /** + * Maximum PA-TNC attribute size + */ + uint32_t max_attr_size; + + /** + * Maximum PA-TNC attribute segment size + */ + uint32_t max_seg_size; + + /** + * Maximum PA-TNC attribute segment size + */ + uint32_t last_base_attr_id; + + /** + * List of attribute segment envelopes + */ + + linked_list_t *seg_envs; + + /** + * Is this a null contract? + */ + bool is_null; + + /** + * Contract role + */ + bool is_issuer; + + /** + * Issuer ID (either IMV or IMC ID) + */ + TNC_UInt32 issuer_id; + + /** + * Responder ID (either IMC or IMV ID) + */ + TNC_UInt32 responder_id; + + /** + * IMC/IMV role + */ + bool is_imc; + +}; + +METHOD(seg_contract_t, get_msg_type, pen_type_t, + private_seg_contract_t *this) +{ + return this->msg_type; +} + +METHOD(seg_contract_t, set_max_size, void, + private_seg_contract_t *this, uint32_t max_attr_size, uint32_t max_seg_size) +{ + this->max_attr_size = max_attr_size; + this->max_seg_size = max_seg_size; + this->is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE && + max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE; +} + +METHOD(seg_contract_t, get_max_size, void, + private_seg_contract_t *this, uint32_t *max_attr_size, uint32_t *max_seg_size) +{ + if (max_attr_size) + { + *max_attr_size = this->max_attr_size; + } + if (max_seg_size) + { + *max_seg_size = this->max_seg_size; + } +} + +METHOD(seg_contract_t, check_size, bool, + private_seg_contract_t *this, pa_tnc_attr_t *attr, bool *oversize) +{ + chunk_t attr_value; + size_t attr_len; + + *oversize = FALSE; + + if (this->is_null) + { + /* null segmentation contract */ + return FALSE; + } + attr->build(attr); + attr_value = attr->get_value(attr); + attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len; + + if (attr_len > this->max_attr_size) + { + /* oversize attribute */ + *oversize = TRUE; + return FALSE; + } + if (this->max_seg_size == SEG_CONTRACT_NO_FRAGMENTATION) + { + /* no fragmentation wanted */ + return FALSE; + } + return attr_value.len > this->max_seg_size + TCG_SEG_ATTR_SEG_ENV_HEADER; +} + +METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*, + private_seg_contract_t *this, pa_tnc_attr_t *attr) +{ + seg_env_t *seg_env; + + seg_env = seg_env_create(++this->last_base_attr_id, attr, + this->max_seg_size); + if (!seg_env) + { + return NULL; + } + this->seg_envs->insert_last(this->seg_envs, seg_env); + + return seg_env->first_segment(seg_env); +} + +METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*, + private_seg_contract_t *this, uint32_t base_attr_id) +{ + pa_tnc_attr_t *seg_env_attr = NULL; + seg_env_t *seg_env; + bool last_segment = FALSE; + enumerator_t *enumerator; + + enumerator = this->seg_envs->create_enumerator(this->seg_envs); + while (enumerator->enumerate(enumerator, &seg_env)) + { + if (seg_env->get_base_attr_id(seg_env) == base_attr_id) + { + seg_env_attr = seg_env->next_segment(seg_env, &last_segment); + if (!seg_env_attr) + { + break; + } + if (last_segment) + { + this->seg_envs->remove_at(this->seg_envs, enumerator); + seg_env->destroy(seg_env); + } + break; + } + } + enumerator->destroy(enumerator); + + return seg_env_attr; +} + +METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*, + private_seg_contract_t *this, pa_tnc_attr_t *attr, pa_tnc_attr_t **error, + bool *more) +{ + 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, msg_info; + enumerator_t *enumerator; + + seg_env_attr = (tcg_seg_attr_seg_env_t*)attr; + base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr); + segment_data = seg_env_attr->get_segment(seg_env_attr, &flags); + *more = flags & SEG_ENV_FLAG_MORE; + *error = NULL; + + enumerator = this->seg_envs->create_enumerator(this->seg_envs); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->get_base_attr_id(current) == base_attr_id) + { + seg_env = current; + this->seg_envs->remove_at(this->seg_envs, enumerator); + break; + } + } + enumerator->destroy(enumerator); + + if (flags & SEG_ENV_FLAG_START) + { + if (seg_env) + { + 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, error); + if (!seg_env) + { + return NULL; + } + } + else + { + if (!seg_env) + { + DBG1(DBG_TNC, "base attribute ID %d not found", base_attr_id); + return NULL; + } + DBG2(DBG_TNC, "received %s segment for base attribute ID %d " + "(%d bytes)", (*more) ? "next" : "last", base_attr_id, + segment_data.len); + 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) + { + /* 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); + } + return base_attr; +} + +METHOD(seg_contract_t, is_issuer, bool, + private_seg_contract_t *this) +{ + return this->is_issuer; +} + +METHOD(seg_contract_t, is_null, bool, + private_seg_contract_t *this) +{ + return this->is_null; +} + +METHOD(seg_contract_t, set_responder, void, + private_seg_contract_t *this, TNC_UInt32 responder_id) +{ + this->responder_id = responder_id; +} + +METHOD(seg_contract_t, get_responder, TNC_UInt32, + private_seg_contract_t *this) +{ + return this->responder_id; +} + +METHOD(seg_contract_t, get_issuer, TNC_UInt32, + private_seg_contract_t *this) +{ + return this->issuer_id; +} + +METHOD(seg_contract_t, clone_, seg_contract_t*, + private_seg_contract_t *this) +{ + private_seg_contract_t *clone; + + clone = malloc_thing(private_seg_contract_t); + memcpy(clone, this, sizeof(private_seg_contract_t)); + clone->seg_envs = linked_list_create(); + + return &clone->public; +} + +METHOD(seg_contract_t, get_info_string, void, + private_seg_contract_t *this, char *buf, size_t len, bool request) +{ + enum_name_t *pa_subtype_names; + uint32_t msg_vid, msg_subtype; + char *pos = buf; + int written; + + /* nul-terminate the string buffer */ + buf[--len] = '\0'; + + if (this->is_issuer && request) + { + written = snprintf(pos, len, "%s %d requests", + this->is_imc ? "IMC" : "IMV", this->issuer_id); + } + else + { + written = snprintf(pos, len, "%s %d received", + this->is_imc ? "IMC" : "IMV", + this->is_issuer ? this->issuer_id : + this->responder_id); + } + if (written < 0 || written > len) + { + return; + } + pos += written; + len -= written; + + written = snprintf(pos, len, " a %ssegmentation contract%s ", + this->is_null ? "null" : "", request ? + (this->is_issuer ? "" : " request") : " response"); + if (written < 0 || written > len) + { + return; + } + pos += written; + len -= written; + + if ((!this->is_issuer && this->issuer_id != TNC_IMVID_ANY) || + ( this->is_issuer && this->responder_id != TNC_IMVID_ANY)) + { + written = snprintf(pos, len, "from %s %d ", + this->is_imc ? "IMV" : "IMC", + this->is_issuer ? this->responder_id : + this->issuer_id); + if (written < 0 || written > len) + { + return; + } + pos += written; + len -= written; + } + + msg_vid = this->msg_type.vendor_id; + msg_subtype = this->msg_type.type; + pa_subtype_names = get_pa_subtype_names(msg_vid); + if (pa_subtype_names) + { + written = snprintf(pos, len, "for PA message type '%N/%N' " + "0x%06x/0x%08x", pen_names, msg_vid, + pa_subtype_names, msg_subtype, msg_vid, + msg_subtype); + } + else + { + written = snprintf(pos, len, "for PA message type '%N' " + "0x%06x/0x%08x", pen_names, msg_vid, + msg_vid, msg_subtype); + } + if (written < 0 || written > len) + { + return; + } + pos += written; + len -= written; + + if (!this->is_null) + { + written = snprintf(pos, len, "\n maximum attribute size of %u bytes " + "with ", this->max_attr_size); + if (written < 0 || written > len) + { + return; + } + pos += written; + len -= written; + + if (this->max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE) + { + written = snprintf(pos, len, "no segmentation"); + } + else + { + written = snprintf(pos, len, "maximum segment size of %u bytes", + this->max_seg_size); + } + } +} + +METHOD(seg_contract_t, destroy, void, + private_seg_contract_t *this) +{ + this->seg_envs->destroy_offset(this->seg_envs, offsetof(seg_env_t, destroy)); + free(this); +} + +/** + * See header + */ +seg_contract_t *seg_contract_create(pen_type_t msg_type, + uint32_t max_attr_size, + uint32_t max_seg_size, + bool is_issuer, TNC_UInt32 issuer_id, + bool is_imc) +{ + private_seg_contract_t *this; + + INIT(this, + .public = { + .get_msg_type = _get_msg_type, + .set_max_size = _set_max_size, + .get_max_size = _get_max_size, + .check_size = _check_size, + .first_segment = _first_segment, + .next_segment = _next_segment, + .add_segment = _add_segment, + .is_issuer = _is_issuer, + .is_null = _is_null, + .set_responder = _set_responder, + .get_responder = _get_responder, + .get_issuer = _get_issuer, + .clone = _clone_, + .get_info_string = _get_info_string, + .destroy = _destroy, + }, + .msg_type = msg_type, + .max_attr_size = max_attr_size, + .max_seg_size = max_seg_size, + .seg_envs = linked_list_create(), + .is_issuer = is_issuer, + .issuer_id = issuer_id, + .responder_id = is_imc ? TNC_IMVID_ANY : TNC_IMCID_ANY, + .is_imc = is_imc, + .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE && + max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE, + ); + + return &this->public; +} + diff --git a/src/libimcv/seg/seg_contract.h b/src/libimcv/seg/seg_contract.h new file mode 100644 index 000000000..23676a9f4 --- /dev/null +++ b/src/libimcv/seg/seg_contract.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/** + * @defgroup seg_contract seg_contract + * @{ @ingroup libimcv_seg + */ + +#ifndef SEG_CONTRACT_H_ +#define SEG_CONTRACT_H_ + +typedef struct seg_contract_t seg_contract_t; + +#include "pa_tnc/pa_tnc_attr.h" + +#include <library.h> +#include <pen/pen.h> + +#include <tncif.h> + +#define SEG_CONTRACT_MAX_SIZE_VALUE 0xffffffff +#define SEG_CONTRACT_NO_FRAGMENTATION SEG_CONTRACT_MAX_SIZE_VALUE + +/** + * Interface for a PA-TNC attribute segmentation contract + * + */ +struct seg_contract_t { + + /** + * Get the PA-TNC message type. + * + * @return PA-TNC Message type + */ + pen_type_t (*get_msg_type)(seg_contract_t *this); + + /** + * Set maximum PA-TNC attribute and segment size in octets + * + * @param max_attr_size Maximum PA-TNC attribute size in octets + * @param max_seg_size Maximum PA-TNC attribute segment size in octets + */ + void (*set_max_size)(seg_contract_t *this, uint32_t max_attr_size, + uint32_t max_seg_size); + + /** + * Get maximum PA-TNC attribute and segment size in octets + * + * @param max_attr_size Maximum PA-TNC attribute size in octets + * @param max_seg_size Maximum PA-TNC attribute segment size in octets + */ + void (*get_max_size)(seg_contract_t *this, uint32_t *max_attr_size, + uint32_t *max_seg_size); + + /** + * Check if a PA-TNC attribute must be segmented or is oversized + * + * @param attr PA-TNC attribute to be checked + * @param oversize PA-TNC attribute is larger than maximum size + * @return TRUE if PA-TNC attribute must be segmented + */ + bool (*check_size)(seg_contract_t *this, pa_tnc_attr_t *attr, + bool *oversize); + + /** + * Generate first segment of a PA-TNC attribute according to the contract + * + * @param attr PA-TNC attribute to be segmented + * @return First segment envelope attribute + */ + pa_tnc_attr_t* (*first_segment)(seg_contract_t *this, pa_tnc_attr_t *attr); + + /** + * Generate next segment of a PA-TNC attribute according to the contract + * + * @param base_attr_id Base Attribute ID + * @return Next segment envelope attribute + */ + pa_tnc_attr_t* (*next_segment)(seg_contract_t *this, uint32_t base_attr_id); + + /** + * Add an attribute segments until the PA-TNC attribute is reconstructed + * + * @param attr Segment envelope attribute + * @param error Error attribute if an error occurred or NULL + * @param more Need more segments + * @return Completed PA-TNC attribute or NULL + */ + pa_tnc_attr_t* (*add_segment)(seg_contract_t *this, + pa_tnc_attr_t *attr, pa_tnc_attr_t **error, + bool *more); + + /** + * Get contract role + * + * @return TRUE: contracting party (issuer), + * FALSE: contracted party + */ + bool (*is_issuer)(seg_contract_t *this); + + /** + * Is this a null contract ? + * + * @return TRUE if null contract + */ + bool (*is_null)(seg_contract_t *this); + + /** + * Set the responder ID + * + * @param responder IMC or IMV ID of responder + */ + void (*set_responder)(seg_contract_t *this, TNC_UInt32 responder); + + /** + * Get the responder ID + * + * @return IMC or IMV ID of responder + */ + TNC_UInt32 (*get_responder)(seg_contract_t *this); + + /** + * Get the issuer ID + * + * @return IMC or IMV ID of issuer + */ + TNC_UInt32 (*get_issuer)(seg_contract_t *this); + + /** + * Clone a contract + * + * @return Cloned contract + */ + seg_contract_t* (*clone)(seg_contract_t *this); + + /** + * Get an info string about the contract + * + * @param buf String buffer of at least size len + * @param len Size of string buffer + * @param request TRUE if contract request, FALSE if response + */ + void (*get_info_string)(seg_contract_t *this, char *buf, size_t len, + bool request); + + /** + * Destroys a seg_contract_t object. + */ + void (*destroy)(seg_contract_t *this); +}; + +/** + * Create a PA-TNC attribute segmentation contract + * + * @param msg_type PA-TNC message type + * @param max_attr_size Maximum PA-TNC attribute size in octets + * @param max_seg_size Maximum PA-TNC attribute segment size in octets + * @param is_issuer TRUE if issuer of the contract + * @param issuer_id IMC or IMV ID of issuer + * @param is_imc TRUE if IMC, FALSE if IMV + */ +seg_contract_t* seg_contract_create(pen_type_t msg_type, + uint32_t max_attr_size, + uint32_t max_seg_size, + bool is_issuer, TNC_UInt32 issuer_id, + bool is_imc); + +#endif /** SEG_CONTRACT_H_ @}*/ diff --git a/src/libimcv/seg/seg_contract_manager.c b/src/libimcv/seg/seg_contract_manager.c new file mode 100644 index 000000000..604c51134 --- /dev/null +++ b/src/libimcv/seg/seg_contract_manager.c @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#include "seg_contract_manager.h" + +typedef struct private_seg_contract_manager_t private_seg_contract_manager_t; + +/** + * Private data of a seg_contract_manager_t object. + * + */ +struct private_seg_contract_manager_t { + + /** + * Public seg_contract_manager_t interface. + */ + seg_contract_manager_t public; + + /** + * List of PA-TNC segmentation contracts + */ + linked_list_t *contracts; + +}; + +METHOD(seg_contract_manager_t, add_contract, void, + private_seg_contract_manager_t *this, seg_contract_t *contract) +{ + this->contracts->insert_last(this->contracts, contract); +} + +METHOD(seg_contract_manager_t, get_contract, seg_contract_t*, + private_seg_contract_manager_t *this, pen_type_t msg_type, bool is_issuer, + TNC_UInt32 id) +{ + enumerator_t *enumerator; + seg_contract_t *contract, *found = NULL; + + enumerator = this->contracts->create_enumerator(this->contracts); + while (enumerator->enumerate(enumerator, &contract)) + { + if (contract->is_issuer(contract) == is_issuer && + pen_type_equals(contract->get_msg_type(contract), msg_type) && + id == (is_issuer ? contract->get_responder(contract) : + contract->get_issuer(contract))) + { + found = contract; + break; + } + } + enumerator->destroy(enumerator); + + return found; +} + +METHOD(seg_contract_manager_t, destroy, void, + private_seg_contract_manager_t *this) +{ + this->contracts->destroy_offset(this->contracts, + offsetof(seg_contract_t, destroy)); + free(this); +} + +/** + * See header + */ +seg_contract_manager_t *seg_contract_manager_create(void) +{ + private_seg_contract_manager_t *this; + + INIT(this, + .public = { + .add_contract = _add_contract, + .get_contract = _get_contract, + .destroy = _destroy, + }, + .contracts = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/libimcv/seg/seg_contract_manager.h b/src/libimcv/seg/seg_contract_manager.h new file mode 100644 index 000000000..fa9d23c0f --- /dev/null +++ b/src/libimcv/seg/seg_contract_manager.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/** + * @defgroup seg_contract_manager seg_contract_manager + * @{ @ingroup libimcv_seg + */ + +#ifndef SEG_CONTRACT_MANAGER_H_ +#define SEG_CONTRACT_MANAGER_H_ + +typedef struct seg_contract_manager_t seg_contract_manager_t; + +#include "seg_contract.h" + +/** + * Interface for a PA-TNC attribute segmentation contract manager + * + */ +struct seg_contract_manager_t { + + /** + * Add segmentation contract + * + * @param contract Segmentation contract to be added + */ + void (*add_contract)(seg_contract_manager_t *this, seg_contract_t *contract); + + /** + * Get segmentation contract + * + * @param msg_type PA-TNC message type governed by contract + * @param is_issuer If TRUE get only issuer contracts + * @param id Match either issuer or responder ID + */ + seg_contract_t* (*get_contract)(seg_contract_manager_t *this, + pen_type_t msg_type, bool is_issuer, + TNC_UInt32 id); + + /** + * Destroys a seg_contract_manager_t object. + */ + void (*destroy)(seg_contract_manager_t *this); +}; + +/** + * Create a PA-TNC attribute segmentation contract manager + */ +seg_contract_manager_t* seg_contract_manager_create(); + +#endif /** SEG_CONTRACT_MANAGER_H_ @}*/ diff --git a/src/libimcv/seg/seg_env.c b/src/libimcv/seg/seg_env.c new file mode 100644 index 000000000..c47ce2934 --- /dev/null +++ b/src/libimcv/seg/seg_env.c @@ -0,0 +1,306 @@ +/* + * 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. + */ + +#include "seg_env.h" + +#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> +#include <bio/bio_reader.h> +#include <bio/bio_writer.h> + +#define BASE_ATTR_ID_PREFIX 0xFF + +typedef struct private_seg_env_t private_seg_env_t; + +/** + * Private data of a seg_env_t object. + */ +struct private_seg_env_t { + + /** + * Public seg_env_t interface. + */ + seg_env_t public; + + /** + * Base Attribute ID + */ + uint32_t base_attr_id; + + /** + * Base Attribute + */ + pa_tnc_attr_t *base_attr; + + /** + * Base Attribute Info to be used for PA-TNC error messages + */ + u_char base_attr_info[8]; + + /** + * Base Attribute needs more segment data + */ + bool need_more; + + /** + * 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, + private_seg_env_t *this) +{ + return this->base_attr_id; +} + +METHOD(seg_env_t, get_base_attr, pa_tnc_attr_t*, + private_seg_env_t *this) +{ + return this->need_more ? NULL : this->base_attr->get_ref(this->base_attr); +} + +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*, + private_seg_env_t *this) +{ + pa_tnc_attr_t *seg_env_attr; + bio_writer_t *writer; + pen_type_t type; + chunk_t segment_data, value; + uint8_t flags, seg_env_flags; + + /* 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; + type = this->base_attr->get_type(this->base_attr); + + /* attribute data going into the first segment */ + segment_data = this->data; + segment_data.len = this->max_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); + writer->write_uint8 (writer, flags); + writer->write_uint24(writer, type.vendor_id); + writer->write_uint32(writer, type.type); + writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + this->data.len); + writer->write_data (writer, segment_data); + value = writer->extract_buf(writer); + writer->destroy(writer); + 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); + + seg_env_flags = SEG_ENV_FLAG_START | SEG_ENV_FLAG_MORE; + seg_env_attr = tcg_seg_attr_seg_env_create(value, seg_env_flags, + this->base_attr_id); + chunk_free(&value); + + return seg_env_attr; +} + +METHOD(seg_env_t, next_segment, pa_tnc_attr_t*, + private_seg_env_t *this, bool *last) +{ + pa_tnc_attr_t *seg_env_attr; + chunk_t segment_data; + uint8_t seg_env_flags; + bool is_last_segment; + + if (this->data.len == 0) + { + /* no more attribute data to segment available */ + return NULL; + } + + /* attribute data going into the next segment */ + segment_data = this->data; + segment_data.len = min(this->max_seg_size, this->data.len); + this->data = chunk_skip(this->data, segment_data.len); + + is_last_segment = (this->data.len == 0); + if (last) + { + *last = is_last_segment; + } + DBG2(DBG_TNC, "creating %s segment for base attribute ID %d (%d bytes)", + is_last_segment ? "last" : "next", this->base_attr_id, + segment_data.len); + + seg_env_flags = is_last_segment ? SEG_ENV_FLAG_NONE : SEG_ENV_FLAG_MORE; + seg_env_attr = tcg_seg_attr_seg_env_create(segment_data, seg_env_flags, + this->base_attr_id); + + return seg_env_attr; +} + +METHOD(seg_env_t, add_segment, bool, + private_seg_env_t *this, chunk_t segment, pa_tnc_attr_t **error) +{ + pen_type_t type, error_code; + uint32_t attr_offset; + chunk_t msg_info; + status_t status; + + 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) +{ + DESTROY_IF(this->base_attr); + free(this); +} + +/** + * See header + */ +seg_env_t *seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr, + uint32_t max_seg_size) +{ + private_seg_env_t *this; + chunk_t value; + + base_attr->build(base_attr); + value = base_attr->get_value(base_attr); + + /** + * The PA-TNC attribute header must not be segmented and + * there must be at least a first and one next segment + */ + if (max_seg_size < PA_TNC_ATTR_HEADER_SIZE || + max_seg_size >= PA_TNC_ATTR_HEADER_SIZE + value.len) + { + return NULL; + } + + 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, + .destroy = _destroy, + }, + .base_attr_id = base_attr_id, + .base_attr = base_attr->get_ref(base_attr), + .max_seg_size = max_seg_size, + .data = base_attr->get_value(base_attr), + ); + + return &this->public; +} + +/** + * See header + */ +seg_env_t *seg_env_create_from_data(uint32_t base_attr_id, chunk_t data, + 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, + .destroy = _destroy, + }, + .base_attr_id = base_attr_id, + .max_seg_size = max_seg_size, + ); + + /* 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; +} + diff --git a/src/libimcv/seg/seg_env.h b/src/libimcv/seg/seg_env.h new file mode 100644 index 000000000..08d33d752 --- /dev/null +++ b/src/libimcv/seg/seg_env.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +/** + * @defgroup seg_env seg_env + * @{ @ingroup libimcv_seg + */ + +#ifndef SEG_ENV_H_ +#define SEG_ENV_H_ + +typedef struct seg_env_t seg_env_t; +typedef enum seg_env_flags_t seg_env_flags_t; + +#include <library.h> + +#include <pa_tnc/pa_tnc_attr.h> + +/** + * Segment Envelope flags + */ +enum seg_env_flags_t { + SEG_ENV_FLAG_NONE = 0, + SEG_ENV_FLAG_MORE = (1<<7), + SEG_ENV_FLAG_START = (1<<6) +}; + +/** + * Interface for a PA-TNC attribute segment envelope object + */ +struct seg_env_t { + + /** + * Get Base Attribute ID + * + * @return Base Attribute ID + */ + uint32_t (*get_base_attr_id)(seg_env_t *this); + + /** + * Get Base Attribute if it contains processed [incremental] data + * + * @return Base Attribute (must be destroyed) or NULL + */ + 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 + * + * @return First attribute segment envelope + */ + pa_tnc_attr_t* (*first_segment)(seg_env_t *this); + + /** + * Generate the next segment envelope of the base attribute + * + * @param last TRUE if last segment + * @return Next attribute segment envelope + */ + pa_tnc_attr_t* (*next_segment)(seg_env_t *this, bool *last); + + /** + * 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 + */ + bool (*add_segment)(seg_env_t *this, chunk_t segment, + pa_tnc_attr_t** error); + + /** + * Destroys a seg_env_t object. + */ + void (*destroy)(seg_env_t *this); +}; + +/** + * Create a PA-TNC attribute segment envelope object + * + * @param base_attr_id Base Attribute ID + * @param base_attr Base Attribute to be segmented + * @param max_seg_size Maximum segment size + */ +seg_env_t* seg_env_create(uint32_t base_attr_id, pa_tnc_attr_t *base_attr, + uint32_t max_seg_size); + +/** + * Create a PA-TNC attribute segment envelope 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, + pa_tnc_attr_t** error); + +#endif /** SEG_ENV_H_ @}*/ |