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