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>
23 #include <ita/ita_attr_dummy.h>
25 #include <tncif_names.h>
26 #include <tncif_pa_subtypes.h>
33 static const char imv_name
[] = "Test";
35 #define IMV_VENDOR_ID PEN_ITA
36 #define IMV_SUBTYPE PA_SUBTYPE_ITA_TEST
38 static imv_agent_t
*imv_test
;
41 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
43 TNC_Result
TNC_IMV_Initialize(TNC_IMVID imv_id
,
44 TNC_Version min_version
,
45 TNC_Version max_version
,
46 TNC_Version
*actual_version
)
50 DBG1(DBG_IMV
, "IMV \"%s\" has already been initialized", imv_name
);
51 return TNC_RESULT_ALREADY_INITIALIZED
;
53 imv_test
= imv_agent_create(imv_name
, IMV_VENDOR_ID
, IMV_SUBTYPE
,
54 imv_id
, actual_version
);
57 return TNC_RESULT_FATAL
;
59 if (min_version
> TNC_IFIMV_VERSION_1
|| max_version
< TNC_IFIMV_VERSION_1
)
61 DBG1(DBG_IMV
, "no common IF-IMV version");
62 return TNC_RESULT_NO_COMMON_VERSION
;
64 return TNC_RESULT_SUCCESS
;
68 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
70 TNC_Result
TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id
,
71 TNC_ConnectionID connection_id
,
72 TNC_ConnectionState new_state
)
78 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
79 return TNC_RESULT_NOT_INITIALIZED
;
83 case TNC_CONNECTION_STATE_CREATE
:
84 state
= imv_test_state_create(connection_id
);
85 return imv_test
->create_state(imv_test
, state
);
86 case TNC_CONNECTION_STATE_DELETE
:
87 return imv_test
->delete_state(imv_test
, connection_id
);
89 return imv_test
->change_state(imv_test
, connection_id
,
94 static TNC_Result
receive_message(TNC_IMVID imv_id
,
95 TNC_ConnectionID connection_id
,
99 TNC_MessageSubtype msg_subtype
,
100 TNC_UInt32 src_imc_id
,
101 TNC_UInt32 dst_imv_id
)
103 pa_tnc_msg_t
*pa_tnc_msg
;
106 imv_test_state_t
*test_state
;
107 enumerator_t
*enumerator
;
110 bool fatal_error
, retry
= FALSE
;
114 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
115 return TNC_RESULT_NOT_INITIALIZED
;
118 /* get current IMV state */
119 if (!imv_test
->get_state(imv_test
, connection_id
, &state
))
121 return TNC_RESULT_FATAL
;
123 test_state
= (imv_test_state_t
*)state
;
125 /* parse received PA-TNC message and automatically handle any errors */
126 result
= imv_test
->receive_message(imv_test
, state
, msg
, msg_vid
,
127 msg_subtype
, src_imc_id
, dst_imv_id
, &pa_tnc_msg
);
129 /* no parsed PA-TNC attributes available if an error occurred */
135 /* preprocess any IETF standard error attributes */
136 fatal_error
= pa_tnc_msg
->process_ietf_std_errors(pa_tnc_msg
);
138 /* add any new IMC and set its number of rounds */
139 rounds
= lib
->settings
->get_int(lib
->settings
,
140 "libimcv.plugins.imv-test.rounds", 0);
141 test_state
->add_imc(test_state
, src_imc_id
, rounds
);
143 /* analyze PA-TNC attributes */
144 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
145 while (enumerator
->enumerate(enumerator
, &attr
))
147 if (attr
->get_vendor_id(attr
) != PEN_ITA
)
151 if (attr
->get_type(attr
) == ITA_ATTR_COMMAND
)
153 ita_attr_command_t
*ita_attr
;
156 ita_attr
= (ita_attr_command_t
*)attr
;
157 command
= ita_attr
->get_command(ita_attr
);
159 if (streq(command
, "allow"))
161 state
->set_recommendation(state
,
162 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
163 TNC_IMV_EVALUATION_RESULT_COMPLIANT
);
165 else if (streq(command
, "isolate"))
167 state
->set_recommendation(state
,
168 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
169 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR
);
171 else if (streq(command
, "block") || streq(command
, "none"))
173 state
->set_recommendation(state
,
174 TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
,
175 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
);
177 else if (streq(command
, "retry"))
183 DBG1(DBG_IMV
, "unsupported ITA Command '%s'", command
);
184 state
->set_recommendation(state
,
185 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
186 TNC_IMV_EVALUATION_RESULT_ERROR
);
189 else if (attr
->get_type(attr
) == ITA_ATTR_DUMMY
)
191 ita_attr_dummy_t
*ita_attr
;
193 ita_attr
= (ita_attr_dummy_t
*)attr
;
194 DBG1(DBG_IMV
, "received dummy attribute value (%d bytes)",
195 ita_attr
->get_size(ita_attr
));
198 enumerator
->destroy(enumerator
);
199 pa_tnc_msg
->destroy(pa_tnc_msg
);
203 state
->set_recommendation(state
,
204 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
205 TNC_IMV_EVALUATION_RESULT_ERROR
);
206 return imv_test
->provide_recommendation(imv_test
, connection_id
);
209 /* request a handshake retry ? */
212 test_state
->set_rounds(test_state
, rounds
);
213 return imv_test
->request_handshake_retry(imv_id
, connection_id
,
214 TNC_RETRY_REASON_IMV_SERIOUS_EVENT
);
217 /* repeat the measurement ? */
218 if (test_state
->another_round(test_state
, src_imc_id
))
220 attr
= ita_attr_command_create("repeat");
221 pa_tnc_msg
= pa_tnc_msg_create();
222 pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
);
223 pa_tnc_msg
->build(pa_tnc_msg
);
224 result
= imv_test
->send_message(imv_test
, connection_id
, TRUE
, imv_id
,
225 src_imc_id
, pa_tnc_msg
->get_encoding(pa_tnc_msg
));
226 pa_tnc_msg
->destroy(pa_tnc_msg
);
231 return imv_test
->provide_recommendation(imv_test
, connection_id
);
235 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
237 TNC_Result
TNC_IMV_ReceiveMessage(TNC_IMVID imv_id
,
238 TNC_ConnectionID connection_id
,
239 TNC_BufferReference msg
,
241 TNC_MessageType msg_type
)
243 TNC_VendorID msg_vid
;
244 TNC_MessageSubtype msg_subtype
;
246 msg_vid
= msg_type
>> 8;
247 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
249 return receive_message(imv_id
, connection_id
, 0, chunk_create(msg
, msg_len
),
250 msg_vid
, msg_subtype
, 0, TNC_IMVID_ANY
);
254 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
256 TNC_Result
TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id
,
257 TNC_ConnectionID connection_id
,
258 TNC_UInt32 msg_flags
,
259 TNC_BufferReference msg
,
261 TNC_VendorID msg_vid
,
262 TNC_MessageSubtype msg_subtype
,
263 TNC_UInt32 src_imc_id
,
264 TNC_UInt32 dst_imv_id
)
266 return receive_message(imv_id
, connection_id
, msg_flags
,
267 chunk_create(msg
, msg_len
), msg_vid
, msg_subtype
,
268 src_imc_id
, dst_imv_id
);
272 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
274 TNC_Result
TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id
,
275 TNC_ConnectionID connection_id
)
279 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
280 return TNC_RESULT_NOT_INITIALIZED
;
282 return imv_test
->provide_recommendation(imv_test
, connection_id
);
286 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
288 TNC_Result
TNC_IMV_BatchEnding(TNC_IMVID imv_id
,
289 TNC_ConnectionID connection_id
)
293 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
294 return TNC_RESULT_NOT_INITIALIZED
;
296 return TNC_RESULT_SUCCESS
;
300 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
302 TNC_Result
TNC_IMV_Terminate(TNC_IMVID imv_id
)
306 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
307 return TNC_RESULT_NOT_INITIALIZED
;
309 imv_test
->destroy(imv_test
);
312 return TNC_RESULT_SUCCESS
;
316 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
318 TNC_Result
TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id
,
319 TNC_TNCS_BindFunctionPointer bind_function
)
323 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
324 return TNC_RESULT_NOT_INITIALIZED
;
326 return imv_test
->bind_functions(imv_test
, bind_function
);