Annotation of embedaddon/strongswan/src/libtnccs/plugins/tnccs_20/tnccs_20.c, revision 1.1.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>