wait for the finalization of the Functional Component measurements
[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 <utils/lexparser.h>
19 #include <utils/linked_list.h>
20 #include <debug.h>
21
22 typedef struct private_imv_attestation_state_t private_imv_attestation_state_t;
23 typedef struct file_meas_request_t file_meas_request_t;
24
25 /**
26 * PTS File/Directory Measurement request entry
27 */
28 struct file_meas_request_t {
29 u_int16_t id;
30 int file_id;
31 bool is_dir;
32 };
33
34 /**
35 * Private data of an imv_attestation_state_t object.
36 */
37 struct private_imv_attestation_state_t {
38
39 /**
40 * Public members of imv_attestation_state_t
41 */
42 imv_attestation_state_t public;
43
44 /**
45 * TNCCS connection ID
46 */
47 TNC_ConnectionID connection_id;
48
49 /**
50 * TNCCS connection state
51 */
52 TNC_ConnectionState state;
53
54 /**
55 * Does the TNCCS connection support long message types?
56 */
57 bool has_long;
58
59 /**
60 * Does the TNCCS connection support exclusive delivery?
61 */
62 bool has_excl;
63
64 /**
65 * Maximum PA-TNC message size for this TNCCS connection
66 */
67 u_int32_t max_msg_len;
68
69 /**
70 * IMV Attestation handshake state
71 */
72 imv_attestation_handshake_state_t handshake_state;
73
74 /**
75 * IMV action recommendation
76 */
77 TNC_IMV_Action_Recommendation rec;
78
79 /**
80 * IMV evaluation result
81 */
82 TNC_IMV_Evaluation_Result eval;
83
84 /**
85 * File Measurement Request counter
86 */
87 u_int16_t file_meas_request_counter;
88
89 /**
90 * List of PTS File/Directory Measurement requests
91 */
92 linked_list_t *file_meas_requests;
93
94 /**
95 * List of Functional Components
96 */
97 linked_list_t *components;
98
99 /**
100 * PTS object
101 */
102 pts_t *pts;
103
104 /**
105 * Measurement error
106 */
107 bool measurement_error;
108
109 };
110
111 typedef struct entry_t entry_t;
112
113 /**
114 * Define an internal reason string entry
115 */
116 struct entry_t {
117 char *lang;
118 char *string;
119 };
120
121 /**
122 * Table of multi-lingual reason string entries
123 */
124 static entry_t reasons[] = {
125 { "en", "IMV Attestation: Incorrect/pending file measurement/component"
126 " evidence or invalid TPM Quote signature received" },
127 { "mn", "IMV Attestation: Буруу/хүлээгдэж байгаа файл/компонент хэмжилт "
128 "эсвэл буруу TPM Quote гарын үсэг" },
129 { "de", "IMV Attestation: Falsche/Fehlende Dateimessung/Komponenten Beweis "
130 "oder ungültige TPM Quote Unterschrift ist erhalten" },
131 };
132
133 METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
134 private_imv_attestation_state_t *this)
135 {
136 return this->connection_id;
137 }
138
139 METHOD(imv_state_t, has_long, bool,
140 private_imv_attestation_state_t *this)
141 {
142 return this->has_long;
143 }
144
145 METHOD(imv_state_t, has_excl, bool,
146 private_imv_attestation_state_t *this)
147 {
148 return this->has_excl;
149 }
150
151 METHOD(imv_state_t, set_flags, void,
152 private_imv_attestation_state_t *this, bool has_long, bool has_excl)
153 {
154 this->has_long = has_long;
155 this->has_excl = has_excl;
156 }
157
158 METHOD(imv_state_t, set_max_msg_len, void,
159 private_imv_attestation_state_t *this, u_int32_t max_msg_len)
160 {
161 this->max_msg_len = max_msg_len;
162 }
163
164 METHOD(imv_state_t, get_max_msg_len, u_int32_t,
165 private_imv_attestation_state_t *this)
166 {
167 return this->max_msg_len;
168 }
169
170 METHOD(imv_state_t, change_state, void,
171 private_imv_attestation_state_t *this, TNC_ConnectionState new_state)
172 {
173 this->state = new_state;
174 }
175
176 METHOD(imv_state_t, get_recommendation, void,
177 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation *rec,
178 TNC_IMV_Evaluation_Result *eval)
179 {
180 *rec = this->rec;
181 *eval = this->eval;
182 }
183
184 METHOD(imv_state_t, set_recommendation, void,
185 private_imv_attestation_state_t *this, TNC_IMV_Action_Recommendation rec,
186 TNC_IMV_Evaluation_Result eval)
187 {
188 this->rec = rec;
189 this->eval = eval;
190 }
191
192 METHOD(imv_state_t, get_reason_string, bool,
193 private_imv_attestation_state_t *this, chunk_t preferred_language,
194 chunk_t *reason_string, chunk_t *reason_language)
195 {
196 chunk_t pref_lang, lang;
197 u_char *pos;
198 int i;
199
200 while (eat_whitespace(&preferred_language))
201 {
202 if (!extract_token(&pref_lang, ',', &preferred_language))
203 {
204 /* last entry in a comma-separated list or single entry */
205 pref_lang = preferred_language;
206 }
207
208 /* eat trailing whitespace */
209 pos = pref_lang.ptr + pref_lang.len - 1;
210 while (pref_lang.len && *pos-- == ' ')
211 {
212 pref_lang.len--;
213 }
214
215 for (i = 0 ; i < countof(reasons); i++)
216 {
217 lang = chunk_create(reasons[i].lang, strlen(reasons[i].lang));
218 if (chunk_equals(lang, pref_lang))
219 {
220 *reason_language = lang;
221 *reason_string = chunk_create(reasons[i].string,
222 strlen(reasons[i].string));
223 return TRUE;
224 }
225 }
226 }
227
228 /* no preferred language match found - use the default language */
229 *reason_string = chunk_create(reasons[0].string,
230 strlen(reasons[0].string));
231 *reason_language = chunk_create(reasons[0].lang,
232 strlen(reasons[0].lang));
233 return TRUE;
234 }
235
236 METHOD(imv_state_t, destroy, void,
237 private_imv_attestation_state_t *this)
238 {
239 this->file_meas_requests->destroy_function(this->file_meas_requests, free);
240 this->components->destroy_offset(this->components,
241 offsetof(pts_component_t, destroy));
242 this->pts->destroy(this->pts);
243 free(this);
244 }
245
246 METHOD(imv_attestation_state_t, get_handshake_state,
247 imv_attestation_handshake_state_t, private_imv_attestation_state_t *this)
248 {
249 return this->handshake_state;
250 }
251
252 METHOD(imv_attestation_state_t, set_handshake_state, void,
253 private_imv_attestation_state_t *this,
254 imv_attestation_handshake_state_t new_state)
255 {
256 this->handshake_state = new_state;
257 }
258
259 METHOD(imv_attestation_state_t, get_pts, pts_t*,
260 private_imv_attestation_state_t *this)
261 {
262 return this->pts;
263 }
264
265 METHOD(imv_attestation_state_t, add_file_meas_request, u_int16_t,
266 private_imv_attestation_state_t *this, int file_id, bool is_dir)
267 {
268 file_meas_request_t *request;
269
270 request = malloc_thing(file_meas_request_t);
271 request->id = ++this->file_meas_request_counter;
272 request->file_id = file_id;
273 request->is_dir = is_dir;
274 this->file_meas_requests->insert_last(this->file_meas_requests, request);
275
276 return this->file_meas_request_counter;
277 }
278
279 METHOD(imv_attestation_state_t, check_off_file_meas_request, bool,
280 private_imv_attestation_state_t *this, u_int16_t id, int *file_id,
281 bool* is_dir)
282 {
283 enumerator_t *enumerator;
284 file_meas_request_t *request;
285 bool found = FALSE;
286
287 enumerator = this->file_meas_requests->create_enumerator(this->file_meas_requests);
288 while (enumerator->enumerate(enumerator, &request))
289 {
290 if (request->id == id)
291 {
292 found = TRUE;
293 *file_id = request->file_id;
294 *is_dir = request->is_dir;
295 this->file_meas_requests->remove_at(this->file_meas_requests, enumerator);
296 free(request);
297 break;
298 }
299 }
300 enumerator->destroy(enumerator);
301 return found;
302 }
303
304 METHOD(imv_attestation_state_t, get_file_meas_request_count, int,
305 private_imv_attestation_state_t *this)
306 {
307 return this->file_meas_requests->get_count(this->file_meas_requests);
308 }
309
310 METHOD(imv_attestation_state_t, add_component, void,
311 private_imv_attestation_state_t *this, pts_component_t *entry)
312 {
313 this->components->insert_last(this->components, entry);
314 }
315
316 METHOD(imv_attestation_state_t, get_component, pts_component_t*,
317 private_imv_attestation_state_t *this, pts_comp_func_name_t *name)
318 {
319 enumerator_t *enumerator;
320 pts_component_t *entry, *found = NULL;
321
322 enumerator = this->components->create_enumerator(this->components);
323 while (enumerator->enumerate(enumerator, &entry))
324 {
325 if (name->equals(name, entry->get_comp_func_name(entry)))
326 {
327 found = entry;
328 break;
329 }
330 }
331 enumerator->destroy(enumerator);
332 return found;
333 }
334
335 METHOD(imv_attestation_state_t, get_measurement_error, bool,
336 private_imv_attestation_state_t *this)
337 {
338 return this->measurement_error;
339 }
340
341 METHOD(imv_attestation_state_t, set_measurement_error, void,
342 private_imv_attestation_state_t *this)
343 {
344 this->measurement_error = TRUE;
345 }
346
347 METHOD(imv_attestation_state_t, finalize_components, void,
348 private_imv_attestation_state_t *this)
349 {
350 pts_component_t *entry;
351
352 while (this->components->remove_last(this->components,
353 (void**)&entry) == SUCCESS)
354 {
355 if (!entry->finalize(entry))
356 {
357 _set_measurement_error(this);
358 }
359 entry->destroy(entry);
360 }
361 }
362
363 METHOD(imv_attestation_state_t, components_finalized, bool,
364 private_imv_attestation_state_t *this)
365 {
366 return this->components->get_count(this->components) == 0;
367 }
368
369 /**
370 * Described in header.
371 */
372 imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id)
373 {
374 private_imv_attestation_state_t *this;
375 char *platform_info;
376
377 INIT(this,
378 .public = {
379 .interface = {
380 .get_connection_id = _get_connection_id,
381 .has_long = _has_long,
382 .has_excl = _has_excl,
383 .set_flags = _set_flags,
384 .set_max_msg_len = _set_max_msg_len,
385 .get_max_msg_len = _get_max_msg_len,
386 .change_state = _change_state,
387 .get_recommendation = _get_recommendation,
388 .set_recommendation = _set_recommendation,
389 .get_reason_string = _get_reason_string,
390 .destroy = _destroy,
391 },
392 .get_handshake_state = _get_handshake_state,
393 .set_handshake_state = _set_handshake_state,
394 .get_pts = _get_pts,
395 .add_file_meas_request = _add_file_meas_request,
396 .check_off_file_meas_request = _check_off_file_meas_request,
397 .get_file_meas_request_count = _get_file_meas_request_count,
398 .add_component = _add_component,
399 .get_component = _get_component,
400 .finalize_components = _finalize_components,
401 .components_finalized = _components_finalized,
402 .get_measurement_error = _get_measurement_error,
403 .set_measurement_error = _set_measurement_error,
404 },
405 .connection_id = connection_id,
406 .state = TNC_CONNECTION_STATE_CREATE,
407 .handshake_state = IMV_ATTESTATION_STATE_INIT,
408 .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
409 .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
410 .file_meas_requests = linked_list_create(),
411 .components = linked_list_create(),
412 .pts = pts_create(FALSE),
413 );
414
415 platform_info = lib->settings->get_str(lib->settings,
416 "libimcv.plugins.imv-attestation.platform_info", NULL);
417 if (platform_info)
418 {
419 this->pts->set_platform_info(this->pts, platform_info);
420 }
421
422 return &this->public.interface;
423 }