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