Separated IMV session management from IMV policy database
[strongswan.git] / src / libpts / plugins / imv_attestation / imv_attestation_state.c
1 /*
2 * Copyright (C) 2011-2012 Sansar Choinyambuu
3 * Copyright (C) 2011-2014 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "imv_attestation_state.h"
18
19 #include <libpts.h>
20
21 #include <imv/imv_lang_string.h>
22 #include "imv/imv_reason_string.h"
23
24 #include <tncif_policy.h>
25
26 #include <collections/linked_list.h>
27 #include <utils/debug.h>
28
29 typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
30 typedef struct file_meas_request_t file_meas_request_t;
31 typedef struct func_comp_t func_comp_t;
32
33 /**
34 * Private data of an imv_attestation_state_t object.
35 */
36 struct private_imv_attestation_state_t {
37
38 /**
39 * Public members of imv_attestation_state_t
40 */
41 imv_attestation_state_t public;
42
43 /**
44 * TNCCS connection ID
45 */
46 TNC_ConnectionID connection_id;
47
48 /**
49 * TNCCS connection state
50 */
51 TNC_ConnectionState state;
52
53 /**
54 * Does the TNCCS connection support long message types?
55 */
56 bool has_long;
57
58 /**
59 * Does the TNCCS connection support exclusive delivery?
60 */
61 bool has_excl;
62
63 /**
64 * Maximum PA-TNC message size for this TNCCS connection
65 */
66 uint32_t max_msg_len;
67
68 /**
69 * Flags set for completed actions
70 */
71 uint32_t action_flags;
72
73 /**
74 * IMV database session associated with TNCCS connection
75 */
76 imv_session_t *session;
77
78 /**
79 * IMV Attestation handshake state
80 */
81 imv_attestation_handshake_state_t handshake_state;
82
83 /**
84 * IMV action recommendation
85 */
86 TNC_IMV_Action_Recommendation rec;
87
88 /**
89 * IMV evaluation result
90 */
91 TNC_IMV_Evaluation_Result eval;
92
93 /**
94 * List of Functional Components
95 */
96 linked_list_t *components;
97
98 /**
99 * PTS object
100 */
101 pts_t *pts;
102
103 /**
104 * Measurement error flags
105 */
106 uint32_t measurement_error;
107
108 /**
109 * TNC Reason String
110 */
111 imv_reason_string_t *reason_string;
112
113 };
114
115 /**
116 * PTS Functional Component entry
117 */
118 struct func_comp_t {
119 pts_component_t *comp;
120 pts_comp_func_name_t* name;
121 };
122
123 /**
124 * Frees a func_comp_t object
125 */
126 static void free_func_comp(func_comp_t *this)
127 {
128 this->comp->destroy(this->comp);
129 this->name->destroy(this->name);
130 free(this);
131 }
132
133 /**
134 * Supported languages
135 */
136 static char* languages[] = { "en", "de", "mn" };
137
138 /**
139 * Table of reason strings
140 */
141 static imv_lang_string_t reason_file_meas_fail[] = {
142 { "en", "Incorrect file measurement" },
143 { "de", "Falsche Dateimessung" },
144 { "mn", "Буруу байгаа файл" },
145 { NULL, NULL }
146 };
147
148 static imv_lang_string_t reason_file_meas_pend[] = {
149 { "en", "Pending file measurement" },
150 { "de", "Ausstehende Dateimessung" },
151 { "mn", "Xүлээгдэж байгаа файл" },
152 { NULL, NULL }
153 };
154
155 static imv_lang_string_t reason_no_trusted_aik[] = {
156 { "en", "No trusted AIK available" },
157 { "de", "Kein vetrauenswürdiger AIK verfügbar" },
158 { NULL, NULL }
159 };
160
161 static imv_lang_string_t reason_comp_evid_fail[] = {
162 { "en", "Incorrect component evidence" },
163 { "de", "Falsche Komponenten-Evidenz" },
164 { "mn", "Буруу компонент хэмжилт" },
165 { NULL, NULL }
166 };
167
168 static imv_lang_string_t reason_comp_evid_pend[] = {
169 { "en", "Pending component evidence" },
170 { "de", "Ausstehende Komponenten-Evidenz" },
171 { "mn", "Xүлээгдэж компонент хэмжилт" },
172 { NULL, NULL }
173 };
174
175 static imv_lang_string_t reason_tpm_quote_fail[] = {
176 { "en", "Invalid TPM Quote signature received" },
177 { "de", "Falsche TPM Quote Signature erhalten" },
178 { "mn", "Буруу TPM Quote гарын үсэг" },
179 { NULL, NULL }
180 };
181
182 METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
183 private_imv_attestation_state_t *this)
184 {
185 return this->connection_id;
186 }
187
188 METHOD(imv_state_t, has_long, bool,
189 private_imv_attestation_state_t *this)
190 {
191 return this->has_long;
192 }
193
194 METHOD(imv_state_t, has_excl, bool,
195 private_imv_attestation_state_t *this)
196 {
197 return this->has_excl;
198 }
199
200 METHOD(imv_state_t, set_flags, void,
201 private_imv_attestation_state_t *this, bool has_long, bool has_excl)
202 {
203 this->has_long = has_long;
204 this->has_excl = has_excl;
205 }
206
207 METHOD(imv_state_t, set_max_msg_len, void,
208 private_imv_attestation_state_t *this, uint32_t max_msg_len)
209 {
210 this->max_msg_len = max_msg_len;
211 }
212
213 METHOD(imv_state_t, get_max_msg_len, uint32_t,
214 private_imv_attestation_state_t *this)
215 {
216 return this->max_msg_len;
217 }
218
219 METHOD(imv_state_t, set_action_flags, void,
220 private_imv_attestation_state_t *this, uint32_t flags)
221 {
222 this->action_flags |= flags;
223 }
224
225 METHOD(imv_state_t, get_action_flags, uint32_t,
226 private_imv_attestation_state_t *this)
227 {
228 return this->action_flags;
229 }
230
231 METHOD(imv_state_t, set_session, void,
232 private_imv_attestation_state_t *this, imv_session_t *session)
233 {
234 this->session = session;
235 }
236
237 METHOD(imv_state_t, get_session, imv_session_t*,
238 private_imv_attestation_state_t *this)
239 {
240 return this->session;
241 }
242
243 METHOD(imv_state_t, change_state, void,
244 private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
245 {
246 this->state = new_state;
247 }
248
249 METHOD(imv_state_t, get_recommendation, void,
250 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec,
251 TNC_IMV_Evaluation_Result *eval)
252 {
253 *rec = this->rec;
254 *eval = this->eval;
255 }
256
257 METHOD(imv_state_t, set_recommendation, void,
258 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
259 TNC_IMV_Evaluation_Result eval)
260 {
261 this->rec = rec;
262 this->eval = eval;
263 }
264
265 METHOD(imv_state_t, update_recommendation, void,
266 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
267 TNC_IMV_Evaluation_Result eval)
268 {
269 this->rec = tncif_policy_update_recommendation(this->rec, rec);
270 this->eval = tncif_policy_update_evaluation(this->eval, eval);
271 }
272
273 METHOD(imv_attestation_state_t, add_file_meas_reasons, void,
274 private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
275 {
276 if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL)
277 {
278 reason_string->add_reason(reason_string, reason_file_meas_fail);
279 }
280 if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_PEND)
281 {
282 reason_string->add_reason(reason_string, reason_file_meas_pend);
283 }
284 }
285
286 METHOD(imv_attestation_state_t, add_comp_evid_reasons, void,
287 private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
288 {
289 if (this->measurement_error & IMV_ATTESTATION_ERROR_NO_TRUSTED_AIK)
290 {
291 reason_string->add_reason(reason_string, reason_no_trusted_aik);
292 }
293 if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_FAIL)
294 {
295 reason_string->add_reason(reason_string, reason_comp_evid_fail);
296 }
297 if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_PEND)
298 {
299 reason_string->add_reason(reason_string, reason_comp_evid_pend);
300 }
301 if (this->measurement_error & IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)
302 {
303 reason_string->add_reason(reason_string, reason_tpm_quote_fail);
304 }
305 }
306
307 METHOD(imv_state_t, get_reason_string, bool,
308 private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
309 chunk_t *reason_string, char **reason_language)
310 {
311 *reason_language = imv_lang_string_select_lang(language_enumerator,
312 languages, countof(languages));
313
314 /* Instantiate a TNC Reason String object */
315 DESTROY_IF(this->reason_string);
316 this->reason_string = imv_reason_string_create(*reason_language, "\n");
317 add_file_meas_reasons(this, this->reason_string);
318 add_comp_evid_reasons(this, this->reason_string);
319 *reason_string = this->reason_string->get_encoding(this->reason_string);
320
321 return TRUE;
322 }
323
324 METHOD(imv_state_t, get_remediation_instructions, bool,
325 private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
326 chunk_t *string, char **lang_code, char **uri)
327 {
328 return FALSE;
329 }
330
331 METHOD(imv_state_t, destroy, void,
332 private_imv_attestation_state_t *this)
333 {
334 DESTROY_IF(this->session);
335 DESTROY_IF(this->reason_string);
336 this->components->destroy_function(this->components, (void *)free_func_comp);
337 this->pts->destroy(this->pts);
338 free(this);
339 }
340
341 METHOD(imv_attestation_state_t, get_handshake_state,
342 imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
343 {
344 return this->handshake_state;
345 }
346
347 METHOD(imv_attestation_state_t, set_handshake_state, void,
348 private_imv_attestation_state_t *this,
349 imv_attestation_handshake_state_t new_state)
350 {
351 this->handshake_state = new_state;
352 }
353
354 METHOD(imv_attestation_state_t, get_pts, pts_t*,
355 private_imv_attestation_state_t *this)
356 {
357 return this->pts;
358 }
359
360 METHOD(imv_attestation_state_t, create_component, pts_component_t*,
361 private_imv_attestation_state_t *this, pts_comp_func_name_t *name,
362 uint32_t depth, pts_database_t *pts_db)
363 {
364 enumerator_t *enumerator;
365 func_comp_t *entry, *new_entry;
366 pts_component_t *component;
367 bool found = FALSE;
368
369 enumerator = this->components->create_enumerator(this->components);
370 while (enumerator->enumerate(enumerator, &entry))
371 {
372 if (name->equals(name, entry->comp->get_comp_func_name(entry->comp)))
373 {
374 found = TRUE;
375 break;
376 }
377 }
378 enumerator->destroy(enumerator);
379
380 if (found)
381 {
382 if (name->equals(name, entry->name))
383 {
384 /* duplicate entry */
385 return NULL;
386 }
387 new_entry = malloc_thing(func_comp_t);
388 new_entry->name = name->clone(name);
389 new_entry->comp = entry->comp->get_ref(entry->comp);
390 this->components->insert_last(this->components, new_entry);
391 return entry->comp;
392 }
393 else
394 {
395 component = pts_components->create(pts_components, name, depth, pts_db);
396 if (!component)
397 {
398 /* unsupported component */
399 return NULL;
400 }
401 new_entry = malloc_thing(func_comp_t);
402 new_entry->name = name->clone(name);
403 new_entry->comp = component;
404 this->components->insert_last(this->components, new_entry);
405 return component;
406 }
407 }
408
409 /**
410 * Enumerate file measurement entries
411 */
412 static bool entry_filter(void *null, func_comp_t **entry, u_int8_t *flags,
413 void *i2, uint32_t *depth,
414 void *i3, pts_comp_func_name_t **comp_name)
415 {
416 pts_component_t *comp;
417 pts_comp_func_name_t *name;
418
419 comp = (*entry)->comp;
420 name = (*entry)->name;
421
422 *flags = comp->get_evidence_flags(comp);
423 *depth = comp->get_depth(comp);
424 *comp_name = name;
425
426 return TRUE;
427 }
428
429 METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
430 private_imv_attestation_state_t *this)
431 {
432 return enumerator_create_filter(
433 this->components->create_enumerator(this->components),
434 (void*)entry_filter, NULL, NULL);
435 }
436
437 METHOD(imv_attestation_state_t, get_component, pts_component_t*,
438 private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
439 {
440 enumerator_t *enumerator;
441 func_comp_t *entry;
442 pts_component_t *found = NULL;
443
444 enumerator = this->components->create_enumerator(this->components);
445 while (enumerator->enumerate(enumerator, &entry))
446 {
447 if (name->equals(name, entry->name))
448 {
449 found = entry->comp;
450 break;
451 }
452 }
453 enumerator->destroy(enumerator);
454 return found;
455 }
456
457 METHOD(imv_attestation_state_t, get_measurement_error, uint32_t,
458 private_imv_attestation_state_t *this)
459 {
460 return this->measurement_error;
461 }
462
463 METHOD(imv_attestation_state_t, set_measurement_error, void,
464 private_imv_attestation_state_t *this, uint32_t error)
465 {
466 this->measurement_error |= error;
467 }
468
469 METHOD(imv_attestation_state_t, finalize_components, void,
470 private_imv_attestation_state_t *this)
471 {
472 func_comp_t *entry;
473
474 while (this->components->remove_last(this->components,
475 (void**)&entry) == SUCCESS)
476 {
477 if (!entry->comp->finalize(entry->comp,
478 entry->name->get_qualifier(entry->name)))
479 {
480 set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND);
481 }
482 free_func_comp(entry);
483 }
484 }
485
486 /**
487 * Described in header.
488 */
489 imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
490 {
491 private_imv_attestation_state_t *this;
492
493 INIT(this,
494 .public = {
495 .interface = {
496 .get_connection_id = _get_connection_id,
497 .has_long = _has_long,
498 .has_excl = _has_excl,
499 .set_flags = _set_flags,
500 .set_max_msg_len = _set_max_msg_len,
501 .get_max_msg_len = _get_max_msg_len,
502 .set_action_flags = _set_action_flags,
503 .get_action_flags = _get_action_flags,
504 .set_session = _set_session,
505 .get_session = _get_session,
506 .change_state = _change_state,
507 .get_recommendation = _get_recommendation,
508 .set_recommendation = _set_recommendation,
509 .update_recommendation = _update_recommendation,
510 .get_reason_string = _get_reason_string,
511 .get_remediation_instructions = _get_remediation_instructions,
512 .destroy = _destroy,
513 },
514 .get_handshake_state = _get_handshake_state,
515 .set_handshake_state = _set_handshake_state,
516 .get_pts = _get_pts,
517 .create_component = _create_component,
518 .create_component_enumerator = _create_component_enumerator,
519 .get_component = _get_component,
520 .finalize_components = _finalize_components,
521 .get_measurement_error = _get_measurement_error,
522 .set_measurement_error = _set_measurement_error,
523 .add_file_meas_reasons = _add_file_meas_reasons,
524 .add_comp_evid_reasons = _add_comp_evid_reasons,
525 },
526 .connection_id = connection_id,
527 .state = TNC_CONNECTION_STATE_CREATE,
528 .handshake_state = IMV_ATTESTATION_STATE_INIT,
529 .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
530 .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
531 .components = linked_list_create(),
532 .pts = pts_create(FALSE),
533 );
534
535 return &this->public.interface;
536 }