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