Replaced DH_NONCE state with TPM_INIT state
[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 <ietf/ietf_attr_product_info.h>
23
24 #include <libpts.h>
25
26 #include <pts/pts_database.h>
27 #include <pts/pts_creds.h>
28 #include <pts/pts_error.h>
29
30 #include <tcg/tcg_attr.h>
31 #include <tcg/tcg_pts_attr_proto_caps.h>
32 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
33 #include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
34 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
35 #include <tcg/tcg_pts_attr_meas_algo.h>
36 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
37 #include <tcg/tcg_pts_attr_tpm_version_info.h>
38 #include <tcg/tcg_pts_attr_get_aik.h>
39 #include <tcg/tcg_pts_attr_aik.h>
40 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
41 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
42 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
43 #include <tcg/tcg_pts_attr_simple_evid_final.h>
44 #include <tcg/tcg_pts_attr_req_file_meas.h>
45 #include <tcg/tcg_pts_attr_file_meas.h>
46 #include <tcg/tcg_pts_attr_req_file_meta.h>
47 #include <tcg/tcg_pts_attr_unix_file_meta.h>
48
49 #include <tncif_pa_subtypes.h>
50
51 #include <pen/pen.h>
52 #include <debug.h>
53 #include <credentials/credential_manager.h>
54 #include <utils/linked_list.h>
55
56 /* IMV definitions */
57
58 static const char imv_name[] = "Attestation";
59
60 #define IMV_VENDOR_ID PEN_TCG
61 #define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
62
63 static imv_agent_t *imv_attestation;
64
65 /**
66 * Supported PTS measurement algorithms
67 */
68 static pts_meas_algorithms_t supported_algorithms = 0;
69
70 /**
71 * Supported PTS Diffie Hellman Groups
72 */
73 static pts_dh_group_t supported_dh_groups = 0;
74
75 /**
76 * PTS file measurement database
77 */
78 static pts_database_t *pts_db;
79
80 /**
81 * PTS credentials
82 */
83 static pts_creds_t *pts_creds;
84
85 /**
86 * PTS credential manager
87 */
88 static credential_manager_t *pts_credmgr;
89
90 /**
91 * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
92 */
93 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
94 TNC_Version min_version,
95 TNC_Version max_version,
96 TNC_Version *actual_version)
97 {
98 char *hash_alg, *dh_group, *uri, *cadir;
99
100 if (imv_attestation)
101 {
102 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
103 return TNC_RESULT_ALREADY_INITIALIZED;
104 }
105 if (!pts_meas_probe_algorithms(&supported_algorithms))
106 {
107 return TNC_RESULT_FATAL;
108 }
109 if (!pts_probe_dh_groups(&supported_dh_groups))
110 {
111 return TNC_RESULT_FATAL;
112 }
113 imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
114 imv_id, actual_version);
115 if (!imv_attestation)
116 {
117 return TNC_RESULT_FATAL;
118 }
119
120 libpts_init();
121
122 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
123 {
124 DBG1(DBG_IMV, "no common IF-IMV version");
125 return TNC_RESULT_NO_COMMON_VERSION;
126 }
127
128 /**
129 * Specify supported PTS measurement algorithms
130 *
131 * sha1 : PTS_MEAS_ALGO_SHA1
132 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
133 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
134 *
135 * we expect the PTS-IMC to select the strongest supported algorithm
136 */
137 hash_alg = lib->settings->get_str(lib->settings,
138 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
139 if (!strcaseeq(hash_alg, "sha384") && !strcaseeq(hash_alg, "sha2_384"))
140 {
141 /* remove SHA384 algorithm */
142 supported_algorithms &= ~PTS_MEAS_ALGO_SHA384;
143 }
144 if (strcaseeq(hash_alg, "sha1"))
145 {
146 /* remove SHA256 algorithm */
147 supported_algorithms &= ~PTS_MEAS_ALGO_SHA256;
148 }
149
150 /**
151 * Specify supported PTS Diffie Hellman Groups
152 *
153 * ike2: PTS_DH_GROUP_IKE2
154 * ike5: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
155 * ike14: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
156 * ike19: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE19
157 * ike20: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 | PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
158 *
159 * we expect the PTS-IMC to select the strongest supported group
160 */
161 dh_group = lib->settings->get_str(lib->settings,
162 "libimcv.plugins.imv-attestation.dh_group", "ike19");
163 if (!pts_update_supported_dh_groups(dh_group, &supported_dh_groups))
164 {
165 return TNC_RESULT_FATAL;
166 }
167
168 /* create a PTS credential manager */
169 pts_credmgr = credential_manager_create();
170
171 /* create PTS credential set */
172 cadir = lib->settings->get_str(lib->settings,
173 "libimcv.plugins.imv-attestation.cadir", NULL);
174 pts_creds = pts_creds_create(cadir);
175 if (pts_creds)
176 {
177 pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
178 }
179
180 /* attach file measurement database */
181 uri = lib->settings->get_str(lib->settings,
182 "libimcv.plugins.imv-attestation.database", NULL);
183 pts_db = pts_database_create(uri);
184
185 return TNC_RESULT_SUCCESS;
186 }
187
188 /**
189 * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
190 */
191 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
192 TNC_ConnectionID connection_id,
193 TNC_ConnectionState new_state)
194 {
195 imv_state_t *state;
196 imv_attestation_state_t *attestation_state;
197 TNC_Result result;
198
199 if (!imv_attestation)
200 {
201 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
202 return TNC_RESULT_NOT_INITIALIZED;
203 }
204 switch (new_state)
205 {
206 case TNC_CONNECTION_STATE_CREATE:
207 state = imv_attestation_state_create(connection_id);
208 return imv_attestation->create_state(imv_attestation, state);
209 case TNC_CONNECTION_STATE_DELETE:
210 return imv_attestation->delete_state(imv_attestation, connection_id);
211 case TNC_CONNECTION_STATE_HANDSHAKE:
212 result = imv_attestation->change_state(imv_attestation, connection_id,
213 new_state, &state);
214 if (result != TNC_RESULT_SUCCESS)
215 {
216 return result;
217 }
218 attestation_state = (imv_attestation_state_t*)state;
219
220 /* TODO: Get some configurations */
221
222 return TNC_RESULT_SUCCESS;
223 default:
224 return imv_attestation->change_state(imv_attestation, connection_id,
225 new_state, NULL);
226 }
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 imv_state_t *state;
235 imv_attestation_state_t *attestation_state;
236 imv_attestation_handshake_state_t handshake_state;
237 TNC_Result result;
238
239 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
240 {
241 return TNC_RESULT_FATAL;
242 }
243 attestation_state = (imv_attestation_state_t*)state;
244 handshake_state = attestation_state->get_handshake_state(attestation_state);
245 pts = attestation_state->get_pts(attestation_state);
246
247 msg = pa_tnc_msg_create();
248
249
250 /* Switch on the attribute type IMV has received */
251 switch (handshake_state)
252 {
253 case IMV_ATTESTATION_STATE_INIT:
254 {
255 pts_proto_caps_flag_t flags;
256
257 /* Send Request Protocol Capabilities attribute */
258 flags = pts->get_proto_caps(pts);
259 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
260 attr->set_noskip_flag(attr, TRUE);
261 msg->add_attribute(msg, attr);
262
263 /* Send Measurement Algorithms attribute */
264 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
265 attr->set_noskip_flag(attr, TRUE);
266 msg->add_attribute(msg, attr);
267
268 attestation_state->set_handshake_state(attestation_state,
269 IMV_ATTESTATION_STATE_DH_NONCE);
270 break;
271 }
272 case IMV_ATTESTATION_STATE_DH_NONCE:
273 {
274 bool request_sent = FALSE;
275
276 /* Jump to Measurement state if IMC has no TPM */
277 if(!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
278 {
279 attestation_state->set_handshake_state(attestation_state,
280 IMV_ATTESTATION_STATE_MEAS);
281 }
282 else if (!request_sent)
283 {
284 /* Send DH nonce parameters request attribute */
285 attr = tcg_pts_attr_dh_nonce_params_req_create(0, supported_dh_groups);
286 attr->set_noskip_flag(attr, TRUE);
287 msg->add_attribute(msg, attr);
288 request_sent = TRUE;
289 }
290 else if (request_sent)
291 {
292 /* Send DH nonce finish attribute */
293 attestation_state->set_handshake_state(attestation_state,
294 IMV_ATTESTATION_STATE_MEAS);
295 }
296
297 break;
298
299 }
300
301 case IMV_ATTESTATION_STATE_MEAS:
302 {
303 enumerator_t *enumerator;
304 u_int32_t delimiter = SOLIDUS_UTF;
305 char *platform_info, *pathname;
306 u_int16_t request_id;
307 int id, type;
308 bool is_dir;
309
310 attestation_state->set_handshake_state(attestation_state,
311 IMV_ATTESTATION_STATE_COMP_EVID);
312
313 /* Does the PTS-IMC have TPM support? */
314 {
315 /* Send Get TPM Version attribute */
316 attr = tcg_pts_attr_get_tpm_version_info_create();
317 attr->set_noskip_flag(attr, TRUE);
318 msg->add_attribute(msg, attr);
319
320 /* Send Get AIK attribute */
321 attr = tcg_pts_attr_get_aik_create();
322 attr->set_noskip_flag(attr, TRUE);
323 msg->add_attribute(msg, attr);
324 }
325
326 /* Get Platform and OS of the PTS-IMC */
327 platform_info = pts->get_platform_info(pts);
328
329 if (!pts_db || !platform_info)
330 {
331 DBG1(DBG_IMV, "%s%s%s not available",
332 (pts_db) ? "" : "pts database",
333 (!pts_db && !platform_info) ? "and" : "",
334 (platform_info) ? "" : "platform info");
335 break;
336 }
337 DBG1(DBG_IMV, "platform is '%s'", platform_info);
338
339 /* Send Request File Metadata attribute */
340 attr = tcg_pts_attr_req_file_meta_create(FALSE, SOLIDUS_UTF, "/etc/tnc_config");
341 attr->set_noskip_flag(attr, TRUE);
342 msg->add_attribute(msg, attr);
343
344 /* Send Request File Measurement attribute */
345 enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
346 if (!enumerator)
347 {
348 break;
349 }
350 while (enumerator->enumerate(enumerator, &id, &type, &pathname))
351 {
352 is_dir = (type != 0);
353 request_id = attestation_state->add_request(attestation_state,
354 id, is_dir);
355 DBG2(DBG_IMV, "measurement request %d for %s '%s'",
356 request_id, is_dir ? "directory" : "file", pathname);
357 attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
358 delimiter, pathname);
359 attr->set_noskip_flag(attr, TRUE);
360 msg->add_attribute(msg, attr);
361 }
362 enumerator->destroy(enumerator);
363 break;
364 }
365 case IMV_ATTESTATION_STATE_COMP_EVID:
366 {
367 pts_attr_req_funct_comp_evid_flag_t flags;
368 u_int32_t sub_comp_depth;
369 pts_qualifier_t qualifier;
370 pts_funct_comp_name_t name;
371
372 attestation_state->set_handshake_state(attestation_state,
373 IMV_ATTESTATION_STATE_END);
374
375 flags = PTS_REQ_FUNC_COMP_FLAG_PCR;
376 sub_comp_depth = 1;
377 qualifier.kernel = FALSE;
378 qualifier.sub_component = FALSE;
379 qualifier.type = PTS_FUNC_COMP_TYPE_ALL;
380 name = PTS_FUNC_COMP_NAME_BIOS;
381
382 /* Send Request Functional Component Evidence attribute */
383 attr = tcg_pts_attr_req_funct_comp_evid_create(flags, sub_comp_depth,
384 PEN_TCG, qualifier, name);
385 attr->set_noskip_flag(attr, TRUE);
386 msg->add_attribute(msg, attr);
387 /* Send Generate Attestation Evidence attribute */
388 attr = tcg_pts_attr_gen_attest_evid_create();
389 attr->set_noskip_flag(attr, TRUE);
390 msg->add_attribute(msg, attr);
391
392 break;
393 }
394 default:
395 DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
396 handshake_state);
397 return TNC_RESULT_FATAL;
398 }
399
400 msg->build(msg);
401 result = imv_attestation->send_message(imv_attestation, connection_id,
402 msg->get_encoding(msg));
403 msg->destroy(msg);
404
405 return result;
406 }
407
408 /**
409 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
410 */
411 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
412 TNC_ConnectionID connection_id,
413 TNC_BufferReference msg,
414 TNC_UInt32 msg_len,
415 TNC_MessageType msg_type)
416 {
417 pa_tnc_msg_t *pa_tnc_msg;
418 pa_tnc_attr_t *attr;
419 imv_state_t *state;
420 imv_attestation_state_t *attestation_state;
421 pts_t *pts;
422 enumerator_t *enumerator;
423 TNC_Result result;
424 bool fatal_error = FALSE;
425 bool measurement_error = FALSE;
426
427 if (!imv_attestation)
428 {
429 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
430 return TNC_RESULT_NOT_INITIALIZED;
431 }
432
433 /* get current IMV state */
434 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
435 {
436 return TNC_RESULT_FATAL;
437 }
438 attestation_state = (imv_attestation_state_t*)state;
439 pts = attestation_state->get_pts(attestation_state);
440
441 /* parse received PA-TNC message and automatically handle any errors */
442 result = imv_attestation->receive_message(imv_attestation, connection_id,
443 chunk_create(msg, msg_len), msg_type,
444 &pa_tnc_msg);
445
446 /* no parsed PA-TNC attributes available if an error occurred */
447 if (!pa_tnc_msg)
448 {
449 return result;
450 }
451
452 /* analyze PA-TNC attributes */
453 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
454 while (enumerator->enumerate(enumerator, &attr))
455 {
456 if (attr->get_vendor_id(attr) == PEN_IETF)
457 {
458 if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
459 {
460 ietf_attr_pa_tnc_error_t *error_attr;
461 pen_t error_vendor_id;
462 pa_tnc_error_code_t error_code;
463 chunk_t msg_info, attr_info;
464 u_int32_t offset;
465
466 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
467 error_vendor_id = error_attr->get_vendor_id(error_attr);
468 error_code = error_attr->get_error_code(error_attr);
469 msg_info = error_attr->get_msg_info(error_attr);
470
471 if (error_vendor_id == PEN_IETF)
472 {
473 DBG1(DBG_IMV, "received PA-TNC error '%N' "
474 "concerning message %#B",
475 pa_tnc_error_code_names, error_code, &msg_info);
476
477 switch (error_code)
478 {
479 case PA_ERROR_INVALID_PARAMETER:
480 offset = error_attr->get_offset(error_attr);
481 DBG1(DBG_IMV, " occurred at offset of %u bytes",
482 offset);
483 break;
484 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
485 attr_info = error_attr->get_attr_info(error_attr);
486 DBG1(DBG_IMV, " unsupported attribute %#B",
487 &attr_info);
488 break;
489 default:
490 break;
491 }
492 }
493 else if (error_vendor_id == PEN_TCG)
494 {
495 DBG1(DBG_IMV, "received TCG-PTS error '%N'",
496 pts_error_code_names, error_code);
497 DBG1(DBG_IMV, "error information: %B", &msg_info);
498 }
499 fatal_error = TRUE;
500 }
501 else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
502 {
503 ietf_attr_product_info_t *attr_cast;
504 char *platform_info;
505
506 attr_cast = (ietf_attr_product_info_t*)attr;
507 platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
508 pts->set_platform_info(pts, platform_info);
509 }
510 }
511 else if (attr->get_vendor_id(attr) == PEN_TCG)
512 {
513 switch (attr->get_type(attr))
514 {
515 case TCG_PTS_PROTO_CAPS:
516 {
517 tcg_pts_attr_proto_caps_t *attr_cast;
518 pts_proto_caps_flag_t flags;
519
520 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
521 flags = attr_cast->get_flags(attr_cast);
522 pts->set_proto_caps(pts, flags);
523 break;
524 }
525 case TCG_PTS_DH_NONCE_PARAMS_RESP:
526 {
527 /* TODO: Implement */
528 break;
529 }
530 case TCG_PTS_MEAS_ALGO_SELECTION:
531 {
532 tcg_pts_attr_meas_algo_t *attr_cast;
533 pts_meas_algorithms_t selected_algorithm;
534
535 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
536 selected_algorithm = attr_cast->get_algorithms(attr_cast);
537 pts->set_meas_algorithm(pts, selected_algorithm);
538 break;
539 }
540 case TCG_PTS_TPM_VERSION_INFO:
541 {
542 tcg_pts_attr_tpm_version_info_t *attr_cast;
543 chunk_t tpm_version_info;
544
545 attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
546 tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
547 pts->set_tpm_version_info(pts, tpm_version_info);
548 break;
549 }
550 case TCG_PTS_AIK:
551 {
552 tcg_pts_attr_aik_t *attr_cast;
553 certificate_t *aik, *issuer;
554 enumerator_t *e;
555 bool trusted = FALSE;
556
557 attr_cast = (tcg_pts_attr_aik_t*)attr;
558 aik = attr_cast->get_aik(attr_cast);
559 if (!aik)
560 {
561 /* TODO generate error attribute */
562 break;
563 }
564 if (aik->get_type(aik) == CERT_X509)
565 {
566 DBG1(DBG_IMV, "verifying AIK certificate");
567 e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
568 KEY_ANY, aik->get_issuer(aik), FALSE);
569 while (e->enumerate(e, &issuer))
570 {
571 if (aik->issued_by(aik, issuer))
572 {
573 trusted = TRUE;
574 break;
575 }
576 }
577 e->destroy(e);
578 DBG1(DBG_IMV, "AIK certificate is %strusted",
579 trusted ? "" : "not ");
580 }
581 pts->set_aik(pts, aik);
582 break;
583 }
584
585 /* PTS-based Attestation Evidence */
586 case TCG_PTS_SIMPLE_COMP_EVID:
587 {
588 /** TODO: Implement saving the PCR number, Hash Algo = communicated one,
589 * PCR transform (truncate SHA256, SHA384), PCR before and after values
590 */
591 break;
592 }
593
594 case TCG_PTS_SIMPLE_EVID_FINAL:
595 {
596 /** TODO: Implement construct Quote structure over saved values from
597 * TCG_PTS_SIMPLE_COMP_EVID and compare with received one
598 */
599 break;
600 }
601
602 case TCG_PTS_FILE_MEAS:
603 {
604 tcg_pts_attr_file_meas_t *attr_cast;
605 u_int16_t request_id;
606 int file_count, file_id;
607 pts_meas_algorithms_t algo;
608 pts_file_meas_t *measurements;
609 char *platform_info;
610 enumerator_t *e_hash;
611 bool is_dir;
612
613 platform_info = pts->get_platform_info(pts);
614 if (!pts_db || !platform_info)
615 {
616 break;
617 }
618
619 attr_cast = (tcg_pts_attr_file_meas_t*)attr;
620 measurements = attr_cast->get_measurements(attr_cast);
621 algo = pts->get_meas_algorithm(pts);
622 request_id = measurements->get_request_id(measurements);
623 file_count = measurements->get_file_count(measurements);
624
625 DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
626 request_id, file_count, (file_count == 1) ? "":"s");
627
628 if (!attestation_state->check_off_request(attestation_state,
629 request_id, &file_id, &is_dir))
630 {
631 DBG1(DBG_IMV, " no entry found for this request");
632 break;
633 }
634
635 /* check hashes from database against measurements */
636 e_hash = pts_db->create_hash_enumerator(pts_db,
637 platform_info, algo, file_id, is_dir);
638 if (!measurements->verify(measurements, e_hash, is_dir))
639 {
640 measurement_error = TRUE;
641 }
642 e_hash->destroy(e_hash);
643 break;
644 }
645 case TCG_PTS_UNIX_FILE_META:
646 {
647 tcg_pts_attr_file_meta_t *attr_cast;
648 int file_count;
649 pts_file_meta_t *metadata;
650 enumerator_t *e;
651 pts_file_metadata_t *entry;
652
653 attr_cast = (tcg_pts_attr_file_meta_t*)attr;
654 metadata = attr_cast->get_metadata(attr_cast);
655 file_count = metadata->get_file_count(metadata);
656
657 DBG1(DBG_IMV, "metadata request returned %d file%s:",
658 file_count, (file_count == 1) ? "":"s");
659
660 e = metadata->create_enumerator(metadata);
661 while(e->enumerate(e, &entry))
662 {
663 DBG1(DBG_IMV, "File name: %s", entry->filename);
664 DBG1(DBG_IMV, " type: %d", entry->type);
665 DBG1(DBG_IMV, " size: %d", entry->filesize);
666 DBG1(DBG_IMV, " create time: %s", ctime(&entry->create_time));
667 DBG1(DBG_IMV, " last modified: %s", ctime(&entry->last_modify_time));
668 DBG1(DBG_IMV, " last accessed: %s", ctime(&entry->last_access_time));
669 DBG1(DBG_IMV, " owner id: %d", entry->owner_id);
670 DBG1(DBG_IMV, " group id: %d", entry->group_id);
671 }
672
673 e->destroy(e);
674
675 break;
676 }
677
678 /* TODO: Not implemented yet */
679 case TCG_PTS_INTEG_MEAS_LOG:
680 /* Attributes using XML */
681 case TCG_PTS_TEMPL_REF_MANI_SET_META:
682 case TCG_PTS_VERIFICATION_RESULT:
683 case TCG_PTS_INTEG_REPORT:
684 /* On Windows only*/
685 case TCG_PTS_WIN_FILE_META:
686 case TCG_PTS_REGISTRY_VALUE:
687 /* Received on IMC side only*/
688 case TCG_PTS_REQ_PROTO_CAPS:
689 case TCG_PTS_DH_NONCE_PARAMS_REQ:
690 case TCG_PTS_DH_NONCE_FINISH:
691 case TCG_PTS_MEAS_ALGO:
692 case TCG_PTS_GET_TPM_VERSION_INFO:
693 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
694 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
695 case TCG_PTS_GET_AIK:
696 case TCG_PTS_REQ_FUNCT_COMP_EVID:
697 case TCG_PTS_GEN_ATTEST_EVID:
698 case TCG_PTS_REQ_FILE_META:
699 case TCG_PTS_REQ_FILE_MEAS:
700 case TCG_PTS_REQ_INTEG_MEAS_LOG:
701 default:
702 DBG1(DBG_IMV, "received unsupported attribute '%N'",
703 tcg_attr_names, attr->get_type(attr));
704 break;
705 }
706 }
707 }
708 enumerator->destroy(enumerator);
709 pa_tnc_msg->destroy(pa_tnc_msg);
710
711
712 if (fatal_error)
713 {
714 state->set_recommendation(state,
715 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
716 TNC_IMV_EVALUATION_RESULT_ERROR);
717 return imv_attestation->provide_recommendation(imv_attestation,
718 connection_id);
719 }
720
721 if (attestation_state->get_handshake_state(attestation_state) &
722 IMV_ATTESTATION_STATE_END)
723 {
724 if (attestation_state->get_request_count(attestation_state))
725 {
726 DBG1(DBG_IMV, "failure due to %d pending file measurements",
727 attestation_state->get_request_count(attestation_state));
728 measurement_error = TRUE;
729 }
730 if (measurement_error)
731 {
732 state->set_recommendation(state,
733 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
734 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
735 }
736 else
737 {
738 state->set_recommendation(state,
739 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
740 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
741 }
742 return imv_attestation->provide_recommendation(imv_attestation,
743 connection_id);
744 }
745
746 return send_message(connection_id);
747 }
748
749 /**
750 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
751 */
752 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
753 TNC_ConnectionID connection_id)
754 {
755 if (!imv_attestation)
756 {
757 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
758 return TNC_RESULT_NOT_INITIALIZED;
759 }
760 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
761 }
762
763 /**
764 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
765 */
766 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
767 TNC_ConnectionID connection_id)
768 {
769 imv_state_t *state;
770 imv_attestation_state_t *attestation_state;
771
772 if (!imv_attestation)
773 {
774 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
775 return TNC_RESULT_NOT_INITIALIZED;
776 }
777 /* get current IMV state */
778 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
779 {
780 return TNC_RESULT_FATAL;
781 }
782 attestation_state = (imv_attestation_state_t*)state;
783
784 /* Check if IMV has to initiate the PA-TNC exchange */
785 if (attestation_state->get_handshake_state(attestation_state) ==
786 IMV_ATTESTATION_STATE_INIT)
787 {
788 return send_message(connection_id);
789 }
790 return TNC_RESULT_SUCCESS;
791 }
792
793 /**
794 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
795 */
796 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
797 {
798 if (!imv_attestation)
799 {
800 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
801 return TNC_RESULT_NOT_INITIALIZED;
802 }
803 if (pts_creds)
804 {
805 pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
806 pts_creds->destroy(pts_creds);
807 }
808 DESTROY_IF(pts_db);
809 DESTROY_IF(pts_credmgr);
810
811 libpts_deinit();
812
813 imv_attestation->destroy(imv_attestation);
814 imv_attestation = NULL;
815
816 return TNC_RESULT_SUCCESS;
817 }
818
819 /**
820 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
821 */
822 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
823 TNC_TNCS_BindFunctionPointer bind_function)
824 {
825 if (!imv_attestation)
826 {
827 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
828 return TNC_RESULT_NOT_INITIALIZED;
829 }
830 return imv_attestation->bind_functions(imv_attestation, bind_function);
831 }