Annotation of embedaddon/strongswan/src/libimcv/seg/seg_contract.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2014-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 "seg_contract.h"
! 17: #include "seg_env.h"
! 18: #include "ietf/ietf_attr_pa_tnc_error.h"
! 19: #include "tcg/seg/tcg_seg_attr_seg_env.h"
! 20:
! 21: #include <utils/debug.h>
! 22: #include <bio/bio_writer.h>
! 23:
! 24: #include <tncif_pa_subtypes.h>
! 25:
! 26: typedef struct private_seg_contract_t private_seg_contract_t;
! 27:
! 28: /**
! 29: * Private data of a seg_contract_t object.
! 30: */
! 31: struct private_seg_contract_t {
! 32:
! 33: /**
! 34: * Public seg_contract_t interface.
! 35: */
! 36: seg_contract_t public;
! 37:
! 38: /**
! 39: * PA-TNC message type
! 40: */
! 41: pen_type_t msg_type;
! 42:
! 43: /**
! 44: * Maximum PA-TNC attribute size
! 45: */
! 46: uint32_t max_attr_size;
! 47:
! 48: /**
! 49: * Maximum PA-TNC attribute segment size
! 50: */
! 51: uint32_t max_seg_size;
! 52:
! 53: /**
! 54: * Maximum PA-TNC attribute segment size
! 55: */
! 56: uint32_t last_base_attr_id;
! 57:
! 58: /**
! 59: * List of attribute segment envelopes
! 60: */
! 61:
! 62: linked_list_t *seg_envs;
! 63:
! 64: /**
! 65: * Is this a null contract?
! 66: */
! 67: bool is_null;
! 68:
! 69: /**
! 70: * Contract role
! 71: */
! 72: bool is_issuer;
! 73:
! 74: /**
! 75: * Issuer ID (either IMV or IMC ID)
! 76: */
! 77: TNC_UInt32 issuer_id;
! 78:
! 79: /**
! 80: * Responder ID (either IMC or IMV ID)
! 81: */
! 82: TNC_UInt32 responder_id;
! 83:
! 84: /**
! 85: * IMC/IMV role
! 86: */
! 87: bool is_imc;
! 88:
! 89: };
! 90:
! 91: METHOD(seg_contract_t, get_msg_type, pen_type_t,
! 92: private_seg_contract_t *this)
! 93: {
! 94: return this->msg_type;
! 95: }
! 96:
! 97: METHOD(seg_contract_t, set_max_size, void,
! 98: private_seg_contract_t *this, uint32_t max_attr_size, uint32_t max_seg_size)
! 99: {
! 100: this->max_attr_size = max_attr_size;
! 101: this->max_seg_size = max_seg_size;
! 102: this->is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
! 103: max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE;
! 104: }
! 105:
! 106: METHOD(seg_contract_t, get_max_size, void,
! 107: private_seg_contract_t *this, uint32_t *max_attr_size, uint32_t *max_seg_size)
! 108: {
! 109: if (max_attr_size)
! 110: {
! 111: *max_attr_size = this->max_attr_size;
! 112: }
! 113: if (max_seg_size)
! 114: {
! 115: *max_seg_size = this->max_seg_size;
! 116: }
! 117: }
! 118:
! 119: METHOD(seg_contract_t, check_size, bool,
! 120: private_seg_contract_t *this, pa_tnc_attr_t *attr, bool *oversize)
! 121: {
! 122: chunk_t attr_value;
! 123: size_t attr_len;
! 124:
! 125: *oversize = FALSE;
! 126:
! 127: if (this->is_null)
! 128: {
! 129: /* null segmentation contract */
! 130: return FALSE;
! 131: }
! 132: attr->build(attr);
! 133: attr_value = attr->get_value(attr);
! 134: attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len;
! 135:
! 136: if (attr_len > this->max_attr_size)
! 137: {
! 138: /* oversize attribute */
! 139: *oversize = TRUE;
! 140: return FALSE;
! 141: }
! 142: if (this->max_seg_size == SEG_CONTRACT_NO_FRAGMENTATION)
! 143: {
! 144: /* no fragmentation wanted */
! 145: return FALSE;
! 146: }
! 147: return attr_value.len > this->max_seg_size + TCG_SEG_ATTR_SEG_ENV_HEADER;
! 148: }
! 149:
! 150: METHOD(seg_contract_t, first_segment, pa_tnc_attr_t*,
! 151: private_seg_contract_t *this, pa_tnc_attr_t *attr, size_t max_attr_len)
! 152: {
! 153: seg_env_t *seg_env;
! 154:
! 155: seg_env = seg_env_create(++this->last_base_attr_id, attr,
! 156: this->max_seg_size);
! 157: if (!seg_env)
! 158: {
! 159: return NULL;
! 160: }
! 161: this->seg_envs->insert_last(this->seg_envs, seg_env);
! 162:
! 163: return seg_env->first_segment(seg_env, max_attr_len);
! 164: }
! 165:
! 166: METHOD(seg_contract_t, next_segment, pa_tnc_attr_t*,
! 167: private_seg_contract_t *this, uint32_t base_attr_id)
! 168: {
! 169: pa_tnc_attr_t *seg_env_attr = NULL;
! 170: seg_env_t *seg_env;
! 171: bool last_segment = FALSE;
! 172: enumerator_t *enumerator;
! 173:
! 174: enumerator = this->seg_envs->create_enumerator(this->seg_envs);
! 175: while (enumerator->enumerate(enumerator, &seg_env))
! 176: {
! 177: if (seg_env->get_base_attr_id(seg_env) == base_attr_id)
! 178: {
! 179: seg_env_attr = seg_env->next_segment(seg_env, &last_segment);
! 180: if (!seg_env_attr)
! 181: {
! 182: break;
! 183: }
! 184: if (last_segment)
! 185: {
! 186: this->seg_envs->remove_at(this->seg_envs, enumerator);
! 187: seg_env->destroy(seg_env);
! 188: }
! 189: break;
! 190: }
! 191: }
! 192: enumerator->destroy(enumerator);
! 193:
! 194: return seg_env_attr;
! 195: }
! 196:
! 197: METHOD(seg_contract_t, add_segment, pa_tnc_attr_t*,
! 198: private_seg_contract_t *this, pa_tnc_attr_t *attr, pa_tnc_attr_t **error,
! 199: bool *more)
! 200: {
! 201: tcg_seg_attr_seg_env_t *seg_env_attr;
! 202: seg_env_t *current, *seg_env = NULL;
! 203: pa_tnc_attr_t *base_attr;
! 204: pen_type_t error_code;
! 205: uint32_t base_attr_id;
! 206: uint8_t flags;
! 207: chunk_t segment_data, msg_info;
! 208: enumerator_t *enumerator;
! 209:
! 210: seg_env_attr = (tcg_seg_attr_seg_env_t*)attr;
! 211: base_attr_id = seg_env_attr->get_base_attr_id(seg_env_attr);
! 212: segment_data = seg_env_attr->get_segment(seg_env_attr, &flags);
! 213: *more = flags & SEG_ENV_FLAG_MORE;
! 214: *error = NULL;
! 215:
! 216: enumerator = this->seg_envs->create_enumerator(this->seg_envs);
! 217: while (enumerator->enumerate(enumerator, ¤t))
! 218: {
! 219: if (current->get_base_attr_id(current) == base_attr_id)
! 220: {
! 221: seg_env = current;
! 222: this->seg_envs->remove_at(this->seg_envs, enumerator);
! 223: break;
! 224: }
! 225: }
! 226: enumerator->destroy(enumerator);
! 227:
! 228: if (flags & SEG_ENV_FLAG_START)
! 229: {
! 230: if (seg_env)
! 231: {
! 232: DBG1(DBG_TNC, "base attribute ID %d is already in use",
! 233: base_attr_id);
! 234: this->seg_envs->insert_last(this->seg_envs, seg_env);
! 235: return NULL;
! 236: }
! 237: DBG2(DBG_TNC, "received first segment for base attribute ID %d "
! 238: "(%d bytes)", base_attr_id, segment_data.len);
! 239: seg_env = seg_env_create_from_data(base_attr_id, segment_data,
! 240: this->max_seg_size, error);
! 241: if (!seg_env)
! 242: {
! 243: return NULL;
! 244: }
! 245: }
! 246: else
! 247: {
! 248: if (!seg_env)
! 249: {
! 250: DBG1(DBG_TNC, "base attribute ID %d not found", base_attr_id);
! 251: return NULL;
! 252: }
! 253: DBG2(DBG_TNC, "received %s segment for base attribute ID %d "
! 254: "(%d bytes)", (*more) ? "next" : "last", base_attr_id,
! 255: segment_data.len);
! 256: if (!seg_env->add_segment(seg_env, segment_data, error))
! 257: {
! 258: seg_env->destroy(seg_env);
! 259: return NULL;
! 260: }
! 261: }
! 262: base_attr = seg_env->get_base_attr(seg_env);
! 263:
! 264: if (*more)
! 265: {
! 266: /* reinsert into list since more segments are to come */
! 267: this->seg_envs->insert_last(this->seg_envs, seg_env);
! 268: }
! 269: else
! 270: {
! 271: /* added the last segment */
! 272: if (!base_attr)
! 273: {
! 274: /* base attribute waits for more data */
! 275: DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value");
! 276: msg_info = seg_env->get_base_attr_info(seg_env);
! 277: error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER);
! 278: *error = ietf_attr_pa_tnc_error_create_with_offset(error_code,
! 279: msg_info, PA_TNC_ATTR_INFO_SIZE);
! 280: }
! 281: seg_env->destroy(seg_env);
! 282: }
! 283: return base_attr;
! 284: }
! 285:
! 286: METHOD(seg_contract_t, is_issuer, bool,
! 287: private_seg_contract_t *this)
! 288: {
! 289: return this->is_issuer;
! 290: }
! 291:
! 292: METHOD(seg_contract_t, is_null, bool,
! 293: private_seg_contract_t *this)
! 294: {
! 295: return this->is_null;
! 296: }
! 297:
! 298: METHOD(seg_contract_t, set_responder, void,
! 299: private_seg_contract_t *this, TNC_UInt32 responder_id)
! 300: {
! 301: this->responder_id = responder_id;
! 302: }
! 303:
! 304: METHOD(seg_contract_t, get_responder, TNC_UInt32,
! 305: private_seg_contract_t *this)
! 306: {
! 307: return this->responder_id;
! 308: }
! 309:
! 310: METHOD(seg_contract_t, get_issuer, TNC_UInt32,
! 311: private_seg_contract_t *this)
! 312: {
! 313: return this->issuer_id;
! 314: }
! 315:
! 316: METHOD(seg_contract_t, clone_, seg_contract_t*,
! 317: private_seg_contract_t *this)
! 318: {
! 319: private_seg_contract_t *clone;
! 320:
! 321: clone = malloc_thing(private_seg_contract_t);
! 322: memcpy(clone, this, sizeof(private_seg_contract_t));
! 323: clone->seg_envs = linked_list_create();
! 324:
! 325: return &clone->public;
! 326: }
! 327:
! 328: METHOD(seg_contract_t, get_info_string, void,
! 329: private_seg_contract_t *this, char *buf, size_t len, bool request)
! 330: {
! 331: enum_name_t *pa_subtype_names;
! 332: uint32_t msg_vid, msg_subtype;
! 333: char *pos = buf;
! 334: int written;
! 335:
! 336: /* nul-terminate the string buffer */
! 337: buf[--len] = '\0';
! 338:
! 339: if (this->is_issuer && request)
! 340: {
! 341: written = snprintf(pos, len, "%s %lu requests",
! 342: this->is_imc ? "IMC" : "IMV", this->issuer_id);
! 343: }
! 344: else
! 345: {
! 346: written = snprintf(pos, len, "%s %lu received",
! 347: this->is_imc ? "IMC" : "IMV",
! 348: this->is_issuer ? this->issuer_id :
! 349: this->responder_id);
! 350: }
! 351: if (written < 0 || written > len)
! 352: {
! 353: return;
! 354: }
! 355: pos += written;
! 356: len -= written;
! 357:
! 358: written = snprintf(pos, len, " a %ssegmentation contract%s ",
! 359: this->is_null ? "null" : "", request ?
! 360: (this->is_issuer ? "" : " request") : " response");
! 361: if (written < 0 || written > len)
! 362: {
! 363: return;
! 364: }
! 365: pos += written;
! 366: len -= written;
! 367:
! 368: if ((!this->is_issuer && this->issuer_id != TNC_IMVID_ANY) ||
! 369: ( this->is_issuer && this->responder_id != TNC_IMVID_ANY))
! 370: {
! 371: written = snprintf(pos, len, "from %s %lu ",
! 372: this->is_imc ? "IMV" : "IMC",
! 373: this->is_issuer ? this->responder_id :
! 374: this->issuer_id);
! 375: if (written < 0 || written > len)
! 376: {
! 377: return;
! 378: }
! 379: pos += written;
! 380: len -= written;
! 381: }
! 382:
! 383: msg_vid = this->msg_type.vendor_id;
! 384: msg_subtype = this->msg_type.type;
! 385: pa_subtype_names = get_pa_subtype_names(msg_vid);
! 386: if (pa_subtype_names)
! 387: {
! 388: written = snprintf(pos, len, "for PA message type '%N/%N' "
! 389: "0x%06x/0x%08x", pen_names, msg_vid,
! 390: pa_subtype_names, msg_subtype, msg_vid,
! 391: msg_subtype);
! 392: }
! 393: else
! 394: {
! 395: written = snprintf(pos, len, "for PA message type '%N' "
! 396: "0x%06x/0x%08x", pen_names, msg_vid,
! 397: msg_vid, msg_subtype);
! 398: }
! 399: if (written < 0 || written > len)
! 400: {
! 401: return;
! 402: }
! 403: pos += written;
! 404: len -= written;
! 405:
! 406: if (!this->is_null)
! 407: {
! 408: written = snprintf(pos, len, "\n maximum attribute size of %u bytes "
! 409: "with ", this->max_attr_size);
! 410: if (written < 0 || written > len)
! 411: {
! 412: return;
! 413: }
! 414: pos += written;
! 415: len -= written;
! 416:
! 417: if (this->max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE)
! 418: {
! 419: written = snprintf(pos, len, "no segmentation");
! 420: }
! 421: else
! 422: {
! 423: written = snprintf(pos, len, "maximum segment size of %u bytes",
! 424: this->max_seg_size);
! 425: }
! 426: }
! 427: }
! 428:
! 429: METHOD(seg_contract_t, destroy, void,
! 430: private_seg_contract_t *this)
! 431: {
! 432: this->seg_envs->destroy_offset(this->seg_envs, offsetof(seg_env_t, destroy));
! 433: free(this);
! 434: }
! 435:
! 436: /**
! 437: * See header
! 438: */
! 439: seg_contract_t *seg_contract_create(pen_type_t msg_type,
! 440: uint32_t max_attr_size,
! 441: uint32_t max_seg_size,
! 442: bool is_issuer, TNC_UInt32 issuer_id,
! 443: bool is_imc)
! 444: {
! 445: private_seg_contract_t *this;
! 446:
! 447: INIT(this,
! 448: .public = {
! 449: .get_msg_type = _get_msg_type,
! 450: .set_max_size = _set_max_size,
! 451: .get_max_size = _get_max_size,
! 452: .check_size = _check_size,
! 453: .first_segment = _first_segment,
! 454: .next_segment = _next_segment,
! 455: .add_segment = _add_segment,
! 456: .is_issuer = _is_issuer,
! 457: .is_null = _is_null,
! 458: .set_responder = _set_responder,
! 459: .get_responder = _get_responder,
! 460: .get_issuer = _get_issuer,
! 461: .clone = _clone_,
! 462: .get_info_string = _get_info_string,
! 463: .destroy = _destroy,
! 464: },
! 465: .msg_type = msg_type,
! 466: .max_attr_size = max_attr_size,
! 467: .max_seg_size = max_seg_size,
! 468: .seg_envs = linked_list_create(),
! 469: .is_issuer = is_issuer,
! 470: .issuer_id = issuer_id,
! 471: .responder_id = is_imc ? TNC_IMVID_ANY : TNC_IMCID_ANY,
! 472: .is_imc = is_imc,
! 473: .is_null = max_attr_size == SEG_CONTRACT_MAX_SIZE_VALUE &&
! 474: max_seg_size == SEG_CONTRACT_MAX_SIZE_VALUE,
! 475: );
! 476:
! 477: return &this->public;
! 478: }
! 479:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>