554077dcfd1e91d986cdf9365c021af7f1db3e58
[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 <tcg/tcg_attr.h>
23
24 #include <tcg/tcg_pts_attr_proto_caps.h>
25 #include <tcg/tcg_pts_attr_meas_algo.h>
26 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
27 #include <tcg/tcg_pts_attr_tpm_version_info.h>
28 #include <tcg/tcg_pts_attr_get_aik.h>
29 #include <tcg/tcg_pts_attr_aik.h>
30 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
31 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
32 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
33 #include <tcg/tcg_pts_attr_simple_evid_final.h>
34 #include <tcg/tcg_pts_attr_req_file_meas.h>
35 #include <tcg/tcg_pts_attr_file_meas.h>
36
37 #include <tncif_pa_subtypes.h>
38
39 #include <pen/pen.h>
40 #include <debug.h>
41 #include <utils/linked_list.h>
42
43 #include <trousers/tss.h>
44 #include <trousers/trousers.h>
45
46 /* IMV definitions */
47
48 static const char imv_name[] = "Attestation";
49
50 #define IMV_VENDOR_ID PEN_TCG
51 #define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
52
53 /**
54 * UTF-8 encoding of the character used to delimiter the filename
55 */
56 #define SOLIDUS_UTF 0x002F
57 #define REVERSE_SOLIDUS_UTF 0x005C
58
59 static imv_agent_t *imv_attestation;
60
61 /**
62 * Supported PTS measurement algorithms
63 */
64 static pts_meas_algorithms_t supported_algorithms = 0;
65
66 /**
67 * List of files and directories to measure
68 */
69 static linked_list_t *file_list, *directory_list;
70
71 /**
72 * Monotonic increasing number for Request File Measurement attribute
73 */
74 static u_int16_t request_id_counter = 0;
75
76 /* TODO: Move the struct to some header file? Duplicate with imc_attestation*/
77 /**
78 * Struct to hold file or directory name with the request ID for Request File Measurement attribute
79 */
80 typedef struct measurement_req_entry_t measurement_req_entry_t;
81
82 struct measurement_req_entry_t {
83 char *path;
84 u_int16_t request_id;
85 };
86
87 /**
88 * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
89 */
90 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
91 TNC_Version min_version,
92 TNC_Version max_version,
93 TNC_Version *actual_version)
94 {
95 char *hash_alg;
96
97 if (imv_attestation)
98 {
99 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
100 return TNC_RESULT_ALREADY_INITIALIZED;
101 }
102 imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
103 imv_id, actual_version);
104 if (!imv_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
105 {
106 return TNC_RESULT_FATAL;
107 }
108 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
109 {
110 DBG1(DBG_IMV, "no common IF-IMV version");
111 return TNC_RESULT_NO_COMMON_VERSION;
112 }
113
114 /**
115 * Specify supported PTS measurement algorithms
116 *
117 * sha1 : PTS_MEAS_ALGO_SHA1
118 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
119 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
120 *
121 * we expect the PTS-IMC to select the strongest supported algorithm
122 */
123 hash_alg = lib->settings->get_str(lib->settings,
124 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
125 if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384"))
126 {
127 /* remove SHA384 algorithm */
128 supported_algorithms &= ~PTS_MEAS_ALGO_SHA384;
129 }
130 if (strcaseeq(hash_alg, "sha1"))
131 {
132 /* remove SHA256 algorithm */
133 supported_algorithms &= ~PTS_MEAS_ALGO_SHA256;
134 }
135
136 return TNC_RESULT_SUCCESS;
137 }
138
139 /**
140 * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
141 */
142 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
143 TNC_ConnectionID connection_id,
144 TNC_ConnectionState new_state)
145 {
146 imv_state_t *state;
147 imv_attestation_state_t *attestation_state;
148 enumerator_t *enumerator;
149 char *files;
150 char *directories;
151 measurement_req_entry_t *entry;
152 char *token;
153 TNC_Result result;
154
155 if (!imv_attestation)
156 {
157 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
158 return TNC_RESULT_NOT_INITIALIZED;
159 }
160 switch (new_state)
161 {
162 case TNC_CONNECTION_STATE_CREATE:
163 state = imv_attestation_state_create(connection_id);
164 return imv_attestation->create_state(imv_attestation, state);
165 case TNC_CONNECTION_STATE_DELETE:
166 return imv_attestation->delete_state(imv_attestation, connection_id);
167 case TNC_CONNECTION_STATE_HANDSHAKE:
168 result = imv_attestation->change_state(imv_attestation, connection_id,
169 new_state, &state);
170 if (result != TNC_RESULT_SUCCESS)
171 {
172 return result;
173 }
174 attestation_state = (imv_attestation_state_t*)state;
175
176 /**
177 * Get the files to measure for
178 * PTS Request File Measurement attribute
179 */
180
181 file_list = linked_list_create();
182 directory_list = linked_list_create();
183
184 files = lib->settings->get_str(lib->settings,
185 "libimcv.plugins.imc-attestation.files", "none");
186 enumerator = enumerator_create_token(files, " ", " ");
187 while (enumerator->enumerate(enumerator, &token))
188 {
189 entry = malloc_thing(measurement_req_entry_t);
190 token = strdup(token);
191 entry->path = token;
192 entry->request_id = request_id_counter;
193 file_list->insert_last(file_list, entry);
194 free(token);
195 request_id_counter ++;
196 }
197
198 /**
199 * Get the directories to measure for
200 * PTS Request File Measurement attribute
201 */
202
203 directories = lib->settings->get_str(lib->settings,
204 "libimcv.plugins.imc-attestation.directories", "none");
205 enumerator = enumerator_create_token(directories, " ", " ");
206 while (enumerator->enumerate(enumerator, &token))
207 {
208 entry = malloc_thing(measurement_req_entry_t);
209 token = strdup(token);
210 entry->path = token;
211 entry->request_id = request_id_counter;
212 directory_list->insert_last(directory_list, entry);
213 free(token);
214 request_id_counter ++;
215 }
216 enumerator->destroy(enumerator);
217 return TNC_RESULT_SUCCESS;
218 default:
219 return imv_attestation->change_state(imv_attestation, connection_id,
220 new_state, NULL);
221 }
222 }
223
224 static TNC_Result send_message(TNC_ConnectionID connection_id)
225 {
226 pa_tnc_msg_t *msg;
227 pa_tnc_attr_t *attr;
228 TNC_Result result;
229 imv_state_t *state;
230 imv_attestation_state_t *attestation_state;
231 imv_attestation_handshake_state_t handshake_state;
232
233 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
234 {
235 return TNC_RESULT_FATAL;
236 }
237
238 attestation_state = (imv_attestation_state_t*)state;
239 handshake_state = attestation_state->get_handshake_state(attestation_state);
240
241 /* Switch on the attribute type IMV has received */
242 switch (handshake_state)
243 {
244 case IMV_ATTESTATION_STATE_INIT:
245 {
246 pts_proto_caps_flag_t flags;
247
248 /* Send Request Protocol Capabilities attribute */
249 flags = PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_V | PTS_PROTO_CAPS_C;
250 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
251 break;
252 }
253 case IMV_ATTESTATION_STATE_PROTO_CAP:
254 {
255 /* Send Measurement Algorithms attribute */
256 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
257 break;
258 }
259 case IMV_ATTESTATION_STATE_MEAS_ALGO:
260 {
261 /* Send Get TPM Version Information attribute */
262 attr = tcg_pts_attr_get_tpm_version_info_create();
263 break;
264 }
265 case IMV_ATTESTATION_STATE_TPM_INFO:
266 {
267 /* Send Get AIK attribute */
268 /* TODO: Uncomment when the retrieving of AIK on IMC side is implemented */
269 //attr = tcg_pts_attr_get_aik_create();
270 //break;
271 }
272 case IMV_ATTESTATION_STATE_AIK:
273 {
274 /* Send Request File Measurement attribute */
275 enumerator_t *enumerator;
276 measurement_req_entry_t *entry;
277 char *path;
278 u_int16_t request_id;
279 u_int32_t delimiter = SOLIDUS_UTF;
280
281 msg = pa_tnc_msg_create();
282
283 /**
284 * Add files to measure to PTS Request File Measurement attribute
285 */
286 enumerator = enumerator_create_single(file_list, NULL);
287 while (enumerator->enumerate(enumerator, &entry))
288 {
289 attr = tcg_pts_attr_req_file_meas_create(false,
290 entry->request_id, delimiter,
291 chunk_create(entry->path, strlen(entry->path)));
292 attr->set_noskip_flag(attr, TRUE);
293 msg->add_attribute(msg, attr);
294 }
295 /** Add directories to measure to PTS Request File Measurement attribute
296 */
297 enumerator = enumerator_create_single(directory_list, NULL);
298 while (enumerator->enumerate(enumerator, &entry))
299 {
300 attr = tcg_pts_attr_req_file_meas_create(true,
301 entry->request_id, delimiter,
302 chunk_create(entry->path, strlen(entry->path)));
303 attr->set_noskip_flag(attr, TRUE);
304 msg->add_attribute(msg, attr);
305 }
306 enumerator->destroy(enumerator);
307 goto end;
308 }
309 case IMV_ATTESTATION_STATE_SIMPLE_COMP_EVID:
310 case IMV_ATTESTATION_STATE_SIMPLE_EVID_FINAL:
311 case IMV_ATTESTATION_STATE_FILE_METADATA:
312 case IMV_ATTESTATION_STATE_FILE_MEAS:
313 case IMV_ATTESTATION_STATE_IML:
314 DBG1(DBG_IMV, "Attestation IMV has nothing to send: \"%s\"", handshake_state);
315 return TNC_RESULT_FATAL;
316 default:
317 DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"", handshake_state);
318 return TNC_RESULT_FATAL;
319 }
320
321 msg = pa_tnc_msg_create();
322 attr->set_noskip_flag(attr, TRUE);
323 msg->add_attribute(msg, attr);
324
325 end:
326 msg->build(msg);
327 result = imv_attestation->send_message(imv_attestation, connection_id,
328 msg->get_encoding(msg));
329 msg->destroy(msg);
330
331 return result;
332 }
333
334 /**
335 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
336 */
337 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
338 TNC_ConnectionID connection_id,
339 TNC_BufferReference msg,
340 TNC_UInt32 msg_len,
341 TNC_MessageType msg_type)
342 {
343 pa_tnc_msg_t *pa_tnc_msg;
344 pa_tnc_attr_t *attr;
345 imv_state_t *state;
346 imv_attestation_state_t *attestation_state;
347 enumerator_t *enumerator;
348 TNC_Result result;
349 bool fatal_error = FALSE;
350
351 if (!imv_attestation)
352 {
353 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
354 return TNC_RESULT_NOT_INITIALIZED;
355 }
356
357 /* get current IMV state */
358 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
359 {
360 return TNC_RESULT_FATAL;
361 }
362
363 /* parse received PA-TNC message and automatically handle any errors */
364 result = imv_attestation->receive_message(imv_attestation, connection_id,
365 chunk_create(msg, msg_len), msg_type,
366 &pa_tnc_msg);
367
368 /* no parsed PA-TNC attributes available if an error occurred */
369 if (!pa_tnc_msg)
370 {
371 return result;
372 }
373
374 /* analyze PA-TNC attributes */
375 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
376 while (enumerator->enumerate(enumerator, &attr))
377 {
378 if (attr->get_vendor_id(attr) == PEN_IETF &&
379 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
380 {
381 ietf_attr_pa_tnc_error_t *error_attr;
382 pa_tnc_error_code_t error_code;
383 chunk_t msg_info, attr_info;
384 u_int32_t offset;
385
386 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
387 error_code = error_attr->get_error_code(error_attr);
388 msg_info = error_attr->get_msg_info(error_attr);
389
390 DBG1(DBG_IMV, "received PA-TNC error '%N' concerning message %#B",
391 pa_tnc_error_code_names, error_code, &msg_info);
392 switch (error_code)
393 {
394 case PA_ERROR_INVALID_PARAMETER:
395 offset = error_attr->get_offset(error_attr);
396 DBG1(DBG_IMV, " occurred at offset of %u bytes", offset);
397 break;
398 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
399 attr_info = error_attr->get_attr_info(error_attr);
400 DBG1(DBG_IMV, " unsupported attribute %#B", &attr_info);
401 break;
402 default:
403 break;
404 }
405 fatal_error = TRUE;
406 }
407 else if (attr->get_vendor_id(attr) == PEN_TCG)
408 {
409 /**
410 * Handle TCG PTS attributes
411 */
412
413 /* get current IMC state */
414 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
415 {
416 return TNC_RESULT_FATAL;
417 }
418 attestation_state = (imv_attestation_state_t*)state;
419
420 switch(attr->get_type(attr))
421 {
422 case TCG_PTS_PROTO_CAPS:
423 {
424 tcg_pts_attr_proto_caps_t *attr_proto_caps;
425 pts_proto_caps_flag_t proto_caps;
426
427 attr_proto_caps = (tcg_pts_attr_proto_caps_t*)attr;
428 proto_caps = attr_proto_caps->get_flags(attr_proto_caps);
429 /* TODO: What to do with the protocol capabilities from imc */
430 attestation_state->set_handshake_state(attestation_state,
431 IMV_ATTESTATION_STATE_PROTO_CAP);
432 break;
433 }
434 case TCG_PTS_MEAS_ALGO_SELECTION:
435 {
436 tcg_pts_attr_meas_algo_t *attr_meas;
437 pts_meas_algorithms_t selected_algorithm;
438 hash_algorithm_t hash_alg;
439
440 attr_meas = (tcg_pts_attr_meas_algo_t*)attr;
441 selected_algorithm = attr_meas->get_algorithms(attr_meas);
442 hash_alg = pts_meas_to_hash_algorithm(selected_algorithm);
443 if (hash_alg == HASH_UNKNOWN)
444 {
445 /* TODO generate an error message */
446 break;
447 }
448 DBG2(DBG_IMV, "selected PTS measurement algorithm is %N",
449 hash_algorithm_names, hash_alg);
450 /* TODO: What to do with the selected algorithm from imc */
451
452 attestation_state->set_handshake_state(attestation_state,
453 IMV_ATTESTATION_STATE_MEAS_ALGO);
454 break;
455 }
456 case TCG_PTS_TPM_VERSION_INFO:
457 {
458 tcg_pts_attr_tpm_version_info_t *attr_tpm;
459 chunk_t tpm_version_info;
460 TSS_RESULT result;
461 TPM_CAP_VERSION_INFO versionInfo;
462 UINT64 offset = 0;
463
464 attr_tpm = (tcg_pts_attr_tpm_version_info_t*)attr;
465 tpm_version_info = attr_tpm->get_tpm_version_info(attr_tpm);
466
467 result = Trspi_UnloadBlob_CAP_VERSION_INFO(&offset,
468 tpm_version_info.ptr, &versionInfo);
469 if (result != TSS_SUCCESS)
470 {
471 DBG1(DBG_IMV, "TSS Error 0x%x", result);
472 return TNC_RESULT_FATAL;
473 }
474 DBG2(DBG_IMV, "TPM 1.2 Version Info: "
475 "Chip Version: %hhu.%hhu.%hhu.%hhu, "
476 "Spec Level: %hu, Errata Rev: %hhu, Vendor ID: %.4s",
477 versionInfo.version.major, versionInfo.version.minor,
478 versionInfo.version.revMajor, versionInfo.version.revMinor,
479 versionInfo.specLevel, versionInfo.errataRev,
480 versionInfo.tpmVendorID);
481
482 attestation_state->set_handshake_state(attestation_state,
483 IMV_ATTESTATION_STATE_TPM_INFO);
484 break;
485 }
486 case TCG_PTS_AIK:
487 {
488 /* TODO: Save the AIK key and certificate */
489 attestation_state->set_handshake_state(attestation_state,
490 IMV_ATTESTATION_STATE_AIK);
491 break;
492 }
493
494 /* PTS-based Attestation Evidence */
495 case TCG_PTS_SIMPLE_COMP_EVID:
496 break;
497 case TCG_PTS_SIMPLE_EVID_FINAL:
498 break;
499 case TCG_PTS_FILE_MEAS:
500 {
501 tcg_pts_attr_file_meas_t *attr_file_meas;
502 u_int64_t num_of_files;
503 u_int16_t request_id;
504 u_int16_t meas_len;
505
506 attr_file_meas = (tcg_pts_attr_file_meas_t*)attr;
507 num_of_files = attr_file_meas->get_number_of_files(attr_file_meas);
508 request_id = attr_file_meas->get_request_id(attr_file_meas);
509 meas_len = attr_file_meas->get_meas_len(attr_file_meas);
510
511 /* TODO: Start working here */
512
513 attestation_state->set_handshake_state(attestation_state,
514 IMV_ATTESTATION_STATE_FILE_MEAS);
515 break;
516 }
517
518 /* TODO: Not implemented yet */
519 case TCG_PTS_DH_NONCE_PARAMS_RESP:
520 case TCG_PTS_UNIX_FILE_META:
521 case TCG_PTS_INTEG_MEAS_LOG:
522 /* Attributes using XML */
523 case TCG_PTS_TEMPL_REF_MANI_SET_META:
524 case TCG_PTS_VERIFICATION_RESULT:
525 case TCG_PTS_INTEG_REPORT:
526 /* On Windows only*/
527 case TCG_PTS_WIN_FILE_META:
528 case TCG_PTS_REGISTRY_VALUE:
529 /* Received on IMC side only*/
530 case TCG_PTS_REQ_PROTO_CAPS:
531 case TCG_PTS_DH_NONCE_PARAMS_REQ:
532 case TCG_PTS_DH_NONCE_FINISH:
533 case TCG_PTS_MEAS_ALGO:
534 case TCG_PTS_GET_TPM_VERSION_INFO:
535 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
536 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
537 case TCG_PTS_GET_AIK:
538 case TCG_PTS_REQ_FUNCT_COMP_EVID:
539 case TCG_PTS_GEN_ATTEST_EVID:
540 case TCG_PTS_REQ_FILE_META:
541 case TCG_PTS_REQ_FILE_MEAS:
542 case TCG_PTS_REQ_INTEG_MEAS_LOG:
543 default:
544 DBG1(DBG_IMV, "received unsupported attribute '%N'",
545 tcg_attr_names, attr->get_type(attr));
546 break;
547 }
548 }
549 }
550 enumerator->destroy(enumerator);
551 pa_tnc_msg->destroy(pa_tnc_msg);
552
553 if (fatal_error)
554 {
555 state->set_recommendation(state,
556 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
557 TNC_IMV_EVALUATION_RESULT_ERROR);
558 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
559 }
560 return send_message(connection_id);
561 }
562
563 /**
564 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
565 */
566 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
567 TNC_ConnectionID connection_id)
568 {
569 if (!imv_attestation)
570 {
571 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
572 return TNC_RESULT_NOT_INITIALIZED;
573 }
574 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
575 }
576
577 /**
578 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
579 */
580 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
581 TNC_ConnectionID connection_id)
582 {
583 imv_state_t *state;
584 imv_attestation_state_t *attestation_state;
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 /* get current IMV state */
592 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
593 {
594 return TNC_RESULT_FATAL;
595 }
596 attestation_state = (imv_attestation_state_t*)state;
597
598 /* Check if IMV has to initiate the PA-TNC exchange */
599 if (attestation_state->get_handshake_state(attestation_state) ==
600 IMV_ATTESTATION_STATE_INIT)
601 {
602 return send_message(connection_id);
603 }
604 return TNC_RESULT_SUCCESS;
605 }
606
607 /**
608 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
609 */
610 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
611 {
612 if (!imv_attestation)
613 {
614 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
615 return TNC_RESULT_NOT_INITIALIZED;
616 }
617 imv_attestation->destroy(imv_attestation);
618 imv_attestation = NULL;
619
620 return TNC_RESULT_SUCCESS;
621 }
622
623 /**
624 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
625 */
626 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
627 TNC_TNCS_BindFunctionPointer bind_function)
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 return imv_attestation->bind_functions(imv_attestation, bind_function);
635 }