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