2 * Copyright (C) 2013-2017 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "imc_swid_state.h"
18 #include <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include "tcg/seg/tcg_seg_attr_max_size.h"
21 #include "tcg/seg/tcg_seg_attr_seg_env.h"
22 #include "tcg/swid/tcg_swid_attr_req.h"
23 #include "tcg/swid/tcg_swid_attr_tag_inv.h"
24 #include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
25 #include "swid/swid_inventory.h"
26 #include "swid/swid_error.h"
28 #include <tncif_pa_subtypes.h>
31 #include <utils/debug.h>
35 static const char imc_name
[] = "SWID";
37 static pen_type_t msg_types
[] = {
38 { PEN_TCG
, PA_SUBTYPE_TCG_SWID
}
41 static imc_agent_t
*imc_swid
;
44 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
46 TNC_Result
TNC_IMC_Initialize(TNC_IMCID imc_id
,
47 TNC_Version min_version
,
48 TNC_Version max_version
,
49 TNC_Version
*actual_version
)
53 DBG1(DBG_IMC
, "IMC \"%s\" has already been initialized", imc_name
);
54 return TNC_RESULT_ALREADY_INITIALIZED
;
56 imc_swid
= imc_agent_create(imc_name
, msg_types
, countof(msg_types
),
57 imc_id
, actual_version
);
60 return TNC_RESULT_FATAL
;
62 if (min_version
> TNC_IFIMC_VERSION_1
|| max_version
< TNC_IFIMC_VERSION_1
)
64 DBG1(DBG_IMC
, "no common IF-IMC version");
65 return TNC_RESULT_NO_COMMON_VERSION
;
67 return TNC_RESULT_SUCCESS
;
71 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
73 TNC_Result
TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id
,
74 TNC_ConnectionID connection_id
,
75 TNC_ConnectionState new_state
)
81 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
82 return TNC_RESULT_NOT_INITIALIZED
;
86 case TNC_CONNECTION_STATE_CREATE
:
87 state
= imc_swid_state_create(connection_id
);
88 return imc_swid
->create_state(imc_swid
, state
);
89 case TNC_CONNECTION_STATE_HANDSHAKE
:
90 if (imc_swid
->change_state(imc_swid
, connection_id
, new_state
,
91 &state
) != TNC_RESULT_SUCCESS
)
93 return TNC_RESULT_FATAL
;
95 state
->set_result(state
, imc_id
,
96 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
97 return TNC_RESULT_SUCCESS
;
98 case TNC_CONNECTION_STATE_DELETE
:
99 return imc_swid
->delete_state(imc_swid
, connection_id
);
101 return imc_swid
->change_state(imc_swid
, connection_id
,
107 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
109 TNC_Result
TNC_IMC_BeginHandshake(TNC_IMCID imc_id
,
110 TNC_ConnectionID connection_id
)
115 seg_contract_t
*contract
;
116 seg_contract_manager_t
*contracts
;
117 size_t max_attr_size
= SWID_MAX_ATTR_SIZE
;
120 TNC_Result result
= TNC_RESULT_SUCCESS
;
124 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
125 return TNC_RESULT_NOT_INITIALIZED
;
127 if (!imc_swid
->get_state(imc_swid
, connection_id
, &state
))
129 return TNC_RESULT_FATAL
;
132 /* Determine maximum PA-TNC attribute segment size */
133 max_seg_size
= state
->get_max_msg_len(state
) - PA_TNC_HEADER_SIZE
134 - PA_TNC_ATTR_HEADER_SIZE
135 - TCG_SEG_ATTR_SEG_ENV_HEADER
;
137 /* Announce support of PA-TNC segmentation to IMV */
138 contract
= seg_contract_create(msg_types
[0], max_attr_size
, max_seg_size
,
140 contract
->get_info_string(contract
, buf
, BUF_LEN
, TRUE
);
141 DBG2(DBG_IMC
, "%s", buf
);
142 contracts
= state
->get_contracts(state
);
143 contracts
->add_contract(contracts
, contract
);
144 attr
= tcg_seg_attr_max_size_create(max_attr_size
, max_seg_size
, TRUE
);
146 /* send PA-TNC message with the excl flag not set */
147 out_msg
= imc_msg_create(imc_swid
, state
, connection_id
, imc_id
,
148 TNC_IMVID_ANY
, msg_types
[0]);
149 out_msg
->add_attribute(out_msg
, attr
);
150 result
= out_msg
->send(out_msg
, FALSE
);
151 out_msg
->destroy(out_msg
);
157 * Add one or multiple SWID Inventory attributes to the send queue
159 static bool add_swid_inventory(imc_state_t
*state
, imc_msg_t
*msg
,
160 uint32_t request_id
, bool full_tags
,
161 swid_inventory_t
*targets
)
163 pa_tnc_attr_t
*attr
, *attr_error
;
164 imc_swid_state_t
*swid_state
;
165 swid_inventory_t
*swid_inventory
;
166 char *swid_directory
;
168 bool swid_pretty
, swid_full
;
169 enumerator_t
*enumerator
;
171 swid_directory
= lib
->settings
->get_str(lib
->settings
,
172 "%s.plugins.imc-swid.swid_directory",
173 SWID_DIRECTORY
, lib
->ns
);
174 swid_pretty
= lib
->settings
->get_bool(lib
->settings
,
175 "%s.plugins.imc-swid.swid_pretty",
177 swid_full
= lib
->settings
->get_bool(lib
->settings
,
178 "%s.plugins.imc-swid.swid_full",
181 swid_inventory
= swid_inventory_create(full_tags
);
182 if (!swid_inventory
->collect(swid_inventory
, swid_directory
, targets
,
183 swid_pretty
, swid_full
))
185 swid_inventory
->destroy(swid_inventory
);
186 attr_error
= swid_error_create(TCG_SWID_ERROR
, request_id
,
187 0, "error in SWID tag collection");
188 msg
->add_attribute(msg
, attr_error
);
191 DBG1(DBG_IMC
, "collected %d SWID tag%s%s",
192 swid_inventory
->get_count(swid_inventory
), full_tags
? "" : " ID",
193 swid_inventory
->get_count(swid_inventory
) == 1 ? "" : "s");
195 swid_state
= (imc_swid_state_t
*)state
;
196 eid_epoch
= swid_state
->get_eid_epoch(swid_state
);
200 tcg_swid_attr_tag_inv_t
*swid_attr
;
203 /* Send a TCG SWID Tag Inventory attribute */
204 attr
= tcg_swid_attr_tag_inv_create(request_id
, eid_epoch
, 1);
205 swid_attr
= (tcg_swid_attr_tag_inv_t
*)attr
;
207 enumerator
= swid_inventory
->create_enumerator(swid_inventory
);
208 while (enumerator
->enumerate(enumerator
, &tag
))
210 swid_attr
->add(swid_attr
, tag
->get_ref(tag
));
212 enumerator
->destroy(enumerator
);
216 tcg_swid_attr_tag_id_inv_t
*swid_id_attr
;
217 swid_tag_id_t
*tag_id
;
219 /* Send a TCG SWID Tag ID Inventory attribute */
220 attr
= tcg_swid_attr_tag_id_inv_create(request_id
, eid_epoch
, 1);
221 swid_id_attr
= (tcg_swid_attr_tag_id_inv_t
*)attr
;
223 enumerator
= swid_inventory
->create_enumerator(swid_inventory
);
224 while (enumerator
->enumerate(enumerator
, &tag_id
))
226 swid_id_attr
->add(swid_id_attr
, tag_id
->get_ref(tag_id
));
228 enumerator
->destroy(enumerator
);
231 msg
->add_attribute(msg
, attr
);
232 swid_inventory
->destroy(swid_inventory
);
237 static TNC_Result
receive_message(imc_state_t
*state
, imc_msg_t
*in_msg
)
241 enumerator_t
*enumerator
;
244 bool fatal_error
= FALSE
;
246 /* generate an outgoing PA-TNC message - we might need it */
247 out_msg
= imc_msg_create_as_reply(in_msg
);
249 /* parse received PA-TNC message and handle local and remote errors */
250 result
= in_msg
->receive(in_msg
, out_msg
, &fatal_error
);
251 if (result
!= TNC_RESULT_SUCCESS
)
253 out_msg
->destroy(out_msg
);
257 /* analyze PA-TNC attributes */
258 enumerator
= in_msg
->create_attribute_enumerator(in_msg
);
259 while (enumerator
->enumerate(enumerator
, &attr
))
261 tcg_swid_attr_req_t
*attr_req
;
265 swid_inventory_t
*targets
;
267 type
= attr
->get_type(attr
);
269 if (type
.vendor_id
!= PEN_TCG
|| type
.type
!= TCG_SWID_REQUEST
)
274 attr_req
= (tcg_swid_attr_req_t
*)attr
;
275 flags
= attr_req
->get_flags(attr_req
);
276 request_id
= attr_req
->get_request_id(attr_req
);
277 targets
= attr_req
->get_targets(attr_req
);
279 if (flags
& (TCG_SWID_ATTR_REQ_FLAG_S
| TCG_SWID_ATTR_REQ_FLAG_C
))
281 attr
= swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED
, request_id
,
282 0, "no subscription available yet");
283 out_msg
->add_attribute(out_msg
, attr
);
286 full_tags
= (flags
& TCG_SWID_ATTR_REQ_FLAG_R
) == 0;
288 if (!add_swid_inventory(state
, out_msg
, request_id
, full_tags
, targets
))
293 enumerator
->destroy(enumerator
);
297 result
= TNC_RESULT_FATAL
;
301 /* send PA-TNC message with the EXCL flag set */
302 result
= out_msg
->send(out_msg
, TRUE
);
304 out_msg
->destroy(out_msg
);
310 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
313 TNC_Result
TNC_IMC_ReceiveMessage(TNC_IMCID imc_id
,
314 TNC_ConnectionID connection_id
,
315 TNC_BufferReference msg
,
317 TNC_MessageType msg_type
)
325 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
326 return TNC_RESULT_NOT_INITIALIZED
;
328 if (!imc_swid
->get_state(imc_swid
, connection_id
, &state
))
330 return TNC_RESULT_FATAL
;
332 in_msg
= imc_msg_create_from_data(imc_swid
, state
, connection_id
, msg_type
,
333 chunk_create(msg
, msg_len
));
334 result
= receive_message(state
, in_msg
);
335 in_msg
->destroy(in_msg
);
341 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
343 TNC_Result
TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id
,
344 TNC_ConnectionID connection_id
,
345 TNC_UInt32 msg_flags
,
346 TNC_BufferReference msg
,
348 TNC_VendorID msg_vid
,
349 TNC_MessageSubtype msg_subtype
,
350 TNC_UInt32 src_imv_id
,
351 TNC_UInt32 dst_imc_id
)
359 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
360 return TNC_RESULT_NOT_INITIALIZED
;
362 if (!imc_swid
->get_state(imc_swid
, connection_id
, &state
))
364 return TNC_RESULT_FATAL
;
366 in_msg
= imc_msg_create_from_long_data(imc_swid
, state
, connection_id
,
367 src_imv_id
, dst_imc_id
,msg_vid
, msg_subtype
,
368 chunk_create(msg
, msg_len
));
369 result
=receive_message(state
, in_msg
);
370 in_msg
->destroy(in_msg
);
376 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
378 TNC_Result
TNC_IMC_BatchEnding(TNC_IMCID imc_id
,
379 TNC_ConnectionID connection_id
)
383 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
384 return TNC_RESULT_NOT_INITIALIZED
;
386 return TNC_RESULT_SUCCESS
;
390 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
392 TNC_Result
TNC_IMC_Terminate(TNC_IMCID imc_id
)
396 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
397 return TNC_RESULT_NOT_INITIALIZED
;
399 imc_swid
->destroy(imc_swid
);
402 return TNC_RESULT_SUCCESS
;
406 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
408 TNC_Result
TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id
,
409 TNC_TNCC_BindFunctionPointer bind_function
)
413 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
414 return TNC_RESULT_NOT_INITIALIZED
;
416 return imc_swid
->bind_functions(imc_swid
, bind_function
);