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