change measurement not found debug level
[strongswan.git] / src / libimcv / plugins / imv_attestation / imv_attestation.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 <imv/imv_agent.h>
19 #include <pa_tnc/pa_tnc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ietf/ietf_attr_pa_tnc_error.h>
22 #include <ietf/ietf_attr_product_info.h>
23
24 #include <tcg/pts/pts_database.h>
25 #include <tcg/pts/pts_creds.h>
26 #include <tcg/pts/pts_error.h>
27
28 #include <tcg/tcg_attr.h>
29 #include <tcg/tcg_pts_attr_proto_caps.h>
30 #include <tcg/tcg_pts_attr_meas_algo.h>
31 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
32 #include <tcg/tcg_pts_attr_tpm_version_info.h>
33 #include <tcg/tcg_pts_attr_get_aik.h>
34 #include <tcg/tcg_pts_attr_aik.h>
35 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
36 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
37 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
38 #include <tcg/tcg_pts_attr_simple_evid_final.h>
39 #include <tcg/tcg_pts_attr_req_file_meas.h>
40 #include <tcg/tcg_pts_attr_file_meas.h>
41
42 #include <tncif_pa_subtypes.h>
43
44 #include <pen/pen.h>
45 #include <debug.h>
46 #include <utils/linked_list.h>
47
48 /* IMV definitions */
49
50 static const char imv_name[] = "Attestation";
51
52 #define IMV_VENDOR_ID PEN_TCG
53 #define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
54
55 /**
56 * UTF-8 encoding of the character used to delimiter the filename
57 */
58 #define SOLIDUS_UTF 0x002F
59 #define REVERSE_SOLIDUS_UTF 0x005C
60
61 static imv_agent_t *imv_attestation;
62
63 /**
64 * Supported PTS measurement algorithms
65 */
66 static pts_meas_algorithms_t supported_algorithms = 0;
67
68 /**
69 * PTS file measurement database
70 */
71 static pts_database_t *pts_db;
72
73 /**
74 * PTS credentials
75 */
76 static pts_creds_t *pts_creds;
77
78 /**
79 * List of id's for the files that are requested for measurement
80 */
81 static linked_list_t *requested_files;
82
83 /**
84 * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
85 */
86 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
87 TNC_Version min_version,
88 TNC_Version max_version,
89 TNC_Version *actual_version)
90 {
91 char *hash_alg, *uri, *cadir;
92
93 if (imv_attestation)
94 {
95 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
96 return TNC_RESULT_ALREADY_INITIALIZED;
97 }
98 imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
99 imv_id, actual_version);
100 if (!imv_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
101 {
102 return TNC_RESULT_FATAL;
103 }
104 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
105 {
106 DBG1(DBG_IMV, "no common IF-IMV version");
107 return TNC_RESULT_NO_COMMON_VERSION;
108 }
109
110 /**
111 * Specify supported PTS measurement algorithms
112 *
113 * sha1 : PTS_MEAS_ALGO_SHA1
114 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
115 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
116 *
117 * we expect the PTS-IMC to select the strongest supported algorithm
118 */
119 hash_alg = lib->settings->get_str(lib->settings,
120 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
121 if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384"))
122 {
123 /* remove SHA384 algorithm */
124 supported_algorithms &= ~PTS_MEAS_ALGO_SHA384;
125 }
126 if (strcaseeq(hash_alg, "sha1"))
127 {
128 /* remove SHA256 algorithm */
129 supported_algorithms &= ~PTS_MEAS_ALGO_SHA256;
130 }
131
132 /* attach file measurement database */
133 uri = lib->settings->get_str(lib->settings,
134 "libimcv.plugins.imv-attestation.database", NULL);
135 pts_db = pts_database_create(uri);
136
137 /* create PTS credential set */
138 cadir = lib->settings->get_str(lib->settings,
139 "libimcv.plugins.imv-attestation.cadir", NULL);
140 pts_creds = pts_creds_create(cadir);
141
142 return TNC_RESULT_SUCCESS;
143 }
144
145 /**
146 * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
147 */
148 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
149 TNC_ConnectionID connection_id,
150 TNC_ConnectionState new_state)
151 {
152 imv_state_t *state;
153 imv_attestation_state_t *attestation_state;
154 TNC_Result result;
155
156 if (!imv_attestation)
157 {
158 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
159 return TNC_RESULT_NOT_INITIALIZED;
160 }
161 switch (new_state)
162 {
163 case TNC_CONNECTION_STATE_CREATE:
164 state = imv_attestation_state_create(connection_id);
165 return imv_attestation->create_state(imv_attestation, state);
166 case TNC_CONNECTION_STATE_DELETE:
167 return imv_attestation->delete_state(imv_attestation, connection_id);
168 case TNC_CONNECTION_STATE_HANDSHAKE:
169 result = imv_attestation->change_state(imv_attestation, connection_id,
170 new_state, &state);
171 if (result != TNC_RESULT_SUCCESS)
172 {
173 return result;
174 }
175 attestation_state = (imv_attestation_state_t*)state;
176
177 /* TODO: Get some configurations */
178
179 return TNC_RESULT_SUCCESS;
180 default:
181 return imv_attestation->change_state(imv_attestation, connection_id,
182 new_state, NULL);
183 }
184 }
185
186 static TNC_Result send_message(TNC_ConnectionID connection_id)
187 {
188 pa_tnc_msg_t *msg;
189 pa_tnc_attr_t *attr;
190 pts_t *pts;
191 imv_state_t *state;
192 imv_attestation_state_t *attestation_state;
193 imv_attestation_handshake_state_t handshake_state;
194 TNC_Result result;
195
196 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
197 {
198 return TNC_RESULT_FATAL;
199 }
200 attestation_state = (imv_attestation_state_t*)state;
201 handshake_state = attestation_state->get_handshake_state(attestation_state);
202 pts = attestation_state->get_pts(attestation_state);
203
204 msg = pa_tnc_msg_create();
205
206
207 /* Switch on the attribute type IMV has received */
208 switch (handshake_state)
209 {
210 case IMV_ATTESTATION_STATE_INIT:
211 {
212 pts_proto_caps_flag_t flags;
213
214 /* Send Request Protocol Capabilities attribute */
215 flags = pts->get_proto_caps(pts);
216 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
217 attr->set_noskip_flag(attr, TRUE);
218 msg->add_attribute(msg, attr);
219
220 /* Send Measurement Algorithms attribute */
221 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
222 attr->set_noskip_flag(attr, TRUE);
223 msg->add_attribute(msg, attr);
224
225 attestation_state->set_handshake_state(attestation_state,
226 IMV_ATTESTATION_STATE_MEAS);
227 break;
228 }
229
230 case IMV_ATTESTATION_STATE_MEAS:
231 {
232 enumerator_t *enumerator;
233 u_int32_t delimiter = SOLIDUS_UTF;
234 char *platform_info, *pathname;
235 int id, type;
236 bool is_directory;
237
238 /* Does the PTS-IMC have TPM support? */
239 if (pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T)
240 {
241 /* Send Get TPM Version attribute */
242 attr = tcg_pts_attr_get_tpm_version_info_create();
243 attr->set_noskip_flag(attr, TRUE);
244 msg->add_attribute(msg, attr);
245
246 /* Send Get AIK attribute */
247 attr = tcg_pts_attr_get_aik_create();
248 attr->set_noskip_flag(attr, TRUE);
249 msg->add_attribute(msg, attr);
250 }
251
252 /* Get Platform and OS of the PTS-IMC */
253 platform_info = pts->get_platform_info(pts);
254
255 if (!pts_db || !platform_info)
256 {
257 DBG1(DBG_IMV, "%s%s%s not available",
258 (pts_db) ? "" : "pts database",
259 (!pts_db && !platform_info) ? "and" : "",
260 (platform_info) ? "" : "platform info");
261 break;
262 }
263 DBG1(DBG_IMV, "platform is '%s'", platform_info);
264
265 /* Send Request File Measurement attribute */
266 enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
267 if (!enumerator)
268 {
269 break;
270 }
271
272 requested_files = linked_list_create();
273 while (enumerator->enumerate(enumerator, &id, &type, &pathname))
274 {
275 is_directory = (type != 0);
276 DBG2(DBG_IMV, "measurement request %d for %s '%s'",
277 id, is_directory ? "directory" : "file", pathname);
278 attr = tcg_pts_attr_req_file_meas_create(is_directory, id,
279 delimiter, pathname);
280 attr->set_noskip_flag(attr, TRUE);
281 msg->add_attribute(msg, attr);
282 requested_files->insert_last(requested_files, (void*)id);
283 }
284 enumerator->destroy(enumerator);
285
286 attestation_state->set_handshake_state(attestation_state,
287 IMV_ATTESTATION_STATE_END);
288 break;
289 }
290 case IMV_ATTESTATION_STATE_COMP_EVID:
291 case IMV_ATTESTATION_STATE_IML:
292 DBG1(DBG_IMV, "Attestation IMV has nothing to send: \"%s\"",
293 handshake_state);
294 return TNC_RESULT_FATAL;
295 default:
296 DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
297 handshake_state);
298 return TNC_RESULT_FATAL;
299 }
300
301 msg->build(msg);
302 result = imv_attestation->send_message(imv_attestation, connection_id,
303 msg->get_encoding(msg));
304 msg->destroy(msg);
305
306 return result;
307 }
308
309 /**
310 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
311 */
312 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
313 TNC_ConnectionID connection_id,
314 TNC_BufferReference msg,
315 TNC_UInt32 msg_len,
316 TNC_MessageType msg_type)
317 {
318 pa_tnc_msg_t *pa_tnc_msg;
319 pa_tnc_attr_t *attr;
320 imv_state_t *state;
321 imv_attestation_state_t *attestation_state;
322 pts_t *pts;
323 enumerator_t *enumerator;
324 TNC_Result result;
325 bool fatal_error = FALSE;
326 bool measurement_error = FALSE;
327
328 if (!imv_attestation)
329 {
330 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
331 return TNC_RESULT_NOT_INITIALIZED;
332 }
333
334 /* get current IMV state */
335 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
336 {
337 return TNC_RESULT_FATAL;
338 }
339 attestation_state = (imv_attestation_state_t*)state;
340 pts = attestation_state->get_pts(attestation_state);
341
342 /* parse received PA-TNC message and automatically handle any errors */
343 result = imv_attestation->receive_message(imv_attestation, connection_id,
344 chunk_create(msg, msg_len), msg_type,
345 &pa_tnc_msg);
346
347 /* no parsed PA-TNC attributes available if an error occurred */
348 if (!pa_tnc_msg)
349 {
350 return result;
351 }
352
353 /* analyze PA-TNC attributes */
354 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
355 while (enumerator->enumerate(enumerator, &attr))
356 {
357 if (attr->get_vendor_id(attr) == PEN_IETF)
358 {
359 if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
360 {
361 ietf_attr_pa_tnc_error_t *error_attr;
362 pen_t error_vendor_id;
363 pa_tnc_error_code_t error_code;
364 chunk_t msg_info, attr_info;
365 u_int32_t offset;
366
367 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
368 error_vendor_id = error_attr->get_vendor_id(error_attr);
369 error_code = error_attr->get_error_code(error_attr);
370 msg_info = error_attr->get_msg_info(error_attr);
371
372 if (error_vendor_id == PEN_IETF)
373 {
374 DBG1(DBG_IMV, "received PA-TNC error '%N' "
375 "concerning message %#B",
376 pa_tnc_error_code_names, error_code, &msg_info);
377
378 switch (error_code)
379 {
380 case PA_ERROR_INVALID_PARAMETER:
381 offset = error_attr->get_offset(error_attr);
382 DBG1(DBG_IMV, " occurred at offset of %u bytes",
383 offset);
384 break;
385 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
386 attr_info = error_attr->get_attr_info(error_attr);
387 DBG1(DBG_IMV, " unsupported attribute %#B",
388 &attr_info);
389 break;
390 default:
391 break;
392 }
393 }
394 else if (error_vendor_id == PEN_TCG)
395 {
396 DBG1(DBG_IMV, "received TCG-PTS error '%N'",
397 pts_error_code_names, error_code);
398 DBG1(DBG_IMV, "error information: %B", &msg_info);
399 }
400 fatal_error = TRUE;
401 }
402 else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
403 {
404 ietf_attr_product_info_t *attr_cast;
405 char *platform_info;
406
407 attr_cast = (ietf_attr_product_info_t*)attr;
408 platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
409 pts->set_platform_info(pts, platform_info);
410 }
411 }
412 else if (attr->get_vendor_id(attr) == PEN_TCG)
413 {
414 switch (attr->get_type(attr))
415 {
416 case TCG_PTS_PROTO_CAPS:
417 {
418 tcg_pts_attr_proto_caps_t *attr_cast;
419 pts_proto_caps_flag_t flags;
420
421 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
422 flags = attr_cast->get_flags(attr_cast);
423 pts->set_proto_caps(pts, flags);
424 break;
425 }
426 case TCG_PTS_MEAS_ALGO_SELECTION:
427 {
428 tcg_pts_attr_meas_algo_t *attr_cast;
429 pts_meas_algorithms_t selected_algorithm;
430
431 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
432 selected_algorithm = attr_cast->get_algorithms(attr_cast);
433 pts->set_meas_algorithm(pts, selected_algorithm);
434 break;
435 }
436 case TCG_PTS_TPM_VERSION_INFO:
437 {
438 tcg_pts_attr_tpm_version_info_t *attr_cast;
439 chunk_t tpm_version_info;
440
441 attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
442 tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
443 pts->set_tpm_version_info(pts, tpm_version_info);
444 break;
445 }
446 case TCG_PTS_AIK:
447 {
448 tcg_pts_attr_aik_t *attr_cast;
449 certificate_t *aik;
450
451 attr_cast = (tcg_pts_attr_aik_t*)attr;
452 aik = attr_cast->get_aik(attr_cast);
453 if (!aik)
454 {
455 /* TODO generate error attribute */
456 break;
457 }
458 pts->set_aik(pts, aik);
459 break;
460 }
461
462 /* PTS-based Attestation Evidence */
463 case TCG_PTS_SIMPLE_COMP_EVID:
464 break;
465 case TCG_PTS_SIMPLE_EVID_FINAL:
466 break;
467 case TCG_PTS_FILE_MEAS:
468 {
469 tcg_pts_attr_file_meas_t *attr_cast;
470 u_int16_t request_id;
471 int file_count;
472 pts_meas_algorithms_t algo;
473 pts_file_meas_t *measurements;
474 chunk_t measurement;
475 char *platform_info, *filename;
476 enumerator_t *e_meas;
477 bool is_directory;
478 linked_list_t *files_in_dir_with_meas;
479
480 files_in_dir_with_meas = linked_list_create();
481 platform_info = pts->get_platform_info(pts);
482 if (!pts_db || !platform_info)
483 {
484 break;
485 }
486
487 attr_cast = (tcg_pts_attr_file_meas_t*)attr;
488 measurements = attr_cast->get_measurements(attr_cast);
489 algo = pts->get_meas_algorithm(pts);
490 request_id = measurements->get_request_id(measurements);
491 file_count = measurements->get_file_count(measurements);
492
493 DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
494 request_id, file_count, (file_count == 1) ? "":"s");
495
496 if (!pts_db->is_directory(pts_db, request_id, &is_directory))
497 {
498 DBG1(DBG_IMV, "file entry with request id:%d not found", request_id);
499 break;
500 }
501
502 if (!is_directory)
503 {
504 requested_files->remove(requested_files, (void*)request_id, NULL);
505 }
506 else
507 {
508 enumerator_t *e;
509 char *file;
510
511 e = pts_db->create_files_in_dir_enumerator(pts_db, request_id);
512 while (e->enumerate(e, &file))
513 {
514 files_in_dir_with_meas->insert_last(files_in_dir_with_meas, file);
515 DBG3(DBG_IMV, "expecting measurement for: %s with request_id: %d", file, request_id);
516 }
517 }
518
519 e_meas = measurements->create_enumerator(measurements);
520 while (e_meas->enumerate(e_meas, &filename, &measurement))
521 {
522 enumerator_t *e;
523 chunk_t db_measurement;
524
525 e = (is_directory) ? pts_db->create_dir_meas_enumerator(pts_db,
526 platform_info, request_id, filename, algo) :
527 pts_db->create_file_meas_enumerator(pts_db,
528 platform_info, request_id, algo);
529 if (!e)
530 {
531 DBG1(DBG_IMV, " database enumerator failed");
532 continue;
533 }
534 if (!e->enumerate(e, &db_measurement))
535 {
536 DBG2(DBG_IMV, " measurement for '%s' not found"
537 " in database", filename);
538 e->destroy(e);
539 continue;
540 }
541 if (chunk_equals(db_measurement, measurement))
542 {
543 DBG2(DBG_IMV, " %#B for '%s' is ok",
544 &measurement, filename);
545 }
546 else
547 {
548 DBG1(DBG_IMV, " %#B for '%s' does not match %#B",
549 &measurement, filename, &db_measurement);
550 measurement_error = TRUE;
551 }
552
553 if (is_directory)
554 {
555 files_in_dir_with_meas->remove(files_in_dir_with_meas,
556 filename, (bool (*)(void*,void*))strcmp);
557 }
558 e->destroy(e);
559 }
560
561 if (is_directory &&
562 !files_in_dir_with_meas->get_count(files_in_dir_with_meas))
563 {
564 requested_files->remove(requested_files, (void*)request_id, NULL);
565 }
566
567 e_meas->destroy(e_meas);
568 break;
569 }
570
571 /* TODO: Not implemented yet */
572 case TCG_PTS_DH_NONCE_PARAMS_RESP:
573 case TCG_PTS_UNIX_FILE_META:
574 case TCG_PTS_INTEG_MEAS_LOG:
575 /* Attributes using XML */
576 case TCG_PTS_TEMPL_REF_MANI_SET_META:
577 case TCG_PTS_VERIFICATION_RESULT:
578 case TCG_PTS_INTEG_REPORT:
579 /* On Windows only*/
580 case TCG_PTS_WIN_FILE_META:
581 case TCG_PTS_REGISTRY_VALUE:
582 /* Received on IMC side only*/
583 case TCG_PTS_REQ_PROTO_CAPS:
584 case TCG_PTS_DH_NONCE_PARAMS_REQ:
585 case TCG_PTS_DH_NONCE_FINISH:
586 case TCG_PTS_MEAS_ALGO:
587 case TCG_PTS_GET_TPM_VERSION_INFO:
588 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
589 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
590 case TCG_PTS_GET_AIK:
591 case TCG_PTS_REQ_FUNCT_COMP_EVID:
592 case TCG_PTS_GEN_ATTEST_EVID:
593 case TCG_PTS_REQ_FILE_META:
594 case TCG_PTS_REQ_FILE_MEAS:
595 case TCG_PTS_REQ_INTEG_MEAS_LOG:
596 default:
597 DBG1(DBG_IMV, "received unsupported attribute '%N'",
598 tcg_attr_names, attr->get_type(attr));
599 break;
600 }
601 }
602 }
603 enumerator->destroy(enumerator);
604 pa_tnc_msg->destroy(pa_tnc_msg);
605
606
607
608 if (fatal_error)
609 {
610 state->set_recommendation(state,
611 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
612 TNC_IMV_EVALUATION_RESULT_ERROR);
613 return imv_attestation->provide_recommendation(imv_attestation,
614 connection_id);
615 }
616
617 if (attestation_state->get_handshake_state(attestation_state) &
618 IMV_ATTESTATION_STATE_END)
619 {
620 if (measurement_error || requested_files->get_count(requested_files))
621 {
622 enumerator_t *e;
623 int request;
624
625 e = requested_files->create_enumerator(requested_files);
626 while (e->enumerate(e, &request))
627 {
628 DBG1(DBG_IMV, "measurement/s not received for requests: %d", request);
629 }
630
631 e->destroy(e);
632 state->set_recommendation(state,
633 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
634 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
635 }
636 else
637 {
638 state->set_recommendation(state,
639 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
640 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
641 }
642 return imv_attestation->provide_recommendation(imv_attestation,
643 connection_id);
644 }
645
646 return send_message(connection_id);
647 }
648
649 /**
650 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
651 */
652 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
653 TNC_ConnectionID connection_id)
654 {
655 if (!imv_attestation)
656 {
657 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
658 return TNC_RESULT_NOT_INITIALIZED;
659 }
660 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
661 }
662
663 /**
664 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
665 */
666 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
667 TNC_ConnectionID connection_id)
668 {
669 imv_state_t *state;
670 imv_attestation_state_t *attestation_state;
671
672 if (!imv_attestation)
673 {
674 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
675 return TNC_RESULT_NOT_INITIALIZED;
676 }
677 /* get current IMV state */
678 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
679 {
680 return TNC_RESULT_FATAL;
681 }
682 attestation_state = (imv_attestation_state_t*)state;
683
684 /* Check if IMV has to initiate the PA-TNC exchange */
685 if (attestation_state->get_handshake_state(attestation_state) ==
686 IMV_ATTESTATION_STATE_INIT)
687 {
688 return send_message(connection_id);
689 }
690 return TNC_RESULT_SUCCESS;
691 }
692
693 /**
694 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
695 */
696 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
697 {
698 if (!imv_attestation)
699 {
700 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
701 return TNC_RESULT_NOT_INITIALIZED;
702 }
703 DESTROY_IF(pts_db);
704 DESTROY_IF(pts_creds);
705 imv_attestation->destroy(imv_attestation);
706 imv_attestation = NULL;
707
708 return TNC_RESULT_SUCCESS;
709 }
710
711 /**
712 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
713 */
714 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
715 TNC_TNCS_BindFunctionPointer bind_function)
716 {
717 if (!imv_attestation)
718 {
719 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
720 return TNC_RESULT_NOT_INITIALIZED;
721 }
722 return imv_attestation->bind_functions(imv_attestation, bind_function);
723 }