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