moved attribute processing to imc_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 linked_list_t *attr_list;
421 imv_state_t *state;
422 imv_attestation_state_t *attestation_state;
423 pts_t *pts;
424 enumerator_t *enumerator;
425 TNC_Result result;
426
427 if (!imv_attestation)
428 {
429 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
430 return TNC_RESULT_NOT_INITIALIZED;
431 }
432
433 /* get current IMV state */
434 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
435 {
436 return TNC_RESULT_FATAL;
437 }
438 attestation_state = (imv_attestation_state_t*)state;
439 pts = attestation_state->get_pts(attestation_state);
440
441 /* parse received PA-TNC message and automatically handle any errors */
442 result = imv_attestation->receive_message(imv_attestation, connection_id,
443 chunk_create(msg, msg_len), msg_type,
444 &pa_tnc_msg);
445
446 /* no parsed PA-TNC attributes available if an error occurred */
447 if (!pa_tnc_msg)
448 {
449 return result;
450 }
451
452 attr_list = linked_list_create();
453 result = TNC_RESULT_SUCCESS;
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 result = TNC_RESULT_FATAL;
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 result = TNC_RESULT_FATAL;
520 break;
521 }
522 }
523 }
524 enumerator->destroy(enumerator);
525 pa_tnc_msg->destroy(pa_tnc_msg);
526
527 if (result != TNC_RESULT_SUCCESS)
528 {
529 attr_list->destroy(attr_list);
530 state->set_recommendation(state,
531 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
532 TNC_IMV_EVALUATION_RESULT_ERROR);
533 return imv_attestation->provide_recommendation(imv_attestation,
534 connection_id);
535 }
536
537 if (attr_list->get_count(attr_list))
538 {
539 pa_tnc_msg = pa_tnc_msg_create();
540
541 enumerator = attr_list->create_enumerator(attr_list);
542 while (enumerator->enumerate(enumerator, &attr))
543 {
544 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
545 }
546 enumerator->destroy(enumerator);
547
548 pa_tnc_msg->build(pa_tnc_msg);
549 result = imv_attestation->send_message(imv_attestation, connection_id,
550 pa_tnc_msg->get_encoding(pa_tnc_msg));
551
552 pa_tnc_msg->destroy(pa_tnc_msg);
553 attr_list->destroy(attr_list);
554
555 return result;
556 }
557 attr_list->destroy(attr_list);
558
559 if (attestation_state->get_handshake_state(attestation_state) &
560 IMV_ATTESTATION_STATE_END)
561 {
562 if (attestation_state->get_request_count(attestation_state))
563 {
564 DBG1(DBG_IMV, "failure due to %d pending file measurements",
565 attestation_state->get_request_count(attestation_state));
566 attestation_state->set_measurement_error(attestation_state);
567 }
568 if (attestation_state->get_measurement_error(attestation_state))
569 {
570 state->set_recommendation(state,
571 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
572 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
573 }
574 else
575 {
576 state->set_recommendation(state,
577 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
578 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
579 }
580 return imv_attestation->provide_recommendation(imv_attestation,
581 connection_id);
582 }
583
584 return send_message(connection_id);
585 }
586
587 /**
588 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
589 */
590 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
591 TNC_ConnectionID connection_id)
592 {
593 if (!imv_attestation)
594 {
595 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
596 return TNC_RESULT_NOT_INITIALIZED;
597 }
598 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
599 }
600
601 /**
602 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
603 */
604 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
605 TNC_ConnectionID connection_id)
606 {
607 imv_state_t *state;
608 imv_attestation_state_t *attestation_state;
609
610 if (!imv_attestation)
611 {
612 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
613 return TNC_RESULT_NOT_INITIALIZED;
614 }
615 /* get current IMV state */
616 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
617 {
618 return TNC_RESULT_FATAL;
619 }
620 attestation_state = (imv_attestation_state_t*)state;
621
622 /* Check if IMV has to initiate the PA-TNC exchange */
623 if (attestation_state->get_handshake_state(attestation_state) ==
624 IMV_ATTESTATION_STATE_INIT)
625 {
626 return send_message(connection_id);
627 }
628 return TNC_RESULT_SUCCESS;
629 }
630
631 /**
632 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
633 */
634 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
635 {
636 if (!imv_attestation)
637 {
638 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
639 return TNC_RESULT_NOT_INITIALIZED;
640 }
641 if (pts_creds)
642 {
643 pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
644 pts_creds->destroy(pts_creds);
645 }
646 DESTROY_IF(pts_db);
647 DESTROY_IF(pts_credmgr);
648
649 libpts_deinit();
650
651 imv_attestation->destroy(imv_attestation);
652 imv_attestation = NULL;
653
654 return TNC_RESULT_SUCCESS;
655 }
656
657 /**
658 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
659 */
660 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
661 TNC_TNCS_BindFunctionPointer bind_function)
662 {
663 if (!imv_attestation)
664 {
665 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
666 return TNC_RESULT_NOT_INITIALIZED;
667 }
668 return imv_attestation->bind_functions(imv_attestation, bind_function);
669 }