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