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