Separated IMV session management from IMV policy database
[strongswan.git] / src / libpts / plugins / imv_attestation / imv_attestation_agent.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 #define _GNU_SOURCE /* for stdndup() */
18 #include <string.h>
19
20 #include "imv_attestation_agent.h"
21 #include "imv_attestation_state.h"
22 #include "imv_attestation_process.h"
23 #include "imv_attestation_build.h"
24
25 #include <imcv.h>
26 #include <imv/imv_agent.h>
27 #include <imv/imv_msg.h>
28 #include <imv/imv_session.h>
29 #include <imv/imv_os_info.h>
30 #include <ietf/ietf_attr.h>
31 #include <ietf/ietf_attr_attr_request.h>
32 #include <ietf/ietf_attr_pa_tnc_error.h>
33 #include <ietf/ietf_attr_product_info.h>
34 #include <ietf/ietf_attr_string_version.h>
35
36 #include <libpts.h>
37
38 #include <pts/pts.h>
39 #include <pts/pts_database.h>
40 #include <pts/pts_creds.h>
41 #include <pts/components/ita/ita_comp_func_name.h>
42
43 #include <tcg/tcg_attr.h>
44 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
45 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
46 #include <tcg/pts/tcg_pts_attr_req_file_meas.h>
47 #include <tcg/pts/tcg_pts_attr_req_file_meta.h>
48
49 #include <tncif_pa_subtypes.h>
50
51 #include <pen/pen.h>
52 #include <utils/debug.h>
53 #include <credentials/credential_manager.h>
54 #include <collections/linked_list.h>
55
56 typedef struct private_imv_attestation_agent_t private_imv_attestation_agent_t;
57
58 /* Subscribed PA-TNC message subtypes */
59 static pen_type_t msg_types[] = {
60 { PEN_TCG, PA_SUBTYPE_TCG_PTS },
61 { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
62 };
63
64 /**
65 * Private data of an imv_attestation_agent_t object.
66 */
67 struct private_imv_attestation_agent_t {
68
69 /**
70 * Public members of imv_attestation_agent_t
71 */
72 imv_agent_if_t public;
73
74 /**
75 * IMV agent responsible for generic functions
76 */
77 imv_agent_t *agent;
78
79 /**
80 * Supported PTS measurement algorithms
81 */
82 pts_meas_algorithms_t supported_algorithms;
83
84 /**
85 * Supported PTS Diffie Hellman Groups
86 */
87 pts_dh_group_t supported_dh_groups;
88
89 /**
90 * PTS file measurement database
91 */
92 pts_database_t *pts_db;
93
94 /**
95 * PTS credentials
96 */
97 pts_creds_t *pts_creds;
98
99 /**
100 * PTS credential manager
101 */
102 credential_manager_t *pts_credmgr;
103
104 };
105
106 METHOD(imv_agent_if_t, bind_functions, TNC_Result,
107 private_imv_attestation_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
108 {
109 return this->agent->bind_functions(this->agent, bind_function);
110 }
111
112 METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
113 private_imv_attestation_agent_t *this, TNC_ConnectionID id,
114 TNC_ConnectionState new_state)
115 {
116 imv_state_t *state;
117
118 switch (new_state)
119 {
120 case TNC_CONNECTION_STATE_CREATE:
121 state = imv_attestation_state_create(id);
122 return this->agent->create_state(this->agent, state);
123 case TNC_CONNECTION_STATE_DELETE:
124 return this->agent->delete_state(this->agent, id);
125 default:
126 return this->agent->change_state(this->agent, id, new_state, NULL);
127 }
128 }
129
130 /**
131 * Process a received message
132 */
133 static TNC_Result receive_msg(private_imv_attestation_agent_t *this,
134 imv_state_t *state, imv_msg_t *in_msg)
135 {
136 imv_msg_t *out_msg;
137 imv_session_t *session;
138 imv_os_info_t *os_info = NULL;
139 enumerator_t *enumerator;
140 pa_tnc_attr_t *attr;
141 pen_type_t type;
142 TNC_Result result;
143 chunk_t os_name, os_version;
144 bool fatal_error = FALSE;
145
146 /* parse received PA-TNC message and handle local and remote errors */
147 result = in_msg->receive(in_msg, &fatal_error);
148 if (result != TNC_RESULT_SUCCESS)
149 {
150 return result;
151 }
152
153 session = state->get_session(state);
154 os_info = session->get_os_info(session);
155
156 out_msg = imv_msg_create_as_reply(in_msg);
157 out_msg->set_msg_type(out_msg, msg_types[0]);
158
159 /* analyze PA-TNC attributes */
160 enumerator = in_msg->create_attribute_enumerator(in_msg);
161 while (enumerator->enumerate(enumerator, &attr))
162 {
163 type = attr->get_type(attr);
164
165 if (type.vendor_id == PEN_IETF)
166 {
167 switch (type.type)
168 {
169 case IETF_ATTR_PA_TNC_ERROR:
170 {
171 ietf_attr_pa_tnc_error_t *error_attr;
172 pen_type_t error_code;
173 chunk_t msg_info;
174
175 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
176 error_code = error_attr->get_error_code(error_attr);
177
178 if (error_code.vendor_id == PEN_TCG)
179 {
180 msg_info = error_attr->get_msg_info(error_attr);
181
182 DBG1(DBG_IMV, "received TCG-PTS error '%N'",
183 pts_error_code_names, error_code.type);
184 DBG1(DBG_IMV, "error information: %B", &msg_info);
185 fatal_error = TRUE;
186 }
187 break;
188 }
189 case IETF_ATTR_PRODUCT_INFORMATION:
190 {
191 ietf_attr_product_info_t *attr_cast;
192
193 state->set_action_flags(state,
194 IMV_ATTESTATION_ATTR_PRODUCT_INFO);
195 attr_cast = (ietf_attr_product_info_t*)attr;
196 os_name = attr_cast->get_info(attr_cast, NULL, NULL);
197 os_info->set_name(os_info, os_name);
198 break;
199 }
200 case IETF_ATTR_STRING_VERSION:
201 {
202 ietf_attr_string_version_t *attr_cast;
203
204 state->set_action_flags(state,
205 IMV_ATTESTATION_ATTR_STRING_VERSION);
206 attr_cast = (ietf_attr_string_version_t*)attr;
207 os_version = attr_cast->get_version(attr_cast, NULL, NULL);
208 os_info->set_version(os_info, os_version);
209 break;
210 }
211 default:
212 break;
213 }
214 }
215 else if (type.vendor_id == PEN_TCG)
216 {
217 if (!imv_attestation_process(attr, out_msg, state,
218 this->supported_algorithms, this->supported_dh_groups,
219 this->pts_db, this->pts_credmgr))
220 {
221 result = TNC_RESULT_FATAL;
222 break;
223 }
224 }
225 }
226 enumerator->destroy(enumerator);
227
228 if (fatal_error || result != TNC_RESULT_SUCCESS)
229 {
230 state->set_recommendation(state,
231 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
232 TNC_IMV_EVALUATION_RESULT_ERROR);
233 result = out_msg->send_assessment(out_msg);
234 out_msg->destroy(out_msg);
235 if (result != TNC_RESULT_SUCCESS)
236 {
237 return result;
238 }
239 return this->agent->provide_recommendation(this->agent, state);
240 }
241
242 /* send PA-TNC message with excl flag set */
243 result = out_msg->send(out_msg, TRUE);
244 out_msg->destroy(out_msg);
245
246 return result;
247 }
248
249 METHOD(imv_agent_if_t, receive_message, TNC_Result,
250 private_imv_attestation_agent_t *this, TNC_ConnectionID id,
251 TNC_MessageType msg_type, chunk_t msg)
252 {
253 imv_state_t *state;
254 imv_msg_t *in_msg;
255 TNC_Result result;
256
257 if (!this->agent->get_state(this->agent, id, &state))
258 {
259 return TNC_RESULT_FATAL;
260 }
261 in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
262 result = receive_msg(this, state, in_msg);
263 in_msg->destroy(in_msg);
264
265 return result;
266 }
267
268 METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
269 private_imv_attestation_agent_t *this, TNC_ConnectionID id,
270 TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
271 TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
272 {
273 imv_state_t *state;
274 imv_msg_t *in_msg;
275 TNC_Result result;
276
277 if (!this->agent->get_state(this->agent, id, &state))
278 {
279 return TNC_RESULT_FATAL;
280 }
281 in_msg = imv_msg_create_from_long_data(this->agent, state, id,
282 src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
283 result = receive_msg(this, state, in_msg);
284 in_msg->destroy(in_msg);
285
286 return result;
287 }
288
289 /**
290 * Build an IETF Attribute Request attribute for missing attributes
291 */
292 static pa_tnc_attr_t* build_attr_request(u_int32_t received)
293 {
294 pa_tnc_attr_t *attr;
295 ietf_attr_attr_request_t *attr_cast;
296
297 attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
298 attr_cast = (ietf_attr_attr_request_t*)attr;
299
300 if (!(received & IMV_ATTESTATION_ATTR_PRODUCT_INFO) ||
301 !(received & IMV_ATTESTATION_ATTR_STRING_VERSION))
302 {
303 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
304 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
305 }
306 /*
307 if (!(received & IMV_ATTESTATION_ATTR_DEVICE_ID))
308 {
309 attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
310 }
311 */
312 return attr;
313 }
314
315 METHOD(imv_agent_if_t, batch_ending, TNC_Result,
316 private_imv_attestation_agent_t *this, TNC_ConnectionID id)
317 {
318 imv_msg_t *out_msg;
319 imv_state_t *state;
320 imv_session_t *session;
321 imv_os_info_t *os_info;
322 imv_attestation_state_t *attestation_state;
323 imv_attestation_handshake_state_t handshake_state;
324 imv_workitem_t *workitem;
325 TNC_IMV_Action_Recommendation rec;
326 TNC_IMV_Evaluation_Result eval;
327 TNC_IMVID imv_id;
328 TNC_Result result = TNC_RESULT_SUCCESS;
329 pts_t *pts;
330 u_int32_t actions;
331 enumerator_t *enumerator;
332
333 if (!this->agent->get_state(this->agent, id, &state))
334 {
335 return TNC_RESULT_FATAL;
336 }
337 attestation_state = (imv_attestation_state_t*)state;
338 pts = attestation_state->get_pts(attestation_state);
339 handshake_state = attestation_state->get_handshake_state(attestation_state);
340 actions = state->get_action_flags(state);
341 session = state->get_session(state);
342 imv_id = this->agent->get_id(this->agent);
343
344 /* exit if a recommendation has already been provided */
345 if (actions & IMV_ATTESTATION_REC)
346 {
347 return TNC_RESULT_SUCCESS;
348 }
349
350 /* send an IETF attribute request if no platform info was received */
351 if (!(actions & IMV_ATTESTATION_ATTR_REQ))
352 {
353 if ((actions & IMV_ATTESTATION_ATTR_MUST) != IMV_ATTESTATION_ATTR_MUST)
354 {
355 imv_msg_t *os_msg;
356
357 /* create attribute request for missing mandatory attributes */
358 os_msg = imv_msg_create(this->agent, state, id, imv_id,
359 TNC_IMCID_ANY, msg_types[1]);
360 os_msg->add_attribute(os_msg, build_attr_request(actions));
361 result = os_msg->send(os_msg, FALSE);
362 os_msg->destroy(os_msg);
363
364 if (result != TNC_RESULT_SUCCESS)
365 {
366 return result;
367 }
368 }
369 state->set_action_flags(state, IMV_ATTESTATION_ATTR_REQ);
370 }
371
372 if (handshake_state == IMV_ATTESTATION_STATE_INIT)
373 {
374 pa_tnc_attr_t *attr;
375 pts_proto_caps_flag_t flags;
376
377 out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
378 msg_types[0]);
379
380 /* Send Request Protocol Capabilities attribute */
381 flags = pts->get_proto_caps(pts);
382 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
383 attr->set_noskip_flag(attr, TRUE);
384 out_msg->add_attribute(out_msg, attr);
385
386 /* Send Measurement Algorithms attribute */
387 attr = tcg_pts_attr_meas_algo_create(this->supported_algorithms, FALSE);
388 attr->set_noskip_flag(attr, TRUE);
389 out_msg->add_attribute(out_msg, attr);
390
391 attestation_state->set_handshake_state(attestation_state,
392 IMV_ATTESTATION_STATE_DISCOVERY);
393
394 /* send these initial PTS attributes and exit */
395 result = out_msg->send(out_msg, FALSE);
396 out_msg->destroy(out_msg);
397
398 return result;
399 }
400
401 /* exit if we are not ready yet for PTS measurements */
402 if (!session->get_policy_started(session) || !(actions & IMV_ATTESTATION_ALGO))
403 {
404 return TNC_RESULT_SUCCESS;
405 }
406 os_info = session->get_os_info(session);
407 pts->set_platform_info(pts, os_info->get_info(os_info));
408
409 /* create an empty out message - we might need it */
410 out_msg = imv_msg_create(this->agent, state, id, imv_id, TNC_IMCID_ANY,
411 msg_types[0]);
412
413 /* establish the PTS measurements to be taken */
414 if (!(actions & IMV_ATTESTATION_FILE_MEAS))
415 {
416 bool is_dir, no_workitems = TRUE;
417 u_int32_t delimiter = SOLIDUS_UTF;
418 u_int16_t request_id;
419 pa_tnc_attr_t *attr;
420 char *pathname;
421
422 attestation_state->set_handshake_state(attestation_state,
423 IMV_ATTESTATION_STATE_END);
424
425 enumerator = session->create_workitem_enumerator(session);
426 if (enumerator)
427 {
428 while (enumerator->enumerate(enumerator, &workitem))
429 {
430 if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY)
431 {
432 continue;
433 }
434
435 switch (workitem->get_type(workitem))
436 {
437 case IMV_WORKITEM_FILE_REF_MEAS:
438 case IMV_WORKITEM_FILE_MEAS:
439 case IMV_WORKITEM_FILE_META:
440 is_dir = FALSE;
441 break;
442 case IMV_WORKITEM_DIR_REF_MEAS:
443 case IMV_WORKITEM_DIR_MEAS:
444 case IMV_WORKITEM_DIR_META:
445 is_dir = TRUE;
446 break;
447 case IMV_WORKITEM_TPM_ATTEST:
448 {
449 pts_component_t *comp;
450 pts_comp_func_name_t *comp_name;
451 bool no_d_flag, no_t_flag;
452 char result_str[BUF_LEN];
453
454 workitem->set_imv_id(workitem, imv_id);
455 no_workitems = FALSE;
456 no_d_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D);
457 no_t_flag = !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T);
458 if (no_d_flag || no_t_flag)
459 {
460 snprintf(result_str, BUF_LEN, "%s%s%s",
461 (no_t_flag) ? "no TPM available" : "",
462 (no_t_flag && no_d_flag) ? ", " : "",
463 (no_d_flag) ? "no DH nonce negotiation" : "");
464 eval = TNC_IMV_EVALUATION_RESULT_ERROR;
465 session->remove_workitem(session, enumerator);
466 rec = workitem->set_result(workitem, result_str, eval);
467 state->update_recommendation(state, rec, eval);
468 imcv_db->finalize_workitem(imcv_db, workitem);
469 workitem->destroy(workitem);
470 continue;
471 }
472
473 /* do TPM BIOS measurements */
474 if (strchr(workitem->get_arg_str(workitem), 'B'))
475 {
476 comp_name = pts_comp_func_name_create(PEN_ITA,
477 PTS_ITA_COMP_FUNC_NAME_IMA,
478 PTS_ITA_QUALIFIER_FLAG_KERNEL |
479 PTS_ITA_QUALIFIER_TYPE_TRUSTED);
480 comp = attestation_state->create_component(
481 attestation_state, comp_name,
482 0, this->pts_db);
483 if (!comp)
484 {
485 comp_name->log(comp_name, "unregistered ");
486 comp_name->destroy(comp_name);
487 }
488 }
489
490 /* do TPM IMA measurements */
491 if (strchr(workitem->get_arg_str(workitem), 'I'))
492 {
493 comp_name = pts_comp_func_name_create(PEN_ITA,
494 PTS_ITA_COMP_FUNC_NAME_IMA,
495 PTS_ITA_QUALIFIER_FLAG_KERNEL |
496 PTS_ITA_QUALIFIER_TYPE_OS);
497 comp = attestation_state->create_component(
498 attestation_state, comp_name,
499 0, this->pts_db);
500 if (!comp)
501 {
502 comp_name->log(comp_name, "unregistered ");
503 comp_name->destroy(comp_name);
504 }
505 }
506
507 /* do TPM TRUSTED BOOT measurements */
508 if (strchr(workitem->get_arg_str(workitem), 'T'))
509 {
510 comp_name = pts_comp_func_name_create(PEN_ITA,
511 PTS_ITA_COMP_FUNC_NAME_TBOOT,
512 PTS_ITA_QUALIFIER_FLAG_KERNEL |
513 PTS_ITA_QUALIFIER_TYPE_TRUSTED);
514 comp = attestation_state->create_component(
515 attestation_state, comp_name,
516 0, this->pts_db);
517 if (!comp)
518 {
519 comp_name->log(comp_name, "unregistered ");
520 comp_name->destroy(comp_name);
521 }
522 }
523 attestation_state->set_handshake_state(attestation_state,
524 IMV_ATTESTATION_STATE_NONCE_REQ);
525 continue;
526 }
527 default:
528 continue;
529 }
530
531 /* initiate file and directory measurements */
532 pathname = this->pts_db->get_pathname(this->pts_db, is_dir,
533 workitem->get_arg_int(workitem));
534 if (!pathname)
535 {
536 continue;
537 }
538 workitem->set_imv_id(workitem, imv_id);
539 no_workitems = FALSE;
540
541 if (workitem->get_type(workitem) == IMV_WORKITEM_FILE_META)
542 {
543 TNC_IMV_Action_Recommendation rec;
544 TNC_IMV_Evaluation_Result eval;
545 char result_str[BUF_LEN];
546
547 DBG2(DBG_IMV, "IMV %d requests metadata for %s '%s'",
548 imv_id, is_dir ? "directory" : "file", pathname);
549
550 /* currently just fire and forget metadata requests */
551 attr = tcg_pts_attr_req_file_meta_create(is_dir,
552 delimiter, pathname);
553 snprintf(result_str, BUF_LEN, "%s metadata requested",
554 is_dir ? "directory" : "file");
555 eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
556 session->remove_workitem(session, enumerator);
557 rec = workitem->set_result(workitem, result_str, eval);
558 state->update_recommendation(state, rec, eval);
559 imcv_db->finalize_workitem(imcv_db, workitem);
560 workitem->destroy(workitem);
561 }
562 else
563 {
564 /* use lower 16 bits of the workitem ID as request ID */
565 request_id = workitem->get_id(workitem) & 0xffff;
566
567 DBG2(DBG_IMV, "IMV %d requests measurement %d for %s '%s'",
568 imv_id, request_id, is_dir ? "directory" : "file",
569 pathname);
570 attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
571 delimiter, pathname);
572 }
573 free(pathname);
574 attr->set_noskip_flag(attr, TRUE);
575 out_msg->add_attribute(out_msg, attr);
576 }
577 enumerator->destroy(enumerator);
578
579 /* sent all file and directory measurement and metadata requests */
580 state->set_action_flags(state, IMV_ATTESTATION_FILE_MEAS);
581
582 if (no_workitems)
583 {
584 DBG2(DBG_IMV, "IMV %d has no workitems - "
585 "no evaluation requested", imv_id);
586 state->set_recommendation(state,
587 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
588 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
589 }
590 }
591 }
592
593 /* check the IMV state for the next PA-TNC attributes to send */
594 enumerator = session->create_workitem_enumerator(session);
595 while (enumerator->enumerate(enumerator, &workitem))
596 {
597 if (workitem->get_type(workitem) == IMV_WORKITEM_TPM_ATTEST)
598 {
599 if (!imv_attestation_build(out_msg, state,
600 this->supported_dh_groups, this->pts_db))
601 {
602 imv_reason_string_t *reason_string;
603 chunk_t result;
604 char *result_str;
605
606 reason_string = imv_reason_string_create("en", ", ");
607 attestation_state->add_comp_evid_reasons(attestation_state,
608 reason_string);
609 result = reason_string->get_encoding(reason_string);
610 result_str = strndup(result.ptr, result.len);
611 reason_string->destroy(reason_string);
612
613 eval = TNC_IMV_EVALUATION_RESULT_ERROR;
614 session->remove_workitem(session, enumerator);
615 rec = workitem->set_result(workitem, result_str, eval);
616 state->update_recommendation(state, rec, eval);
617 imcv_db->finalize_workitem(imcv_db, workitem);
618 }
619 break;
620 }
621 }
622 enumerator->destroy(enumerator);
623
624 /* finalized all workitems? */
625 if (session->get_policy_started(session) &&
626 session->get_workitem_count(session, imv_id) == 0 &&
627 attestation_state->get_handshake_state(attestation_state) ==
628 IMV_ATTESTATION_STATE_END)
629 {
630 result = out_msg->send_assessment(out_msg);
631 out_msg->destroy(out_msg);
632 state->set_action_flags(state, IMV_ATTESTATION_REC);
633
634 if (result != TNC_RESULT_SUCCESS)
635 {
636 return result;
637 }
638 return this->agent->provide_recommendation(this->agent, state);
639 }
640
641 /* send non-empty PA-TNC message with excl flag not set */
642 if (out_msg->get_attribute_count(out_msg))
643 {
644 result = out_msg->send(out_msg, FALSE);
645 }
646 out_msg->destroy(out_msg);
647
648 return result;
649 }
650
651 METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
652 private_imv_attestation_agent_t *this, TNC_ConnectionID id)
653 {
654 TNC_IMVID imv_id;
655 imv_state_t *state;
656 imv_attestation_state_t *attestation_state;
657 imv_session_t *session;
658
659 if (!this->agent->get_state(this->agent, id, &state))
660 {
661 return TNC_RESULT_FATAL;
662 }
663 attestation_state = (imv_attestation_state_t*)state;
664 session = state->get_session(state);
665 imv_id = this->agent->get_id(this->agent);
666
667 if (imcv_db)
668 {
669 TNC_IMV_Evaluation_Result eval;
670 TNC_IMV_Action_Recommendation rec;
671 imv_workitem_t *workitem;
672 enumerator_t *enumerator;
673 char *result_str;
674 int pending_file_meas = 0;
675
676 enumerator = session->create_workitem_enumerator(session);
677 if (enumerator)
678 {
679 while (enumerator->enumerate(enumerator, &workitem))
680 {
681 if (workitem->get_imv_id(workitem) != imv_id)
682 {
683 continue;
684 }
685 switch (workitem->get_type(workitem))
686 {
687 case IMV_WORKITEM_FILE_REF_MEAS:
688 case IMV_WORKITEM_FILE_MEAS:
689 case IMV_WORKITEM_DIR_REF_MEAS:
690 case IMV_WORKITEM_DIR_MEAS:
691 result_str = "Pending file measurements";
692 pending_file_meas++;
693 break;
694 case IMV_WORKITEM_TPM_ATTEST:
695 attestation_state->finalize_components(attestation_state);
696 result_str = "Pending component evidence";
697 break;
698 default:
699 continue;
700 }
701 session->remove_workitem(session, enumerator);
702 eval = TNC_IMV_EVALUATION_RESULT_ERROR;
703 rec = workitem->set_result(workitem, result_str, eval);
704 state->update_recommendation(state, rec, eval);
705 imcv_db->finalize_workitem(imcv_db, workitem);
706 workitem->destroy(workitem);
707 }
708 enumerator->destroy(enumerator);
709
710 if (pending_file_meas)
711 {
712 DBG1(DBG_IMV, "failure due to %d pending file measurements",
713 pending_file_meas);
714 attestation_state->set_measurement_error(attestation_state,
715 IMV_ATTESTATION_ERROR_FILE_MEAS_PEND);
716 }
717 }
718 }
719 return this->agent->provide_recommendation(this->agent, state);
720 }
721
722 METHOD(imv_agent_if_t, destroy, void,
723 private_imv_attestation_agent_t *this)
724 {
725 if (this->pts_creds)
726 {
727 this->pts_credmgr->remove_set(this->pts_credmgr,
728 this->pts_creds->get_set(this->pts_creds));
729 this->pts_creds->destroy(this->pts_creds);
730 }
731 DESTROY_IF(this->pts_db);
732 DESTROY_IF(this->pts_credmgr);
733 DESTROY_IF(this->agent);
734 free(this);
735 libpts_deinit();
736 }
737
738 /**
739 * Described in header.
740 */
741 imv_agent_if_t *imv_attestation_agent_create(const char *name, TNC_IMVID id,
742 TNC_Version *actual_version)
743 {
744 private_imv_attestation_agent_t *this;
745 imv_agent_t *agent;
746 char *hash_alg, *dh_group, *cadir;
747 bool mandatory_dh_groups;
748
749 agent = imv_agent_create(name, msg_types, countof(msg_types), id,
750 actual_version);
751 if (!agent)
752 {
753 return NULL;
754 }
755
756 hash_alg = lib->settings->get_str(lib->settings,
757 "%s.plugins.imv-attestation.hash_algorithm", "sha256", lib->ns);
758 dh_group = lib->settings->get_str(lib->settings,
759 "%s.plugins.imv-attestation.dh_group", "ecp256", lib->ns);
760 mandatory_dh_groups = lib->settings->get_bool(lib->settings,
761 "%s.plugins.imv-attestation.mandatory_dh_groups", TRUE, lib->ns);
762 cadir = lib->settings->get_str(lib->settings,
763 "%s.plugins.imv-attestation.cadir", NULL, lib->ns);
764
765 INIT(this,
766 .public = {
767 .bind_functions = _bind_functions,
768 .notify_connection_change = _notify_connection_change,
769 .receive_message = _receive_message,
770 .receive_message_long = _receive_message_long,
771 .batch_ending = _batch_ending,
772 .solicit_recommendation = _solicit_recommendation,
773 .destroy = _destroy,
774 },
775 .agent = agent,
776 .supported_algorithms = PTS_MEAS_ALGO_NONE,
777 .supported_dh_groups = PTS_DH_GROUP_NONE,
778 .pts_credmgr = credential_manager_create(),
779 .pts_creds = pts_creds_create(cadir),
780 .pts_db = pts_database_create(imcv_db),
781 );
782
783 libpts_init();
784
785 if (!pts_meas_algo_probe(&this->supported_algorithms) ||
786 !pts_dh_group_probe(&this->supported_dh_groups, mandatory_dh_groups) ||
787 !pts_meas_algo_update(hash_alg, &this->supported_algorithms) ||
788 !pts_dh_group_update(dh_group, &this->supported_dh_groups))
789 {
790 destroy(this);
791 return NULL;
792 }
793
794 if (this->pts_creds)
795 {
796 this->pts_credmgr->add_set(this->pts_credmgr,
797 this->pts_creds->get_set(this->pts_creds));
798 }
799
800 return &this->public;
801 }