Annotation of embedaddon/strongswan/src/libtnccs/plugins/tnccs_20/tnccs_20.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010 Sansar Choinyambuu
! 3: * Copyright (C) 2010-2015 Andreas Steffen
! 4: * HSR Hochschule fuer Technik Rapperswil
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #include "tnccs_20.h"
! 18: #include "tnccs_20_handler.h"
! 19: #include "tnccs_20_server.h"
! 20: #include "tnccs_20_client.h"
! 21: #include "batch/pb_tnc_batch.h"
! 22: #include "messages/pb_tnc_msg.h"
! 23: #include "messages/ietf/pb_pa_msg.h"
! 24:
! 25: #include <tncif_names.h>
! 26: #include <tncif_pa_subtypes.h>
! 27:
! 28: #include <utils/debug.h>
! 29:
! 30: typedef struct private_tnccs_20_t private_tnccs_20_t;
! 31:
! 32: /**
! 33: * Private data of a tnccs_20_t object.
! 34: */
! 35: struct private_tnccs_20_t {
! 36:
! 37: /**
! 38: * Public tnccs_t interface.
! 39: */
! 40: tnccs_t public;
! 41:
! 42: /**
! 43: * TNCC if TRUE, TNCS if FALSE
! 44: */
! 45: bool is_server;
! 46:
! 47: /**
! 48: * Server identity
! 49: */
! 50: identification_t *server_id;
! 51:
! 52: /**
! 53: * Client identity
! 54: */
! 55: identification_t *peer_id;
! 56:
! 57: /**
! 58: * Server IP address
! 59: */
! 60: host_t *server_ip;
! 61:
! 62: /**
! 63: * Client IP address
! 64: */
! 65: host_t *peer_ip;
! 66:
! 67: /**
! 68: * Underlying TNC IF-T transport protocol
! 69: */
! 70: tnc_ift_type_t transport;
! 71:
! 72: /**
! 73: * TNC IF-T transport protocol for EAP methods
! 74: */
! 75: bool eap_transport;
! 76:
! 77: /**
! 78: * Type of TNC client authentication
! 79: */
! 80: uint32_t auth_type;
! 81:
! 82: /**
! 83: * Mutual PB-TNC protocol enabled
! 84: */
! 85: bool mutual;
! 86:
! 87: /**
! 88: * Direction the next batch will go to
! 89: */
! 90: bool to_server;
! 91:
! 92: /**
! 93: * TNC Server
! 94: */
! 95: tnccs_20_handler_t *tnc_server;
! 96:
! 97: /**
! 98: * TNC Client
! 99: */
! 100: tnccs_20_handler_t *tnc_client;
! 101:
! 102: /**
! 103: * Active TNCSS handler
! 104: */
! 105: tnccs_20_handler_t *tnccs_handler;
! 106:
! 107: /**
! 108: * Maximum PB-TNC batch size
! 109: */
! 110: size_t max_batch_len;
! 111:
! 112: /**
! 113: * Maximum PA-TNC message size
! 114: */
! 115: size_t max_msg_len;
! 116:
! 117: /**
! 118: * Callback function to communicate recommendation (TNC Server only)
! 119: */
! 120: tnccs_cb_t callback;
! 121:
! 122: /**
! 123: * reference count
! 124: */
! 125: refcount_t ref;
! 126:
! 127: };
! 128:
! 129: METHOD(tls_t, is_complete, bool,
! 130: private_tnccs_20_t *this)
! 131: {
! 132: TNC_IMV_Action_Recommendation rec;
! 133: TNC_IMV_Evaluation_Result eval;
! 134: tnccs_20_server_t *tnc_server;
! 135:
! 136: if (this->tnc_server)
! 137: {
! 138: tnc_server = (tnccs_20_server_t*)this->tnc_server;
! 139: if (tnc_server->have_recommendation(tnc_server, &rec, &eval))
! 140: {
! 141: return this->callback ? this->callback(rec, eval) : TRUE;
! 142: }
! 143: }
! 144: return FALSE;
! 145: }
! 146:
! 147: METHOD(tnccs_t, send_msg, TNC_Result,
! 148: private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
! 149: TNC_UInt32 msg_flags,
! 150: TNC_BufferReference msg,
! 151: TNC_UInt32 msg_len,
! 152: TNC_VendorID msg_vid,
! 153: TNC_MessageSubtype msg_subtype)
! 154: {
! 155: pb_tnc_msg_t *pb_tnc_msg;
! 156: enum_name_t *pa_subtype_names;
! 157: bool excl;
! 158:
! 159: if (!this->tnccs_handler->get_send_flag(this->tnccs_handler))
! 160: {
! 161: DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
! 162: this->to_server ? "IMC" : "IMV",
! 163: this->to_server ? imc_id : imv_id);
! 164:
! 165: return TNC_RESULT_ILLEGAL_OPERATION;
! 166: }
! 167: excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
! 168:
! 169: pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
! 170: excl, chunk_create(msg, msg_len));
! 171:
! 172: pa_subtype_names = get_pa_subtype_names(msg_vid);
! 173: if (pa_subtype_names)
! 174: {
! 175: DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
! 176: pen_names, msg_vid, pa_subtype_names, msg_subtype,
! 177: msg_vid, msg_subtype);
! 178: }
! 179: else
! 180: {
! 181: DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
! 182: pen_names, msg_vid, msg_vid, msg_subtype);
! 183: }
! 184: this->tnccs_handler->add_msg(this->tnccs_handler, pb_tnc_msg);
! 185:
! 186: return TNC_RESULT_SUCCESS;
! 187: }
! 188:
! 189: METHOD(tls_t, process, status_t,
! 190: private_tnccs_20_t *this, void *buf, size_t buflen)
! 191: {
! 192: pb_tnc_batch_t *batch;
! 193: bool from_server, fatal_header_error = FALSE;
! 194: status_t status;
! 195: chunk_t data;
! 196:
! 197: /* On arrival of first batch from TNC client create TNC server */
! 198: if (this->is_server && !this->tnc_server)
! 199: {
! 200: this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
! 201: this->max_batch_len, this->max_msg_len,
! 202: this->eap_transport);
! 203: if (!this->tnc_server)
! 204: {
! 205: return FAILED;
! 206: }
! 207: this->tnccs_handler = this->tnc_server;
! 208: this->tnccs_handler->begin_handshake(this->tnccs_handler, FALSE);
! 209: }
! 210:
! 211: data = chunk_create(buf, buflen);
! 212: DBG1(DBG_TNC, "received TNCCS batch (%u bytes)", data.len);
! 213: DBG3(DBG_TNC, "%B", &data);
! 214:
! 215: /* Parse the header of the received PB-TNC batch */
! 216: batch = pb_tnc_batch_create_from_data(data);
! 217: status = batch->process_header(batch, !this->mutual, this->is_server,
! 218: &from_server);
! 219: if (status == FAILED)
! 220: {
! 221: fatal_header_error = TRUE;
! 222: status = VERIFY_ERROR;
! 223: }
! 224: this->to_server = this->mutual ? from_server : !this->is_server;
! 225:
! 226: /* In the mutual case, first batch from TNC server requires a TNC client */
! 227: if (this->to_server && !this->tnc_client)
! 228: {
! 229: this->tnc_client = tnccs_20_client_create(&this->public, _send_msg,
! 230: this->max_batch_len, this->max_msg_len);
! 231: if (!this->tnc_client)
! 232: {
! 233: batch->destroy(batch);
! 234: return FAILED;
! 235: }
! 236: this->tnccs_handler = this->tnc_client;
! 237: this->tnccs_handler->begin_handshake(this->tnccs_handler, this->mutual);
! 238: }
! 239: else
! 240: {
! 241: /* Set active TNCCS handler for processing */
! 242: this->tnccs_handler = this->to_server ? this->tnc_client :
! 243: this->tnc_server;
! 244: }
! 245: DBG2(DBG_TNC, "TNC %s is handling inbound connection",
! 246: this->to_server ? "client" : "server");
! 247:
! 248: if (status == SUCCESS)
! 249: {
! 250: status = this->tnccs_handler->process(this->tnccs_handler, batch);
! 251: }
! 252: if (status == VERIFY_ERROR)
! 253: {
! 254: this->tnccs_handler->handle_errors(this->tnccs_handler, batch,
! 255: fatal_header_error);
! 256: status = NEED_MORE;
! 257: }
! 258: batch->destroy(batch);
! 259:
! 260: /* Has a mutual connection been established? */
! 261: this->mutual = this->is_server ?
! 262: this->tnc_server->get_mutual(this->tnc_server) :
! 263: this->tnc_client->get_mutual(this->tnc_client);
! 264:
! 265: if (this->mutual && !this->is_server)
! 266: {
! 267: pb_tnc_state_t client_state, server_state;
! 268:
! 269: client_state = !this->tnc_client ? PB_STATE_INIT :
! 270: this->tnc_client->get_state(this->tnc_client);
! 271: server_state = !this->tnc_server ? PB_STATE_INIT :
! 272: this->tnc_server->get_state(this->tnc_server);
! 273:
! 274: /* In half-duplex mutual mode toggle the direction on the client side */
! 275: if ((!this->to_server && client_state != PB_STATE_DECIDED) ||
! 276: ( this->to_server && server_state != PB_STATE_END))
! 277: {
! 278: this->to_server = !this->to_server;
! 279: }
! 280: else if (client_state == PB_STATE_DECIDED &&
! 281: server_state == PB_STATE_END)
! 282: {
! 283: /* Cause the final CLOSE batch to be sent to the TNC server */
! 284: this->to_server = TRUE;
! 285: }
! 286:
! 287: /* Suppress a successful CLOSE batch coming from the TNC server */
! 288: if (status == SUCCESS)
! 289: {
! 290: is_complete(this);
! 291: status = NEED_MORE;
! 292: }
! 293: }
! 294:
! 295: return status;
! 296: }
! 297:
! 298: METHOD(tls_t, build, status_t,
! 299: private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
! 300: {
! 301: if (this->to_server)
! 302: {
! 303: DBG2(DBG_TNC, "TNC client is handling outbound connection");
! 304:
! 305: /* Before sending the first PB-TNC batch create TNC client */
! 306: if (this->tnc_client)
! 307: {
! 308: this->tnccs_handler = this->tnc_client;
! 309: }
! 310: else
! 311: {
! 312: this->tnc_client = tnccs_20_client_create(&this->public, _send_msg,
! 313: this->max_batch_len,
! 314: this->max_msg_len);
! 315: if (!this->tnc_client)
! 316: {
! 317: return FAILED;
! 318: }
! 319: this->tnccs_handler = this->tnc_client;
! 320: this->tnccs_handler->begin_handshake(this->tnccs_handler,
! 321: this->mutual);
! 322: }
! 323: }
! 324: else
! 325: {
! 326: DBG2(DBG_TNC, "TNC server is handling outbound connection");
! 327:
! 328: /* Before sending the first PB-TNC batch create TNC server */
! 329: if (this->tnc_server)
! 330: {
! 331: this->tnccs_handler = this->tnc_server;
! 332: }
! 333: else
! 334: {
! 335: this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
! 336: this->max_batch_len, this->max_msg_len,
! 337: this->eap_transport);
! 338: if (!this->tnc_server)
! 339: {
! 340: return FAILED;
! 341: }
! 342: this->tnccs_handler = this->tnc_server;
! 343: this->tnccs_handler->begin_handshake(this->tnccs_handler,
! 344: this->mutual);
! 345: }
! 346: }
! 347: return this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen);
! 348: }
! 349:
! 350: METHOD(tls_t, is_server, bool,
! 351: private_tnccs_20_t *this)
! 352: {
! 353: return this->is_server;
! 354: }
! 355:
! 356: METHOD(tls_t, get_server_id, identification_t*,
! 357: private_tnccs_20_t *this)
! 358: {
! 359: return this->server_id;
! 360: }
! 361:
! 362: METHOD(tls_t, set_peer_id, void,
! 363: private_tnccs_20_t *this, identification_t *id)
! 364: {
! 365: DESTROY_IF(this->peer_id);
! 366: this->peer_id = id->clone(id);
! 367: }
! 368:
! 369: METHOD(tls_t, get_peer_id, identification_t*,
! 370: private_tnccs_20_t *this)
! 371: {
! 372: return this->peer_id;
! 373: }
! 374:
! 375: METHOD(tls_t, get_purpose, tls_purpose_t,
! 376: private_tnccs_20_t *this)
! 377: {
! 378: return TLS_PURPOSE_EAP_TNC;
! 379: }
! 380:
! 381: METHOD(tls_t, get_eap_msk, chunk_t,
! 382: private_tnccs_20_t *this)
! 383: {
! 384: return chunk_empty;
! 385: }
! 386:
! 387: METHOD(tls_t, destroy, void,
! 388: private_tnccs_20_t *this)
! 389: {
! 390: if (ref_put(&this->ref))
! 391: {
! 392: DESTROY_IF(this->tnc_server);
! 393: DESTROY_IF(this->tnc_client);
! 394: this->server_id->destroy(this->server_id);
! 395: this->peer_id->destroy(this->peer_id);
! 396: this->server_ip->destroy(this->server_ip);
! 397: this->peer_ip->destroy(this->peer_ip);
! 398: free(this);
! 399: }
! 400: }
! 401:
! 402: METHOD(tnccs_t, get_server_ip, host_t*,
! 403: private_tnccs_20_t *this)
! 404: {
! 405: return this->server_ip;
! 406: }
! 407:
! 408: METHOD(tnccs_t, get_peer_ip, host_t*,
! 409: private_tnccs_20_t *this)
! 410: {
! 411: return this->peer_ip;
! 412: }
! 413:
! 414: METHOD(tnccs_t, get_transport, tnc_ift_type_t,
! 415: private_tnccs_20_t *this)
! 416: {
! 417: return this->transport;
! 418: }
! 419:
! 420: METHOD(tnccs_t, set_transport, void,
! 421: private_tnccs_20_t *this, tnc_ift_type_t transport)
! 422: {
! 423: this->transport = transport;
! 424: }
! 425:
! 426: METHOD(tnccs_t, get_auth_type, uint32_t,
! 427: private_tnccs_20_t *this)
! 428: {
! 429: return this->auth_type;
! 430: }
! 431:
! 432: METHOD(tnccs_t, set_auth_type, void,
! 433: private_tnccs_20_t *this, uint32_t auth_type)
! 434: {
! 435: this->auth_type = auth_type;
! 436: }
! 437:
! 438: METHOD(tnccs_t, get_pdp_server, chunk_t,
! 439: private_tnccs_20_t *this, uint16_t *port)
! 440: {
! 441: if (this->tnc_client)
! 442: {
! 443: tnccs_20_client_t *tnc_client;
! 444:
! 445: tnc_client = (tnccs_20_client_t*)this->tnc_client;
! 446:
! 447: return tnc_client->get_pdp_server(tnc_client, port);
! 448: }
! 449: else
! 450: {
! 451: *port = 0;
! 452: return chunk_empty;
! 453: }
! 454: }
! 455:
! 456: METHOD(tnccs_t, get_ref, tnccs_t*,
! 457: private_tnccs_20_t *this)
! 458: {
! 459: ref_get(&this->ref);
! 460: return &this->public;
! 461: }
! 462:
! 463: /**
! 464: * See header
! 465: */
! 466: tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id,
! 467: identification_t *peer_id, host_t *server_ip,
! 468: host_t *peer_ip, tnc_ift_type_t transport,
! 469: tnccs_cb_t cb)
! 470: {
! 471: private_tnccs_20_t *this;
! 472: size_t max_batch_size, default_max_batch_size;
! 473: size_t max_message_size, default_max_message_size;
! 474:
! 475: /* Determine the maximum PB-TNC batch size and PA-TNC message size */
! 476: switch (transport)
! 477: {
! 478: case TNC_IFT_TLS_2_0:
! 479: case TNC_IFT_TLS_1_0:
! 480: default_max_batch_size = 128 * TLS_MAX_FRAGMENT_LEN - 16;
! 481: break;
! 482: case TNC_IFT_EAP_2_0:
! 483: case TNC_IFT_EAP_1_1:
! 484: case TNC_IFT_EAP_1_0:
! 485: case TNC_IFT_UNKNOWN:
! 486: default:
! 487: default_max_batch_size = 4 * TLS_MAX_FRAGMENT_LEN - 14;
! 488: break;
! 489: }
! 490:
! 491: max_batch_size = min(default_max_batch_size,
! 492: lib->settings->get_int(lib->settings,
! 493: "%s.plugins.tnccs-20.max_batch_size",
! 494: default_max_batch_size, lib->ns));
! 495:
! 496: default_max_message_size = max_batch_size - PB_TNC_BATCH_HEADER_SIZE
! 497: - PB_TNC_MSG_HEADER_SIZE
! 498: - PB_PA_MSG_HEADER_SIZE;
! 499:
! 500: max_message_size = min(default_max_message_size,
! 501: lib->settings->get_int(lib->settings,
! 502: "%s.plugins.tnccs-20.max_message_size",
! 503: default_max_message_size, lib->ns));
! 504:
! 505: INIT(this,
! 506: .public = {
! 507: .tls = {
! 508: .process = _process,
! 509: .build = _build,
! 510: .is_server = _is_server,
! 511: .get_server_id = _get_server_id,
! 512: .set_peer_id = _set_peer_id,
! 513: .get_peer_id = _get_peer_id,
! 514: .get_purpose = _get_purpose,
! 515: .is_complete = _is_complete,
! 516: .get_eap_msk = _get_eap_msk,
! 517: .destroy = _destroy,
! 518: },
! 519: .get_server_ip = _get_server_ip,
! 520: .get_peer_ip = _get_peer_ip,
! 521: .get_transport = _get_transport,
! 522: .set_transport = _set_transport,
! 523: .get_auth_type = _get_auth_type,
! 524: .set_auth_type = _set_auth_type,
! 525: .get_pdp_server = _get_pdp_server,
! 526: .get_ref = _get_ref,
! 527: },
! 528: .is_server = is_server,
! 529: .to_server = !is_server,
! 530: .server_id = server_id->clone(server_id),
! 531: .peer_id = peer_id->clone(peer_id),
! 532: .server_ip = server_ip->clone(server_ip),
! 533: .peer_ip = peer_ip->clone(peer_ip),
! 534: .transport = transport,
! 535: .eap_transport = transport == TNC_IFT_EAP_1_1 ||
! 536: transport == TNC_IFT_EAP_2_0,
! 537: .callback = cb,
! 538: .max_batch_len = max_batch_size,
! 539: .max_msg_len = max_message_size,
! 540: .ref = 1,
! 541: );
! 542:
! 543: return &this->public;
! 544: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>