moved attribute processing to imv_attestation_process
[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 #include "imv_attestation_process.h"
18
19 #include <imv/imv_agent.h>
20 #include <pa_tnc/pa_tnc_msg.h>
21 #include <ietf/ietf_attr.h>
22 #include <ietf/ietf_attr_pa_tnc_error.h>
23 #include <ietf/ietf_attr_product_info.h>
24
25 #include <libpts.h>
26
27 #include <pts/pts.h>
28 #include <pts/pts_database.h>
29 #include <pts/pts_creds.h>
30
31 #include <tcg/tcg_attr.h>
32 #include <tcg/tcg_pts_attr_proto_caps.h>
33 #include <tcg/tcg_pts_attr_meas_algo.h>
34 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
35 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
36 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
37 #include <tcg/tcg_pts_attr_get_aik.h>
38 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
39 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
40 #include <tcg/tcg_pts_attr_req_file_meas.h>
41 #include <tcg/tcg_pts_attr_req_file_meta.h>
42
43 #include <tncif_pa_subtypes.h>
44
45 #include <pen/pen.h>
46 #include <debug.h>
47 #include <credentials/credential_manager.h>
48 #include <utils/linked_list.h>
49
50 /* IMV definitions */
51
52 static const char imv_name[] = "Attestation";
53
54 #define IMV_VENDOR_ID PEN_TCG
55 #define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
56
57 static imv_agent_t *imv_attestation;
58
59 /**
60 * Supported PTS measurement algorithms
61 */
62 static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
63
64 /**
65 * Supported PTS Diffie Hellman Groups
66 */
67 static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
68
69 /**
70 * PTS file measurement database
71 */
72 static pts_database_t *pts_db;
73
74 /**
75 * PTS credentials
76 */
77 static pts_creds_t *pts_creds;
78
79 /**
80 * PTS credential manager
81 */
82 static credential_manager_t *pts_credmgr;
83
84 /**
85 * TRUE if DH Nonce Parameters Request attribute is sent
86 */
87 static bool dh_nonce_req_sent = FALSE;
88
89 /**
90 * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
91 */
92 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
93 TNC_Version min_version,
94 TNC_Version max_version,
95 TNC_Version *actual_version)
96 {
97 char *hash_alg, *dh_group, *uri, *cadir;
98
99 if (imv_attestation)
100 {
101 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
102 return TNC_RESULT_ALREADY_INITIALIZED;
103 }
104 if (!pts_meas_algo_probe(&supported_algorithms) ||
105 !pts_dh_group_probe(&supported_dh_groups))
106 {
107 return TNC_RESULT_FATAL;
108 }
109 imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
110 imv_id, actual_version);
111 if (!imv_attestation)
112 {
113 return TNC_RESULT_FATAL;
114 }
115
116 libpts_init();
117
118 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
119 {
120 DBG1(DBG_IMV, "no common IF-IMV version");
121 return TNC_RESULT_NO_COMMON_VERSION;
122 }
123
124 /**
125 * Specify supported PTS measurement algorithms
126 *
127 * sha1 : PTS_MEAS_ALGO_SHA1
128 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
129 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
130 *
131 * we expect the PTS-IMC to select the strongest supported algorithm
132 */
133 hash_alg = lib->settings->get_str(lib->settings,
134 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
135
136 /**
137 * Specify supported PTS Diffie-Hellman groups
138 *
139 * modp1024: PTS_DH_GROUP_IKE2
140 * modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
141 * modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
142 * ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
143 * PTS_DH_GROUP_IKE19
144 * ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
145 * PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
146 *
147 * we expect the PTS-IMC to select the strongest supported group
148 */
149 dh_group = lib->settings->get_str(lib->settings,
150 "libimcv.plugins.imv-attestation.dh_group", "ecp256");
151
152 if (!pts_meas_algo_update(hash_alg, &supported_algorithms) ||
153 !pts_dh_group_update(dh_group, &supported_dh_groups))
154 {
155 return TNC_RESULT_FATAL;
156 }
157
158 /* create a PTS credential manager */
159 pts_credmgr = credential_manager_create();
160
161 /* create PTS credential set */
162 cadir = lib->settings->get_str(lib->settings,
163 "libimcv.plugins.imv-attestation.cadir", NULL);
164 pts_creds = pts_creds_create(cadir);
165 if (pts_creds)
166 {
167 pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
168 }
169
170 /* attach file measurement database */
171 uri = lib->settings->get_str(lib->settings,
172 "libimcv.plugins.imv-attestation.database", NULL);
173 pts_db = pts_database_create(uri);
174
175 return TNC_RESULT_SUCCESS;
176 }
177
178 /**
179 * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
180 */
181 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
182 TNC_ConnectionID connection_id,
183 TNC_ConnectionState new_state)
184 {
185 imv_state_t *state;
186 imv_attestation_state_t *attestation_state;
187 TNC_Result result;
188
189 if (!imv_attestation)
190 {
191 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
192 return TNC_RESULT_NOT_INITIALIZED;
193 }
194 switch (new_state)
195 {
196 case TNC_CONNECTION_STATE_CREATE:
197 state = imv_attestation_state_create(connection_id);
198 return imv_attestation->create_state(imv_attestation, state);
199 case TNC_CONNECTION_STATE_DELETE:
200 return imv_attestation->delete_state(imv_attestation, connection_id);
201 case TNC_CONNECTION_STATE_HANDSHAKE:
202 result = imv_attestation->change_state(imv_attestation, connection_id,
203 new_state, &state);
204 if (result != TNC_RESULT_SUCCESS)
205 {
206 return result;
207 }
208 attestation_state = (imv_attestation_state_t*)state;
209
210 /* TODO: Get some configurations */
211
212 return TNC_RESULT_SUCCESS;
213 default:
214 return imv_attestation->change_state(imv_attestation, connection_id,
215 new_state, NULL);
216 }
217 }
218
219 static TNC_Result send_message(TNC_ConnectionID connection_id)
220 {
221 pa_tnc_msg_t *msg;
222 pa_tnc_attr_t *attr;
223 pts_t *pts;
224 imv_state_t *state;
225 imv_attestation_state_t *attestation_state;
226 imv_attestation_handshake_state_t handshake_state;
227 TNC_Result result;
228
229 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
230 {
231 return TNC_RESULT_FATAL;
232 }
233 attestation_state = (imv_attestation_state_t*)state;
234 handshake_state = attestation_state->get_handshake_state(attestation_state);
235 pts = attestation_state->get_pts(attestation_state);
236
237 msg = pa_tnc_msg_create();
238
239 /* Jump to Measurement state if IMC has no TPM */
240 if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT &&
241 !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
242 {
243 handshake_state = IMV_ATTESTATION_STATE_MEAS;
244 DBG3(DBG_IMV, "TPM is not available on IMC side, ",
245 "jumping to measurement phase");
246 }
247
248 /* Switch on the attribute type IMV has received */
249 switch (handshake_state)
250 {
251 case IMV_ATTESTATION_STATE_INIT:
252 {
253 pts_proto_caps_flag_t flags;
254
255 /* Send Request Protocol Capabilities attribute */
256 flags = pts->get_proto_caps(pts);
257 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
258 attr->set_noskip_flag(attr, TRUE);
259 msg->add_attribute(msg, attr);
260
261 /* Send Measurement Algorithms attribute */
262 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
263 attr->set_noskip_flag(attr, TRUE);
264 msg->add_attribute(msg, attr);
265
266 attestation_state->set_handshake_state(attestation_state,
267 IMV_ATTESTATION_STATE_TPM_INIT);
268 break;
269 }
270 case IMV_ATTESTATION_STATE_TPM_INIT:
271 {
272 if (!dh_nonce_req_sent)
273 {
274 int min_nonce_len;
275
276 /* Send DH nonce parameters request attribute */
277 min_nonce_len = lib->settings->get_int(lib->settings,
278 "libimcv.plugins.imv-attestation.min_nonce_len", 0);
279 attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
280 supported_dh_groups);
281 attr->set_noskip_flag(attr, TRUE);
282 msg->add_attribute(msg, attr);
283 dh_nonce_req_sent = TRUE;
284 }
285 else
286 {
287 pts_meas_algorithms_t selected_algorithm;
288 chunk_t initiator_value, initiator_nonce;
289
290 /* Send DH nonce finish attribute */
291 selected_algorithm = pts->get_meas_algorithm(pts);
292 pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
293 attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
294 initiator_value, initiator_nonce);
295 attr->set_noskip_flag(attr, TRUE);
296 msg->add_attribute(msg, attr);
297
298 /* Send Get TPM Version attribute */
299 attr = tcg_pts_attr_get_tpm_version_info_create();
300 attr->set_noskip_flag(attr, TRUE);
301 msg->add_attribute(msg, attr);
302
303 /* Send Get AIK attribute */
304 attr = tcg_pts_attr_get_aik_create();
305 attr->set_noskip_flag(attr, TRUE);
306 msg->add_attribute(msg, attr);
307
308 attestation_state->set_handshake_state(attestation_state,
309 IMV_ATTESTATION_STATE_MEAS);
310 }
311
312 break;
313 }
314 case IMV_ATTESTATION_STATE_MEAS:
315 {
316
317 enumerator_t *enumerator;
318 u_int32_t delimiter = SOLIDUS_UTF;
319 char *platform_info, *pathname;
320 u_int16_t request_id;
321 int id, type;
322 bool is_dir;
323
324 attestation_state->set_handshake_state(attestation_state,
325 IMV_ATTESTATION_STATE_COMP_EVID);
326
327 /* Get Platform and OS of the PTS-IMC */
328 platform_info = pts->get_platform_info(pts);
329
330 if (!pts_db || !platform_info)
331 {
332 DBG1(DBG_IMV, "%s%s%s not available",
333 (pts_db) ? "" : "pts database",
334 (!pts_db && !platform_info) ? "and" : "",
335 (platform_info) ? "" : "platform info");
336 break;
337 }
338 DBG1(DBG_IMV, "platform is '%s'", platform_info);
339
340 /* Send Request File Metadata attribute */
341 attr = tcg_pts_attr_req_file_meta_create(FALSE, SOLIDUS_UTF, "/etc/tnc_config");
342 attr->set_noskip_flag(attr, TRUE);
343 msg->add_attribute(msg, attr);
344
345 /* Send Request File Measurement attribute */
346 enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
347 if (!enumerator)
348 {
349 break;
350 }
351 while (enumerator->enumerate(enumerator, &id, &type, &pathname))
352 {
353 is_dir = (type != 0);
354 request_id = attestation_state->add_request(attestation_state,
355 id, is_dir);
356 DBG2(DBG_IMV, "measurement request %d for %s '%s'",
357 request_id, is_dir ? "directory" : "file", pathname);
358 attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
359 delimiter, pathname);
360 attr->set_noskip_flag(attr, TRUE);
361 msg->add_attribute(msg, attr);
362 }
363 enumerator->destroy(enumerator);
364 break;
365 }
366 case IMV_ATTESTATION_STATE_COMP_EVID:
367 {
368 pts_attr_req_funct_comp_evid_flag_t flags;
369 u_int32_t sub_comp_depth;
370 pts_qualifier_t qualifier;
371 pts_funct_comp_name_t name;
372
373 attestation_state->set_handshake_state(attestation_state,
374 IMV_ATTESTATION_STATE_END);
375
376 flags = PTS_REQ_FUNC_COMP_FLAG_PCR;
377 sub_comp_depth = 0;
378 qualifier.kernel = FALSE;
379 qualifier.sub_component = FALSE;
380 qualifier.type = PTS_FUNC_COMP_TYPE_ALL;
381 name = PTS_FUNC_COMP_NAME_BIOS;
382
383 /* Send Request Functional Component Evidence attribute */
384 attr = tcg_pts_attr_req_funct_comp_evid_create(flags, sub_comp_depth,
385 PEN_TCG, qualifier, name);
386 attr->set_noskip_flag(attr, TRUE);
387 msg->add_attribute(msg, attr);
388 /* Send Generate Attestation Evidence attribute */
389 attr = tcg_pts_attr_gen_attest_evid_create();
390 attr->set_noskip_flag(attr, TRUE);
391 msg->add_attribute(msg, attr);
392
393 break;
394 }
395 default:
396 DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
397 handshake_state);
398 return TNC_RESULT_FATAL;
399 }
400
401 msg->build(msg);
402 result = imv_attestation->send_message(imv_attestation, connection_id,
403 msg->get_encoding(msg));
404 msg->destroy(msg);
405
406 return result;
407 }
408
409 /**
410 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
411 */
412 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
413 TNC_ConnectionID connection_id,
414 TNC_BufferReference msg,
415 TNC_UInt32 msg_len,
416 TNC_MessageType msg_type)
417 {
418 pa_tnc_msg_t *pa_tnc_msg;
419 pa_tnc_attr_t *attr;
420 imv_state_t *state;
421 imv_attestation_state_t *attestation_state;
422 pts_t *pts;
423 enumerator_t *enumerator;
424 TNC_Result result;
425 bool fatal_error = FALSE;
426 linked_list_t *attr_list;
427
428 if (!imv_attestation)
429 {
430 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
431 return TNC_RESULT_NOT_INITIALIZED;
432 }
433
434 /* get current IMV state */
435 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
436 {
437 return TNC_RESULT_FATAL;
438 }
439 attestation_state = (imv_attestation_state_t*)state;
440 pts = attestation_state->get_pts(attestation_state);
441
442 /* parse received PA-TNC message and automatically handle any errors */
443 result = imv_attestation->receive_message(imv_attestation, connection_id,
444 chunk_create(msg, msg_len), msg_type,
445 &pa_tnc_msg);
446
447 /* no parsed PA-TNC attributes available if an error occurred */
448 if (!pa_tnc_msg)
449 {
450 return result;
451 }
452
453 attr_list = linked_list_create();
454
455 /* analyze PA-TNC attributes */
456 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
457 while (enumerator->enumerate(enumerator, &attr))
458 {
459 if (attr->get_vendor_id(attr) == PEN_IETF)
460 {
461 if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
462 {
463 ietf_attr_pa_tnc_error_t *error_attr;
464 pen_t error_vendor_id;
465 pa_tnc_error_code_t error_code;
466 chunk_t msg_info, attr_info;
467 u_int32_t offset;
468
469 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
470 error_vendor_id = error_attr->get_vendor_id(error_attr);
471 error_code = error_attr->get_error_code(error_attr);
472 msg_info = error_attr->get_msg_info(error_attr);
473
474 if (error_vendor_id == PEN_IETF)
475 {
476 DBG1(DBG_IMV, "received PA-TNC error '%N' "
477 "concerning message %#B",
478 pa_tnc_error_code_names, error_code, &msg_info);
479
480 switch (error_code)
481 {
482 case PA_ERROR_INVALID_PARAMETER:
483 offset = error_attr->get_offset(error_attr);
484 DBG1(DBG_IMV, " occurred at offset of %u bytes",
485 offset);
486 break;
487 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
488 attr_info = error_attr->get_attr_info(error_attr);
489 DBG1(DBG_IMV, " unsupported attribute %#B",
490 &attr_info);
491 break;
492 default:
493 break;
494 }
495 }
496 else if (error_vendor_id == PEN_TCG)
497 {
498 DBG1(DBG_IMV, "received TCG-PTS error '%N'",
499 pts_error_code_names, error_code);
500 DBG1(DBG_IMV, "error information: %B", &msg_info);
501 }
502 fatal_error = TRUE;
503 }
504 else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
505 {
506 ietf_attr_product_info_t *attr_cast;
507 char *platform_info;
508
509 attr_cast = (ietf_attr_product_info_t*)attr;
510 platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
511 pts->set_platform_info(pts, platform_info);
512 }
513 }
514 else if (attr->get_vendor_id(attr) == PEN_TCG)
515 {
516 if (!imv_attestation_process(attr, attr_list, attestation_state,
517 supported_algorithms, supported_dh_groups, pts_db, pts_credmgr))
518 {
519 return TNC_RESULT_FATAL;
520 }
521 }
522 }
523 enumerator->destroy(enumerator);
524 pa_tnc_msg->destroy(pa_tnc_msg);
525
526 if (fatal_error)
527 {
528 state->set_recommendation(state,
529 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
530 TNC_IMV_EVALUATION_RESULT_ERROR);
531 return imv_attestation->provide_recommendation(imv_attestation,
532 connection_id);
533 }
534
535 if (attr_list->get_count(attr_list))
536 {
537 pa_tnc_msg = pa_tnc_msg_create();
538
539 enumerator = attr_list->create_enumerator(attr_list);
540 while (enumerator->enumerate(enumerator, &attr))
541 {
542 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
543 }
544 enumerator->destroy(enumerator);
545
546 pa_tnc_msg->build(pa_tnc_msg);
547 result = imv_attestation->send_message(imv_attestation, connection_id,
548 pa_tnc_msg->get_encoding(pa_tnc_msg));
549
550 pa_tnc_msg->destroy(pa_tnc_msg);
551 attr_list->destroy(attr_list);
552
553 return result;
554 }
555 DESTROY_IF(attr_list);
556
557 if (attestation_state->get_handshake_state(attestation_state) &
558 IMV_ATTESTATION_STATE_END)
559 {
560 if (attestation_state->get_request_count(attestation_state))
561 {
562 DBG1(DBG_IMV, "failure due to %d pending file measurements",
563 attestation_state->get_request_count(attestation_state));
564 attestation_state->set_measurement_error(attestation_state);
565 }
566 if (attestation_state->get_measurement_error(attestation_state))
567 {
568 state->set_recommendation(state,
569 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
570 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
571 }
572 else
573 {
574 state->set_recommendation(state,
575 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
576 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
577 }
578 return imv_attestation->provide_recommendation(imv_attestation,
579 connection_id);
580 }
581
582 return send_message(connection_id);
583 }
584
585 /**
586 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
587 */
588 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
589 TNC_ConnectionID connection_id)
590 {
591 if (!imv_attestation)
592 {
593 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
594 return TNC_RESULT_NOT_INITIALIZED;
595 }
596 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
597 }
598
599 /**
600 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
601 */
602 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
603 TNC_ConnectionID connection_id)
604 {
605 imv_state_t *state;
606 imv_attestation_state_t *attestation_state;
607
608 if (!imv_attestation)
609 {
610 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
611 return TNC_RESULT_NOT_INITIALIZED;
612 }
613 /* get current IMV state */
614 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
615 {
616 return TNC_RESULT_FATAL;
617 }
618 attestation_state = (imv_attestation_state_t*)state;
619
620 /* Check if IMV has to initiate the PA-TNC exchange */
621 if (attestation_state->get_handshake_state(attestation_state) ==
622 IMV_ATTESTATION_STATE_INIT)
623 {
624 return send_message(connection_id);
625 }
626 return TNC_RESULT_SUCCESS;
627 }
628
629 /**
630 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
631 */
632 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
633 {
634 if (!imv_attestation)
635 {
636 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
637 return TNC_RESULT_NOT_INITIALIZED;
638 }
639 if (pts_creds)
640 {
641 pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
642 pts_creds->destroy(pts_creds);
643 }
644 DESTROY_IF(pts_db);
645 DESTROY_IF(pts_credmgr);
646
647 libpts_deinit();
648
649 imv_attestation->destroy(imv_attestation);
650 imv_attestation = NULL;
651
652 return TNC_RESULT_SUCCESS;
653 }
654
655 /**
656 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
657 */
658 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
659 TNC_TNCS_BindFunctionPointer bind_function)
660 {
661 if (!imv_attestation)
662 {
663 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
664 return TNC_RESULT_NOT_INITIALIZED;
665 }
666 return imv_attestation->bind_functions(imv_attestation, bind_function);
667 }