diff options
Diffstat (limited to 'src/libimcv/pa_tnc/pa_tnc_msg.c')
-rw-r--r-- | src/libimcv/pa_tnc/pa_tnc_msg.c | 165 |
1 files changed, 111 insertions, 54 deletions
diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c index b5df0a5b5..b1476fc7f 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.c +++ b/src/libimcv/pa_tnc/pa_tnc_msg.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -90,6 +89,16 @@ struct private_pa_tnc_msg_t { u_int32_t identifier; /** + * Current PA-TNC Message size + */ + size_t msg_len; + + /** + * Maximum PA-TNC Message size + */ + size_t max_msg_len; + + /** * Encoded message */ chunk_t encoding; @@ -101,67 +110,84 @@ METHOD(pa_tnc_msg_t, get_encoding, chunk_t, return this->encoding; } -METHOD(pa_tnc_msg_t, add_attribute, void, +METHOD(pa_tnc_msg_t, add_attribute, bool, private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr) { + 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) + { + /* attribute just does not fit into this message */ + return FALSE; + } + this->msg_len += attr_len; + this->attributes->insert_last(this->attributes, attr); + return TRUE; } -METHOD(pa_tnc_msg_t, build, void, +METHOD(pa_tnc_msg_t, build, bool, private_pa_tnc_msg_t *this) { bio_writer_t *writer; enumerator_t *enumerator; pa_tnc_attr_t *attr; enum_name_t *pa_attr_names; - pen_t vendor_id; - u_int32_t type; + pen_type_t type; u_int8_t flags; chunk_t value; - rng_t *rng; + nonce_gen_t *ng; - /* create a random message identifier */ - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, sizeof(this->identifier), (u_int8_t*)&this->identifier); - rng->destroy(rng); - DBG2(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier); + /* generate a nonce as a message identifier */ + ng = lib->crypto->create_nonce_gen(lib->crypto); + if (!ng || !ng->get_nonce(ng, 4, (u_int8_t*)&this->identifier)) + { + DBG1(DBG_TNC, "failed to generate random PA-TNC message identifier"); + DESTROY_IF(ng); + return FALSE; + } + ng->destroy(ng); + DBG1(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier); /* build message header */ - writer = bio_writer_create(PA_TNC_HEADER_SIZE); + writer = bio_writer_create(this->msg_len); writer->write_uint8 (writer, PA_TNC_VERSION); writer->write_uint24(writer, PA_TNC_RESERVED); writer->write_uint32(writer, this->identifier); - /* build and append encoding of PA-TNC attributes */ + /* append encoded value of PA-TNC attributes */ enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attr)) { - attr->build(attr); - vendor_id = attr->get_vendor_id(attr); - type = attr->get_type(attr); + type = attr->get_type(attr); value = attr->get_value(attr); flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE; pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes, - vendor_id); + type.vendor_id); if (pa_attr_names) { DBG2(DBG_TNC, "creating PA-TNC attribute type '%N/%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - pa_attr_names, type, vendor_id, type); + "0x%06x/0x%08x", pen_names, type.vendor_id, + pa_attr_names, type.type, type.vendor_id, type.type); } else { DBG2(DBG_TNC, "creating PA-TNC attribute type '%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - vendor_id, type); + "0x%06x/0x%08x", pen_names, type.vendor_id, + type.vendor_id, type.type); } DBG3(DBG_TNC, "%B", &value); writer->write_uint8 (writer, flags); - writer->write_uint24(writer, vendor_id); - writer->write_uint32(writer, type); + writer->write_uint24(writer, type.vendor_id); + writer->write_uint32(writer, type.type); writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len); writer->write_data (writer, value); } @@ -170,6 +196,8 @@ METHOD(pa_tnc_msg_t, build, void, free(this->encoding.ptr); this->encoding = chunk_clone(writer->get_buf(writer)); writer->destroy(writer); + + return TRUE; } METHOD(pa_tnc_msg_t, process, status_t, @@ -179,6 +207,7 @@ METHOD(pa_tnc_msg_t, process, status_t, pa_tnc_attr_t *error; u_int8_t version; u_int32_t reserved, offset, attr_offset; + pen_type_t error_code; /* process message header */ if (this->encoding.len < PA_TNC_HEADER_SIZE) @@ -191,13 +220,14 @@ METHOD(pa_tnc_msg_t, process, status_t, reader->read_uint8 (reader, &version); reader->read_uint24(reader, &reserved); reader->read_uint32(reader, &this->identifier); - DBG2(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier); + DBG1(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier); if (version != PA_TNC_VERSION) { + pen_type_t error_code = { PEN_IETF, PA_ERROR_VERSION_NOT_SUPPORTED }; + DBG1(DBG_TNC, "PA-TNC version %u not supported", version); - error = ietf_attr_pa_tnc_error_create(PEN_IETF, - PA_ERROR_VERSION_NOT_SUPPORTED, this->encoding); + error = ietf_attr_pa_tnc_error_create(error_code, this->encoding); goto err; } @@ -214,6 +244,7 @@ METHOD(pa_tnc_msg_t, process, status_t, pa_tnc_attr_t *attr; enum_name_t *pa_attr_names; ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; attr_info = reader->peek(reader); attr_info.len = PA_TNC_ATTR_INFO_SIZE; @@ -241,18 +272,18 @@ METHOD(pa_tnc_msg_t, process, status_t, { DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length", length); - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, - offset + PA_TNC_ATTR_INFO_SIZE); + 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_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(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, - offset + PA_TNC_ATTR_INFO_SIZE); + 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_INFO_SIZE); goto err; } DBG3(DBG_TNC, "%B", &value); @@ -264,8 +295,10 @@ METHOD(pa_tnc_msg_t, process, status_t, if (flags & PA_TNC_ATTR_FLAG_NOSKIP) { DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag"); - error = ietf_attr_pa_tnc_error_create(PEN_IETF, - PA_ERROR_ATTR_TYPE_NOT_SUPPORTED, this->encoding); + 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_attr_info(error_attr, attr_info); goto err; @@ -281,18 +314,21 @@ METHOD(pa_tnc_msg_t, process, status_t, if (attr->process(attr, &attr_offset) != SUCCESS) { attr->destroy(attr); - if (vendor_id == PEN_IETF && type == IETF_ATTR_PA_TNC_ERROR) + if (error_code.vendor_id == PEN_IETF && + error_code.type == IETF_ATTR_PA_TNC_ERROR) { /* error while processing a PA-TNC error attribute - abort */ reader->destroy(reader); return FAILED; } - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, + error_code = pen_type_create(PEN_IETF, + PA_ERROR_ATTR_TYPE_NOT_SUPPORTED); + error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + this->encoding, offset + PA_TNC_ATTR_HEADER_SIZE + attr_offset); goto err; } - add_attribute(this, attr); + this->attributes->insert_last(this->attributes, attr); offset += length; } @@ -302,8 +338,9 @@ METHOD(pa_tnc_msg_t, process, status_t, return SUCCESS; } DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute header"); - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, offset); + 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); err: reader->destroy(reader); @@ -316,35 +353,35 @@ METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool, { enumerator_t *enumerator; pa_tnc_attr_t *attr; + pen_type_t type; bool fatal_error = FALSE; enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR) { ietf_attr_pa_tnc_error_t *error_attr; - pen_t error_vendor_id; - pa_tnc_error_code_t error_code; + pen_type_t error_code; chunk_t msg_info, attr_info; u_int32_t offset; error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_vendor_id = error_attr->get_vendor_id(error_attr); error_code = error_attr->get_error_code(error_attr); msg_info = error_attr->get_msg_info(error_attr); /* skip errors from non-IETF namespaces */ - if (error_vendor_id != PEN_IETF) + if (error_code.vendor_id != PEN_IETF) { continue; } DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message " - "0x%08x/0x%08x", pa_tnc_error_code_names, error_code, + "0x%08x/0x%08x", pa_tnc_error_code_names, error_code.type, untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4)); - switch (error_code) + switch (error_code.type) { case PA_ERROR_INVALID_PARAMETER: offset = error_attr->get_offset(error_attr); @@ -358,8 +395,9 @@ METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool, break; } - /* remove the processed IETF standard error attribute */ + /* remove and delete the processed IETF standard error attribute */ this->attributes->remove_at(this->attributes, enumerator); + attr->destroy(attr); fatal_error = TRUE; } } @@ -394,7 +432,7 @@ METHOD(pa_tnc_msg_t, destroy, void, /** * See header */ -pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) +pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len) { private_pa_tnc_msg_t *this; @@ -409,9 +447,10 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) .create_error_enumerator = _create_error_enumerator, .destroy = _destroy, }, - .encoding = chunk_clone(data), .attributes = linked_list_create(), .errors = linked_list_create(), + .msg_len = PA_TNC_HEADER_SIZE, + .max_msg_len = max_msg_len, ); return &this->public; @@ -420,8 +459,26 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) /** * See header */ -pa_tnc_msg_t *pa_tnc_msg_create(void) +pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) { - return pa_tnc_msg_create_from_data(chunk_empty); + private_pa_tnc_msg_t *this; + + INIT(this, + .public = { + .get_encoding = _get_encoding, + .add_attribute = _add_attribute, + .build = _build, + .process = _process, + .process_ietf_std_errors = _process_ietf_std_errors, + .create_attribute_enumerator = _create_attribute_enumerator, + .create_error_enumerator = _create_error_enumerator, + .destroy = _destroy, + }, + .encoding = chunk_clone(data), + .attributes = linked_list_create(), + .errors = linked_list_create(), + ); + + return &this->public; } |