nothing to send with BeginHandshake
[strongswan.git] / src / libimcv / plugins / imc_attestation / imc_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 "imc_attestation_state.h"
17
18 #include <imc/imc_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
23 #include <tcg/tcg_pts_attr_proto_caps.h>
24 #include <tcg/tcg_pts_attr_meas_algo.h>
25 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
26 #include <tcg/tcg_pts_attr_tpm_version_info.h>
27 #include <tcg/tcg_pts_attr_get_aik.h>
28 #include <tcg/tcg_pts_attr_aik.h>
29 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
30 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
31 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
32 #include <tcg/tcg_pts_attr_simple_evid_final.h>
33 #include <tcg/tcg_pts_attr_req_file_meas.h>
34 #include <tcg/tcg_pts_attr_file_meas.h>
35
36 #include <tncif_pa_subtypes.h>
37
38 #include <pen/pen.h>
39 #include <debug.h>
40 #include <utils/linked_list.h>
41 #include <crypto/hashers/hasher.h>
42 #include <dirent.h>
43 #include <errno.h>
44
45 /* IMC definitions */
46
47 static const char imc_name[] = "Attestation";
48
49 #define IMC_VENDOR_ID PEN_TCG
50 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
51 #define IMC_ATTESTATION_BUF_SIZE 32768
52
53 static imc_agent_t *imc_attestation;
54
55 /**
56 * Supported PTS measurement algorithms
57 */
58 static pts_meas_algorithms_t supported_algorithms = 0;
59
60 /**
61 * List of files and directories to measure
62 */
63 static linked_list_t *file_list, *directory_list;
64
65 /**
66 * List of file measurements
67 */
68 static linked_list_t *file_measurements;
69
70 /* TODO: Move the struct to some header file? Duplicate with imv_attestation*/
71 /**
72 * Struct to hold file or directory name with the request ID for Request File Measurement attribute
73 */
74 typedef struct measurement_req_entry_t measurement_req_entry_t;
75
76 struct measurement_req_entry_t {
77 char *path;
78 u_int16_t request_id;
79 };
80
81 /**
82 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
83 */
84 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
85 TNC_Version min_version,
86 TNC_Version max_version,
87 TNC_Version *actual_version)
88 {
89 if (imc_attestation)
90 {
91 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
92 return TNC_RESULT_ALREADY_INITIALIZED;
93 }
94 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
95 imc_id, actual_version);
96 if (!imc_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
97 {
98 return TNC_RESULT_FATAL;
99 }
100 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
101 {
102 DBG1(DBG_IMC, "no common IF-IMC version");
103 return TNC_RESULT_NO_COMMON_VERSION;
104 }
105 return TNC_RESULT_SUCCESS;
106 }
107
108 /**
109 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
110 */
111 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
112 TNC_ConnectionID connection_id,
113 TNC_ConnectionState new_state)
114 {
115 imc_state_t *state;
116 /* TODO: Not used so far */
117 //imc_attestation_state_t *attestation_state;
118
119 if (!imc_attestation)
120 {
121 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
122 return TNC_RESULT_NOT_INITIALIZED;
123 }
124 switch (new_state)
125 {
126 case TNC_CONNECTION_STATE_CREATE:
127 state = imc_attestation_state_create(connection_id);
128 return imc_attestation->create_state(imc_attestation, state);
129 case TNC_CONNECTION_STATE_DELETE:
130 return imc_attestation->delete_state(imc_attestation, connection_id);
131 case TNC_CONNECTION_STATE_HANDSHAKE:
132 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
133 case TNC_CONNECTION_STATE_ACCESS_NONE:
134 default:
135 return imc_attestation->change_state(imc_attestation, connection_id,
136 new_state, NULL);
137 }
138 }
139
140
141 /**
142 * Get Hash Measurement of a file
143 */
144 static TNC_Result hash_file(char *path, char *out)
145 {
146 char buffer[IMC_ATTESTATION_BUF_SIZE];
147 FILE *file;
148 int bytes_read;
149 pts_meas_algorithms_t selected_algorithm;
150 hasher_t *hasher;
151 hash_algorithm_t hash_alg;
152
153 /* Create a hasher */
154 selected_algorithm = PTS_MEAS_ALGO_SHA256; /* temporary fix, move to pts */
155 hash_alg = pts_meas_to_hash_algorithm(selected_algorithm);
156 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
157 if (!hasher)
158 {
159 DBG1(DBG_IMC, "hasher %N not available", hash_algorithm_names, hash_alg);
160 return TNC_RESULT_FATAL;
161 }
162
163 file = fopen(path, "rb");
164 if (!file)
165 {
166 DBG1(DBG_IMC,"file '%s' can not be opened", path);
167 hasher->destroy(hasher);
168 return TNC_RESULT_FATAL;
169 }
170 while (TRUE)
171 {
172 bytes_read = fread(buffer, 1, sizeof(buffer), file);
173 if (bytes_read > 0)
174 {
175 hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL);
176 }
177 else
178 {
179 hasher->get_hash(hasher, chunk_empty, out);
180 break;
181 }
182 }
183 fclose(file);
184 hasher->destroy(hasher);
185
186 return TNC_RESULT_SUCCESS;
187 }
188
189 /**
190 * Get hash of all the files in a directory
191 */
192 static TNC_Result hash_directory(char *path)
193 {
194 DIR *dir;
195 struct dirent *ent;
196 linked_list_t *file_measurements;
197 file_meas_entry_t *entry;
198
199 file_measurements = linked_list_create();
200 entry = malloc_thing(file_meas_entry_t);
201
202 dir = opendir(path);
203 if (dir == NULL)
204 {
205 DBG1(DBG_IMC, "opening directory '%s' failed: %s", path, strerror(errno));
206 return TNC_RESULT_FATAL;
207 }
208 while ((ent = readdir(dir)))
209 {
210 char *file_hash;
211
212 if(hash_file(ent->d_name,file_hash) != TNC_RESULT_SUCCESS)
213 {
214 DBG1(DBG_IMC, "Hashing the given file has failed");
215 return TNC_RESULT_FATAL;
216 }
217
218 entry->measurement = chunk_create(file_hash,strlen(file_hash));
219 entry->file_name_len = strlen(ent->d_name);
220 entry->file_name = chunk_create(ent->d_name,strlen(ent->d_name));
221
222 file_measurements->insert_last(file_measurements,entry);
223 }
224 closedir(dir);
225
226 return TNC_RESULT_SUCCESS;
227 }
228
229 static TNC_Result send_message(TNC_ConnectionID connection_id)
230 {
231 pa_tnc_msg_t *msg;
232 pa_tnc_attr_t *attr;
233 pts_t *pts;
234 imc_state_t *state;
235 imc_attestation_state_t *attestation_state;
236 imc_attestation_handshake_state_t handshake_state;
237 TNC_Result result;
238
239 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
240 {
241 return TNC_RESULT_FATAL;
242 }
243 attestation_state = (imc_attestation_state_t*)state;
244 handshake_state = attestation_state->get_handshake_state(attestation_state);
245 pts = attestation_state->get_pts(attestation_state);
246
247 /* Switch on the attribute type IMC has received */
248 switch (handshake_state)
249 {
250 case IMC_ATTESTATION_STATE_REQ_PROTO_CAPS:
251 {
252 pts_proto_caps_flag_t flags;
253
254 flags = pts->get_proto_caps(pts);
255 attr = tcg_pts_attr_proto_caps_create(flags, FALSE);
256 break;
257 }
258 case IMC_ATTESTATION_STATE_REQ_MEAS_ALGO:
259 {
260 pts_meas_algorithms_t selected_algorithm;
261
262 selected_algorithm = pts->get_meas_algorithm(pts);
263 attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
264 break;
265 }
266 case IMC_ATTESTATION_STATE_GET_TPM_INFO:
267 {
268 chunk_t tpm_version_info;
269
270 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
271 {
272 /* TODO return TCG_PTS_TPM_VERS_NOT_SUPPORTED error attribute */
273 }
274 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
275 break;
276 }
277 case IMC_ATTESTATION_STATE_REQ_FILE_MEAS:
278 {
279 measurement_req_entry_t *entry;
280 enumerator_t *enumerator;
281 tcg_pts_attr_file_meas_t *attr_file_meas;
282 u_int16_t meas_len = HASH_SIZE_SHA1;
283 pts_meas_algorithms_t selected_algorithm;
284
285 selected_algorithm = PTS_MEAS_ALGO_SHA256; /* temporary fix, move to pts */
286 if (selected_algorithm & PTS_MEAS_ALGO_SHA384)
287 {
288 meas_len = HASH_SIZE_SHA384;
289 }
290 else if(selected_algorithm & PTS_MEAS_ALGO_SHA256)
291 {
292 meas_len = HASH_SIZE_SHA512;
293 }
294
295 msg = pa_tnc_msg_create();
296
297 /**
298 * Hash the files and add them as attribute
299 */
300 enumerator = enumerator_create_single(file_list, NULL);
301 while (enumerator->enumerate(enumerator, &entry))
302 {
303 char * file_hash;
304
305 attr = tcg_pts_attr_file_meas_create(1,
306 entry->request_id, meas_len);
307 attr->set_noskip_flag(attr, TRUE);
308 attr_file_meas = (tcg_pts_attr_file_meas_t*)attr;
309
310 if(hash_file(entry->path,file_hash) != TNC_RESULT_SUCCESS)
311 {
312 DBG1(DBG_IMC, "Hashing the given file has failed");
313 return TNC_RESULT_FATAL;
314 }
315 attr_file_meas->add_file_meas(attr_file_meas,
316 chunk_create(file_hash,strlen(file_hash)),
317 chunk_create(entry->path,strlen(entry->path)));
318
319 msg->add_attribute(msg, attr);
320 }
321
322 /**
323 * Hash the files in each directory and add them as attribute
324 */
325 enumerator = enumerator_create_single(directory_list, NULL);
326 while (enumerator->enumerate(enumerator, &entry))
327 {
328 enumerator_t *meas_enumerator;
329 file_meas_entry_t *meas_entry;
330 u_int64_t num_of_files = 0 ;
331
332 if(hash_directory(entry->path) != TNC_RESULT_SUCCESS)
333 {
334 DBG1(DBG_IMC, "Hashing the files in a given directory has failed");
335 return TNC_RESULT_FATAL;
336 }
337
338 attr = tcg_pts_attr_file_meas_create(0,
339 entry->request_id, meas_len);
340 attr->set_noskip_flag(attr, TRUE);
341 attr_file_meas = (tcg_pts_attr_file_meas_t*)attr;
342
343 meas_enumerator = enumerator_create_single(file_measurements, NULL);
344 while (meas_enumerator->enumerate(meas_enumerator, &meas_entry))
345 {
346 num_of_files++;
347 attr_file_meas->add_file_meas(attr_file_meas,
348 meas_entry->measurement,
349 meas_entry->file_name);
350 }
351
352 attr_file_meas->set_number_of_files(attr_file_meas,
353 num_of_files);
354 msg->add_attribute(msg, attr);
355 }
356 enumerator->destroy(enumerator);
357 goto end;
358 }
359 case IMC_ATTESTATION_STATE_GET_AIK:
360 /* TODO: Implement AIK retrieve */
361 case IMC_ATTESTATION_STATE_REQ_FUNCT_COMP_EVID:
362 case IMC_ATTESTATION_STATE_GEN_ATTEST_EVID:
363 case IMC_ATTESTATION_STATE_REQ_FILE_METADATA:
364 case IMC_ATTESTATION_STATE_REQ_IML:
365 case IMC_ATTESTATION_STATE_INIT:
366 DBG1(DBG_IMC, "Attestation IMC has nothing to send: \"%s\"", handshake_state);
367 return TNC_RESULT_FATAL;
368 default:
369 DBG1(DBG_IMC, "Attestation IMC is in unknown state: \"%s\"", handshake_state);
370 return TNC_RESULT_FATAL;
371 }
372
373
374 attr->set_noskip_flag(attr, TRUE);
375 msg = pa_tnc_msg_create();
376 msg->add_attribute(msg, attr);
377
378 end:
379 msg->build(msg);
380 result = imc_attestation->send_message(imc_attestation, connection_id,
381 msg->get_encoding(msg));
382 msg->destroy(msg);
383
384 return result;
385 }
386
387 /**
388 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
389 */
390 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
391 TNC_ConnectionID connection_id)
392 {
393 if (!imc_attestation)
394 {
395 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
396 return TNC_RESULT_NOT_INITIALIZED;
397 }
398 return TNC_RESULT_SUCCESS;
399 }
400
401 /**
402 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
403 */
404 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
405 TNC_ConnectionID connection_id,
406 TNC_BufferReference msg,
407 TNC_UInt32 msg_len,
408 TNC_MessageType msg_type)
409 {
410 pa_tnc_msg_t *pa_tnc_msg;
411 pa_tnc_attr_t *attr;
412 imc_state_t *state;
413 imc_attestation_state_t *attestation_state;
414 enumerator_t *enumerator;
415 pts_t *pts;
416 TNC_Result result;
417 bool fatal_error = FALSE;
418
419 if (!imc_attestation)
420 {
421 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
422 return TNC_RESULT_NOT_INITIALIZED;
423 }
424
425 /* get current IMC state */
426 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
427 {
428 return TNC_RESULT_FATAL;
429 }
430 attestation_state = (imc_attestation_state_t*)state;
431 pts = attestation_state->get_pts(attestation_state);
432
433 /* parse received PA-TNC message and automatically handle any errors */
434 result = imc_attestation->receive_message(imc_attestation, connection_id,
435 chunk_create(msg, msg_len), msg_type,
436 &pa_tnc_msg);
437
438 /* no parsed PA-TNC attributes available if an error occurred */
439 if (!pa_tnc_msg)
440 {
441 return result;
442 }
443
444 /* analyze PA-TNC attributes */
445 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
446 while (enumerator->enumerate(enumerator, &attr))
447 {
448 if (attr->get_vendor_id(attr) == PEN_IETF &&
449 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
450 {
451 ietf_attr_pa_tnc_error_t *error_attr;
452 pa_tnc_error_code_t error_code;
453 chunk_t msg_info, attr_info;
454 u_int32_t offset;
455
456 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
457 error_code = error_attr->get_error_code(error_attr);
458 msg_info = error_attr->get_msg_info(error_attr);
459
460 DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
461 pa_tnc_error_code_names, error_code, &msg_info);
462 switch (error_code)
463 {
464 case PA_ERROR_INVALID_PARAMETER:
465 offset = error_attr->get_offset(error_attr);
466 DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
467 break;
468 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
469 attr_info = error_attr->get_attr_info(error_attr);
470 DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
471 break;
472 default:
473 break;
474 }
475 fatal_error = TRUE;
476 }
477 else if (attr->get_vendor_id(attr) == PEN_TCG)
478 {
479 switch(attr->get_type(attr))
480 {
481 case TCG_PTS_REQ_PROTO_CAPS:
482 {
483 tcg_pts_attr_proto_caps_t *attr_cast;
484 pts_proto_caps_flag_t imc_flags, imv_flags;
485
486 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
487 imv_flags = attr_cast->get_flags(attr_cast);
488 imc_flags = pts->get_proto_caps(pts);
489 pts->set_proto_caps(pts, imc_flags & imv_flags);
490
491 attestation_state->set_handshake_state(attestation_state,
492 IMC_ATTESTATION_STATE_REQ_PROTO_CAPS);
493 break;
494 }
495 case TCG_PTS_MEAS_ALGO:
496 {
497 tcg_pts_attr_meas_algo_t *attr_cast;
498 pts_meas_algorithms_t selected_algorithm;
499
500 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
501 selected_algorithm = attr_cast->get_algorithms(attr_cast);
502
503 if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
504 (selected_algorithm & PTS_MEAS_ALGO_SHA384))
505 {
506 selected_algorithm = PTS_MEAS_ALGO_SHA384;
507 }
508 else if (selected_algorithm & PTS_MEAS_ALGO_SHA256)
509 {
510 selected_algorithm = PTS_MEAS_ALGO_SHA256;
511 }
512 else if (selected_algorithm & PTS_MEAS_ALGO_SHA1)
513 {
514 selected_algorithm = PTS_MEAS_ALGO_SHA1;
515 }
516 else
517 {
518 /* TODO send a TCG_PTS_HASH_ALG_NOT_SUPPORTED error */
519 }
520 pts->set_meas_algorithm(pts, selected_algorithm);
521
522 attestation_state->set_handshake_state(attestation_state,
523 IMC_ATTESTATION_STATE_REQ_MEAS_ALGO);
524 break;
525 }
526
527 case TCG_PTS_GET_TPM_VERSION_INFO:
528 {
529 attestation_state->set_handshake_state(attestation_state,
530 IMC_ATTESTATION_STATE_GET_TPM_INFO);
531 break;
532 }
533 case TCG_PTS_GET_AIK:
534 {
535 attestation_state->set_handshake_state(attestation_state,
536 IMC_ATTESTATION_STATE_GET_AIK);
537 break;
538 }
539
540 /* PTS-based Attestation Evidence */
541 case TCG_PTS_REQ_FUNCT_COMP_EVID:
542 break;
543 case TCG_PTS_GEN_ATTEST_EVID:
544 break;
545 case TCG_PTS_REQ_FILE_MEAS:
546 {
547 tcg_pts_attr_req_file_meas_t *attr_cast;
548 measurement_req_entry_t *entry;
549 u_int32_t delimiter;
550
551 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
552 file_list = linked_list_create();
553 directory_list = linked_list_create();
554 delimiter = attr_cast->get_delimiter(attr_cast);
555 entry = malloc_thing(measurement_req_entry_t);
556 entry->request_id = attr_cast->get_request_id(attr_cast);
557 entry->path = attr_cast->get_file_path(attr_cast).ptr;
558
559 attr_cast->get_directory_flag(attr_cast) ?
560 directory_list->insert_last(directory_list, entry) :
561 file_list->insert_last(file_list, entry);
562
563 attestation_state->set_handshake_state(attestation_state,
564 IMC_ATTESTATION_STATE_REQ_FILE_MEAS);
565 break;
566 }
567
568 /* TODO: Not implemented yet */
569 case TCG_PTS_DH_NONCE_PARAMS_REQ:
570 case TCG_PTS_DH_NONCE_FINISH:
571 case TCG_PTS_REQ_FILE_META:
572 case TCG_PTS_REQ_INTEG_MEAS_LOG:
573 /* Attributes using XML */
574 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
575 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
576 /* On Windows only*/
577 case TCG_PTS_REQ_REGISTRY_VALUE:
578 /* Received on IMV side only*/
579 case TCG_PTS_PROTO_CAPS:
580 case TCG_PTS_DH_NONCE_PARAMS_RESP:
581 case TCG_PTS_MEAS_ALGO_SELECTION:
582 case TCG_PTS_TPM_VERSION_INFO:
583 case TCG_PTS_TEMPL_REF_MANI_SET_META:
584 case TCG_PTS_AIK:
585 case TCG_PTS_SIMPLE_COMP_EVID:
586 case TCG_PTS_SIMPLE_EVID_FINAL:
587 case TCG_PTS_VERIFICATION_RESULT:
588 case TCG_PTS_INTEG_REPORT:
589 case TCG_PTS_UNIX_FILE_META:
590 case TCG_PTS_FILE_MEAS:
591 case TCG_PTS_INTEG_MEAS_LOG:
592 default:
593 DBG1(DBG_IMC, "received unsupported attribute '%N'",
594 tcg_attr_names, attr->get_type(attr));
595 break;
596 }
597
598
599 }
600 }
601 enumerator->destroy(enumerator);
602 pa_tnc_msg->destroy(pa_tnc_msg);
603
604 /* if no error occurred then always return the same response */
605 return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id);
606 }
607
608 /**
609 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
610 */
611 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
612 TNC_ConnectionID connection_id)
613 {
614 if (!imc_attestation)
615 {
616 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
617 return TNC_RESULT_NOT_INITIALIZED;
618 }
619 return TNC_RESULT_SUCCESS;
620 }
621
622 /**
623 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
624 */
625 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
626 {
627 if (!imc_attestation)
628 {
629 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
630 return TNC_RESULT_NOT_INITIALIZED;
631 }
632 imc_attestation->destroy(imc_attestation);
633 imc_attestation = NULL;
634
635 return TNC_RESULT_SUCCESS;
636 }
637
638 /**
639 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
640 */
641 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
642 TNC_TNCC_BindFunctionPointer bind_function)
643 {
644 if (!imc_attestation)
645 {
646 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
647 return TNC_RESULT_NOT_INITIALIZED;
648 }
649 return imc_attestation->bind_functions(imc_attestation, bind_function);
650 }