]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libtnccs/plugins/tnccs_20/tnccs_20.c
33b01288055f25c8e5e5be1ae7bbd5ff98c4cfd4
[thirdparty/strongswan.git] / src / libtnccs / plugins / tnccs_20 / tnccs_20.c
1 /*
2 * Copyright (C) 2010 Sansar Choinyanbuu
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 u_int32_t auth_type;
81
82 /**
83 * Mutual TNC measurements
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(tnccs_t, send_msg, TNC_Result,
130 private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
131 TNC_UInt32 msg_flags,
132 TNC_BufferReference msg,
133 TNC_UInt32 msg_len,
134 TNC_VendorID msg_vid,
135 TNC_MessageSubtype msg_subtype)
136 {
137 pb_tnc_msg_t *pb_tnc_msg;
138 enum_name_t *pa_subtype_names;
139 bool excl;
140
141 if (!this->tnccs_handler->get_send_flag(this->tnccs_handler))
142 {
143 DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()",
144 this->to_server ? "IMC" : "IMV",
145 this->to_server ? imc_id : imv_id);
146
147 return TNC_RESULT_ILLEGAL_OPERATION;
148 }
149 excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0;
150
151 pb_tnc_msg = pb_pa_msg_create(msg_vid, msg_subtype, imc_id, imv_id,
152 excl, chunk_create(msg, msg_len));
153
154 pa_subtype_names = get_pa_subtype_names(msg_vid);
155 if (pa_subtype_names)
156 {
157 DBG2(DBG_TNC, "creating PB-PA message type '%N/%N' 0x%06x/0x%08x",
158 pen_names, msg_vid, pa_subtype_names, msg_subtype,
159 msg_vid, msg_subtype);
160 }
161 else
162 {
163 DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x",
164 pen_names, msg_vid, msg_vid, msg_subtype);
165 }
166 this->tnccs_handler->add_msg(this->tnccs_handler, pb_tnc_msg);
167
168 return TNC_RESULT_SUCCESS;
169 }
170
171 METHOD(tls_t, process, status_t,
172 private_tnccs_20_t *this, void *buf, size_t buflen)
173 {
174 chunk_t data;
175 pb_tnc_batch_t *batch;
176 bool from_server, mutual;
177 status_t status;
178
179 /* On arrival of first PB-TNC batch create TNC server */
180 if (this->is_server && !this->tnc_server)
181 {
182 this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
183 this->max_batch_len, this->max_msg_len,
184 this->eap_transport);
185 if (!this->tnc_server)
186 {
187 return FAILED;
188 }
189 this->tnccs_handler = this->tnc_server;
190 this->tnccs_handler->begin_handshake(this->tnccs_handler);
191 }
192
193 data = chunk_create(buf, buflen);
194 DBG1(DBG_TNC, "received TNCCS batch (%u bytes)", data.len);
195 DBG3(DBG_TNC, "%B", &data);
196
197 /* Has a mutual connection been established? */
198 mutual = this->tnc_client && this->tnc_server;
199
200 /* Parse the header of the received PB-TNC batch */
201 batch = pb_tnc_batch_create_from_data(data);
202 status = batch->process_header(batch, !mutual, this->is_server,
203 &from_server);
204 this->to_server = mutual ? from_server : !this->is_server;
205
206 /* Set active TNCCS handler */
207 this->tnccs_handler = this->to_server ? this->tnc_client : this->tnc_server;
208 DBG2(DBG_TNC, "TNC %s is handling the connection",
209 this->to_server ? "client" : "server");
210
211 if (status == SUCCESS)
212 {
213 status = this->tnccs_handler->process(this->tnccs_handler, batch);
214 }
215 if (status == VERIFY_ERROR)
216 {
217 this->tnccs_handler->handle_errors(this->tnccs_handler, batch);
218 status = NEED_MORE;
219 }
220 batch->destroy(batch);
221
222 return status;
223 }
224
225 METHOD(tls_t, build, status_t,
226 private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen)
227 {
228 status_t status;
229
230 if (this->to_server)
231 {
232 /* Before sending the first PB-TNC batch create TNC client */
233 if (!this->tnc_client)
234 {
235 DBG2(DBG_TNC, "TNC client is handling the connection");
236 this->tnc_client = tnccs_20_client_create(&this->public, _send_msg,
237 this->max_batch_len,
238 this->max_msg_len);
239 if (!this->tnc_client)
240 {
241 status = FAILED;
242 }
243 this->tnccs_handler = this->tnc_client;
244 this->tnccs_handler->begin_handshake(this->tnccs_handler);
245 }
246 }
247 else
248 {
249 /* Before sending the first PB-TNC batch create TNC server */
250 if (!this->tnc_server)
251 {
252 DBG2(DBG_TNC, "TNC server is handling the connection");
253 this->tnc_server = tnccs_20_server_create(&this->public, _send_msg,
254 this->max_batch_len, this->max_msg_len,
255 this->eap_transport);
256 if (!this->tnc_server)
257 {
258 status = FAILED;
259 }
260 this->tnccs_handler = this->tnc_server;
261 this->tnccs_handler->begin_handshake(this->tnccs_handler);
262 }
263 }
264 status = this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen);
265
266 return status;
267 }
268
269 METHOD(tls_t, is_server, bool,
270 private_tnccs_20_t *this)
271 {
272 return this->is_server;
273 }
274
275 METHOD(tls_t, get_server_id, identification_t*,
276 private_tnccs_20_t *this)
277 {
278 return this->server_id;
279 }
280
281 METHOD(tls_t, set_peer_id, void,
282 private_tnccs_20_t *this, identification_t *id)
283 {
284 DESTROY_IF(this->peer_id);
285 this->peer_id = id->clone(id);
286 }
287
288 METHOD(tls_t, get_peer_id, identification_t*,
289 private_tnccs_20_t *this)
290 {
291 return this->peer_id;
292 }
293
294 METHOD(tls_t, get_purpose, tls_purpose_t,
295 private_tnccs_20_t *this)
296 {
297 return TLS_PURPOSE_EAP_TNC;
298 }
299
300 METHOD(tls_t, is_complete, bool,
301 private_tnccs_20_t *this)
302 {
303 TNC_IMV_Action_Recommendation rec;
304 TNC_IMV_Evaluation_Result eval;
305
306 if (this->tnc_server)
307 {
308 tnccs_20_server_t *tnc_server;
309
310 tnc_server = (tnccs_20_server_t*)this->tnc_server;
311 if (tnc_server->have_recommendation(tnc_server, &rec, &eval))
312 {
313 return this->callback ? this->callback(rec, eval) : TRUE;
314 }
315 }
316 return FALSE;
317 }
318
319 METHOD(tls_t, get_eap_msk, chunk_t,
320 private_tnccs_20_t *this)
321 {
322 return chunk_empty;
323 }
324
325 METHOD(tls_t, destroy, void,
326 private_tnccs_20_t *this)
327 {
328 if (ref_put(&this->ref))
329 {
330 DESTROY_IF(this->tnc_server);
331 DESTROY_IF(this->tnc_client);
332 this->server_id->destroy(this->server_id);
333 this->peer_id->destroy(this->peer_id);
334 this->server_ip->destroy(this->server_ip);
335 this->peer_ip->destroy(this->peer_ip);
336 free(this);
337 }
338 }
339
340 METHOD(tnccs_t, get_server_ip, host_t*,
341 private_tnccs_20_t *this)
342 {
343 return this->server_ip;
344 }
345
346 METHOD(tnccs_t, get_peer_ip, host_t*,
347 private_tnccs_20_t *this)
348 {
349 return this->peer_ip;
350 }
351
352 METHOD(tnccs_t, get_transport, tnc_ift_type_t,
353 private_tnccs_20_t *this)
354 {
355 return this->transport;
356 }
357
358 METHOD(tnccs_t, set_transport, void,
359 private_tnccs_20_t *this, tnc_ift_type_t transport)
360 {
361 this->transport = transport;
362 }
363
364 METHOD(tnccs_t, get_auth_type, u_int32_t,
365 private_tnccs_20_t *this)
366 {
367 return this->auth_type;
368 }
369
370 METHOD(tnccs_t, set_auth_type, void,
371 private_tnccs_20_t *this, u_int32_t auth_type)
372 {
373 this->auth_type = auth_type;
374 }
375
376 METHOD(tnccs_t, get_pdp_server, chunk_t,
377 private_tnccs_20_t *this, u_int16_t *port)
378 {
379 if (this->tnc_client)
380 {
381 tnccs_20_client_t *tnc_client;
382
383 tnc_client = (tnccs_20_client_t*)this->tnc_client;
384
385 return tnc_client->get_pdp_server(tnc_client, port);
386 }
387 else
388 {
389 *port = 0;
390 return chunk_empty;
391 }
392 }
393
394 METHOD(tnccs_t, get_ref, tnccs_t*,
395 private_tnccs_20_t *this)
396 {
397 ref_get(&this->ref);
398 return &this->public;
399 }
400
401 /**
402 * See header
403 */
404 tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id,
405 identification_t *peer_id, host_t *server_ip,
406 host_t *peer_ip, tnc_ift_type_t transport,
407 tnccs_cb_t cb)
408 {
409 private_tnccs_20_t *this;
410 size_t max_batch_size, default_max_batch_size;
411 size_t max_message_size, default_max_message_size;
412
413 /* Determine the maximum PB-TNC batch size and PA-TNC message size */
414 switch (transport)
415 {
416 case TNC_IFT_TLS_2_0:
417 case TNC_IFT_TLS_1_0:
418 default_max_batch_size = 128 * TLS_MAX_FRAGMENT_LEN - 16;
419 break;
420 case TNC_IFT_EAP_2_0:
421 case TNC_IFT_EAP_1_1:
422 case TNC_IFT_EAP_1_0:
423 case TNC_IFT_UNKNOWN:
424 default:
425 default_max_batch_size = 4 * TLS_MAX_FRAGMENT_LEN - 14;
426 break;
427 }
428
429 max_batch_size = min(default_max_batch_size,
430 lib->settings->get_int(lib->settings,
431 "%s.plugins.tnccs-20.max_batch_size",
432 default_max_batch_size, lib->ns));
433
434 default_max_message_size = max_batch_size - PB_TNC_BATCH_HEADER_SIZE
435 - PB_TNC_MSG_HEADER_SIZE
436 - PB_PA_MSG_HEADER_SIZE;
437
438 max_message_size = min(default_max_message_size,
439 lib->settings->get_int(lib->settings,
440 "%s.plugins.tnccs-20.max_message_size",
441 default_max_message_size, lib->ns));
442
443 INIT(this,
444 .public = {
445 .tls = {
446 .process = _process,
447 .build = _build,
448 .is_server = _is_server,
449 .get_server_id = _get_server_id,
450 .set_peer_id = _set_peer_id,
451 .get_peer_id = _get_peer_id,
452 .get_purpose = _get_purpose,
453 .is_complete = _is_complete,
454 .get_eap_msk = _get_eap_msk,
455 .destroy = _destroy,
456 },
457 .get_server_ip = _get_server_ip,
458 .get_peer_ip = _get_peer_ip,
459 .get_transport = _get_transport,
460 .set_transport = _set_transport,
461 .get_auth_type = _get_auth_type,
462 .set_auth_type = _set_auth_type,
463 .get_pdp_server = _get_pdp_server,
464 .get_ref = _get_ref,
465 },
466 .is_server = is_server,
467 .to_server = !is_server,
468 .server_id = server_id->clone(server_id),
469 .peer_id = peer_id->clone(peer_id),
470 .server_ip = server_ip->clone(server_ip),
471 .peer_ip = peer_ip->clone(peer_ip),
472 .transport = transport,
473 .eap_transport = transport == TNC_IFT_EAP_1_1 ||
474 transport == TNC_IFT_EAP_2_0,
475 .callback = cb,
476 .max_batch_len = max_batch_size,
477 .max_msg_len = max_message_size,
478 .ref = 1,
479 );
480
481 return &this->public;
482 }