2 * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 #include "imv_test_state.h"
17 #include <imv/imv_agent.h>
18 #include <pa_tnc/pa_tnc_msg.h>
19 #include <ietf/ietf_attr.h>
20 #include <ietf/ietf_attr_pa_tnc_error.h>
21 #include <ita/ita_attr.h>
22 #include <ita/ita_attr_command.h>
24 #include <tncif_names.h>
25 #include <tncif_pa_subtypes.h>
32 static const char imv_name
[] = "Test";
34 #define IMV_VENDOR_ID PEN_ITA
35 #define IMV_SUBTYPE PA_SUBTYPE_ITA_TEST
37 static imv_agent_t
*imv_test
;
40 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
42 TNC_Result
TNC_IMV_Initialize(TNC_IMVID imv_id
,
43 TNC_Version min_version
,
44 TNC_Version max_version
,
45 TNC_Version
*actual_version
)
49 DBG1(DBG_IMV
, "IMV \"%s\" has already been initialized", imv_name
);
50 return TNC_RESULT_ALREADY_INITIALIZED
;
52 imv_test
= imv_agent_create(imv_name
, IMV_VENDOR_ID
, IMV_SUBTYPE
,
53 imv_id
, actual_version
);
56 return TNC_RESULT_FATAL
;
58 if (min_version
> TNC_IFIMV_VERSION_1
|| max_version
< TNC_IFIMV_VERSION_1
)
60 DBG1(DBG_IMV
, "no common IF-IMV version");
61 return TNC_RESULT_NO_COMMON_VERSION
;
63 return TNC_RESULT_SUCCESS
;
67 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
69 TNC_Result
TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id
,
70 TNC_ConnectionID connection_id
,
71 TNC_ConnectionState new_state
)
74 imv_test_state_t
*test_state
;
80 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
81 return TNC_RESULT_NOT_INITIALIZED
;
85 case TNC_CONNECTION_STATE_CREATE
:
86 state
= imv_test_state_create(connection_id
);
87 return imv_test
->create_state(imv_test
, state
);
88 case TNC_CONNECTION_STATE_DELETE
:
89 return imv_test
->delete_state(imv_test
, connection_id
);
90 case TNC_CONNECTION_STATE_HANDSHAKE
:
91 /* get updated IMV state */
92 result
= imv_test
->change_state(imv_test
, connection_id
,
94 if (result
!= TNC_RESULT_SUCCESS
)
98 test_state
= (imv_test_state_t
*)state
;
100 /* set the number of measurement rounds */
101 rounds
= lib
->settings
->get_int(lib
->settings
,
102 "libimcv.plugins.imv-test.rounds", 0);
103 test_state
->set_rounds(test_state
, rounds
);
104 return TNC_RESULT_SUCCESS
;
106 return imv_test
->change_state(imv_test
, connection_id
,
111 static TNC_Result
send_message(TNC_ConnectionID connection_id
)
117 attr
= ita_attr_command_create("repeat");
118 msg
= pa_tnc_msg_create();
119 msg
->add_attribute(msg
, attr
);
121 result
= imv_test
->send_message(imv_test
, connection_id
, FALSE
, 0,
122 TNC_IMCID_ANY
, msg
->get_encoding(msg
));
128 static TNC_Result
receive_message(TNC_IMVID imv_id
,
129 TNC_ConnectionID connection_id
,
130 TNC_UInt32 msg_flags
,
132 TNC_VendorID msg_vid
,
133 TNC_MessageSubtype msg_subtype
,
134 TNC_UInt32 src_imc_id
,
135 TNC_UInt32 dst_imv_id
)
137 pa_tnc_msg_t
*pa_tnc_msg
;
140 imv_test_state_t
*imv_test_state
;
141 enumerator_t
*enumerator
;
143 bool fatal_error
= FALSE
, retry
= FALSE
;
147 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
148 return TNC_RESULT_NOT_INITIALIZED
;
151 /* get current IMV state */
152 if (!imv_test
->get_state(imv_test
, connection_id
, &state
))
154 return TNC_RESULT_FATAL
;
157 /* parse received PA-TNC message and automatically handle any errors */
158 result
= imv_test
->receive_message(imv_test
, state
, msg
, msg_vid
,
159 msg_subtype
, src_imc_id
, dst_imv_id
, &pa_tnc_msg
);
161 /* no parsed PA-TNC attributes available if an error occurred */
167 /* analyze PA-TNC attributes */
168 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
169 while (enumerator
->enumerate(enumerator
, &attr
))
171 if (attr
->get_vendor_id(attr
) == PEN_IETF
&&
172 attr
->get_type(attr
) == IETF_ATTR_PA_TNC_ERROR
)
174 ietf_attr_pa_tnc_error_t
*error_attr
;
175 pa_tnc_error_code_t error_code
;
176 chunk_t msg_info
, attr_info
;
179 error_attr
= (ietf_attr_pa_tnc_error_t
*)attr
;
180 error_code
= error_attr
->get_error_code(error_attr
);
181 msg_info
= error_attr
->get_msg_info(error_attr
);
183 DBG1(DBG_IMV
, "received PA-TNC error '%N' concerning message %#B",
184 pa_tnc_error_code_names
, error_code
, &msg_info
);
187 case PA_ERROR_INVALID_PARAMETER
:
188 offset
= error_attr
->get_offset(error_attr
);
189 DBG1(DBG_IMV
, " occurred at offset of %u bytes", offset
);
191 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
192 attr_info
= error_attr
->get_attr_info(error_attr
);
193 DBG1(DBG_IMV
, " unsupported attribute %#B", &attr_info
);
200 else if (attr
->get_vendor_id(attr
) == PEN_ITA
&&
201 attr
->get_type(attr
) == ITA_ATTR_COMMAND
)
203 ita_attr_command_t
*ita_attr
;
206 ita_attr
= (ita_attr_command_t
*)attr
;
207 command
= ita_attr
->get_command(ita_attr
);
209 if (streq(command
, "allow"))
211 state
->set_recommendation(state
,
212 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
213 TNC_IMV_EVALUATION_RESULT_COMPLIANT
);
215 else if (streq(command
, "isolate"))
217 state
->set_recommendation(state
,
218 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
219 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR
);
221 else if (streq(command
, "block") || streq(command
, "none"))
223 state
->set_recommendation(state
,
224 TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
,
225 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
);
227 else if (streq(command
, "retry"))
233 DBG1(DBG_IMV
, "unsupported ITA Command '%s'", command
);
234 state
->set_recommendation(state
,
235 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
236 TNC_IMV_EVALUATION_RESULT_ERROR
);
240 enumerator
->destroy(enumerator
);
241 pa_tnc_msg
->destroy(pa_tnc_msg
);
245 state
->set_recommendation(state
,
246 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
247 TNC_IMV_EVALUATION_RESULT_ERROR
);
248 return imv_test
->provide_recommendation(imv_test
, connection_id
);
251 /* request a handshake retry ? */
254 return imv_test
->request_handshake_retry(imv_id
, connection_id
,
255 TNC_RETRY_REASON_IMV_SERIOUS_EVENT
);
258 /* repeat the measurement ? */
259 imv_test_state
= (imv_test_state_t
*)state
;
260 if (imv_test_state
->another_round(imv_test_state
))
262 return send_message(connection_id
);
265 return imv_test
->provide_recommendation(imv_test
, connection_id
);
269 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
271 TNC_Result
TNC_IMV_ReceiveMessage(TNC_IMVID imv_id
,
272 TNC_ConnectionID connection_id
,
273 TNC_BufferReference msg
,
275 TNC_MessageType msg_type
)
277 TNC_VendorID msg_vid
;
278 TNC_MessageSubtype msg_subtype
;
280 msg_vid
= msg_type
>> 8;
281 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
283 return receive_message(imv_id
, connection_id
, 0, chunk_create(msg
, msg_len
),
284 msg_vid
, msg_subtype
, 0, TNC_IMVID_ANY
);
288 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
290 TNC_Result
TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id
,
291 TNC_ConnectionID connection_id
,
292 TNC_UInt32 msg_flags
,
293 TNC_BufferReference msg
,
295 TNC_VendorID msg_vid
,
296 TNC_MessageSubtype msg_subtype
,
297 TNC_UInt32 src_imc_id
,
298 TNC_UInt32 dst_imv_id
)
300 return receive_message(imv_id
, connection_id
, msg_flags
,
301 chunk_create(msg
, msg_len
), msg_vid
, msg_subtype
,
302 src_imc_id
, dst_imv_id
);
306 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
308 TNC_Result
TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id
,
309 TNC_ConnectionID connection_id
)
313 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
314 return TNC_RESULT_NOT_INITIALIZED
;
316 return imv_test
->provide_recommendation(imv_test
, connection_id
);
320 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
322 TNC_Result
TNC_IMV_BatchEnding(TNC_IMVID imv_id
,
323 TNC_ConnectionID connection_id
)
327 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
328 return TNC_RESULT_NOT_INITIALIZED
;
330 return TNC_RESULT_SUCCESS
;
334 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
336 TNC_Result
TNC_IMV_Terminate(TNC_IMVID imv_id
)
340 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
341 return TNC_RESULT_NOT_INITIALIZED
;
343 imv_test
->destroy(imv_test
);
346 return TNC_RESULT_SUCCESS
;
350 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
352 TNC_Result
TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id
,
353 TNC_TNCS_BindFunctionPointer bind_function
)
357 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
358 return TNC_RESULT_NOT_INITIALIZED
;
360 return imv_test
->bind_functions(imv_test
, bind_function
);