Do TPM measurements only if there is a TPMRA workitem
[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_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, u_int32_t max_msg_len)
213 {
214 this->max_msg_len = max_msg_len;
215 }
216
217 METHOD(imv_state_t, get_max_msg_len, u_int32_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, u_int32_t flags)
225 {
226 this->action_flags |= flags;
227 }
228
229 METHOD(imv_state_t, get_action_flags, u_int32_t,
230 private_imv_attestation_state_t *this)
231 {
232 return this->action_flags;
233 }
234
235 METHOD(imv_state_t, set_ar_id, void,
236 private_imv_attestation_state_t *this, u_int32_t id_type, chunk_t id_value)
237 {
238 this->ar_id_type = id_type;
239 this->ar_id_value = chunk_clone(id_value);
240 }
241
242 METHOD(imv_state_t, get_ar_id, chunk_t,
243 private_imv_attestation_state_t *this, u_int32_t *id_type)
244 {
245 if (id_type)
246 {
247 *id_type = this->ar_id_type;
248 }
249 return this->ar_id_value;
250 }
251
252 METHOD(imv_state_t, set_session, void,
253 private_imv_attestation_state_t *this, imv_session_t *session)
254 {
255 this->session = session;
256 }
257
258 METHOD(imv_state_t, get_session, imv_session_t*,
259 private_imv_attestation_state_t *this)
260 {
261 return this->session;
262 }
263
264 METHOD(imv_state_t, change_state, void,
265 private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
266 {
267 this->state = new_state;
268 }
269
270 METHOD(imv_state_t, get_recommendation, void,
271 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec,
272 TNC_IMV_Evaluation_Result *eval)
273 {
274 *rec = this->rec;
275 *eval = this->eval;
276 }
277
278 METHOD(imv_state_t, set_recommendation, void,
279 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
280 TNC_IMV_Evaluation_Result eval)
281 {
282 this->rec = rec;
283 this->eval = eval;
284 }
285
286 METHOD(imv_state_t, update_recommendation, void,
287 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
288 TNC_IMV_Evaluation_Result eval)
289 {
290 this->rec = tncif_policy_update_recommendation(this->rec, rec);
291 this->eval = tncif_policy_update_evaluation(this->eval, eval);
292 }
293
294 METHOD(imv_attestation_state_t, add_file_meas_reasons, void,
295 private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
296 {
297 if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_FAIL)
298 {
299 reason_string->add_reason(reason_string, reason_file_meas_fail);
300 }
301 if (this->measurement_error & IMV_ATTESTATION_ERROR_FILE_MEAS_PEND)
302 {
303 reason_string->add_reason(reason_string, reason_file_meas_pend);
304 }
305 }
306
307 METHOD(imv_attestation_state_t, add_comp_evid_reasons, void,
308 private_imv_attestation_state_t *this, imv_reason_string_t *reason_string)
309 {
310 if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_FAIL)
311 {
312 reason_string->add_reason(reason_string, reason_comp_evid_fail);
313 }
314 if (this->measurement_error & IMV_ATTESTATION_ERROR_COMP_EVID_PEND)
315 {
316 reason_string->add_reason(reason_string, reason_comp_evid_pend);
317 }
318 if (this->measurement_error & IMV_ATTESTATION_ERROR_TPM_QUOTE_FAIL)
319 {
320 reason_string->add_reason(reason_string, reason_tpm_quote_fail);
321 }
322 }
323
324 METHOD(imv_state_t, get_reason_string, bool,
325 private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
326 chunk_t *reason_string, char **reason_language)
327 {
328 *reason_language = imv_lang_string_select_lang(language_enumerator,
329 languages, countof(languages));
330
331 /* Instantiate a TNC Reason String object */
332 DESTROY_IF(this->reason_string);
333 this->reason_string = imv_reason_string_create(*reason_language, "\n");
334 add_file_meas_reasons(this, this->reason_string);
335 add_comp_evid_reasons(this, this->reason_string);
336 *reason_string = this->reason_string->get_encoding(this->reason_string);
337
338 return TRUE;
339 }
340
341 METHOD(imv_state_t, get_remediation_instructions, bool,
342 private_imv_attestation_state_t *this, enumerator_t *language_enumerator,
343 chunk_t *string, char **lang_code, char **uri)
344 {
345 return FALSE;
346 }
347
348 METHOD(imv_state_t, destroy, void,
349 private_imv_attestation_state_t *this)
350 {
351 DESTROY_IF(this->session);
352 DESTROY_IF(this->reason_string);
353 this->components->destroy_function(this->components, (void *)free_func_comp);
354 this->pts->destroy(this->pts);
355 free(this->ar_id_value.ptr);
356 free(this);
357 }
358
359 METHOD(imv_attestation_state_t, get_handshake_state,
360 imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
361 {
362 return this->handshake_state;
363 }
364
365 METHOD(imv_attestation_state_t, set_handshake_state, void,
366 private_imv_attestation_state_t *this,
367 imv_attestation_handshake_state_t new_state)
368 {
369 this->handshake_state = new_state;
370 }
371
372 METHOD(imv_attestation_state_t, get_pts, pts_t*,
373 private_imv_attestation_state_t *this)
374 {
375 return this->pts;
376 }
377
378 METHOD(imv_attestation_state_t, create_component, pts_component_t*,
379 private_imv_attestation_state_t *this, pts_comp_func_name_t *name,
380 u_int32_t depth, pts_database_t *pts_db)
381 {
382 enumerator_t *enumerator;
383 func_comp_t *entry, *new_entry;
384 pts_component_t *component;
385 bool found = FALSE;
386
387 enumerator = this->components->create_enumerator(this->components);
388 while (enumerator->enumerate(enumerator, &entry))
389 {
390 if (name->equals(name, entry->comp->get_comp_func_name(entry->comp)))
391 {
392 found = TRUE;
393 break;
394 }
395 }
396 enumerator->destroy(enumerator);
397
398 if (found)
399 {
400 if (name->equals(name, entry->name))
401 {
402 /* duplicate entry */
403 return NULL;
404 }
405 new_entry = malloc_thing(func_comp_t);
406 new_entry->name = name->clone(name);
407 new_entry->comp = entry->comp->get_ref(entry->comp);
408 this->components->insert_last(this->components, new_entry);
409 return entry->comp;
410 }
411 else
412 {
413 component = pts_components->create(pts_components, name, depth, pts_db);
414 if (!component)
415 {
416 /* unsupported component */
417 return NULL;
418 }
419 new_entry = malloc_thing(func_comp_t);
420 new_entry->name = name->clone(name);
421 new_entry->comp = component;
422 this->components->insert_last(this->components, new_entry);
423 return component;
424 }
425 }
426
427 /**
428 * Enumerate file measurement entries
429 */
430 static bool entry_filter(void *null, func_comp_t **entry, u_int8_t *flags,
431 void *i2, u_int32_t *depth,
432 void *i3, pts_comp_func_name_t **comp_name)
433 {
434 pts_component_t *comp;
435 pts_comp_func_name_t *name;
436
437 comp = (*entry)->comp;
438 name = (*entry)->name;
439
440 *flags = comp->get_evidence_flags(comp);
441 *depth = comp->get_depth(comp);
442 *comp_name = name;
443
444 return TRUE;
445 }
446
447 METHOD(imv_attestation_state_t, create_component_enumerator, enumerator_t*,
448 private_imv_attestation_state_t *this)
449 {
450 return enumerator_create_filter(
451 this->components->create_enumerator(this->components),
452 (void*)entry_filter, NULL, NULL);
453 }
454
455 METHOD(imv_attestation_state_t, get_component, pts_component_t*,
456 private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
457 {
458 enumerator_t *enumerator;
459 func_comp_t *entry;
460 pts_component_t *found = NULL;
461
462 enumerator = this->components->create_enumerator(this->components);
463 while (enumerator->enumerate(enumerator, &entry))
464 {
465 if (name->equals(name, entry->name))
466 {
467 found = entry->comp;
468 break;
469 }
470 }
471 enumerator->destroy(enumerator);
472 return found;
473 }
474
475 METHOD(imv_attestation_state_t, get_measurement_error, u_int32_t,
476 private_imv_attestation_state_t *this)
477 {
478 return this->measurement_error;
479 }
480
481 METHOD(imv_attestation_state_t, set_measurement_error, void,
482 private_imv_attestation_state_t *this, u_int32_t error)
483 {
484 this->measurement_error |= error;
485 }
486
487 METHOD(imv_attestation_state_t, finalize_components, void,
488 private_imv_attestation_state_t *this)
489 {
490 func_comp_t *entry;
491
492 while (this->components->remove_last(this->components,
493 (void**)&entry) == SUCCESS)
494 {
495 if (!entry->comp->finalize(entry->comp,
496 entry->name->get_qualifier(entry->name)))
497 {
498 set_measurement_error(this, IMV_ATTESTATION_ERROR_COMP_EVID_PEND);
499 }
500 free_func_comp(entry);
501 }
502 }
503
504 METHOD(imv_attestation_state_t, components_finalized, bool,
505 private_imv_attestation_state_t *this)
506 {
507 return this->components->get_count(this->components) == 0;
508 }
509
510 /**
511 * Described in header.
512 */
513 imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
514 {
515 private_imv_attestation_state_t *this;
516
517 INIT(this,
518 .public = {
519 .interface = {
520 .get_connection_id = _get_connection_id,
521 .has_long = _has_long,
522 .has_excl = _has_excl,
523 .set_flags = _set_flags,
524 .set_max_msg_len = _set_max_msg_len,
525 .get_max_msg_len = _get_max_msg_len,
526 .set_action_flags = _set_action_flags,
527 .get_action_flags = _get_action_flags,
528 .set_ar_id = _set_ar_id,
529 .get_ar_id = _get_ar_id,
530 .set_session = _set_session,
531 .get_session = _get_session,
532 .change_state = _change_state,
533 .get_recommendation = _get_recommendation,
534 .set_recommendation = _set_recommendation,
535 .update_recommendation = _update_recommendation,
536 .get_reason_string = _get_reason_string,
537 .get_remediation_instructions = _get_remediation_instructions,
538 .destroy = _destroy,
539 },
540 .get_handshake_state = _get_handshake_state,
541 .set_handshake_state = _set_handshake_state,
542 .get_pts = _get_pts,
543 .create_component = _create_component,
544 .create_component_enumerator = _create_component_enumerator,
545 .get_component = _get_component,
546 .finalize_components = _finalize_components,
547 .components_finalized = _components_finalized,
548 .get_measurement_error = _get_measurement_error,
549 .set_measurement_error = _set_measurement_error,
550 .add_file_meas_reasons = _add_file_meas_reasons,
551 .add_comp_evid_reasons = _add_comp_evid_reasons,
552 },
553 .connection_id = connection_id,
554 .state = TNC_CONNECTION_STATE_CREATE,
555 .handshake_state = IMV_ATTESTATION_STATE_INIT,
556 .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
557 .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
558 .components = linked_list_create(),
559 .pts = pts_create(FALSE),
560 );
561
562 return &this->public.interface;
563 }