Added add_segment() method to IETF attributes
[strongswan.git] / src / libimcv / 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 <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include "tcg/swid/tcg_swid_attr_req.h"
21 #include "tcg/swid/tcg_swid_attr_tag_inv.h"
22 #include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
23 #include "swid/swid_inventory.h"
24 #include "swid/swid_error.h"
25
26 #include <tncif_pa_subtypes.h>
27
28 #include <pen/pen.h>
29 #include <utils/debug.h>
30
31 #define SWID_GENERATOR "/usr/local/bin/swid_generator"
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
114 if (!imc_swid)
115 {
116 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
117 return TNC_RESULT_NOT_INITIALIZED;
118 }
119 if (!imc_swid->get_state(imc_swid, connection_id, &state))
120 {
121 return TNC_RESULT_FATAL;
122 }
123
124 return TNC_RESULT_SUCCESS;
125 }
126
127 /**
128 * Add one or multiple SWID Inventory attributes to the send queue
129 */
130 static bool add_swid_inventory(imc_state_t *state, imc_msg_t *msg,
131 uint32_t request_id, bool full_tags,
132 swid_inventory_t *targets)
133 {
134 pa_tnc_attr_t *attr, *attr_error;
135 imc_swid_state_t *swid_state;
136 swid_inventory_t *swid_inventory;
137 char *swid_directory, *swid_generator;
138 uint32_t eid_epoch;
139 bool swid_pretty, swid_full;
140 enumerator_t *enumerator;
141
142 swid_directory = lib->settings->get_str(lib->settings,
143 "%s.plugins.imc-swid.swid_directory",
144 SWID_DIRECTORY, lib->ns);
145 swid_generator = lib->settings->get_str(lib->settings,
146 "%s.plugins.imc-swid.swid_generator",
147 SWID_GENERATOR, lib->ns);
148 swid_pretty = lib->settings->get_bool(lib->settings,
149 "%s.plugins.imc-swid.swid_pretty",
150 FALSE, lib->ns);
151 swid_full = lib->settings->get_bool(lib->settings,
152 "%s.plugins.imc-swid.swid_full",
153 FALSE, lib->ns);
154
155 swid_inventory = swid_inventory_create(full_tags);
156 if (!swid_inventory->collect(swid_inventory, swid_directory, swid_generator,
157 targets, swid_pretty, swid_full))
158 {
159 swid_inventory->destroy(swid_inventory);
160 attr_error = swid_error_create(TCG_SWID_ERROR, request_id,
161 0, "error in SWID tag collection");
162 msg->add_attribute(msg, attr_error);
163 return FALSE;
164 }
165 DBG1(DBG_IMC, "collected %d SWID tag%s%s",
166 swid_inventory->get_count(swid_inventory), full_tags ? "" : " ID",
167 swid_inventory->get_count(swid_inventory) == 1 ? "" : "s");
168
169 swid_state = (imc_swid_state_t*)state;
170 eid_epoch = swid_state->get_eid_epoch(swid_state);
171
172 if (full_tags)
173 {
174 tcg_swid_attr_tag_inv_t *swid_attr;
175 swid_tag_t *tag;
176
177 /* Send a TCG SWID Tag Inventory attribute */
178 attr = tcg_swid_attr_tag_inv_create(request_id, eid_epoch, 1);
179 swid_attr = (tcg_swid_attr_tag_inv_t*)attr;
180
181 enumerator = swid_inventory->create_enumerator(swid_inventory);
182 while (enumerator->enumerate(enumerator, &tag))
183 {
184 swid_attr->add(swid_attr, tag->get_ref(tag));
185 }
186 enumerator->destroy(enumerator);
187 }
188 else
189 {
190 tcg_swid_attr_tag_id_inv_t *swid_id_attr;
191 swid_tag_id_t *tag_id;
192
193 /* Send a TCG SWID Tag ID Inventory attribute */
194 attr = tcg_swid_attr_tag_id_inv_create(request_id, eid_epoch, 1);
195 swid_id_attr = (tcg_swid_attr_tag_id_inv_t*)attr;
196
197 enumerator = swid_inventory->create_enumerator(swid_inventory);
198 while (enumerator->enumerate(enumerator, &tag_id))
199 {
200 swid_id_attr->add(swid_id_attr, tag_id->get_ref(tag_id));
201 }
202 enumerator->destroy(enumerator);
203 }
204
205 msg->add_attribute(msg, attr);
206 swid_inventory->destroy(swid_inventory);
207
208 return TRUE;
209 }
210
211 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
212 {
213 imc_msg_t *out_msg;
214 pa_tnc_attr_t *attr;
215 enumerator_t *enumerator;
216 pen_type_t type;
217 TNC_Result result;
218 bool fatal_error = FALSE;
219
220 /* generate an outgoing PA-TNC message - we might need it */
221 out_msg = imc_msg_create_as_reply(in_msg);
222
223 /* parse received PA-TNC message and handle local and remote errors */
224 result = in_msg->receive(in_msg, out_msg, &fatal_error);
225 if (result != TNC_RESULT_SUCCESS)
226 {
227 out_msg->destroy(out_msg);
228 return result;
229 }
230
231 /* analyze PA-TNC attributes */
232 enumerator = in_msg->create_attribute_enumerator(in_msg);
233 while (enumerator->enumerate(enumerator, &attr))
234 {
235 tcg_swid_attr_req_t *attr_req;
236 uint8_t flags;
237 uint32_t request_id;
238 bool full_tags;
239 swid_inventory_t *targets;
240
241 type = attr->get_type(attr);
242
243 if (type.vendor_id != PEN_TCG || type.type != TCG_SWID_REQUEST)
244 {
245 continue;
246 }
247
248 attr_req = (tcg_swid_attr_req_t*)attr;
249 flags = attr_req->get_flags(attr_req);
250 request_id = attr_req->get_request_id(attr_req);
251 targets = attr_req->get_targets(attr_req);
252
253 if (flags & (TCG_SWID_ATTR_REQ_FLAG_S | TCG_SWID_ATTR_REQ_FLAG_C))
254 {
255 attr = swid_error_create(TCG_SWID_SUBSCRIPTION_DENIED, request_id,
256 0, "no subscription available yet");
257 out_msg->add_attribute(out_msg, attr);
258 break;
259 }
260 full_tags = (flags & TCG_SWID_ATTR_REQ_FLAG_R) == 0;
261
262 if (!add_swid_inventory(state, out_msg, request_id, full_tags, targets))
263 {
264 break;
265 }
266 }
267 enumerator->destroy(enumerator);
268
269 if (fatal_error)
270 {
271 result = TNC_RESULT_FATAL;
272 }
273 else
274 {
275 /* send PA-TNC message with the EXCL flag set */
276 result = out_msg->send(out_msg, TRUE);
277 }
278 out_msg->destroy(out_msg);
279
280 return result;
281 }
282
283 /**
284 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
285
286 */
287 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
288 TNC_ConnectionID connection_id,
289 TNC_BufferReference msg,
290 TNC_UInt32 msg_len,
291 TNC_MessageType msg_type)
292 {
293 imc_state_t *state;
294 imc_msg_t *in_msg;
295 TNC_Result result;
296
297 if (!imc_swid)
298 {
299 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
300 return TNC_RESULT_NOT_INITIALIZED;
301 }
302 if (!imc_swid->get_state(imc_swid, connection_id, &state))
303 {
304 return TNC_RESULT_FATAL;
305 }
306 in_msg = imc_msg_create_from_data(imc_swid, state, connection_id, msg_type,
307 chunk_create(msg, msg_len));
308 result = receive_message(state, in_msg);
309 in_msg->destroy(in_msg);
310
311 return result;
312 }
313
314 /**
315 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
316 */
317 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
318 TNC_ConnectionID connection_id,
319 TNC_UInt32 msg_flags,
320 TNC_BufferReference msg,
321 TNC_UInt32 msg_len,
322 TNC_VendorID msg_vid,
323 TNC_MessageSubtype msg_subtype,
324 TNC_UInt32 src_imv_id,
325 TNC_UInt32 dst_imc_id)
326 {
327 imc_state_t *state;
328 imc_msg_t *in_msg;
329 TNC_Result result;
330
331 if (!imc_swid)
332 {
333 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
334 return TNC_RESULT_NOT_INITIALIZED;
335 }
336 if (!imc_swid->get_state(imc_swid, connection_id, &state))
337 {
338 return TNC_RESULT_FATAL;
339 }
340 in_msg = imc_msg_create_from_long_data(imc_swid, state, connection_id,
341 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
342 chunk_create(msg, msg_len));
343 result =receive_message(state, in_msg);
344 in_msg->destroy(in_msg);
345
346 return result;
347 }
348
349 /**
350 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
351 */
352 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
353 TNC_ConnectionID connection_id)
354 {
355 if (!imc_swid)
356 {
357 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
358 return TNC_RESULT_NOT_INITIALIZED;
359 }
360 return TNC_RESULT_SUCCESS;
361 }
362
363 /**
364 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
365 */
366 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
367 {
368 if (!imc_swid)
369 {
370 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
371 return TNC_RESULT_NOT_INITIALIZED;
372 }
373 imc_swid->destroy(imc_swid);
374 imc_swid = NULL;
375
376 return TNC_RESULT_SUCCESS;
377 }
378
379 /**
380 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
381 */
382 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
383 TNC_TNCC_BindFunctionPointer bind_function)
384 {
385 if (!imc_swid)
386 {
387 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
388 return TNC_RESULT_NOT_INITIALIZED;
389 }
390 return imc_swid->bind_functions(imc_swid, bind_function);
391 }