Annotation of embedaddon/strongswan/src/libimcv/pa_tnc/pa_tnc_msg.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011-2015 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "imcv.h"
! 17: #include "pa_tnc_msg.h"
! 18: #include "ietf/ietf_attr_pa_tnc_error.h"
! 19:
! 20: #include <bio/bio_writer.h>
! 21: #include <bio/bio_reader.h>
! 22: #include <collections/linked_list.h>
! 23: #include <pen/pen.h>
! 24: #include <utils/debug.h>
! 25:
! 26: typedef struct private_pa_tnc_msg_t private_pa_tnc_msg_t;
! 27:
! 28: /**
! 29: * PA-TNC message header
! 30: *
! 31: * 1 2 3
! 32: * 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
! 33: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 34: * | Version | Reserved |
! 35: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 36: * | Message Identifier |
! 37: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! 38: */
! 39:
! 40: #define PA_TNC_RESERVED 0x000000
! 41:
! 42: /**
! 43: * Private data of a pa_tnc_msg_t object.
! 44: *
! 45: */
! 46: struct private_pa_tnc_msg_t {
! 47:
! 48: /**
! 49: * Public pa_tnc_msg_t interface.
! 50: */
! 51: pa_tnc_msg_t public;
! 52:
! 53: /**
! 54: * List of PA-TNC attributes
! 55: */
! 56: linked_list_t *attributes;
! 57:
! 58: /**
! 59: * linked list of PA-TNC error messages
! 60: */
! 61: linked_list_t *errors;
! 62:
! 63: /**
! 64: * Message identifier
! 65: */
! 66: uint32_t identifier;
! 67:
! 68: /**
! 69: * Current PA-TNC Message size
! 70: */
! 71: size_t msg_len;
! 72:
! 73: /**
! 74: * Maximum PA-TNC Message size
! 75: */
! 76: size_t max_msg_len;
! 77:
! 78: /**
! 79: * TRUE if attribute was extracted from data
! 80: */
! 81: bool from_data;
! 82:
! 83: /**
! 84: * Encoded message
! 85: */
! 86: chunk_t encoding;
! 87: };
! 88:
! 89: METHOD(pa_tnc_msg_t, get_encoding, chunk_t,
! 90: private_pa_tnc_msg_t *this)
! 91: {
! 92: return this->encoding;
! 93: }
! 94:
! 95: METHOD(pa_tnc_msg_t, get_space, size_t,
! 96: private_pa_tnc_msg_t *this)
! 97: {
! 98: return this->max_msg_len ? this->max_msg_len - this->msg_len : 0;
! 99: }
! 100:
! 101: METHOD(pa_tnc_msg_t, add_attribute, bool,
! 102: private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr)
! 103: {
! 104: chunk_t attr_value;
! 105: size_t attr_len;
! 106:
! 107: if (!this->from_data)
! 108: {
! 109: attr->build(attr);
! 110: attr_value = attr->get_value(attr);
! 111: attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
! 112:
! 113: if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len)
! 114: {
! 115: /* attribute just does not fit into this message */
! 116: return FALSE;
! 117: }
! 118: this->msg_len += attr_len;
! 119: }
! 120: this->attributes->insert_last(this->attributes, attr);
! 121: return TRUE;
! 122: }
! 123:
! 124: METHOD(pa_tnc_msg_t, build, bool,
! 125: private_pa_tnc_msg_t *this)
! 126: {
! 127: bio_writer_t *writer;
! 128: enumerator_t *enumerator;
! 129: pa_tnc_attr_t *attr;
! 130: enum_name_t *pa_attr_names;
! 131: pen_type_t type;
! 132: uint8_t flags;
! 133: chunk_t value;
! 134: nonce_gen_t *ng;
! 135:
! 136: /* generate a nonce as a message identifier */
! 137: ng = lib->crypto->create_nonce_gen(lib->crypto);
! 138: if (!ng || !ng->get_nonce(ng, 4, (uint8_t*)&this->identifier))
! 139: {
! 140: DBG1(DBG_TNC, "failed to generate random PA-TNC message identifier");
! 141: DESTROY_IF(ng);
! 142: return FALSE;
! 143: }
! 144: ng->destroy(ng);
! 145: DBG1(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier);
! 146:
! 147: /* build message header */
! 148: writer = bio_writer_create(this->msg_len);
! 149: writer->write_uint8 (writer, PA_TNC_VERSION);
! 150: writer->write_uint24(writer, PA_TNC_RESERVED);
! 151: writer->write_uint32(writer, this->identifier);
! 152:
! 153: /* append encoded value of PA-TNC attributes */
! 154: enumerator = this->attributes->create_enumerator(this->attributes);
! 155: while (enumerator->enumerate(enumerator, &attr))
! 156: {
! 157: type = attr->get_type(attr);
! 158: value = attr->get_value(attr);
! 159: flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP :
! 160: PA_TNC_ATTR_FLAG_NONE;
! 161:
! 162: pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
! 163: type.vendor_id);
! 164: if (pa_attr_names)
! 165: {
! 166: DBG2(DBG_TNC, "creating PA-TNC attribute type '%N/%N' "
! 167: "0x%06x/0x%08x", pen_names, type.vendor_id,
! 168: pa_attr_names, type.type, type.vendor_id, type.type);
! 169: }
! 170: else
! 171: {
! 172: DBG2(DBG_TNC, "creating PA-TNC attribute type '%N' "
! 173: "0x%06x/0x%08x", pen_names, type.vendor_id,
! 174: type.vendor_id, type.type);
! 175: }
! 176: DBG3(DBG_TNC, "%B", &value);
! 177:
! 178: writer->write_uint8 (writer, flags);
! 179: writer->write_uint24(writer, type.vendor_id);
! 180: writer->write_uint32(writer, type.type);
! 181: writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len);
! 182: writer->write_data (writer, value);
! 183: }
! 184: enumerator->destroy(enumerator);
! 185:
! 186: free(this->encoding.ptr);
! 187: this->encoding = writer->extract_buf(writer);
! 188: writer->destroy(writer);
! 189:
! 190: return TRUE;
! 191: }
! 192:
! 193: METHOD(pa_tnc_msg_t, process, status_t,
! 194: private_pa_tnc_msg_t *this)
! 195: {
! 196: bio_reader_t *reader;
! 197: pa_tnc_attr_t *attr, *error;
! 198: pen_type_t attr_type;
! 199: chunk_t attr_value;
! 200: uint8_t version;
! 201: uint32_t reserved, offset, attr_offset;
! 202: pen_type_t error_code = { PEN_IETF, PA_ERROR_INVALID_PARAMETER };
! 203:
! 204: /* process message header */
! 205: if (this->encoding.len < PA_TNC_HEADER_SIZE)
! 206: {
! 207: DBG1(DBG_TNC, "%u bytes insufficient to parse PA-TNC message header",
! 208: this->encoding.len);
! 209: return FAILED;
! 210: }
! 211: reader = bio_reader_create(this->encoding);
! 212: reader->read_uint8 (reader, &version);
! 213: reader->read_uint24(reader, &reserved);
! 214: reader->read_uint32(reader, &this->identifier);
! 215: DBG1(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier);
! 216:
! 217: if (version != PA_TNC_VERSION)
! 218: {
! 219: DBG1(DBG_TNC, "PA-TNC version %u not supported", version);
! 220: error_code = pen_type_create(PEN_IETF, PA_ERROR_VERSION_NOT_SUPPORTED);
! 221: error = ietf_attr_pa_tnc_error_create(error_code, this->encoding);
! 222: goto err;
! 223: }
! 224:
! 225: /* offset of the first PA-TNC attribute in the PA-TNC message */
! 226: offset = PA_TNC_HEADER_SIZE;
! 227:
! 228: /* pre-process PA-TNC attributes */
! 229: while (reader->remaining(reader) > 0)
! 230: {
! 231: attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
! 232: reader, FALSE, &offset, this->encoding, &error);
! 233: if (!attr)
! 234: {
! 235: if (error)
! 236: {
! 237: goto err;
! 238: }
! 239: else
! 240: {
! 241: continue;
! 242: }
! 243: }
! 244: attr_value = attr->get_value(attr);
! 245: attr_type = attr->get_type(attr);
! 246:
! 247: if (attr->process(attr, &attr_offset) != SUCCESS)
! 248: {
! 249: attr->destroy(attr);
! 250:
! 251: if (attr_type.vendor_id == PEN_IETF &&
! 252: attr_type.type == IETF_ATTR_PA_TNC_ERROR)
! 253: {
! 254: /* suppress error while processing a PA-TNC error attribute */
! 255: offset += attr_value.len;
! 256: continue;
! 257: }
! 258: error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
! 259: error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
! 260: this->encoding, offset + attr_offset);
! 261: goto err;
! 262: }
! 263: offset += attr_value.len;
! 264: this->attributes->insert_last(this->attributes, attr);
! 265: }
! 266: reader->destroy(reader);
! 267: return SUCCESS;
! 268:
! 269: err:
! 270: reader->destroy(reader);
! 271: this->errors->insert_last(this->errors, error);
! 272: return VERIFY_ERROR;
! 273: }
! 274:
! 275: METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool,
! 276: private_pa_tnc_msg_t *this, linked_list_t *non_fatal_types)
! 277: {
! 278: enumerator_t *e1, *e2;
! 279: enum_name_t *pa_attr_names;
! 280: pa_tnc_attr_t *attr;
! 281: pen_type_t type, unsupported_type;
! 282: uint8_t flags;
! 283: bool fatal_error = FALSE;
! 284:
! 285: e1 = this->attributes->create_enumerator(this->attributes);
! 286: while (e1->enumerate(e1, &attr))
! 287: {
! 288: type = attr->get_type(attr);
! 289:
! 290: if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR)
! 291: {
! 292: ietf_attr_pa_tnc_error_t *error_attr;
! 293: pen_type_t error_code, *non_fatal_type;
! 294: chunk_t msg_info;
! 295: uint32_t offset;
! 296: bool fatal_current_error = TRUE;
! 297:
! 298: error_attr = (ietf_attr_pa_tnc_error_t*)attr;
! 299: error_code = error_attr->get_error_code(error_attr);
! 300: msg_info = error_attr->get_msg_info(error_attr);
! 301:
! 302: /* skip errors from non-IETF namespaces and non PA-TNC msg errors */
! 303: if (error_code.vendor_id != PEN_IETF ||
! 304: error_code.type > PA_ERROR_PA_TNC_MSG_ROOF)
! 305: {
! 306: continue;
! 307: }
! 308: DBG1(DBG_TNC, "received PA-TNC error '%N' concerning message "
! 309: "0x%08x/0x%08x", pa_tnc_error_code_names, error_code.type,
! 310: untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4));
! 311:
! 312: switch (error_code.type)
! 313: {
! 314: case PA_ERROR_INVALID_PARAMETER:
! 315: offset = error_attr->get_offset(error_attr);
! 316: DBG1(DBG_TNC, " occurred at offset of %u bytes", offset);
! 317: break;
! 318: case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
! 319: unsupported_type =
! 320: error_attr->get_unsupported_attr(error_attr, &flags);
! 321: pa_attr_names =
! 322: imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
! 323: unsupported_type.vendor_id);
! 324: if (pa_attr_names)
! 325: {
! 326: DBG1(DBG_TNC, " unsupported attribute type '%N/%N' "
! 327: "0x%06x/0x%08x, flags 0x%02x",
! 328: pen_names, unsupported_type.vendor_id,
! 329: pa_attr_names, unsupported_type.type,
! 330: unsupported_type.vendor_id, unsupported_type.type,
! 331: flags);
! 332: }
! 333: else
! 334: {
! 335: DBG1(DBG_TNC, " unsupported attribute type '%N' "
! 336: "0x%06x/0x%08x, flags 0x%02x",
! 337: pen_names, unsupported_type.vendor_id,
! 338: unsupported_type.vendor_id, unsupported_type.type,
! 339: flags);
! 340: }
! 341: e2 = non_fatal_types->create_enumerator(non_fatal_types);
! 342: while (e2->enumerate(e2, &non_fatal_type))
! 343: {
! 344: if (pen_type_equals(unsupported_type, *non_fatal_type))
! 345: {
! 346: fatal_current_error = FALSE;
! 347: break;
! 348: }
! 349: }
! 350: e2->destroy(e2);
! 351: break;
! 352: default:
! 353: break;
! 354: }
! 355: if (fatal_current_error)
! 356: {
! 357: fatal_error = TRUE;
! 358: }
! 359: }
! 360: }
! 361: e1->destroy(e1);
! 362:
! 363: return fatal_error;
! 364: }
! 365:
! 366: METHOD(pa_tnc_msg_t, create_attribute_enumerator, enumerator_t*,
! 367: private_pa_tnc_msg_t *this)
! 368: {
! 369: return this->attributes->create_enumerator(this->attributes);
! 370: }
! 371:
! 372: METHOD(pa_tnc_msg_t, create_error_enumerator, enumerator_t*,
! 373: private_pa_tnc_msg_t *this)
! 374: {
! 375: return this->errors->create_enumerator(this->errors);
! 376: }
! 377:
! 378: METHOD(pa_tnc_msg_t, destroy, void,
! 379: private_pa_tnc_msg_t *this)
! 380: {
! 381: this->attributes->destroy_offset(this->attributes,
! 382: offsetof(pa_tnc_attr_t, destroy));
! 383: this->errors->destroy_offset(this->errors,
! 384: offsetof(pa_tnc_attr_t, destroy));
! 385: free(this->encoding.ptr);
! 386: free(this);
! 387: }
! 388:
! 389: /**
! 390: * See header
! 391: */
! 392: pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len)
! 393: {
! 394: private_pa_tnc_msg_t *this;
! 395:
! 396: INIT(this,
! 397: .public = {
! 398: .get_encoding = _get_encoding,
! 399: .get_space = _get_space,
! 400: .add_attribute = _add_attribute,
! 401: .build = _build,
! 402: .process = _process,
! 403: .process_ietf_std_errors = _process_ietf_std_errors,
! 404: .create_attribute_enumerator = _create_attribute_enumerator,
! 405: .create_error_enumerator = _create_error_enumerator,
! 406: .destroy = _destroy,
! 407: },
! 408: .attributes = linked_list_create(),
! 409: .errors = linked_list_create(),
! 410: .msg_len = PA_TNC_HEADER_SIZE,
! 411: .max_msg_len = max_msg_len,
! 412: );
! 413:
! 414: return &this->public;
! 415: }
! 416:
! 417: /**
! 418: * See header
! 419: */
! 420: pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data)
! 421: {
! 422: private_pa_tnc_msg_t *this;
! 423:
! 424: INIT(this,
! 425: .public = {
! 426: .get_encoding = _get_encoding,
! 427: .get_space = _get_space,
! 428: .add_attribute = _add_attribute,
! 429: .build = _build,
! 430: .process = _process,
! 431: .process_ietf_std_errors = _process_ietf_std_errors,
! 432: .create_attribute_enumerator = _create_attribute_enumerator,
! 433: .create_error_enumerator = _create_error_enumerator,
! 434: .destroy = _destroy,
! 435: },
! 436: .encoding = chunk_clone(data),
! 437: .attributes = linked_list_create(),
! 438: .errors = linked_list_create(),
! 439: .from_data = TRUE,
! 440: );
! 441:
! 442: return &this->public;
! 443: }
! 444:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>