diff options
24 files changed, 1660 insertions, 320 deletions
diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index 8b3ca5daa..37041d2b2 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -56,8 +56,9 @@ libimcv_la_SOURCES = \ pa_tnc/pa_tnc_attr.h \ pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \ pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c \ - seg_contract/seg_contract.h seg_contract/seg_contract.c \ - seg_contract/seg_contract_manager.h seg_contract/seg_contract_manager.c + seg/seg_contract.h seg/seg_contract.c \ + seg/seg_contract_manager.h seg/seg_contract_manager.c \ + seg/seg_env.h seg/seg_env.c ipsec_SCRIPTS = imv/_imv_policy EXTRA_DIST = imv/_imv_policy Android.mk diff --git a/src/libimcv/imc/imc_msg.c b/src/libimcv/imc/imc_msg.c index 9b9aeca23..3f2d7aed5 100644 --- a/src/libimcv/imc/imc_msg.c +++ b/src/libimcv/imc/imc_msg.c @@ -24,6 +24,7 @@ #include <tcg/seg/tcg_seg_attr_max_size.h> #include <tcg/seg/tcg_seg_attr_seg_env.h> +#include <tcg/seg/tcg_seg_attr_next_seg.h> #include <pen/pen.h> #include <collections/linked_list.h> @@ -108,11 +109,17 @@ METHOD(imc_msg_t, send_, TNC_Result, pa_tnc_attr_t *attr; TNC_UInt32 msg_flags; TNC_MessageType msg_type; - bool attr_added; + bool attr_added, oversize; chunk_t msg; + seg_contract_t *contract; + seg_contract_manager_t *contracts; enumerator_t *enumerator; TNC_Result result = TNC_RESULT_SUCCESS; + /* Get IF-M segmentation contract for this subtype if any */ + contracts = this->state->get_contracts(this->state); + contract = contracts->get_contract(contracts, this->msg_type, FALSE); + while (this->attr_list->get_count(this->attr_list)) { pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state)); @@ -121,6 +128,17 @@ METHOD(imc_msg_t, send_, TNC_Result, enumerator = this->attr_list->create_enumerator(this->attr_list); while (enumerator->enumerate(enumerator, &attr)) { + if (contract && contract->check_size(contract, attr, &oversize)) + { + if (oversize) + { + /* TODO generate SWID error msg */ + } + else + { + attr = contract->first_segment(contract, attr); + } + } if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr)) { attr_added = TRUE; @@ -274,7 +292,6 @@ METHOD(imc_msg_t, receive, TNC_Result, enumerator = this->pa_msg->create_attribute_enumerator(this->pa_msg); while (enumerator->enumerate(enumerator, &attr)) { - tcg_seg_attr_max_size_t *attr_cast; uint32_t max_attr_size, max_seg_size, my_max_attr_size, my_max_seg_size; seg_contract_t *contract; seg_contract_manager_t *contracts; @@ -283,79 +300,160 @@ METHOD(imc_msg_t, receive, TNC_Result, type = attr->get_type(attr); + contracts = this->state->get_contracts(this->state); + if (type.vendor_id != PEN_TCG) { continue; } - if (type.type == TCG_SEG_MAX_ATTR_SIZE_REQ) + switch (type.type) { - attr_cast = (tcg_seg_attr_max_size_t*)attr; - attr_cast->get_attr_size(attr_cast, &max_attr_size, &max_seg_size); - - contracts = this->state->get_contracts(this->state); - contract = contracts->get_contract(contracts, this->msg_type, FALSE); - if (contract) - { - contract->set_max_size(contract, max_attr_size, max_seg_size); - } - else + case TCG_SEG_MAX_ATTR_SIZE_REQ: { - contract = seg_contract_create(this->msg_type, max_attr_size, + tcg_seg_attr_max_size_t *attr_cast; + + attr_cast = (tcg_seg_attr_max_size_t*)attr; + attr_cast->get_attr_size(attr_cast, &max_attr_size, + &max_seg_size); + contract = contracts->get_contract(contracts, this->msg_type, + FALSE); + if (contract) + { + contract->set_max_size(contract, max_attr_size, + max_seg_size); + } + else + { + contract = seg_contract_create(this->msg_type, max_attr_size, max_seg_size, FALSE, this->src_id, TRUE); - contracts->add_contract(contracts, contract); + contracts->add_contract(contracts, contract); + } + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMC, "%s", buf); + + /* Determine maximum PA-TNC attribute segment size */ + 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; + + /* If segmentation is possible select lower segment size */ + if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && + max_seg_size > my_max_seg_size) + { + max_seg_size = my_max_seg_size; + contract->set_max_size(contract, max_attr_size, + max_seg_size); + DBG2(DBG_IMC, " lowered maximum segment size to %u bytes", + max_seg_size); + } + + /* Add Maximum Attribute Size Response attribute */ + attr = tcg_seg_attr_max_size_create(max_attr_size, + max_seg_size, FALSE); + out_msg->add_attribute(out_msg, attr); + break; } - contract->get_info_string(contract, buf, BUF_LEN, TRUE); - DBG2(DBG_IMC, "%s", buf); - - /* Determine maximum PA-TNC attribute segment size */ - 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; - - /* If segmentation is not prohibited select lower segment size */ - if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && - max_seg_size > my_max_seg_size) + case TCG_SEG_MAX_ATTR_SIZE_RESP: { - max_seg_size = my_max_seg_size; - contract->set_max_size(contract, max_attr_size, max_seg_size); - DBG2(DBG_IMC, " lowered maximum segment size to %u bytes", - max_seg_size); + tcg_seg_attr_max_size_t *attr_cast; + + attr_cast = (tcg_seg_attr_max_size_t*)attr; + attr_cast->get_attr_size(attr_cast, &max_attr_size, + &max_seg_size); + contract = contracts->get_contract(contracts, this->msg_type, + TRUE); + if (contract) + { + contract->get_max_size(contract, &my_max_attr_size, + &my_max_seg_size); + if (my_max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && + my_max_seg_size > max_seg_size) + { + my_max_seg_size = max_seg_size; + contract->set_max_size(contract, my_max_attr_size, + my_max_seg_size); + } + contract->get_info_string(contract, buf, BUF_LEN, FALSE); + DBG2(DBG_IMC, "%s", buf); + } + else + { + /* TODO no request pending */ + DBG1(DBG_IMC, "no contract for this PA message type found"); + } + break; } + case TCG_SEG_ATTR_SEG_ENV: + { + tcg_seg_attr_seg_env_t *seg_env_attr; + pa_tnc_attr_t *error; + uint32_t base_attr_id; + bool more; - /* Add Maximum Attribute Size Response attribute */ - attr = tcg_seg_attr_max_size_create(max_attr_size, - max_seg_size, FALSE); - out_msg->add_attribute(out_msg, attr); - } - else if (type.type == TCG_SEG_MAX_ATTR_SIZE_RESP) - { - attr_cast = (tcg_seg_attr_max_size_t*)attr; - attr_cast->get_attr_size(attr_cast, &max_attr_size, &max_seg_size); + seg_env_attr = (tcg_seg_attr_seg_env_t*)attr; + base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr); - contracts = this->state->get_contracts(this->state); - contract = contracts->get_contract(contracts, this->msg_type, TRUE); - if (contract) - { - contract->get_max_size(contract, &my_max_attr_size, - &my_max_seg_size); - if (my_max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && - my_max_seg_size > max_seg_size) + contract = contracts->get_contract(contracts, this->msg_type, + TRUE); + if (!contract) { - my_max_seg_size = max_seg_size; - contract->set_max_size(contract, my_max_attr_size, - my_max_seg_size); - contract->get_info_string(contract, buf, BUF_LEN, FALSE); - DBG2(DBG_IMC, "%s", buf); + DBG2(DBG_IMC, "no contract for received attribute segment " + "with base attribute ID %u", base_attr_id); + continue; + } + attr = contract->add_segment(contract, attr, &error, &more); + if (error) + { + out_msg->add_attribute(out_msg, error); + } + if (attr) + { + this->pa_msg->add_attribute(this->pa_msg, attr); } + if (more) + { + /* Send Next Segment Request */ + attr = tcg_seg_attr_next_seg_create(base_attr_id, FALSE); + out_msg->add_attribute(out_msg, attr); + } + break; } - else + case TCG_SEG_NEXT_SEG_REQ: { - /* TODO no request pending */ + tcg_seg_attr_next_seg_t *attr_cast; + uint32_t base_attr_id; + + attr_cast = (tcg_seg_attr_next_seg_t*)attr; + base_attr_id = attr_cast->get_base_attr_id(attr_cast); + + contract = contracts->get_contract(contracts, this->msg_type, + FALSE); + if (!contract) + { + /* TODO no contract - generate error message */ + DBG2(DBG_IMC, "no contract for received next segment " + "request with base attribute ID %u", base_attr_id); + continue; + } + attr = contract->next_segment(contract, base_attr_id); + if (attr) + { + out_msg->add_attribute(out_msg, attr); + } + else + { + /* TODO no more segments - generate error message */ + DBG1(DBG_IMC, "no more segments found for " + "base attribute ID %u", base_attr_id); + } + break; } + default: + break; } } enumerator->destroy(enumerator); diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h index e3e83a3b9..efcf567f0 100644 --- a/src/libimcv/imc/imc_state.h +++ b/src/libimcv/imc/imc_state.h @@ -22,7 +22,7 @@ #ifndef IMC_STATE_H_ #define IMC_STATE_H_ -#include "seg_contract/seg_contract_manager.h" +#include "seg/seg_contract_manager.h" #include <tncif.h> #include <tncifimv.h> diff --git a/src/libimcv/imv/imv_msg.c b/src/libimcv/imv/imv_msg.c index 35209dc18..b32b01c06 100644 --- a/src/libimcv/imv/imv_msg.c +++ b/src/libimcv/imv/imv_msg.c @@ -24,6 +24,7 @@ #include <tcg/seg/tcg_seg_attr_max_size.h> #include <tcg/seg/tcg_seg_attr_seg_env.h> +#include <tcg/seg/tcg_seg_attr_next_seg.h> #include <pen/pen.h> #include <collections/linked_list.h> @@ -125,11 +126,17 @@ METHOD(imv_msg_t, send_, TNC_Result, pa_tnc_attr_t *attr; TNC_UInt32 msg_flags; TNC_MessageType msg_type; - bool attr_added; + bool attr_added, oversize; chunk_t msg; + seg_contract_t *contract; + seg_contract_manager_t *contracts; enumerator_t *enumerator; TNC_Result result = TNC_RESULT_SUCCESS; + /* Get IF-M segmentation contract for this subtype if any */ + contracts = this->state->get_contracts(this->state); + contract = contracts->get_contract(contracts, this->msg_type, FALSE); + while (this->attr_list->get_count(this->attr_list)) { pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state)); @@ -138,6 +145,17 @@ METHOD(imv_msg_t, send_, TNC_Result, enumerator = this->attr_list->create_enumerator(this->attr_list); while (enumerator->enumerate(enumerator, &attr)) { + if (contract && contract->check_size(contract, attr, &oversize)) + { + if (oversize) + { + /* TODO generate SWID error msg */ + } + else + { + attr = contract->first_segment(contract, attr); + } + } if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr)) { attr_added = TRUE; @@ -317,15 +335,14 @@ METHOD(imv_msg_t, receive, TNC_Result, return TNC_RESULT_FATAL; } - /* process any IF-M segmentation contracts */ + /* process IF-M segmentation attributes */ enumerator = this->pa_msg->create_attribute_enumerator(this->pa_msg); while (enumerator->enumerate(enumerator, &attr)) { uint32_t max_attr_size, max_seg_size, my_max_attr_size, my_max_seg_size; - tcg_seg_attr_max_size_t *attr_cast; imv_msg_t *out_msg; - seg_contract_t *contract; seg_contract_manager_t *contracts; + seg_contract_t *contract; char buf[BUF_LEN]; pen_type_t type; @@ -336,81 +353,169 @@ METHOD(imv_msg_t, receive, TNC_Result, continue; } - if (type.type == TCG_SEG_MAX_ATTR_SIZE_REQ) - { - attr_cast = (tcg_seg_attr_max_size_t*)attr; - attr_cast->get_attr_size(attr_cast, &max_attr_size, &max_seg_size); + contracts = this->state->get_contracts(this->state); - contracts = this->state->get_contracts(this->state); - contract = contracts->get_contract(contracts, this->msg_type, FALSE); - if (contract) - { - contract->set_max_size(contract, max_attr_size, max_seg_size); - } - else + switch (type.type) + { + case TCG_SEG_MAX_ATTR_SIZE_REQ: { - contract = seg_contract_create(this->msg_type, max_attr_size, + tcg_seg_attr_max_size_t *attr_cast; + + attr_cast = (tcg_seg_attr_max_size_t*)attr; + attr_cast->get_attr_size(attr_cast, &max_attr_size, + &max_seg_size); + contract = contracts->get_contract(contracts, this->msg_type, + FALSE); + if (contract) + { + contract->set_max_size(contract, max_attr_size, + max_seg_size); + } + else + { + contract = seg_contract_create(this->msg_type, max_attr_size, max_seg_size, FALSE, this->src_id, FALSE); - contracts->add_contract(contracts, contract); - } - contract->get_info_string(contract, buf, BUF_LEN, TRUE); - DBG2(DBG_IMV, "%s", buf); - - /* Determine maximum PA-TNC attribute segment size */ - 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; - - /* If segmentation is not prohibited select lower segment size */ - if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && - max_seg_size > my_max_seg_size) - { - max_seg_size = my_max_seg_size; - contract->set_max_size(contract, max_attr_size, max_seg_size); - DBG2(DBG_IMV, " lowered maximum segment size to %u bytes", - max_seg_size); - } + contracts->add_contract(contracts, contract); + } + contract->get_info_string(contract, buf, BUF_LEN, TRUE); + DBG2(DBG_IMV, "%s", buf); + + /* Determine maximum PA-TNC attribute segment size */ + 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; + + /* If segmentation is possible select lower segment size */ + if (max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && + max_seg_size > my_max_seg_size) + { + max_seg_size = my_max_seg_size; + contract->set_max_size(contract, max_attr_size, + max_seg_size); + DBG2(DBG_IMV, " lowered maximum segment size to %u bytes", + max_seg_size); + } - /* Send Maximum Attribute Size Response */ - out_msg = imv_msg_create_as_reply(&this->public); - attr = tcg_seg_attr_max_size_create(max_attr_size, - max_seg_size, FALSE); - out_msg->add_attribute(out_msg, attr); - result = out_msg->send(out_msg, TRUE); - out_msg->destroy(out_msg); - if (result != TNC_RESULT_SUCCESS) - { + /* Send Maximum Attribute Size Response */ + out_msg = imv_msg_create_as_reply(&this->public); + attr = tcg_seg_attr_max_size_create(max_attr_size, + max_seg_size, FALSE); + out_msg->add_attribute(out_msg, attr); + result = out_msg->send(out_msg, TRUE); + out_msg->destroy(out_msg); + if (result != TNC_RESULT_SUCCESS) + { + break; + } break; } - } - else if (type.type == TCG_SEG_MAX_ATTR_SIZE_RESP) - { - attr_cast = (tcg_seg_attr_max_size_t*)attr; - attr_cast->get_attr_size(attr_cast, &max_attr_size, &max_seg_size); - - contracts = this->state->get_contracts(this->state); - contract = contracts->get_contract(contracts, this->msg_type, TRUE); - if (contract) + case TCG_SEG_MAX_ATTR_SIZE_RESP: { - contract->get_max_size(contract, &my_max_attr_size, - &my_max_seg_size); - if (my_max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && - my_max_seg_size > max_seg_size) + tcg_seg_attr_max_size_t *attr_cast; + + attr_cast = (tcg_seg_attr_max_size_t*)attr; + attr_cast->get_attr_size(attr_cast, &max_attr_size, + &max_seg_size); + contract = contracts->get_contract(contracts, this->msg_type, + TRUE); + if (contract) { - my_max_seg_size = max_seg_size; - contract->set_max_size(contract, my_max_attr_size, - my_max_seg_size); + contract->get_max_size(contract, &my_max_attr_size, + &my_max_seg_size); + if (my_max_seg_size != SEG_CONTRACT_NO_FRAGMENTATION && + my_max_seg_size > max_seg_size) + { + my_max_seg_size = max_seg_size; + contract->set_max_size(contract, my_max_attr_size, + my_max_seg_size); + } contract->get_info_string(contract, buf, BUF_LEN, FALSE); DBG2(DBG_IMV, "%s", buf); } + else + { + /* TODO no request pending */ + DBG1(DBG_IMV, "no contract for this PA message type found"); + } + break; } - else + case TCG_SEG_ATTR_SEG_ENV: + { + tcg_seg_attr_seg_env_t *seg_env_attr; + pa_tnc_attr_t *error; + uint32_t base_attr_id; + bool more; + + seg_env_attr = (tcg_seg_attr_seg_env_t*)attr; + base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr); + + contract = contracts->get_contract(contracts, this->msg_type, + TRUE); + if (!contract) + { + DBG2(DBG_IMV, "no contract for received attribute segment " + "with base attribute ID %u", base_attr_id); + continue; + } + attr = contract->add_segment(contract, attr, &error, &more); + if (error) + { + out_msg = imv_msg_create_as_reply(&this->public); + out_msg->add_attribute(out_msg, error); + result = out_msg->send(out_msg, TRUE); + out_msg->destroy(out_msg); + } + if (attr) + { + this->pa_msg->add_attribute(this->pa_msg, attr); + } + if (more) + { + /* Send Next Segment Request */ + out_msg = imv_msg_create_as_reply(&this->public); + attr = tcg_seg_attr_next_seg_create(base_attr_id, FALSE); + out_msg->add_attribute(out_msg, attr); + result = out_msg->send(out_msg, TRUE); + out_msg->destroy(out_msg); + } + break; + } + case TCG_SEG_NEXT_SEG_REQ: { - /* TODO no request pending */ + tcg_seg_attr_next_seg_t *attr_cast; + uint32_t base_attr_id; + + attr_cast = (tcg_seg_attr_next_seg_t*)attr; + base_attr_id = attr_cast->get_base_attr_id(attr_cast); + + contract = contracts->get_contract(contracts, this->msg_type, + FALSE); + if (!contract) + { + /* TODO no contract - generate error message */ + DBG2(DBG_IMV, "no contract for received next segment " + "request with base attribute ID %u", base_attr_id); + continue; + } + attr = contract->next_segment(contract, base_attr_id); + if (attr) + { + out_msg = imv_msg_create_as_reply(&this->public); + out_msg->add_attribute(out_msg, attr); + result = out_msg->send(out_msg, TRUE); + out_msg->destroy(out_msg); + } + else + { + /* TODO no more segments - generate error message */ + } + break; } + default: + break; } } enumerator->destroy(enumerator); diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index 3a93a5f95..30ed612b3 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -23,7 +23,7 @@ #define IMV_STATE_H_ #include "imv_session.h" -#include "seg_contract/seg_contract_manager.h" +#include "seg/seg_contract_manager.h" #include <tncifimv.h> diff --git a/src/libimcv/pa_tnc/pa_tnc_attr.h b/src/libimcv/pa_tnc/pa_tnc_attr.h index 1e0c339c9..a5296692c 100644 --- a/src/libimcv/pa_tnc/pa_tnc_attr.h +++ b/src/libimcv/pa_tnc/pa_tnc_attr.h @@ -28,6 +28,9 @@ typedef struct pa_tnc_attr_t pa_tnc_attr_t; #define PA_TNC_ATTR_HEADER_SIZE 12 +#define PA_TNC_ATTR_FLAG_NONE 0x00 +#define PA_TNC_ATTR_FLAG_NOSKIP (1<<7) + /** * Interface for an RFC 5792 PA-TNC Posture Attribute. * diff --git a/src/libimcv/pa_tnc/pa_tnc_attr_manager.c b/src/libimcv/pa_tnc/pa_tnc_attr_manager.c index 900a55716..7fae9a9dd 100644 --- a/src/libimcv/pa_tnc/pa_tnc_attr_manager.c +++ b/src/libimcv/pa_tnc/pa_tnc_attr_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * * HSR Hochschule fuer Technik Rapperswil * @@ -16,6 +16,10 @@ #include "pa_tnc_attr_manager.h" +#include "imcv.h" +#include "pa_tnc_attr.h" +#include "ietf/ietf_attr_pa_tnc_error.h" + #include <collections/linked_list.h> #include <utils/debug.h> @@ -100,14 +104,102 @@ METHOD(pa_tnc_attr_manager_t, get_names, enum_name_t*, return attr_names; } +/** + * PA-TNC attribute + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Flags | PA-TNC Attribute Vendor ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Attribute Value (Variable Length) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#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, pen_t vendor_id, u_int32_t type, - chunk_t value) + private_pa_tnc_attr_manager_t *this, bio_reader_t *reader, uint32_t *offset, + chunk_t msg_info, pa_tnc_attr_t **error) { + uint8_t flags; + uint32_t type, length, attr_offset; + chunk_t value; + ietf_attr_pa_tnc_error_t *error_attr; + pen_t vendor_id; + pen_type_t unsupported_type; + pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER }; + enum_name_t *pa_attr_names; + pa_tnc_attr_t *attr = NULL; enumerator_t *enumerator; entry_t *entry; - pa_tnc_attr_t *attr = NULL; + /* properly initialize error return argument in case of no error */ + *error = NULL; + + if (reader->remaining(reader) < PA_TNC_ATTR_HEADER_SIZE) + { + DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute header"); + *error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + msg_info, *offset); + return NULL; + } + reader->read_uint8 (reader, &flags); + reader->read_uint24(reader, &vendor_id); + reader->read_uint32(reader, &type); + reader->read_uint32(reader, &length); + + pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes, + vendor_id); + if (pa_attr_names) + { + DBG2(DBG_TNC, "processing PA-TNC attribute type '%N/%N' " + "0x%06x/0x%08x", pen_names, vendor_id, + pa_attr_names, type, vendor_id, type); + } + else + { + DBG2(DBG_TNC, "processing PA-TNC attribute type '%N' " + "0x%06x/0x%08x", pen_names, vendor_id, + vendor_id, type); + } + + if (length < PA_TNC_ATTR_HEADER_SIZE) + { + DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length", + length); + *error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + msg_info, *offset + PA_TNC_ATTR_INFO_SIZE); + return NULL; + } + + if (!reader->read_data(reader, length - PA_TNC_ATTR_HEADER_SIZE, &value)) + { + DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value"); + *error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + msg_info, *offset + PA_TNC_ATTR_INFO_SIZE); + return NULL; + } + DBG3(DBG_TNC, "%B", &value); + + if (vendor_id == PEN_RESERVED) + { + *error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + msg_info, *offset + 1); + return NULL; + } + if (type == IETF_ATTR_RESERVED) + { + *error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + msg_info, *offset + 4); + return NULL; + } + + /* check if the attribute type is registered */ enumerator = this->list->create_enumerator(this->list); while (enumerator->enumerate(enumerator, &entry)) { @@ -122,6 +214,39 @@ METHOD(pa_tnc_attr_manager_t, create, pa_tnc_attr_t*, } enumerator->destroy(enumerator); + if (!attr) + { + if (!(flags & PA_TNC_ATTR_FLAG_NOSKIP)) + { + DBG1(DBG_TNC, "skipping unsupported PA-TNC attribute"); + offset += length; + return NULL; + } + + DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag"); + unsupported_type = pen_type_create(vendor_id, type); + error_code = pen_type_create(PEN_IETF, PA_ERROR_ATTR_TYPE_NOT_SUPPORTED); + *error = ietf_attr_pa_tnc_error_create(error_code, msg_info); + error_attr = (ietf_attr_pa_tnc_error_t*)(*error); + 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; + return attr; } diff --git a/src/libimcv/pa_tnc/pa_tnc_attr_manager.h b/src/libimcv/pa_tnc/pa_tnc_attr_manager.h index 121be7f90..0709c5b22 100644 --- a/src/libimcv/pa_tnc/pa_tnc_attr_manager.h +++ b/src/libimcv/pa_tnc/pa_tnc_attr_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2014 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ typedef struct pa_tnc_attr_manager_t pa_tnc_attr_manager_t; #include "pa_tnc_attr.h" #include <library.h> +#include <bio/bio_reader.h> typedef pa_tnc_attr_t* (*pa_tnc_attr_create_t)(u_int32_t type, chunk_t value); @@ -61,15 +62,17 @@ struct pa_tnc_attr_manager_t { enum_name_t* (*get_names)(pa_tnc_attr_manager_t *this, pen_t vendor_id); /** - * Create a PA-TNC attribute object from data for a given vendor ID and type + * Create and pre-parse a PA-TNC attribute object from data * - * @param vendor_id Private Enterprise Number (PEN) - * @param type PA-TNC attribute type - * @param value PA-TNC attribute value as encoded data + * @param reader PA-TNC attribute as encoded data + * @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, pen_t vendor_id, - u_int32_t type, chunk_t value); + pa_tnc_attr_t* (*create)(pa_tnc_attr_manager_t *this, bio_reader_t *reader, + uint32_t *offset, chunk_t msg_info, + pa_tnc_attr_t **error); /** * Destroys a pa_tnc_attr_manager_t object. diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c index 4cfb9bdd0..5a0afcdc0 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.c +++ b/src/libimcv/pa_tnc/pa_tnc_msg.c @@ -37,28 +37,6 @@ typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t; * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -#define PA_TNC_RESERVED 0x000000 - -/** - * PA-TNC attribute - * - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Flags | PA-TNC Attribute Vendor ID | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | PA-TNC Attribute Type | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | PA-TNC Attribute Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Attribute Value (Variable Length) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -#define PA_TNC_ATTR_FLAG_NONE 0x00 -#define PA_TNC_ATTR_FLAG_NOSKIP (1<<7) -#define PA_TNC_ATTR_INFO_SIZE 8 - /** * Private data of a pa_tnc_msg_t object. * @@ -96,6 +74,11 @@ struct private_pa_tnc_msg_t { size_t max_msg_len; /** + * TRUE if attribute was extracted from data + */ + bool from_data; + + /** * Encoded message */ chunk_t encoding; @@ -113,17 +96,19 @@ METHOD(pa_tnc_msg_t, add_attribute, bool, chunk_t attr_value; size_t attr_len; - attr->build(attr); - attr_value = attr->get_value(attr); - attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len; - - if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len) + if (!this->from_data) { - /* attribute just does not fit into this message */ - return FALSE; - } - this->msg_len += attr_len; + attr->build(attr); + attr_value = attr->get_value(attr); + attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len; + if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len) + { + /* attribute just does not fit into this message */ + return FALSE; + } + this->msg_len += attr_len; + } this->attributes->insert_last(this->attributes, attr); return TRUE; } @@ -201,9 +186,9 @@ METHOD(pa_tnc_msg_t, process, status_t, private_pa_tnc_msg_t *this) { bio_reader_t *reader; - pa_tnc_attr_t *error; + pa_tnc_attr_t *attr, *error; uint8_t version; - uint32_t reserved, offset, attr_offset; + uint32_t reserved, offset; pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER }; /* process message header */ @@ -231,116 +216,21 @@ METHOD(pa_tnc_msg_t, process, status_t, offset = PA_TNC_HEADER_SIZE; /* pre-process PA-TNC attributes */ - while (reader->remaining(reader) >= PA_TNC_ATTR_HEADER_SIZE) + while (reader->remaining(reader) > 0) { - pen_t vendor_id; - uint8_t flags; - uint32_t type, length; - chunk_t value; - pa_tnc_attr_t *attr; - enum_name_t *pa_attr_names; - ietf_attr_pa_tnc_error_t *error_attr; - pen_type_t unsupported_type; - - reader->read_uint8 (reader, &flags); - reader->read_uint24(reader, &vendor_id); - reader->read_uint32(reader, &type); - reader->read_uint32(reader, &length); - - pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes, - vendor_id); - if (pa_attr_names) - { - DBG2(DBG_TNC, "processing PA-TNC attribute type '%N/%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - pa_attr_names, type, vendor_id, type); - } - else - { - DBG2(DBG_TNC, "processing PA-TNC attribute type '%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - vendor_id, type); - } - - if (length < PA_TNC_ATTR_HEADER_SIZE) - { - DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length", - length); - error = ietf_attr_pa_tnc_error_create_with_offset(error_code, - this->encoding, offset + PA_TNC_ATTR_INFO_SIZE); - goto err; - } - - if (!reader->read_data(reader, length - PA_TNC_ATTR_HEADER_SIZE, &value)) - { - DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value"); - error = ietf_attr_pa_tnc_error_create_with_offset(error_code, - this->encoding, offset + PA_TNC_ATTR_INFO_SIZE); - goto err; - } - DBG3(DBG_TNC, "%B", &value); - - if (vendor_id == PEN_RESERVED) - { - error = ietf_attr_pa_tnc_error_create_with_offset(error_code, - this->encoding, offset + 1); - goto err; - } - if (type == IETF_ATTR_RESERVED) - { - error = ietf_attr_pa_tnc_error_create_with_offset(error_code, - this->encoding, offset + 4); - goto err; - } attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes, - vendor_id, type, value); - if (!attr) + reader, &offset, this->encoding, &error); + if (error) { - if (!(flags & PA_TNC_ATTR_FLAG_NOSKIP)) - { - DBG1(DBG_TNC, "skipping unsupported PA-TNC attribute"); - offset += length; - continue; - } - - DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag"); - unsupported_type = pen_type_create(vendor_id, type); - error_code = pen_type_create(PEN_IETF, - PA_ERROR_ATTR_TYPE_NOT_SUPPORTED); - error = ietf_attr_pa_tnc_error_create(error_code, this->encoding); - error_attr = (ietf_attr_pa_tnc_error_t*)error; - error_attr->set_unsupported_attr(error_attr, flags, unsupported_type); goto err; } - - if (attr->process(attr, &attr_offset) != SUCCESS) + if (attr) { - attr->destroy(attr); - if (vendor_id == PEN_IETF && type == IETF_ATTR_PA_TNC_ERROR) - { - /* error while processing a PA-TNC error attribute - abort */ - reader->destroy(reader); - return FAILED; - } - 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 + PA_TNC_ATTR_HEADER_SIZE + attr_offset); - goto err; + this->attributes->insert_last(this->attributes, attr); } - this->attributes->insert_last(this->attributes, attr); - offset += length; } - - if (reader->remaining(reader) == 0) - { - reader->destroy(reader); - return SUCCESS; - } - DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute header"); - error = ietf_attr_pa_tnc_error_create_with_offset(error_code, - this->encoding, offset); + reader->destroy(reader); + return SUCCESS; err: reader->destroy(reader); @@ -509,6 +399,7 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) .encoding = chunk_clone(data), .attributes = linked_list_create(), .errors = linked_list_create(), + .from_data = TRUE, ); return &this->public; diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h index 57ff1a04c..a33690890 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.h +++ b/src/libimcv/pa_tnc/pa_tnc_msg.h @@ -25,6 +25,9 @@ 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" diff --git a/src/libimcv/seg_contract/seg_contract.c b/src/libimcv/seg/seg_contract.c index dab2c239f..589d6d1cd 100644 --- a/src/libimcv/seg_contract/seg_contract.c +++ b/src/libimcv/seg/seg_contract.c @@ -14,16 +14,19 @@ */ #include "seg_contract.h" +#include "seg_env.h" #include <utils/debug.h> +#include <bio/bio_writer.h> #include <tncif_pa_subtypes.h> +#include <tcg/seg/tcg_seg_attr_seg_env.h> + typedef struct private_seg_contract_t private_seg_contract_t; /** * Private data of a seg_contract_t object. - * */ struct private_seg_contract_t { @@ -48,6 +51,17 @@ struct private_seg_contract_t { 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; @@ -97,6 +111,154 @@ METHOD(seg_contract_t, get_max_size, void, } } +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; + uint32_t base_attr_id; + uint8_t flags; + chunk_t segment_data; + 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; + if (!(*more)) + { + 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); + 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); + } + 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); + seg_env->add_segment(seg_env, segment_data); + } + if (*more) + { + return NULL; + } + 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) { @@ -206,6 +368,7 @@ METHOD(seg_contract_t, get_info_string, void, 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); } @@ -225,6 +388,10 @@ seg_contract_t *seg_contract_create(pen_type_t msg_type, .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, .get_info_string = _get_info_string, @@ -233,6 +400,7 @@ seg_contract_t *seg_contract_create(pen_type_t msg_type, .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, .is_imc = is_imc, diff --git a/src/libimcv/seg_contract/seg_contract.h b/src/libimcv/seg/seg_contract.h index 26f55c9ce..48828c472 100644 --- a/src/libimcv/seg_contract/seg_contract.h +++ b/src/libimcv/seg/seg_contract.h @@ -23,6 +23,8 @@ typedef struct seg_contract_t seg_contract_t; +#include "pa_tnc/pa_tnc_attr.h" + #include <library.h> #include <pen/pen.h> @@ -47,8 +49,8 @@ struct seg_contract_t { /** * 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 + * @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); @@ -56,33 +58,71 @@ struct seg_contract_t { /** * 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 + * @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 + * @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 + * @return TRUE if null contract */ bool (*is_null)(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 + * @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); @@ -96,7 +136,7 @@ struct seg_contract_t { /** * Create a PA-TNC attribute segmentation contract * - * @param msg_type PA-TNC message type + * @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 diff --git a/src/libimcv/seg_contract/seg_contract_manager.c b/src/libimcv/seg/seg_contract_manager.c index d099436fc..d099436fc 100644 --- a/src/libimcv/seg_contract/seg_contract_manager.c +++ b/src/libimcv/seg/seg_contract_manager.c diff --git a/src/libimcv/seg_contract/seg_contract_manager.h b/src/libimcv/seg/seg_contract_manager.h index 355822d99..355822d99 100644 --- a/src/libimcv/seg_contract/seg_contract_manager.h +++ b/src/libimcv/seg/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..1f4cfc53f --- /dev/null +++ b/src/libimcv/seg/seg_env.c @@ -0,0 +1,261 @@ +/* + * 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 <utils/debug.h> +#include <bio/bio_reader.h> +#include <bio/bio_writer.h> + +#include <tcg/seg/tcg_seg_attr_seg_env.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; + + /** + * Maximum PA-TNC attribute segment size + */ + uint32_t max_seg_size; + + /** + * TRUE if attribute is assembled from data + */ + bool from_data; + + /** + * Remaining attribute data to be sent or received data being accumulated + */ + chunk_t data; + +}; + +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, pa_tnc_attr_t** error) +{ + *error = NULL; + + 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, 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, void, + private_seg_env_t *this, chunk_t segment_data) +{ + this->data = chunk_cat("mc", this->data, segment_data); +} + +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); +} + +/** + * 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, + .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) +{ + private_seg_env_t *this; + + INIT(this, + .public = { + .get_base_attr_id = _get_base_attr_id, + .get_base_attr = _get_base_attr, + .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, + .data = chunk_clone(data), + .from_data = TRUE, + ); + + 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..0dcefdde8 --- /dev/null +++ b/src/libimcv/seg/seg_env.h @@ -0,0 +1,108 @@ +/* + * 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 + */ + +#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 + * + * @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); + + /** + * 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 + */ + void (*add_segment)(seg_env_t *this, chunk_t segment); + + /** + * 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 + */ +seg_env_t* seg_env_create_from_data(uint32_t base_attr_id, chunk_t data, + uint32_t max_seg_size); + +#endif /** SEG_ENV_H_ @}*/ diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index be5c26c50..f047b5233 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -70,7 +70,8 @@ libpts_la_SOURCES = \ tcg/pts/tcg_pts_attr_req_file_meta.h tcg/pts/tcg_pts_attr_req_file_meta.c \ tcg/pts/tcg_pts_attr_unix_file_meta.h tcg/pts/tcg_pts_attr_unix_file_meta.c \ tcg/seg/tcg_seg_attr_max_size.h tcg/seg/tcg_seg_attr_max_size.c \ - tcg/seg/tcg_seg_attr_seg_env.h \ + tcg/seg/tcg_seg_attr_seg_env.h tcg/seg/tcg_seg_attr_seg_env.c \ + tcg/seg/tcg_seg_attr_next_seg.h tcg/seg/tcg_seg_attr_next_seg.c \ tcg/swid/tcg_swid_attr_req.h tcg/swid/tcg_swid_attr_req.c \ tcg/swid/tcg_swid_attr_tag_id_inv.h tcg/swid/tcg_swid_attr_tag_id_inv.c \ tcg/swid/tcg_swid_attr_tag_inv.h tcg/swid/tcg_swid_attr_tag_inv.c diff --git a/src/libpts/plugins/imc_swid/imc_swid.c b/src/libpts/plugins/imc_swid/imc_swid.c index 5da367bd1..3763731a0 100644 --- a/src/libpts/plugins/imc_swid/imc_swid.c +++ b/src/libpts/plugins/imc_swid/imc_swid.c @@ -241,43 +241,15 @@ static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg, { tcg_swid_attr_tag_id_inv_t *swid_id_attr; swid_tag_id_t *tag_id; - chunk_t tag_creator, unique_sw_id, instance_id; - /* At least one TCG Tag ID Inventory attribute is sent */ - attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_ID_INV_MIN_SIZE; + /* Send a TCG Tag ID Inventory attribute */ attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1); swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr; enumerator = swid_inventory->create_enumerator(swid_inventory); while (enumerator->enumerate(enumerator, &tag_id)) { - tag_creator = tag_id->get_tag_creator(tag_id); - unique_sw_id = tag_id->get_unique_sw_id(tag_id, &instance_id); - entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len + - 2 + instance_id.len; - - if (attr_size + entry_size > max_attr_size) - { - if (first) - { - /** - * Send an ITA Start Angel attribute to the IMV signalling - * that multiple TGC SWID Tag ID Inventory attributes follow - */ - attr_angel = ita_attr_angel_create(TRUE); - msg->add_attribute(msg, attr_angel); - first = FALSE; - } - msg->add_attribute(msg, attr); - - /* create the next TCG SWID Tag ID Inventory attribute */ - attr_size = PA_TNC_ATTR_HEADER_SIZE + - TCG_SWID_TAG_ID_INV_MIN_SIZE; - attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1); - } - swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr; swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id)); - attr_size += entry_size; } enumerator->destroy(enumerator); } diff --git a/src/libpts/plugins/imv_attestation/build-database.sh b/src/libpts/plugins/imv_attestation/build-database.sh index b8d5037b1..980de47ff 100755 --- a/src/libpts/plugins/imv_attestation/build-database.sh +++ b/src/libpts/plugins/imv_attestation/build-database.sh @@ -2,7 +2,7 @@ p="Ubuntu 14.04 x86_64" a="x86_64-linux-gnu" -k="3.13.0-32-generic" +k="3.13.0-34-generic" for hash in sha1 sha256 do diff --git a/src/libpts/tcg/seg/tcg_seg_attr_next_seg.c b/src/libpts/tcg/seg/tcg_seg_attr_next_seg.c new file mode 100644 index 000000000..22934cc1f --- /dev/null +++ b/src/libpts/tcg/seg/tcg_seg_attr_next_seg.c @@ -0,0 +1,235 @@ +/* + * 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 "tcg_seg_attr_next_seg.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <utils/debug.h> + +typedef struct private_tcg_seg_attr_next_seg_t private_tcg_seg_attr_next_seg_t; + +typedef enum { + NEXT_SEG_FLAG_NONE = 0, + NEXT_SEG_FLAG_CANCEL = 1 +} next_seg_flags_t; + +/** + * Next Segment + * see TCG IF-M Segmentation Specification + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |C| Reserved | Base Attribute ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/** + * Private data of an tcg_seg_attr_next_seg_t object. + */ +struct private_tcg_seg_attr_next_seg_t { + + /** + * Public members of tcg_seg_attr_next_seg_t + */ + tcg_seg_attr_next_seg_t public; + + /** + * Vendor-specific attribute type + */ + pen_type_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Cancel flag + */ + bool cancel_flag; + + /** + * Base Attribute ID + */ + uint32_t base_attr_id; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_type, pen_type_t, + private_tcg_seg_attr_next_seg_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_seg_attr_next_seg_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_seg_attr_next_seg_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_seg_attr_next_seg_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_seg_attr_next_seg_t *this) +{ + bio_writer_t *writer; + + if (this->value.ptr) + { + return; + } + writer = bio_writer_create(TCG_SEG_ATTR_NEXT_SEG_SIZE); + writer->write_uint8 (writer, this->cancel_flag ? NEXT_SEG_FLAG_CANCEL : + NEXT_SEG_FLAG_NONE); + writer->write_uint24(writer, this->base_attr_id); + + this->value = writer->extract_buf(writer); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_seg_attr_next_seg_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + uint8_t flags; + + if (this->value.len < TCG_SEG_ATTR_NEXT_SEG_SIZE) + { + DBG1(DBG_TNC, "insufficient data for %N", tcg_attr_names, + this->type.type); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint8 (reader, &flags); + reader->read_uint24(reader, &this->base_attr_id); + reader->destroy(reader); + + this->cancel_flag = (flags & NEXT_SEG_FLAG_CANCEL); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_seg_attr_next_seg_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_seg_attr_next_seg_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(tcg_seg_attr_next_seg_t, get_base_attr_id, uint32_t, + private_tcg_seg_attr_next_seg_t *this) +{ + return this->base_attr_id; +} + +METHOD(tcg_seg_attr_next_seg_t, get_cancel_flag, bool, + private_tcg_seg_attr_next_seg_t *this) +{ + return this->cancel_flag; +} + +/** + * Described in header. + */ +pa_tnc_attr_t* tcg_seg_attr_next_seg_create(uint32_t base_attr_id, bool cancel) +{ + private_tcg_seg_attr_next_seg_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_base_attr_id = _get_base_attr_id, + .get_cancel_flag = _get_cancel_flag, + }, + .type = { PEN_TCG, TCG_SEG_NEXT_SEG_REQ }, + .base_attr_id = base_attr_id, + .cancel_flag = cancel, + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_seg_attr_next_seg_create_from_data(chunk_t data) +{ + private_tcg_seg_attr_next_seg_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_base_attr_id = _get_base_attr_id, + .get_cancel_flag = _get_cancel_flag, + }, + .type = { PEN_TCG, TCG_SEG_NEXT_SEG_REQ }, + .value = chunk_clone(data), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/seg/tcg_seg_attr_next_seg.h b/src/libpts/tcg/seg/tcg_seg_attr_next_seg.h new file mode 100644 index 000000000..c9f53f853 --- /dev/null +++ b/src/libpts/tcg/seg/tcg_seg_attr_next_seg.h @@ -0,0 +1,71 @@ +/* + * 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 tcg_seg_attr_next_seg tcg_seg_attr_next_seg + * @{ @ingroup tcg_attr + */ + +#ifndef TCG_SEG_ATTR_NEXT_SEG_H_ +#define TCG_SEG_ATTR_NEXT_SEG_H_ + +typedef struct tcg_seg_attr_next_seg_t tcg_seg_attr_next_seg_t; + +#include "tcg/tcg_attr.h" + +#define TCG_SEG_ATTR_NEXT_SEG_SIZE 4 + +/** + * Class implementing the TCG Segmentation Next Segment Attribute + */ +struct tcg_seg_attr_next_seg_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get Base Attribute ID + * + * @return Base Attribute ID + */ + uint32_t (*get_base_attr_id)(tcg_seg_attr_next_seg_t *this); + + /** + * Get the Cancel flag + * + * @return Cancel flag + */ + bool (*get_cancel_flag)(tcg_seg_attr_next_seg_t *this); + +}; + +/** + * Creates an tcg_seg_attr_next_seg_t object + * + * @param base_attr_id Base Attribute ID + * @param cancel If TRUE set Cancel flag + */ +pa_tnc_attr_t* tcg_seg_attr_next_seg_create(uint32_t base_attr_id, bool cancel); + +/** + * Creates an tcg_seg_attr_next_seg_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* tcg_seg_attr_next_seg_create_from_data(chunk_t value); + +#endif /** TCG_SEG_ATTR_NEXT_SEG_H_ @}*/ diff --git a/src/libpts/tcg/seg/tcg_seg_attr_seg_env.c b/src/libpts/tcg/seg/tcg_seg_attr_seg_env.c new file mode 100644 index 000000000..833111f8f --- /dev/null +++ b/src/libpts/tcg/seg/tcg_seg_attr_seg_env.c @@ -0,0 +1,234 @@ +/* + * 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 "tcg_seg_attr_seg_env.h" + +#include <pa_tnc/pa_tnc_msg.h> +#include <bio/bio_writer.h> +#include <bio/bio_reader.h> +#include <utils/debug.h> + +typedef struct private_tcg_seg_attr_seg_env_t private_tcg_seg_attr_seg_env_t; + +/** + * Attribute Segment Envelope + * see TCG IF-M Segmentation Specification + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |M|S| Reserved | Base Attribute ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Segment Value (Variable Length) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +/** + * Private data of an tcg_seg_attr_seg_env_t object. + */ +struct private_tcg_seg_attr_seg_env_t { + + /** + * Public members of tcg_seg_attr_seg_env_t + */ + tcg_seg_attr_seg_env_t public; + + /** + * Vendor-specific attribute type + */ + pen_type_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * PA-TNC segmentation flags + */ + uint8_t flags; + + /** + * Base Attribute ID + */ + uint32_t base_attr_id; + + /** + * Attribute value + */ + chunk_t segment; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_type, pen_type_t, + private_tcg_seg_attr_seg_env_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_tcg_seg_attr_seg_env_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_tcg_seg_attr_seg_env_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_tcg_seg_attr_seg_env_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_tcg_seg_attr_seg_env_t *this) +{ + /* constructor already allocated and built value */ + return; +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_tcg_seg_attr_seg_env_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + + if (this->value.len < TCG_SEG_ATTR_SEG_ENV_HEADER) + { + DBG1(DBG_TNC, "insufficient data for %N", tcg_attr_names, + this->type.type); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint8 (reader, &this->flags); + reader->read_uint24(reader, &this->base_attr_id); + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_tcg_seg_attr_seg_env_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_tcg_seg_attr_seg_env_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(tcg_seg_attr_seg_env_t, get_segment, chunk_t, + private_tcg_seg_attr_seg_env_t *this, uint8_t *flags) +{ + if (flags) + { + *flags = this->flags; + } + return chunk_skip(this->value, TCG_SEG_ATTR_SEG_ENV_HEADER); +} + +METHOD(tcg_seg_attr_seg_env_t, get_base_attr_id, uint32_t, + private_tcg_seg_attr_seg_env_t *this) +{ + return this->base_attr_id; +} + +/** + * Described in header. + */ +pa_tnc_attr_t* tcg_seg_attr_seg_env_create(chunk_t segment, uint8_t flags, + uint32_t base_attr_id) +{ + private_tcg_seg_attr_seg_env_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_base_attr_id = _get_base_attr_id, + .get_segment = _get_segment, + }, + .type = { PEN_TCG, TCG_SEG_ATTR_SEG_ENV }, + .flags = flags, + .base_attr_id = base_attr_id, + .value = chunk_alloc(TCG_SEG_ATTR_SEG_ENV_HEADER + segment.len), + .ref = 1, + ); + + htoun32(this->value.ptr, base_attr_id); + *this->value.ptr = flags; + memcpy(this->value.ptr + TCG_SEG_ATTR_SEG_ENV_HEADER, + segment.ptr, segment.len); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *tcg_seg_attr_seg_env_create_from_data(chunk_t data) +{ + private_tcg_seg_attr_seg_env_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_base_attr_id = _get_base_attr_id, + .get_segment = _get_segment, + }, + .type = { PEN_TCG, TCG_SEG_ATTR_SEG_ENV }, + .value = chunk_clone(data), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} diff --git a/src/libpts/tcg/seg/tcg_seg_attr_seg_env.h b/src/libpts/tcg/seg/tcg_seg_attr_seg_env.h index 84cac8c36..19184392b 100644 --- a/src/libpts/tcg/seg/tcg_seg_attr_seg_env.h +++ b/src/libpts/tcg/seg/tcg_seg_attr_seg_env.h @@ -37,22 +37,37 @@ struct tcg_seg_attr_seg_env_t { */ pa_tnc_attr_t pa_tnc_attribute; + /** + * Get enveloped attribute segment + * + * @param flags Segmentation flags + * @return Segment + */ + chunk_t (*get_segment)(tcg_seg_attr_seg_env_t *this, uint8_t *flags); + + /** + * Get Base Attribute ID + * + * @return Base Attribute ID + */ + uint32_t (*get_base_attr_id)(tcg_seg_attr_seg_env_t *this); + }; /** * Creates an tcg_seg_attr_seg_env_t object * - * @param max_attr_size Maximum IF-M attribute size in octets - * @param max_seg_size Maximum IF-M attribute segment size in octets - * @param request TRUE for a request, FALSE for a response + * @param segment Attribute segment + * @param flags Segmentation flags + * @param base_attr_id Base Attribute ID */ -pa_tnc_attr_t* tcg_seg_attr_seg_env_create(chunk_t segment, uint8_t flags); +pa_tnc_attr_t* tcg_seg_attr_seg_env_create(chunk_t segment, uint8_t flags, + uint32_t base_attr_id); /** * Creates an tcg_seg_attr_seg_env_t object from received data * * @param value unparsed attribute value - * @param request TRUE for a request, FALSE for a response */ pa_tnc_attr_t* tcg_seg_attr_seg_env_create_from_data(chunk_t value); diff --git a/src/libpts/tcg/tcg_attr.c b/src/libpts/tcg/tcg_attr.c index 064b0ebc9..d4ae1da67 100644 --- a/src/libpts/tcg/tcg_attr.c +++ b/src/libpts/tcg/tcg_attr.c @@ -35,6 +35,8 @@ #include "tcg/swid/tcg_swid_attr_tag_id_inv.h" #include "tcg/swid/tcg_swid_attr_tag_inv.h" #include "tcg/seg/tcg_seg_attr_max_size.h" +#include "tcg/seg/tcg_seg_attr_seg_env.h" +#include "tcg/seg/tcg_seg_attr_next_seg.h" ENUM_BEGIN(tcg_attr_names, TCG_SCAP_REFERENCES, TCG_SCAP_SUMMARY_RESULTS, @@ -195,6 +197,10 @@ pa_tnc_attr_t* tcg_attr_create_from_data(u_int32_t type, chunk_t value) return tcg_seg_attr_max_size_create_from_data(value, TRUE); case TCG_SEG_MAX_ATTR_SIZE_RESP: return tcg_seg_attr_max_size_create_from_data(value, FALSE); + case TCG_SEG_ATTR_SEG_ENV: + return tcg_seg_attr_seg_env_create_from_data(value); + case TCG_SEG_NEXT_SEG_REQ: + return tcg_seg_attr_next_seg_create_from_data(value); case TCG_PTS_REQ_PROTO_CAPS: return tcg_pts_attr_proto_caps_create_from_data(value, TRUE); case TCG_PTS_PROTO_CAPS: |