87efaff7e405f1f17d450b6aca1000cd016766f1
[strongswan.git] / src / libimcv / plugins / imc_test / imc_test.c
1 /*
2 * Copyright (C) 2011-2012 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 "imc_test_state.h"
17
18 #include <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ita/ita_attr.h>
22 #include <ita/ita_attr_command.h>
23 #include <ita/ita_attr_dummy.h>
24
25 #include <tncif_pa_subtypes.h>
26
27 #include <pen/pen.h>
28 #include <utils/debug.h>
29
30 /* IMC definitions */
31
32 static const char imc_name[] = "Test";
33
34 static pen_type_t msg_types[] = {
35 { PEN_ITA, PA_SUBTYPE_ITA_TEST }
36 };
37
38 static imc_agent_t *imc_test;
39
40 /**
41 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
42 */
43 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
44 TNC_Version min_version,
45 TNC_Version max_version,
46 TNC_Version *actual_version)
47 {
48 if (imc_test)
49 {
50 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
51 return TNC_RESULT_ALREADY_INITIALIZED;
52 }
53 imc_test = imc_agent_create(imc_name, msg_types, 1, imc_id, actual_version);
54 if (!imc_test)
55 {
56 return TNC_RESULT_FATAL;
57 }
58 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
59 {
60 DBG1(DBG_IMC, "no common IF-IMC version");
61 return TNC_RESULT_NO_COMMON_VERSION;
62 }
63 return TNC_RESULT_SUCCESS;
64 }
65
66 /**
67 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
68 */
69 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
70 TNC_ConnectionID connection_id,
71 TNC_ConnectionState new_state)
72 {
73 imc_state_t *state;
74 imc_test_state_t *test_state;
75 TNC_Result result;
76 TNC_UInt32 additional_id;
77 char *command;
78 bool retry;
79 void *pointer;
80 enumerator_t *enumerator;
81 int dummy_size, additional_ids;
82
83 if (!imc_test)
84 {
85 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
86 return TNC_RESULT_NOT_INITIALIZED;
87 }
88
89 switch (new_state)
90 {
91 case TNC_CONNECTION_STATE_CREATE:
92 command = lib->settings->get_str(lib->settings,
93 "libimcv.plugins.imc-test.command", "none");
94 dummy_size = lib->settings->get_int(lib->settings,
95 "libimcv.plugins.imc-test.dummy_size", 0);
96 retry = lib->settings->get_bool(lib->settings,
97 "libimcv.plugins.imc-test.retry", FALSE);
98 state = imc_test_state_create(connection_id, command, dummy_size,
99 retry);
100
101 result = imc_test->create_state(imc_test, state);
102 if (result != TNC_RESULT_SUCCESS)
103 {
104 return result;
105 }
106
107 /* Optionally reserve additional IMC IDs */
108 additional_ids = lib->settings->get_int(lib->settings,
109 "libimcv.plugins.imc-test.additional_ids", 0);
110 imc_test->reserve_additional_ids(imc_test, additional_ids -
111 imc_test->count_additional_ids(imc_test));
112
113 return TNC_RESULT_SUCCESS;
114
115 case TNC_CONNECTION_STATE_HANDSHAKE:
116 /* get updated IMC state */
117 result = imc_test->change_state(imc_test, connection_id,
118 new_state, &state);
119 if (result != TNC_RESULT_SUCCESS)
120 {
121 return TNC_RESULT_FATAL;
122 }
123 test_state = (imc_test_state_t*)state;
124
125 /* is it the first handshake or a retry ? */
126 if (!test_state->is_first_handshake(test_state))
127 {
128 command = lib->settings->get_str(lib->settings,
129 "libimcv.plugins.imc-test.retry_command",
130 test_state->get_command(test_state));
131 test_state->set_command(test_state, command);
132 }
133
134 state->set_result(state, imc_id, TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
135
136 /* Exit if there are no additional IMC IDs */
137 if (!imc_test->count_additional_ids(imc_test))
138 {
139 return result;
140 }
141
142 enumerator = imc_test->create_id_enumerator(imc_test);
143 while (enumerator->enumerate(enumerator, &pointer))
144 {
145 /* interpret pointer as scalar value */
146 additional_id = (TNC_UInt32)pointer;
147
148 state->set_result(state, additional_id,
149 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
150 }
151 enumerator->destroy(enumerator);
152
153 return TNC_RESULT_SUCCESS;
154
155 case TNC_CONNECTION_STATE_DELETE:
156 return imc_test->delete_state(imc_test, connection_id);
157
158 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
159 case TNC_CONNECTION_STATE_ACCESS_NONE:
160 /* get updated IMC state */
161 result = imc_test->change_state(imc_test, connection_id,
162 new_state, &state);
163 if (result != TNC_RESULT_SUCCESS)
164 {
165 return TNC_RESULT_FATAL;
166 }
167 test_state = (imc_test_state_t*)state;
168
169 /* do a handshake retry? */
170 if (test_state->do_handshake_retry(test_state))
171 {
172 return imc_test->request_handshake_retry(imc_id, connection_id,
173 TNC_RETRY_REASON_IMC_REMEDIATION_COMPLETE);
174 }
175 return TNC_RESULT_SUCCESS;
176
177 default:
178 return imc_test->change_state(imc_test, connection_id,
179 new_state, NULL);
180 }
181 }
182
183 static TNC_Result send_message(imc_state_t *state, imc_msg_t *out_msg)
184 {
185 imc_test_state_t *test_state;
186 pa_tnc_attr_t *attr;
187
188 test_state = (imc_test_state_t*)state;
189 if (test_state->get_dummy_size(test_state))
190 {
191 attr = ita_attr_dummy_create(test_state->get_dummy_size(test_state));
192 attr->set_noskip_flag(attr, TRUE);
193 out_msg->add_attribute(out_msg, attr);
194 }
195 attr = ita_attr_command_create(test_state->get_command(test_state));
196 attr->set_noskip_flag(attr, TRUE);
197 out_msg->add_attribute(out_msg, attr);
198
199 /* send PA-TNC message with the excl flag set */
200 return out_msg->send(out_msg, TRUE);
201 }
202
203 /**
204 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
205 */
206 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
207 TNC_ConnectionID connection_id)
208 {
209 imc_state_t *state;
210 imc_msg_t *out_msg;
211 enumerator_t *enumerator;
212 void *pointer;
213 TNC_UInt32 additional_id;
214 TNC_Result result;
215
216 if (!imc_test)
217 {
218 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
219 return TNC_RESULT_NOT_INITIALIZED;
220 }
221 if (!imc_test->get_state(imc_test, connection_id, &state))
222 {
223 return TNC_RESULT_FATAL;
224 }
225
226 /* send PA message for primary IMC ID */
227 out_msg = imc_msg_create(imc_test, state, connection_id, imc_id,
228 TNC_IMVID_ANY, msg_types[0]);
229 result = send_message(state, out_msg);
230 out_msg->destroy(out_msg);
231
232 /* Exit if there are no additional IMC IDs */
233 if (!imc_test->count_additional_ids(imc_test))
234 {
235 return result;
236 }
237
238 /* Do we have support for transporting multiple IMC IDs? */
239 if (!state->has_long(state))
240 {
241 DBG1(DBG_IMC, "IMC %u \"%s\" did not detect support for transporting "
242 "multiple IMC IDs", imc_id, imc_name);
243 return result;
244 }
245
246 /* send PA messages for additional IMC IDs */
247 enumerator = imc_test->create_id_enumerator(imc_test);
248 while (result == TNC_RESULT_SUCCESS &&
249 enumerator->enumerate(enumerator, &pointer))
250 {
251 /* interpret pointer as scalar value */
252 additional_id = (TNC_UInt32)pointer;
253 out_msg = imc_msg_create(imc_test, state, connection_id, additional_id,
254 TNC_IMVID_ANY, msg_types[0]);
255 result = send_message(state, out_msg);
256 out_msg->destroy(out_msg);
257 }
258 enumerator->destroy(enumerator);
259
260 return result;
261 }
262
263 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
264 {
265 imc_msg_t *out_msg;
266 enumerator_t *enumerator;
267 pa_tnc_attr_t *attr;
268 pen_type_t attr_type;
269 TNC_Result result;
270 bool fatal_error = FALSE;
271
272 /* parse received PA-TNC message and handle local and remote errors */
273 result = in_msg->receive(in_msg, &fatal_error);
274 if (result != TNC_RESULT_SUCCESS)
275 {
276 return result;
277 }
278
279 /* analyze PA-TNC attributes */
280 enumerator = in_msg->create_attribute_enumerator(in_msg);
281 while (enumerator->enumerate(enumerator, &attr))
282 {
283 attr_type = attr->get_type(attr);
284
285 if (attr_type.vendor_id != PEN_ITA)
286 {
287 continue;
288 }
289 if (attr_type.type == ITA_ATTR_COMMAND)
290 {
291 ita_attr_command_t *ita_attr;
292
293 ita_attr = (ita_attr_command_t*)attr;
294 DBG1(DBG_IMC, "received command '%s'",
295 ita_attr->get_command(ita_attr));
296 }
297 else if (attr_type.type == ITA_ATTR_DUMMY)
298 {
299 ita_attr_dummy_t *ita_attr;
300
301 ita_attr = (ita_attr_dummy_t*)attr;
302 DBG1(DBG_IMC, "received dummy attribute value (%d bytes)",
303 ita_attr->get_size(ita_attr));
304 }
305 }
306 enumerator->destroy(enumerator);
307
308 if (fatal_error)
309 {
310 return TNC_RESULT_FATAL;
311 }
312
313 /* if no assessment result is known then repeat the measurement */
314 if (state->get_result(state, in_msg->get_dst_id(in_msg), NULL))
315 {
316 return TNC_RESULT_SUCCESS;
317 }
318 out_msg = imc_msg_create_as_reply(in_msg);
319 result = send_message(state, out_msg);
320 out_msg->destroy(out_msg);
321
322 return result;
323 }
324
325 /**
326 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
327 */
328 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
329 TNC_ConnectionID connection_id,
330 TNC_BufferReference msg,
331 TNC_UInt32 msg_len,
332 TNC_MessageType msg_type)
333 {
334 imc_state_t *state;
335 imc_msg_t *in_msg;
336 TNC_Result result;
337
338 if (!imc_test)
339 {
340 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
341 return TNC_RESULT_NOT_INITIALIZED;
342 }
343 if (!imc_test->get_state(imc_test, connection_id, &state))
344 {
345 return TNC_RESULT_FATAL;
346 }
347
348 in_msg = imc_msg_create_from_data(imc_test, state, connection_id, msg_type,
349 chunk_create(msg, msg_len));
350 result = receive_message(state, in_msg);
351 in_msg->destroy(in_msg);
352
353 return result;
354 }
355
356 /**
357 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
358 */
359 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
360 TNC_ConnectionID connection_id,
361 TNC_UInt32 msg_flags,
362 TNC_BufferReference msg,
363 TNC_UInt32 msg_len,
364 TNC_VendorID msg_vid,
365 TNC_MessageSubtype msg_subtype,
366 TNC_UInt32 src_imv_id,
367 TNC_UInt32 dst_imc_id)
368 {
369 imc_state_t *state;
370 imc_msg_t *in_msg;
371 TNC_Result result;
372
373 if (!imc_test)
374 {
375 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
376 return TNC_RESULT_NOT_INITIALIZED;
377 }
378 if (!imc_test->get_state(imc_test, connection_id, &state))
379 {
380 return TNC_RESULT_FATAL;
381 }
382 in_msg = imc_msg_create_from_long_data(imc_test, state, connection_id,
383 src_imv_id, dst_imc_id, msg_vid, msg_subtype,
384 chunk_create(msg, msg_len));
385 result =receive_message(state, in_msg);
386 in_msg->destroy(in_msg);
387
388 return result;
389 }
390
391 /**
392 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
393 */
394 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
395 TNC_ConnectionID connection_id)
396 {
397 if (!imc_test)
398 {
399 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
400 return TNC_RESULT_NOT_INITIALIZED;
401 }
402 return TNC_RESULT_SUCCESS;
403 }
404
405 /**
406 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
407 */
408 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
409 {
410 if (!imc_test)
411 {
412 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
413 return TNC_RESULT_NOT_INITIALIZED;
414 }
415 imc_test->destroy(imc_test);
416 imc_test = NULL;
417
418 return TNC_RESULT_SUCCESS;
419 }
420
421 /**
422 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
423 */
424 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
425 TNC_TNCC_BindFunctionPointer bind_function)
426 {
427 if (!imc_test)
428 {
429 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
430 return TNC_RESULT_NOT_INITIALIZED;
431 }
432 return imc_test->bind_functions(imc_test, bind_function);
433 }