Use python-based swidGenerator to generated SWID tags
[strongswan.git] / src / libpts / plugins / imc_swid / imc_swid.c
1 /*
2 * Copyright (C) 2013-2014 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 "libpts.h"
19 #include "swid/swid_inventory.h"
20 #include "swid/swid_error.h"
21 #include "tcg/swid/tcg_swid_attr_req.h"
22 #include "tcg/swid/tcg_swid_attr_tag_inv.h"
23 #include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
24
25 #include <imc/imc_agent.h>
26 #include <imc/imc_msg.h>
27 #include <ita/ita_attr.h>
28 #include <ita/ita_attr_angel.h>
29
30 #include <tncif_pa_subtypes.h>
31
32 #include <pen/pen.h>
33 #include <utils/debug.h>
34
35 #define SWID_GENERATOR "/usr/local/bin/swid_generator"
36
37 /* IMC definitions */
38
39 static const char imc_name[] = "SWID";
40
41 static pen_type_t msg_types[] = {
42 { PEN_TCG, PA_SUBTYPE_TCG_SWID }
43 };
44
45 static imc_agent_t *imc_swid;
46
47 /**
48 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
49 */
50 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
51 TNC_Version min_version,
52 TNC_Version max_version,
53 TNC_Version *actual_version)
54 {
55 if (imc_swid)
56 {
57 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
58 return TNC_RESULT_ALREADY_INITIALIZED;
59 }
60 imc_swid = imc_agent_create(imc_name, msg_types, countof(msg_types),
61 imc_id, actual_version);
62 if (!imc_swid)
63 {
64 return TNC_RESULT_FATAL;
65 }
66
67 libpts_init();
68
69 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
70 {
71 DBG1(DBG_IMC, "no common IF-IMC version");
72 return TNC_RESULT_NO_COMMON_VERSION;
73 }
74 return TNC_RESULT_SUCCESS;
75 }
76
77 /**
78 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
79 */
80 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
81 TNC_ConnectionID connection_id,
82 TNC_ConnectionState new_state)
83 {
84 imc_state_t *state;
85
86 if (!imc_swid)
87 {
88 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
89 return TNC_RESULT_NOT_INITIALIZED;
90 }
91 switch (new_state)
92 {
93 case TNC_CONNECTION_STATE_CREATE:
94 state = imc_swid_state_create(connection_id);
95 return imc_swid->create_state(imc_swid, state);
96 case TNC_CONNECTION_STATE_HANDSHAKE:
97 if (imc_swid->change_state(imc_swid, connection_id, new_state,
98 &state) != TNC_RESULT_SUCCESS)
99 {
100 return TNC_RESULT_FATAL;
101 }
102 state->set_result(state, imc_id,
103 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
104 return TNC_RESULT_SUCCESS;
105 case TNC_CONNECTION_STATE_DELETE:
106 return imc_swid->delete_state(imc_swid, connection_id);
107 default:
108 return imc_swid->change_state(imc_swid, connection_id,
109 new_state, NULL);
110 }
111 }
112
113 /**
114 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
115 */
116 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
117 TNC_ConnectionID connection_id)
118 {
119 imc_state_t *state;
120
121 if (!imc_swid)
122 {
123 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
124 return TNC_RESULT_NOT_INITIALIZED;
125 }
126 if (!imc_swid->get_state(imc_swid, connection_id, &state))
127 {
128 return TNC_RESULT_FATAL;
129 }
130
131 return TNC_RESULT_SUCCESS;
132 }
133
134 /**
135 * Add one or multiple SWID Inventory attributes to the send queue
136 */
137 static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
138 uint32_t request_id, bool full_tags,
139 swid_inventory_t *targets)
140 {
141 pa_tnc_attr_t *attr, *attr_angel;
142 imc_swid_state_t *swid_state;
143 swid_inventory_t *swid_inventory;
144 char *swid_directory, *swid_generator;
145 uint32_t eid_epoch;
146 size_t max_attr_size, attr_size, entry_size;
147 bool first = TRUE, swid_pretty, swid_full;
148 enumerator_t *enumerator;
149
150 swid_directory = lib->settings->get_str(lib->settings,
151 "%s.plugins.imc-swid.swid_directory",
152 SWID_DIRECTORY, lib->ns);
153 swid_generator = lib->settings->get_str(lib->settings,
154 "%s.plugins.imc-swid.swid_generator",
155 SWID_GENERATOR, lib->ns);
156 swid_pretty = lib->settings->get_bool(lib->settings,
157 "%s.plugins.imc-swid.swid_pretty",
158 FALSE, lib->ns);
159 swid_full = lib->settings->get_bool(lib->settings,
160 "%s.plugins.imc-swid.swid_full",
161 FALSE, lib->ns);
162
163 swid_inventory = swid_inventory_create(full_tags);
164 if (!swid_inventory->collect(swid_inventory, swid_directory, swid_generator,
165 targets, swid_pretty, swid_full))
166 {
167 swid_inventory->destroy(swid_inventory);
168 attr = swid_error_create(TCG_SWID_ERROR, request_id,
169 0, "error in SWID tag collection");
170 msg->add_attribute(msg, attr);
171 return FALSE;
172 }
173 DBG1(DBG_IMC, "collected %d SWID tag%s%s",
174 swid_inventory->get_count(swid_inventory), full_tags ? "" : " ID",
175 swid_inventory->get_count(swid_inventory) == 1 ? "" : "s");
176
177 swid_state = (imc_swid_state_t*)state;
178 eid_epoch = swid_state->get_eid_epoch(swid_state);
179
180 /**
181 * Compute the maximum TCG Tag [ID] Inventory attribute size
182 * leaving space for an additional ITA Angel attribute
183 */
184 max_attr_size = state->get_max_msg_len(state) -
185 PA_TNC_HEADER_SIZE - PA_TNC_ATTR_HEADER_SIZE;
186
187 if (full_tags)
188 {
189 tcg_swid_attr_tag_inv_t *swid_attr;
190 swid_tag_t *tag;
191 chunk_t encoding, tag_file_path;
192
193 /* At least one TCG Tag Inventory attribute is sent */
194 attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE;
195 attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
196
197 enumerator = swid_inventory->create_enumerator(swid_inventory);
198 while (enumerator->enumerate(enumerator, &tag))
199 {
200 tag_file_path = tag->get_tag_file_path(tag);
201 encoding = tag->get_encoding(tag);
202 entry_size = 2 + tag_file_path.len + 4 + encoding.len;
203
204 if (attr_size + entry_size > max_attr_size)
205 {
206 if (first)
207 {
208 /**
209 * Send an ITA Start Angel attribute to the IMV signalling
210 * that multiple TGC SWID Tag Inventory attributes follow
211 */
212 attr_angel = ita_attr_angel_create(TRUE);
213 msg->add_attribute(msg, attr_angel);
214 first = FALSE;
215 }
216 msg->add_attribute(msg, attr);
217
218 /* create the next TCG SWID Tag Inventory attribute */
219 attr_size = PA_TNC_ATTR_HEADER_SIZE +
220 TCG_SWID_TAG_INV_MIN_SIZE;
221 attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
222 }
223 swid_attr = (tcg_swid_attr_tag_inv_t*)attr;
224 swid_attr->add(swid_attr, tag->get_ref(tag));
225 attr_size += entry_size;
226 }
227 enumerator->destroy(enumerator);
228 }
229 else
230 {
231 tcg_swid_attr_tag_id_inv_t *swid_id_attr;
232 swid_tag_id_t *tag_id;
233 chunk_t tag_creator, unique_sw_id, tag_file_path;
234
235 /* At least one TCG Tag ID Inventory attribute is sent */
236 attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_ID_INV_MIN_SIZE;
237 attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
238 swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
239
240 enumerator = swid_inventory->create_enumerator(swid_inventory);
241 while (enumerator->enumerate(enumerator, &tag_id))
242 {
243 tag_creator = tag_id->get_tag_creator(tag_id);
244 unique_sw_id = tag_id->get_unique_sw_id(tag_id, &tag_file_path);
245 entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len +
246 2 + tag_file_path.len;
247
248 if (attr_size + entry_size > max_attr_size)
249 {
250 if (first)
251 {
252 /**
253 * Send an ITA Start Angel attribute to the IMV signalling
254 * that multiple TGC SWID Tag ID Inventory attributes follow
255 */
256 attr_angel = ita_attr_angel_create(TRUE);
257 msg->add_attribute(msg, attr_angel);
258 first = FALSE;
259 }
260 msg->add_attribute(msg, attr);
261
262 /* create the next TCG SWID Tag ID Inventory attribute */
263 attr_size = PA_TNC_ATTR_HEADER_SIZE +
264 TCG_SWID_TAG_ID_INV_MIN_SIZE;
265 attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
266 }
267 swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
268 swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
269 attr_size += entry_size;
270 }
271 enumerator->destroy(enumerator);
272 }
273 msg->add_attribute(msg, attr);
274 swid_inventory->destroy(swid_inventory);
275
276 return TRUE;
277 }
278
279 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
280 {
281 imc_msg_t *out_msg;
282 pa_tnc_attr_t *attr;
283 enumerator_t *enumerator;
284 pen_type_t type;
285 TNC_Result result;
286 bool fatal_error = FALSE;
287
288 /* parse received PA-TNC message and handle local and remote errors */
289 result = in_msg->receive(in_msg, &fatal_error);
290 if (result != TNC_RESULT_SUCCESS)
291 {
292 return result;
293 }
294 out_msg = imc_msg_create_as_reply(in_msg);
295
296 /* analyze PA-TNC attributes */
297 enumerator = in_msg->create_attribute_enumerator(in_msg);
298 while (enumerator->enumerate(enumerator, &attr))
299 {
300 tcg_swid_attr_req_t *attr_req;
301 uint8_t flags;
302 uint32_t request_id;
303 bool full_tags;
304 swid_inventory_t *targets;
305
306 type = attr->get_type(attr);
307
308 if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
309 {
310 continue;
311 }
312
313 attr_req = (tcg_swid_attr_req_t*)attr;
314 flags = attr_req->get_flags(attr_req);
315 request_id = attr_req->get_request_id(attr_req);
316 targets = attr_req->get_targets(attr_req);
317
318 if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
319 {
320 attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id,
321 0, "no subscription available yet");
322 out_msg->add_attribute(out_msg, attr);
323 break;
324 }
325 full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
326
327 if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
328 {
329 break;
330 }
331 }
332 enumerator->destroy(enumerator);
333
334 if (fatal_error)
335 {
336 result = TNC_RESULT_FATAL;
337 }
338 else
339 {
340 result = out_msg->send(out_msg, TRUE);
341 }
342 out_msg->destroy(out_msg);
343
344 return result;
345 }
346
347 /**
348 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
349
350 */
351 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
352 TNC_ConnectionID connection_id,
353 TNC_BufferReference msg,
354 TNC_UInt32 msg_len,
355 TNC_MessageType msg_type)
356 {
357 imc_state_t *state;
358 imc_msg_t *in_msg;
359 TNC_Result result;
360
361 if (!imc_swid)
362 {
363 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
364 return TNC_RESULT_NOT_INITIALIZED;
365 }
366 if (!imc_swid->get_state(imc_swid, connection_id, &state))
367 {
368 return TNC_RESULT_FATAL;
369 }
370 in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type,
371 chunk_create(msg, msg_len));
372 result = receive_message(state, in_msg);
373 in_msg->destroy(in_msg);
374
375 return result;
376 }
377
378 /**
379 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
380 */
381 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
382 TNC_ConnectionID connection_id,
383 TNC_UInt32 msg_flags,
384 TNC_BufferReference msg,
385 TNC_UInt32 msg_len,
386 TNC_VendorID msg_vid,
387 TNC_MessageSubtype msg_subtype,
388 TNC_UInt32 src_imv_id,
389 TNC_UInt32 dst_imc_id)
390 {
391 imc_state_t *state;
392 imc_msg_t *in_msg;
393 TNC_Result result;
394
395 if (!imc_swid)
396 {
397 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
398 return TNC_RESULT_NOT_INITIALIZED;
399 }
400 if (!imc_swid->get_state(imc_swid, connection_id, &state))
401 {
402 return TNC_RESULT_FATAL;
403 }
404 in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id,
405 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
406 chunk_create(msg, msg_len));
407 result =receive_message(state, in_msg);
408 in_msg->destroy(in_msg);
409
410 return result;
411 }
412
413 /**
414 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
415 */
416 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
417 TNC_ConnectionID connection_id)
418 {
419 if (!imc_swid)
420 {
421 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
422 return TNC_RESULT_NOT_INITIALIZED;
423 }
424 return TNC_RESULT_SUCCESS;
425 }
426
427 /**
428 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
429 */
430 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
431 {
432 if (!imc_swid)
433 {
434 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
435 return TNC_RESULT_NOT_INITIALIZED;
436 }
437
438 libpts_deinit();
439
440 imc_swid->destroy(imc_swid);
441 imc_swid = NULL;
442
443 return TNC_RESULT_SUCCESS;
444 }
445
446 /**
447 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
448 */
449 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
450 TNC_TNCC_BindFunctionPointer bind_function)
451 {
452 if (!imc_swid)
453 {
454 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
455 return TNC_RESULT_NOT_INITIALIZED;
456 }
457 return imc_swid->bind_functions(imc_swid, bind_function);
458 }