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