swid-gen: Share SWID generator between sw-collector, imc-swima and imc-swid
[strongswan.git] / src / libimcv / plugins / imc_swid / imc_swid.c
1 /*
2 * Copyright (C) 2013-2017 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_swid_state.h"
17
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"
27
28 #include <tncif_pa_subtypes.h>
29
30 #include <pen/pen.h>
31 #include <utils/debug.h>
32
33 /* IMC definitions */
34
35 static const char imc_name[] = "SWID";
36
37 static pen_type_t msg_types[] = {
38 { PEN_TCG, PA_SUBTYPE_TCG_SWID }
39 };
40
41 static imc_agent_t *imc_swid;
42
43 /**
44 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
45 */
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)
50 {
51 if (imc_swid)
52 {
53 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
54 return TNC_RESULT_ALREADY_INITIALIZED;
55 }
56 imc_swid = imc_agent_create(imc_name, msg_types, countof(msg_types),
57 imc_id, actual_version);
58 if (!imc_swid)
59 {
60 return TNC_RESULT_FATAL;
61 }
62 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
63 {
64 DBG1(DBG_IMC, "no common IF-IMC version");
65 return TNC_RESULT_NO_COMMON_VERSION;
66 }
67 return TNC_RESULT_SUCCESS;
68 }
69
70 /**
71 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
72 */
73 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
74 TNC_ConnectionID connection_id,
75 TNC_ConnectionState new_state)
76 {
77 imc_state_t *state;
78
79 if (!imc_swid)
80 {
81 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
82 return TNC_RESULT_NOT_INITIALIZED;
83 }
84 switch (new_state)
85 {
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)
92 {
93 return TNC_RESULT_FATAL;
94 }
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);
100 default:
101 return imc_swid->change_state(imc_swid, connection_id,
102 new_state, NULL);
103 }
104 }
105
106 /**
107 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
108 */
109 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
110 TNC_ConnectionID connection_id)
111 {
112 imc_state_t *state;
113 imc_msg_t *out_msg;
114 pa_tnc_attr_t *attr;
115 seg_contract_t *contract;
116 seg_contract_manager_t *contracts;
117 size_t max_attr_size = SWID_MAX_ATTR_SIZE;
118 size_t max_seg_size;
119 char buf[BUF_LEN];
120 TNC_Result result = TNC_RESULT_SUCCESS;
121
122 if (!imc_swid)
123 {
124 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
125 return TNC_RESULT_NOT_INITIALIZED;
126 }
127 if (!imc_swid->get_state(imc_swid, connection_id, &state))
128 {
129 return TNC_RESULT_FATAL;
130 }
131
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;
136
137 /* Announce support of PA-TNC segmentation to IMV */
138 contract = seg_contract_create(msg_types[0], max_attr_size, max_seg_size,
139 TRUE, imc_id, TRUE);
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);
145
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);
152
153 return result;
154 }
155
156 /**
157 * Add one or multiple SWID Inventory attributes to the send queue
158 */
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)
162 {
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;
167 uint32_t eid_epoch;
168 bool swid_pretty, swid_full;
169 enumerator_t *enumerator;
170
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",
176 FALSE, lib->ns);
177 swid_full = lib->settings->get_bool(lib->settings,
178 "%s.plugins.imc-swid.swid_full",
179 FALSE, lib->ns);
180
181 swid_inventory = swid_inventory_create(full_tags);
182 if (!swid_inventory->collect(swid_inventory, swid_directory, targets,
183 swid_pretty, swid_full))
184 {
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);
189 return FALSE;
190 }
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");
194
195 swid_state = (imc_swid_state_t*)state;
196 eid_epoch = swid_state->get_eid_epoch(swid_state);
197
198 if (full_tags)
199 {
200 tcg_swid_attr_tag_inv_t *swid_attr;
201 swid_tag_t *tag;
202
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;
206
207 enumerator = swid_inventory->create_enumerator(swid_inventory);
208 while (enumerator->enumerate(enumerator, &tag))
209 {
210 swid_attr->add(swid_attr, tag->get_ref(tag));
211 }
212 enumerator->destroy(enumerator);
213 }
214 else
215 {
216 tcg_swid_attr_tag_id_inv_t *swid_id_attr;
217 swid_tag_id_t *tag_id;
218
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;
222
223 enumerator = swid_inventory->create_enumerator(swid_inventory);
224 while (enumerator->enumerate(enumerator, &tag_id))
225 {
226 swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
227 }
228 enumerator->destroy(enumerator);
229 }
230
231 msg->add_attribute(msg, attr);
232 swid_inventory->destroy(swid_inventory);
233
234 return TRUE;
235 }
236
237 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
238 {
239 imc_msg_t *out_msg;
240 pa_tnc_attr_t *attr;
241 enumerator_t *enumerator;
242 pen_type_t type;
243 TNC_Result result;
244 bool fatal_error = FALSE;
245
246 /* generate an outgoing PA-TNC message - we might need it */
247 out_msg = imc_msg_create_as_reply(in_msg);
248
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)
252 {
253 out_msg->destroy(out_msg);
254 return result;
255 }
256
257 /* analyze PA-TNC attributes */
258 enumerator = in_msg->create_attribute_enumerator(in_msg);
259 while (enumerator->enumerate(enumerator, &attr))
260 {
261 tcg_swid_attr_req_t *attr_req;
262 uint8_t flags;
263 uint32_t request_id;
264 bool full_tags;
265 swid_inventory_t *targets;
266
267 type = attr->get_type(attr);
268
269 if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
270 {
271 continue;
272 }
273
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);
278
279 if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
280 {
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);
284 break;
285 }
286 full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
287
288 if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
289 {
290 break;
291 }
292 }
293 enumerator->destroy(enumerator);
294
295 if (fatal_error)
296 {
297 result = TNC_RESULT_FATAL;
298 }
299 else
300 {
301 /* send PA-TNC message with the EXCL flag set */
302 result = out_msg->send(out_msg, TRUE);
303 }
304 out_msg->destroy(out_msg);
305
306 return result;
307 }
308
309 /**
310 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
311
312 */
313 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
314 TNC_ConnectionID connection_id,
315 TNC_BufferReference msg,
316 TNC_UInt32 msg_len,
317 TNC_MessageType msg_type)
318 {
319 imc_state_t *state;
320 imc_msg_t *in_msg;
321 TNC_Result result;
322
323 if (!imc_swid)
324 {
325 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
326 return TNC_RESULT_NOT_INITIALIZED;
327 }
328 if (!imc_swid->get_state(imc_swid, connection_id, &state))
329 {
330 return TNC_RESULT_FATAL;
331 }
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);
336
337 return result;
338 }
339
340 /**
341 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
342 */
343 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
344 TNC_ConnectionID connection_id,
345 TNC_UInt32 msg_flags,
346 TNC_BufferReference msg,
347 TNC_UInt32 msg_len,
348 TNC_VendorID msg_vid,
349 TNC_MessageSubtype msg_subtype,
350 TNC_UInt32 src_imv_id,
351 TNC_UInt32 dst_imc_id)
352 {
353 imc_state_t *state;
354 imc_msg_t *in_msg;
355 TNC_Result result;
356
357 if (!imc_swid)
358 {
359 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
360 return TNC_RESULT_NOT_INITIALIZED;
361 }
362 if (!imc_swid->get_state(imc_swid, connection_id, &state))
363 {
364 return TNC_RESULT_FATAL;
365 }
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);
371
372 return result;
373 }
374
375 /**
376 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
377 */
378 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
379 TNC_ConnectionID connection_id)
380 {
381 if (!imc_swid)
382 {
383 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
384 return TNC_RESULT_NOT_INITIALIZED;
385 }
386 return TNC_RESULT_SUCCESS;
387 }
388
389 /**
390 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
391 */
392 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
393 {
394 if (!imc_swid)
395 {
396 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
397 return TNC_RESULT_NOT_INITIALIZED;
398 }
399 imc_swid->destroy(imc_swid);
400 imc_swid = NULL;
401
402 return TNC_RESULT_SUCCESS;
403 }
404
405 /**
406 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
407 */
408 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
409 TNC_TNCC_BindFunctionPointer bind_function)
410 {
411 if (!imc_swid)
412 {
413 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
414 return TNC_RESULT_NOT_INITIALIZED;
415 }
416 return imc_swid->bind_functions(imc_swid, bind_function);
417 }