Implemented Diffie Hellman Nonce attributes
[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 #include <ietf/ietf_attr_product_info.h>
23
24 #include <libpts.h>
25
26 #include <pts/pts_error.h>
27
28 #include <tcg/tcg_pts_attr_proto_caps.h>
29 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
30 #include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
31 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
32 #include <tcg/tcg_pts_attr_meas_algo.h>
33 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
34 #include <tcg/tcg_pts_attr_tpm_version_info.h>
35 #include <tcg/tcg_pts_attr_get_aik.h>
36 #include <tcg/tcg_pts_attr_aik.h>
37 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
38 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
39 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
40 #include <tcg/tcg_pts_attr_simple_evid_final.h>
41 #include <tcg/tcg_pts_attr_req_file_meas.h>
42 #include <tcg/tcg_pts_attr_file_meas.h>
43 #include <tcg/tcg_pts_attr_req_file_meta.h>
44 #include <tcg/tcg_pts_attr_unix_file_meta.h>
45
46 #include <tncif_pa_subtypes.h>
47
48 #include <pen/pen.h>
49 #include <debug.h>
50 #include <utils/linked_list.h>
51
52 /* IMC definitions */
53
54 static const char imc_name[] = "Attestation";
55
56 #define IMC_VENDOR_ID PEN_TCG
57 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
58
59 static imc_agent_t *imc_attestation;
60
61 /**
62 * Supported PTS measurement algorithms
63 */
64 static pts_meas_algorithms_t supported_algorithms = 0;
65
66 /**
67 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
68 */
69 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
70 TNC_Version min_version,
71 TNC_Version max_version,
72 TNC_Version *actual_version)
73 {
74 if (imc_attestation)
75 {
76 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
77 return TNC_RESULT_ALREADY_INITIALIZED;
78 }
79 if (!pts_meas_probe_algorithms(&supported_algorithms))
80 {
81 return TNC_RESULT_FATAL;
82 }
83 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
84 imc_id, actual_version);
85 if (!imc_attestation)
86 {
87 return TNC_RESULT_FATAL;
88 }
89
90 libpts_init();
91
92 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
93 {
94 DBG1(DBG_IMC, "no common IF-IMC version");
95 return TNC_RESULT_NO_COMMON_VERSION;
96 }
97 return TNC_RESULT_SUCCESS;
98 }
99
100 /**
101 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
102 */
103 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
104 TNC_ConnectionID connection_id,
105 TNC_ConnectionState new_state)
106 {
107 imc_state_t *state;
108 /* TODO: Not used so far */
109 //imc_attestation_state_t *attestation_state;
110
111 if (!imc_attestation)
112 {
113 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
114 return TNC_RESULT_NOT_INITIALIZED;
115 }
116 switch (new_state)
117 {
118 case TNC_CONNECTION_STATE_CREATE:
119 state = imc_attestation_state_create(connection_id);
120 return imc_attestation->create_state(imc_attestation, state);
121 case TNC_CONNECTION_STATE_DELETE:
122 return imc_attestation->delete_state(imc_attestation, connection_id);
123 case TNC_CONNECTION_STATE_HANDSHAKE:
124 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
125 case TNC_CONNECTION_STATE_ACCESS_NONE:
126 default:
127 return imc_attestation->change_state(imc_attestation, connection_id,
128 new_state, NULL);
129 }
130 }
131
132
133 /**
134 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
135 */
136 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
137 TNC_ConnectionID connection_id)
138 {
139 imc_state_t *state;
140 imc_attestation_state_t *attestation_state;
141 pts_t *pts;
142 char *platform_info;
143 TNC_Result result = TNC_RESULT_SUCCESS;
144
145 if (!imc_attestation)
146 {
147 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
148 return TNC_RESULT_NOT_INITIALIZED;
149 }
150
151 /* get current IMC state */
152 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
153 {
154 return TNC_RESULT_FATAL;
155 }
156 attestation_state = (imc_attestation_state_t*)state;
157 pts = attestation_state->get_pts(attestation_state);
158
159 platform_info = pts->get_platform_info(pts);
160 if (platform_info)
161 {
162 pa_tnc_msg_t *pa_tnc_msg;
163 pa_tnc_attr_t *attr;
164
165 pa_tnc_msg = pa_tnc_msg_create();
166 attr = ietf_attr_product_info_create(0, 0, platform_info);
167 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
168 pa_tnc_msg->build(pa_tnc_msg);
169 result = imc_attestation->send_message(imc_attestation, connection_id,
170 pa_tnc_msg->get_encoding(pa_tnc_msg));
171 pa_tnc_msg->destroy(pa_tnc_msg);
172 }
173
174 return result;
175 }
176
177 /**
178 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
179 */
180 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
181 TNC_ConnectionID connection_id,
182 TNC_BufferReference msg,
183 TNC_UInt32 msg_len,
184 TNC_MessageType msg_type)
185 {
186 pa_tnc_msg_t *pa_tnc_msg;
187 pa_tnc_attr_t *attr;
188 linked_list_t *attr_list;
189 imc_state_t *state;
190 imc_attestation_state_t *attestation_state;
191 enumerator_t *enumerator;
192 pts_t *pts;
193 TNC_Result result;
194 bool fatal_error = FALSE;
195 chunk_t attr_info;
196 pts_error_code_t pts_error;
197 bool valid_path;
198
199 if (!imc_attestation)
200 {
201 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
202 return TNC_RESULT_NOT_INITIALIZED;
203 }
204
205 /* get current IMC state */
206 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
207 {
208 return TNC_RESULT_FATAL;
209 }
210 attestation_state = (imc_attestation_state_t*)state;
211 pts = attestation_state->get_pts(attestation_state);
212
213 /* parse received PA-TNC message and automatically handle any errors */
214 result = imc_attestation->receive_message(imc_attestation, connection_id,
215 chunk_create(msg, msg_len), msg_type,
216 &pa_tnc_msg);
217
218 /* no parsed PA-TNC attributes available if an error occurred */
219 if (!pa_tnc_msg)
220 {
221 return result;
222 }
223
224 attr_list = linked_list_create();
225
226 /* analyze PA-TNC attributes */
227 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
228 while (enumerator->enumerate(enumerator, &attr))
229 {
230 if (attr->get_vendor_id(attr) == PEN_IETF &&
231 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
232 {
233 ietf_attr_pa_tnc_error_t *error_attr;
234 pa_tnc_error_code_t error_code;
235 chunk_t msg_info, attr_info;
236 u_int32_t offset;
237
238 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
239 error_code = error_attr->get_error_code(error_attr);
240 msg_info = error_attr->get_msg_info(error_attr);
241
242 DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
243 pa_tnc_error_code_names, error_code, &msg_info);
244 switch (error_code)
245 {
246 case PA_ERROR_INVALID_PARAMETER:
247 offset = error_attr->get_offset(error_attr);
248 DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
249 break;
250 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
251 attr_info = error_attr->get_attr_info(error_attr);
252 DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
253 break;
254 default:
255 break;
256 }
257 fatal_error = TRUE;
258 }
259 else if (attr->get_vendor_id(attr) == PEN_TCG)
260 {
261 switch (attr->get_type(attr))
262 {
263 case TCG_PTS_REQ_PROTO_CAPS:
264 {
265 tcg_pts_attr_proto_caps_t *attr_cast;
266 pts_proto_caps_flag_t imc_caps, imv_caps;
267
268 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
269 imv_caps = attr_cast->get_flags(attr_cast);
270 imc_caps = pts->get_proto_caps(pts);
271 pts->set_proto_caps(pts, imc_caps & imv_caps);
272
273 /* Send PTS Protocol Capabilities attribute */
274 attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps,
275 FALSE);
276 attr_list->insert_last(attr_list, attr);
277 break;
278 }
279 case TCG_PTS_MEAS_ALGO:
280 {
281 tcg_pts_attr_meas_algo_t *attr_cast;
282 pts_meas_algorithms_t selected_algorithm;
283
284 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
285 selected_algorithm = attr_cast->get_algorithms(attr_cast);
286
287 if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
288 (selected_algorithm & PTS_MEAS_ALGO_SHA384))
289 {
290 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
291 }
292 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
293 (selected_algorithm & PTS_MEAS_ALGO_SHA256))
294 {
295 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
296 }
297
298 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
299 (selected_algorithm & PTS_MEAS_ALGO_SHA1))
300 {
301 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
302 }
303 else
304 {
305 attr = pts_hash_alg_error_create(supported_algorithms);
306 attr_list->insert_last(attr_list, attr);
307 break;
308 }
309
310 /* Send Measurement Algorithm Selection attribute */
311 selected_algorithm = pts->get_meas_algorithm(pts);
312 attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
313 TRUE);
314 attr_list->insert_last(attr_list, attr);
315 break;
316 }
317
318 case TCG_PTS_GET_TPM_VERSION_INFO:
319 {
320 chunk_t tpm_version_info, attr_info;
321
322 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
323 {
324 attr_info = attr->get_value(attr);
325 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
326 TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
327 attr_list->insert_last(attr_list, attr);
328 break;
329 }
330
331 /* Send TPM Version Info attribute */
332 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
333 attr_list->insert_last(attr_list, attr);
334 break;
335 }
336
337 case TCG_PTS_GET_AIK:
338 {
339 certificate_t *aik;
340
341 aik = pts->get_aik(pts);
342 if (!aik)
343 {
344 DBG1(DBG_IMC, "no AIK certificate or public key available");
345 break;
346 }
347
348 /* Send AIK attribute */
349 attr = tcg_pts_attr_aik_create(aik);
350 attr_list->insert_last(attr_list, attr);
351 break;
352 }
353
354 /* PTS-based Attestation Evidence */
355 case TCG_PTS_REQ_FUNCT_COMP_EVID:
356 {
357 tcg_pts_attr_req_funct_comp_evid_t *attr_cast;
358 pts_proto_caps_flag_t negotiated_caps;
359 pts_attr_req_funct_comp_evid_flag_t flags;
360 u_int32_t sub_comp_depth;
361 u_int32_t comp_name_vendor_id;
362 u_int8_t family;
363 pts_qualifier_t qualifier;
364 pts_funct_comp_name_t name;
365
366 attr_info = attr->get_value(attr);
367 attr_cast = (tcg_pts_attr_req_funct_comp_evid_t*)attr;
368 negotiated_caps = pts->get_proto_caps(pts);
369 flags = attr_cast->get_flags(attr_cast);
370
371 if (flags & PTS_REQ_FUNC_COMP_FLAG_TTC)
372 {
373 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
374 TCG_PTS_UNABLE_DET_TTC, attr_info);
375 attr_list->insert_last(attr_list, attr);
376 break;
377 }
378 if (flags & PTS_REQ_FUNC_COMP_FLAG_VER &&
379 !(negotiated_caps & PTS_PROTO_CAPS_V))
380 {
381 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
382 TCG_PTS_UNABLE_LOCAL_VAL, attr_info);
383 attr_list->insert_last(attr_list, attr);
384 break;
385 }
386 if (flags & PTS_REQ_FUNC_COMP_FLAG_CURR &&
387 !(negotiated_caps & PTS_PROTO_CAPS_C))
388 {
389 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
390 TCG_PTS_UNABLE_CUR_EVID, attr_info);
391 attr_list->insert_last(attr_list, attr);
392 break;
393 }
394 if (flags & PTS_REQ_FUNC_COMP_FLAG_PCR &&
395 !(negotiated_caps & PTS_PROTO_CAPS_T))
396 {
397 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
398 TCG_PTS_UNABLE_DET_PCR, attr_info);
399 attr_list->insert_last(attr_list, attr);
400 break;
401 }
402
403 sub_comp_depth = attr_cast->get_sub_component_depth(attr_cast);
404 /* TODO: Implement checking of components with its sub-components */
405 if (sub_comp_depth != 1)
406 {
407 DBG1(DBG_IMC, "Current version of Attestation IMC does not support"
408 "sub component measurement deeper than 1. "
409 "Measuring top level component only.");
410 }
411
412 comp_name_vendor_id = attr_cast->get_comp_funct_name_vendor_id(attr_cast);
413 if (comp_name_vendor_id != PEN_TCG)
414 {
415 DBG1(DBG_IMC, "Current version of Attestation IMC supports"
416 "only functional component namings by TCG ");
417 break;
418 }
419
420 family = attr_cast->get_family(attr_cast);
421 if (family)
422 {
423 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
424 TCG_PTS_INVALID_NAME_FAM, attr_info);
425 attr_list->insert_last(attr_list, attr);
426 break;
427 }
428
429 qualifier = attr_cast->get_qualifier(attr_cast);
430 /* Check if Unknown or Wildcard was set for qualifier */
431 if (qualifier.kernel && qualifier.sub_component &&
432 (qualifier.type & PTS_FUNC_COMP_TYPE_ALL))
433 {
434 DBG2(DBG_IMC, "Wildcard was set for the qualifier of functional"
435 " component. Identifying the component with name binary enumeration");
436 }
437 else if (!qualifier.kernel && !qualifier.sub_component &&
438 (qualifier.type & PTS_FUNC_COMP_TYPE_UNKNOWN))
439 {
440 DBG2(DBG_IMC, "Unknown was set for the qualifier of functional"
441 " component. Identifying the component with name binary enumeration");
442 }
443 else
444 {
445 /* TODO: Implement what todo with received qualifier */
446 }
447
448 name = attr_cast->get_comp_funct_name(attr_cast);
449 switch (name)
450 {
451 case PTS_FUNC_COMP_NAME_BIOS:
452 {
453 /* TODO: Implement BIOS measurement */
454 DBG1(DBG_IMC, "TODO: Implement BIOS measurement");
455 break;
456 }
457 case PTS_FUNC_COMP_NAME_IGNORE:
458 case PTS_FUNC_COMP_NAME_CRTM:
459 case PTS_FUNC_COMP_NAME_PLATFORM_EXT:
460 case PTS_FUNC_COMP_NAME_BOARD:
461 case PTS_FUNC_COMP_NAME_INIT_LOADER:
462 case PTS_FUNC_COMP_NAME_OPT_ROMS:
463 default:
464 {
465 DBG1(DBG_IMC, "Unsupported Functional Component Name");
466 break;
467 }
468 }
469
470 break;
471 }
472 case TCG_PTS_GEN_ATTEST_EVID:
473 {
474 pts_simple_evid_final_flag_t flags;
475 /* TODO: TPM quote operation over included PCR's */
476
477 /* Send Simple Evidence Final attribute */
478 flags = PTS_SIMPLE_EVID_FINAL_FLAG_NO;
479 attr = tcg_pts_attr_simple_evid_final_create(flags, 0,
480 chunk_empty, chunk_empty, chunk_empty);
481 attr_list->insert_last(attr_list, attr);
482 break;
483 }
484 case TCG_PTS_REQ_FILE_META:
485 {
486 tcg_pts_attr_req_file_meta_t *attr_cast;
487 char *pathname;
488 bool is_directory;
489 u_int8_t delimiter;
490 pts_file_meta_t *metadata;
491
492 attr_info = attr->get_value(attr);
493 attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
494 is_directory = attr_cast->get_directory_flag(attr_cast);
495 delimiter = attr_cast->get_delimiter(attr_cast);
496 pathname = attr_cast->get_pathname(attr_cast);
497
498 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
499 if (valid_path && pts_error)
500 {
501 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
502 pts_error, attr_info);
503 attr_list->insert_last(attr_list, attr);
504 break;
505 }
506 else if (!valid_path)
507 {
508 break;
509 }
510 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
511 {
512 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
513 TCG_PTS_INVALID_DELIMITER, attr_info);
514 attr_list->insert_last(attr_list, attr);
515 break;
516 }
517 /* Get File Metadata and send them to PTS-IMV */
518 DBG2(DBG_IMC, "metadata request for %s '%s'",
519 is_directory ? "directory" : "file",
520 pathname);
521 metadata = pts->get_metadata(pts, pathname, is_directory);
522
523 if (!metadata)
524 {
525 /* TODO handle error codes from measurements */
526 return TNC_RESULT_FATAL;
527 }
528 attr = tcg_pts_attr_unix_file_meta_create(metadata);
529 attr->set_noskip_flag(attr, TRUE);
530 attr_list->insert_last(attr_list, attr);
531
532 break;
533 }
534 case TCG_PTS_REQ_FILE_MEAS:
535 {
536 tcg_pts_attr_req_file_meas_t *attr_cast;
537 char *pathname;
538 u_int16_t request_id;
539 bool is_directory;
540 u_int32_t delimiter;
541 pts_file_meas_t *measurements;
542
543 attr_info = attr->get_value(attr);
544 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
545 is_directory = attr_cast->get_directory_flag(attr_cast);
546 request_id = attr_cast->get_request_id(attr_cast);
547 delimiter = attr_cast->get_delimiter(attr_cast);
548 pathname = attr_cast->get_pathname(attr_cast);
549 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
550
551 if (valid_path && pts_error)
552 {
553 attr_info = attr->get_value(attr);
554 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
555 pts_error, attr_info);
556 attr_list->insert_last(attr_list, attr);
557 break;
558 }
559 else if (!valid_path)
560 {
561 break;
562 }
563
564 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
565 {
566 attr_info = attr->get_value(attr);
567 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
568 TCG_PTS_INVALID_DELIMITER, attr_info);
569 attr_list->insert_last(attr_list, attr);
570 break;
571 }
572
573 /* Do PTS File Measurements and send them to PTS-IMV */
574 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
575 request_id, is_directory ? "directory" : "file",
576 pathname);
577 measurements = pts->do_measurements(pts, request_id,
578 pathname, is_directory);
579 if (!measurements)
580 {
581 /* TODO handle error codes from measurements */
582 return TNC_RESULT_FATAL;
583 }
584 attr = tcg_pts_attr_file_meas_create(measurements);
585 attr->set_noskip_flag(attr, TRUE);
586 attr_list->insert_last(attr_list, attr);
587 break;
588 }
589 /* TODO: Not implemented yet */
590 case TCG_PTS_DH_NONCE_PARAMS_REQ:
591 case TCG_PTS_DH_NONCE_FINISH:
592 case TCG_PTS_REQ_INTEG_MEAS_LOG:
593 /* Attributes using XML */
594 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
595 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
596 /* On Windows only*/
597 case TCG_PTS_REQ_REGISTRY_VALUE:
598 /* Received on IMV side only*/
599 case TCG_PTS_PROTO_CAPS:
600 case TCG_PTS_DH_NONCE_PARAMS_RESP:
601 case TCG_PTS_MEAS_ALGO_SELECTION:
602 case TCG_PTS_TPM_VERSION_INFO:
603 case TCG_PTS_TEMPL_REF_MANI_SET_META:
604 case TCG_PTS_AIK:
605 case TCG_PTS_SIMPLE_COMP_EVID:
606 case TCG_PTS_SIMPLE_EVID_FINAL:
607 case TCG_PTS_VERIFICATION_RESULT:
608 case TCG_PTS_INTEG_REPORT:
609 case TCG_PTS_UNIX_FILE_META:
610 case TCG_PTS_FILE_MEAS:
611 case TCG_PTS_INTEG_MEAS_LOG:
612 default:
613 DBG1(DBG_IMC, "received unsupported attribute '%N'",
614 tcg_attr_names, attr->get_type(attr));
615 break;
616 }
617 }
618 }
619 enumerator->destroy(enumerator);
620 pa_tnc_msg->destroy(pa_tnc_msg);
621
622 result = TNC_RESULT_SUCCESS;
623
624 if (attr_list->get_count(attr_list))
625 {
626 pa_tnc_msg = pa_tnc_msg_create();
627
628 enumerator = attr_list->create_enumerator(attr_list);
629 while (enumerator->enumerate(enumerator, &attr))
630 {
631 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
632 }
633 enumerator->destroy(enumerator);
634
635 pa_tnc_msg->build(pa_tnc_msg);
636 result = imc_attestation->send_message(imc_attestation, connection_id,
637 pa_tnc_msg->get_encoding(pa_tnc_msg));
638 pa_tnc_msg->destroy(pa_tnc_msg);
639 }
640 attr_list->destroy(attr_list);
641
642 return result;
643 }
644
645 /**
646 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
647 */
648 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
649 TNC_ConnectionID connection_id)
650 {
651 if (!imc_attestation)
652 {
653 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
654 return TNC_RESULT_NOT_INITIALIZED;
655 }
656 return TNC_RESULT_SUCCESS;
657 }
658
659 /**
660 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
661 */
662 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
663 {
664 if (!imc_attestation)
665 {
666 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
667 return TNC_RESULT_NOT_INITIALIZED;
668 }
669
670 libpts_deinit();
671
672 imc_attestation->destroy(imc_attestation);
673 imc_attestation = NULL;
674
675 return TNC_RESULT_SUCCESS;
676 }
677
678 /**
679 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
680 */
681 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
682 TNC_TNCC_BindFunctionPointer bind_function)
683 {
684 if (!imc_attestation)
685 {
686 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
687 return TNC_RESULT_NOT_INITIALIZED;
688 }
689 return imc_attestation->bind_functions(imc_attestation, bind_function);
690 }