ef3a6a3e39ebdbc871916617100f342ee19e12fd
[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, *attr_error;
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_error = swid_error_create(TCG_SWID_ERROR, request_id,
169 0, "error in SWID tag collection");
170 msg->add_attribute(msg, attr_error);
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 SWID 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 /* Check for oversize tags that cannot be transported */
205 if (PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_INV_MIN_SIZE +
206 entry_size > max_attr_size)
207 {
208 attr_error = swid_error_create(TCG_SWID_RESPONSE_TOO_LARGE,
209 request_id, max_attr_size,
210 "oversize SWID tag omitted");
211 msg->add_attribute(msg, attr_error);
212 continue;
213 }
214
215 if (attr_size + entry_size > max_attr_size)
216 {
217 if (first)
218 {
219 /**
220 * Send an ITA Start Angel attribute to the IMV signalling
221 * that multiple TGC SWID Tag Inventory attributes follow
222 */
223 attr_angel = ita_attr_angel_create(TRUE);
224 msg->add_attribute(msg, attr_angel);
225 first = FALSE;
226 }
227 msg->add_attribute(msg, attr);
228
229 /* create the next TCG SWID Tag Inventory attribute */
230 attr_size = PA_TNC_ATTR_HEADER_SIZE +
231 TCG_SWID_TAG_INV_MIN_SIZE;
232 attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
233 }
234 swid_attr = (tcg_swid_attr_tag_inv_t*)attr;
235 swid_attr->add(swid_attr, tag->get_ref(tag));
236 attr_size += entry_size;
237 }
238 enumerator->destroy(enumerator);
239 }
240 else
241 {
242 tcg_swid_attr_tag_id_inv_t *swid_id_attr;
243 swid_tag_id_t *tag_id;
244 chunk_t tag_creator, unique_sw_id, tag_file_path;
245
246 /* At least one TCG Tag ID Inventory attribute is sent */
247 attr_size = PA_TNC_ATTR_HEADER_SIZE + TCG_SWID_TAG_ID_INV_MIN_SIZE;
248 attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
249 swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
250
251 enumerator = swid_inventory->create_enumerator(swid_inventory);
252 while (enumerator->enumerate(enumerator, &tag_id))
253 {
254 tag_creator = tag_id->get_tag_creator(tag_id);
255 unique_sw_id = tag_id->get_unique_sw_id(tag_id, &tag_file_path);
256 entry_size = 2 + tag_creator.len + 2 + unique_sw_id.len +
257 2 + tag_file_path.len;
258
259 if (attr_size + entry_size > max_attr_size)
260 {
261 if (first)
262 {
263 /**
264 * Send an ITA Start Angel attribute to the IMV signalling
265 * that multiple TGC SWID Tag ID Inventory attributes follow
266 */
267 attr_angel = ita_attr_angel_create(TRUE);
268 msg->add_attribute(msg, attr_angel);
269 first = FALSE;
270 }
271 msg->add_attribute(msg, attr);
272
273 /* create the next TCG SWID Tag ID Inventory attribute */
274 attr_size = PA_TNC_ATTR_HEADER_SIZE +
275 TCG_SWID_TAG_ID_INV_MIN_SIZE;
276 attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
277 }
278 swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
279 swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
280 attr_size += entry_size;
281 }
282 enumerator->destroy(enumerator);
283 }
284 msg->add_attribute(msg, attr);
285 swid_inventory->destroy(swid_inventory);
286
287 if (!first)
288 {
289 /**
290 * If we sent an ITA Start Angel attribute in the first place,
291 * terminate by appending a matching ITA Stop Angel attribute.
292 */
293 attr_angel = ita_attr_angel_create(FALSE);
294 msg->add_attribute(msg, attr_angel);
295 }
296
297 return TRUE;
298 }
299
300 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
301 {
302 imc_msg_t *out_msg;
303 pa_tnc_attr_t *attr;
304 enumerator_t *enumerator;
305 pen_type_t type;
306 TNC_Result result;
307 bool fatal_error = FALSE;
308
309 /* parse received PA-TNC message and handle local and remote errors */
310 result = in_msg->receive(in_msg, &fatal_error);
311 if (result != TNC_RESULT_SUCCESS)
312 {
313 return result;
314 }
315 out_msg = imc_msg_create_as_reply(in_msg);
316
317 /* analyze PA-TNC attributes */
318 enumerator = in_msg->create_attribute_enumerator(in_msg);
319 while (enumerator->enumerate(enumerator, &attr))
320 {
321 tcg_swid_attr_req_t *attr_req;
322 uint8_t flags;
323 uint32_t request_id;
324 bool full_tags;
325 swid_inventory_t *targets;
326
327 type = attr->get_type(attr);
328
329 if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
330 {
331 continue;
332 }
333
334 attr_req = (tcg_swid_attr_req_t*)attr;
335 flags = attr_req->get_flags(attr_req);
336 request_id = attr_req->get_request_id(attr_req);
337 targets = attr_req->get_targets(attr_req);
338
339 if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
340 {
341 attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id,
342 0, "no subscription available yet");
343 out_msg->add_attribute(out_msg, attr);
344 break;
345 }
346 full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
347
348 if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
349 {
350 break;
351 }
352 }
353 enumerator->destroy(enumerator);
354
355 if (fatal_error)
356 {
357 result = TNC_RESULT_FATAL;
358 }
359 else
360 {
361 result = out_msg->send(out_msg, TRUE);
362 }
363 out_msg->destroy(out_msg);
364
365 return result;
366 }
367
368 /**
369 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
370
371 */
372 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
373 TNC_ConnectionID connection_id,
374 TNC_BufferReference msg,
375 TNC_UInt32 msg_len,
376 TNC_MessageType msg_type)
377 {
378 imc_state_t *state;
379 imc_msg_t *in_msg;
380 TNC_Result result;
381
382 if (!imc_swid)
383 {
384 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
385 return TNC_RESULT_NOT_INITIALIZED;
386 }
387 if (!imc_swid->get_state(imc_swid, connection_id, &state))
388 {
389 return TNC_RESULT_FATAL;
390 }
391 in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type,
392 chunk_create(msg, msg_len));
393 result = receive_message(state, in_msg);
394 in_msg->destroy(in_msg);
395
396 return result;
397 }
398
399 /**
400 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
401 */
402 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
403 TNC_ConnectionID connection_id,
404 TNC_UInt32 msg_flags,
405 TNC_BufferReference msg,
406 TNC_UInt32 msg_len,
407 TNC_VendorID msg_vid,
408 TNC_MessageSubtype msg_subtype,
409 TNC_UInt32 src_imv_id,
410 TNC_UInt32 dst_imc_id)
411 {
412 imc_state_t *state;
413 imc_msg_t *in_msg;
414 TNC_Result result;
415
416 if (!imc_swid)
417 {
418 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
419 return TNC_RESULT_NOT_INITIALIZED;
420 }
421 if (!imc_swid->get_state(imc_swid, connection_id, &state))
422 {
423 return TNC_RESULT_FATAL;
424 }
425 in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id,
426 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
427 chunk_create(msg, msg_len));
428 result =receive_message(state, in_msg);
429 in_msg->destroy(in_msg);
430
431 return result;
432 }
433
434 /**
435 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
436 */
437 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
438 TNC_ConnectionID connection_id)
439 {
440 if (!imc_swid)
441 {
442 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
443 return TNC_RESULT_NOT_INITIALIZED;
444 }
445 return TNC_RESULT_SUCCESS;
446 }
447
448 /**
449 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
450 */
451 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
452 {
453 if (!imc_swid)
454 {
455 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
456 return TNC_RESULT_NOT_INITIALIZED;
457 }
458
459 libpts_deinit();
460
461 imc_swid->destroy(imc_swid);
462 imc_swid = NULL;
463
464 return TNC_RESULT_SUCCESS;
465 }
466
467 /**
468 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
469 */
470 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
471 TNC_TNCC_BindFunctionPointer bind_function)
472 {
473 if (!imc_swid)
474 {
475 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
476 return TNC_RESULT_NOT_INITIALIZED;
477 }
478 return imc_swid->bind_functions(imc_swid, bind_function);
479 }