dadd77b0887c6ba6569acf95e2283948b0a6eba4
[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 #define NONCE_LEN_LIMIT 16
64
65 static imv_agent_t *imv_attestation;
66
67 /**
68 * Supported PTS measurement algorithms
69 */
70 static pts_meas_algorithms_t supported_algorithms = PTS_MEAS_ALGO_NONE;
71
72 /**
73 * Supported PTS Diffie Hellman Groups
74 */
75 static pts_dh_group_t supported_dh_groups = PTS_DH_GROUP_NONE;
76
77 /**
78 * PTS file measurement database
79 */
80 static pts_database_t *pts_db;
81
82 /**
83 * PTS credentials
84 */
85 static pts_creds_t *pts_creds;
86
87 /**
88 * PTS credential manager
89 */
90 static credential_manager_t *pts_credmgr;
91
92 /**
93 * TRUE if DH Nonce Parameters Request attribute is sent
94 */
95 static bool dh_nonce_req_sent = FALSE;
96
97 /**
98 * see section 3.7.1 of TCG TNC IF-IMV Specification 1.2
99 */
100 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
101 TNC_Version min_version,
102 TNC_Version max_version,
103 TNC_Version *actual_version)
104 {
105 char *hash_alg, *dh_group, *uri, *cadir;
106
107 if (imv_attestation)
108 {
109 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
110 return TNC_RESULT_ALREADY_INITIALIZED;
111 }
112 if (!pts_meas_algo_probe(&supported_algorithms) ||
113 !pts_dh_group_probe(&supported_dh_groups))
114 {
115 return TNC_RESULT_FATAL;
116 }
117 imv_attestation = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
118 imv_id, actual_version);
119 if (!imv_attestation)
120 {
121 return TNC_RESULT_FATAL;
122 }
123
124 libpts_init();
125
126 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
127 {
128 DBG1(DBG_IMV, "no common IF-IMV version");
129 return TNC_RESULT_NO_COMMON_VERSION;
130 }
131
132 /**
133 * Specify supported PTS measurement algorithms
134 *
135 * sha1 : PTS_MEAS_ALGO_SHA1
136 * sha256: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256
137 * sha384: PTS_MEAS_ALGO_SHA1 | PTS_MEAS_ALGO_SHA256 | PTS_MEAS_ALGO_SHA384
138 *
139 * we expect the PTS-IMC to select the strongest supported algorithm
140 */
141 hash_alg = lib->settings->get_str(lib->settings,
142 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
143
144 /**
145 * Specify supported PTS Diffie-Hellman groups
146 *
147 * modp1024: PTS_DH_GROUP_IKE2
148 * modp1536: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5
149 * modp2048: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14
150 * ecp256: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
151 * PTS_DH_GROUP_IKE19
152 * ecp384: PTS_DH_GROUP_IKE2 | PTS_DH_GROUP_IKE5 | PTS_DH_GROUP_IKE14 |
153 * PTS_DH_GROUP_IKE19 | PTS_DH_GROUP_IKE20
154 *
155 * we expect the PTS-IMC to select the strongest supported group
156 */
157 dh_group = lib->settings->get_str(lib->settings,
158 "libimcv.plugins.imv-attestation.dh_group", "ecp256");
159
160 if (!pts_meas_algo_update(hash_alg, &supported_algorithms) ||
161 !pts_dh_group_update(dh_group, &supported_dh_groups))
162 {
163 return TNC_RESULT_FATAL;
164 }
165
166 /* create a PTS credential manager */
167 pts_credmgr = credential_manager_create();
168
169 /* create PTS credential set */
170 cadir = lib->settings->get_str(lib->settings,
171 "libimcv.plugins.imv-attestation.cadir", NULL);
172 pts_creds = pts_creds_create(cadir);
173 if (pts_creds)
174 {
175 pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds));
176 }
177
178 /* attach file measurement database */
179 uri = lib->settings->get_str(lib->settings,
180 "libimcv.plugins.imv-attestation.database", NULL);
181 pts_db = pts_database_create(uri);
182
183 return TNC_RESULT_SUCCESS;
184 }
185
186 /**
187 * see section 3.7.2 of TCG TNC IF-IMV Specification 1.2
188 */
189 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
190 TNC_ConnectionID connection_id,
191 TNC_ConnectionState new_state)
192 {
193 imv_state_t *state;
194 imv_attestation_state_t *attestation_state;
195 TNC_Result result;
196
197 if (!imv_attestation)
198 {
199 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
200 return TNC_RESULT_NOT_INITIALIZED;
201 }
202 switch (new_state)
203 {
204 case TNC_CONNECTION_STATE_CREATE:
205 state = imv_attestation_state_create(connection_id);
206 return imv_attestation->create_state(imv_attestation, state);
207 case TNC_CONNECTION_STATE_DELETE:
208 return imv_attestation->delete_state(imv_attestation, connection_id);
209 case TNC_CONNECTION_STATE_HANDSHAKE:
210 result = imv_attestation->change_state(imv_attestation, connection_id,
211 new_state, &state);
212 if (result != TNC_RESULT_SUCCESS)
213 {
214 return result;
215 }
216 attestation_state = (imv_attestation_state_t*)state;
217
218 /* TODO: Get some configurations */
219
220 return TNC_RESULT_SUCCESS;
221 default:
222 return imv_attestation->change_state(imv_attestation, connection_id,
223 new_state, NULL);
224 }
225 }
226
227 static TNC_Result send_message(TNC_ConnectionID connection_id)
228 {
229 pa_tnc_msg_t *msg;
230 pa_tnc_attr_t *attr;
231 pts_t *pts;
232 imv_state_t *state;
233 imv_attestation_state_t *attestation_state;
234 imv_attestation_handshake_state_t handshake_state;
235 TNC_Result result;
236
237 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
238 {
239 return TNC_RESULT_FATAL;
240 }
241 attestation_state = (imv_attestation_state_t*)state;
242 handshake_state = attestation_state->get_handshake_state(attestation_state);
243 pts = attestation_state->get_pts(attestation_state);
244
245 msg = pa_tnc_msg_create();
246
247 /* Jump to Measurement state if IMC has no TPM */
248 if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT &&
249 !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
250 {
251 handshake_state = IMV_ATTESTATION_STATE_MEAS;
252 DBG3(DBG_IMV, "TPM is not available on IMC side, ",
253 "jumping to measurement phase");
254 }
255
256 /* Switch on the attribute type IMV has received */
257 switch (handshake_state)
258 {
259 case IMV_ATTESTATION_STATE_INIT:
260 {
261 pts_proto_caps_flag_t flags;
262
263 /* Send Request Protocol Capabilities attribute */
264 flags = pts->get_proto_caps(pts);
265 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
266 attr->set_noskip_flag(attr, TRUE);
267 msg->add_attribute(msg, attr);
268
269 /* Send Measurement Algorithms attribute */
270 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
271 attr->set_noskip_flag(attr, TRUE);
272 msg->add_attribute(msg, attr);
273
274 attestation_state->set_handshake_state(attestation_state,
275 IMV_ATTESTATION_STATE_TPM_INIT);
276 break;
277 }
278 case IMV_ATTESTATION_STATE_TPM_INIT:
279 {
280 if (!dh_nonce_req_sent)
281 {
282 int min_nonce_len;
283
284 /* Send DH nonce parameters request attribute */
285 min_nonce_len = lib->settings->get_int(lib->settings,
286 "libimcv.plugins.imv-attestation.min_nonce_len", 0);
287 attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
288 supported_dh_groups);
289 attr->set_noskip_flag(attr, TRUE);
290 msg->add_attribute(msg, attr);
291 dh_nonce_req_sent = TRUE;
292 }
293 else
294 {
295 pts_meas_algorithms_t selected_algorithm;
296 chunk_t initiator_value, initiator_nonce;
297
298 /* Send DH nonce finish attribute */
299 selected_algorithm = pts->get_meas_algorithm(pts);
300 pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
301 attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
302 initiator_value, initiator_nonce);
303 attr->set_noskip_flag(attr, TRUE);
304 msg->add_attribute(msg, attr);
305
306 /* Send Get TPM Version attribute */
307 attr = tcg_pts_attr_get_tpm_version_info_create();
308 attr->set_noskip_flag(attr, TRUE);
309 msg->add_attribute(msg, attr);
310
311 /* Send Get AIK attribute */
312 attr = tcg_pts_attr_get_aik_create();
313 attr->set_noskip_flag(attr, TRUE);
314 msg->add_attribute(msg, attr);
315
316 attestation_state->set_handshake_state(attestation_state,
317 IMV_ATTESTATION_STATE_MEAS);
318 }
319
320 break;
321 }
322 case IMV_ATTESTATION_STATE_MEAS:
323 {
324
325 enumerator_t *enumerator;
326 u_int32_t delimiter = SOLIDUS_UTF;
327 char *platform_info, *pathname;
328 u_int16_t request_id;
329 int id, type;
330 bool is_dir;
331
332 attestation_state->set_handshake_state(attestation_state,
333 IMV_ATTESTATION_STATE_COMP_EVID);
334
335 /* Get Platform and OS of the PTS-IMC */
336 platform_info = pts->get_platform_info(pts);
337
338 if (!pts_db || !platform_info)
339 {
340 DBG1(DBG_IMV, "%s%s%s not available",
341 (pts_db) ? "" : "pts database",
342 (!pts_db && !platform_info) ? "and" : "",
343 (platform_info) ? "" : "platform info");
344 break;
345 }
346 DBG1(DBG_IMV, "platform is '%s'", platform_info);
347
348 /* Send Request File Metadata attribute */
349 attr = tcg_pts_attr_req_file_meta_create(FALSE, SOLIDUS_UTF, "/etc/tnc_config");
350 attr->set_noskip_flag(attr, TRUE);
351 msg->add_attribute(msg, attr);
352
353 /* Send Request File Measurement attribute */
354 enumerator = pts_db->create_file_enumerator(pts_db, platform_info);
355 if (!enumerator)
356 {
357 break;
358 }
359 while (enumerator->enumerate(enumerator, &id, &type, &pathname))
360 {
361 is_dir = (type != 0);
362 request_id = attestation_state->add_request(attestation_state,
363 id, is_dir);
364 DBG2(DBG_IMV, "measurement request %d for %s '%s'",
365 request_id, is_dir ? "directory" : "file", pathname);
366 attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
367 delimiter, pathname);
368 attr->set_noskip_flag(attr, TRUE);
369 msg->add_attribute(msg, attr);
370 }
371 enumerator->destroy(enumerator);
372 break;
373 }
374 case IMV_ATTESTATION_STATE_COMP_EVID:
375 {
376 pts_attr_req_funct_comp_evid_flag_t flags;
377 u_int32_t sub_comp_depth;
378 pts_qualifier_t qualifier;
379 pts_funct_comp_name_t name;
380
381 attestation_state->set_handshake_state(attestation_state,
382 IMV_ATTESTATION_STATE_END);
383
384 flags = PTS_REQ_FUNC_COMP_FLAG_PCR;
385 sub_comp_depth = 0;
386 qualifier.kernel = FALSE;
387 qualifier.sub_component = FALSE;
388 qualifier.type = PTS_FUNC_COMP_TYPE_ALL;
389 name = PTS_FUNC_COMP_NAME_BIOS;
390
391 /* Send Request Functional Component Evidence attribute */
392 attr = tcg_pts_attr_req_funct_comp_evid_create(flags, sub_comp_depth,
393 PEN_TCG, qualifier, name);
394 attr->set_noskip_flag(attr, TRUE);
395 msg->add_attribute(msg, attr);
396 /* Send Generate Attestation Evidence attribute */
397 attr = tcg_pts_attr_gen_attest_evid_create();
398 attr->set_noskip_flag(attr, TRUE);
399 msg->add_attribute(msg, attr);
400
401 break;
402 }
403 default:
404 DBG1(DBG_IMV, "Attestation IMV is in unknown state: \"%s\"",
405 handshake_state);
406 return TNC_RESULT_FATAL;
407 }
408
409 msg->build(msg);
410 result = imv_attestation->send_message(imv_attestation, connection_id,
411 msg->get_encoding(msg));
412 msg->destroy(msg);
413
414 return result;
415 }
416
417 /**
418 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
419 */
420 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
421 TNC_ConnectionID connection_id,
422 TNC_BufferReference msg,
423 TNC_UInt32 msg_len,
424 TNC_MessageType msg_type)
425 {
426 pa_tnc_msg_t *pa_tnc_msg;
427 pa_tnc_attr_t *attr;
428 imv_state_t *state;
429 imv_attestation_state_t *attestation_state;
430 pts_t *pts;
431 enumerator_t *enumerator;
432 TNC_Result result;
433 bool fatal_error = FALSE;
434 bool measurement_error = FALSE;
435 linked_list_t *attr_list;
436 chunk_t attr_info;
437
438 if (!imv_attestation)
439 {
440 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
441 return TNC_RESULT_NOT_INITIALIZED;
442 }
443
444 /* get current IMV state */
445 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
446 {
447 return TNC_RESULT_FATAL;
448 }
449 attestation_state = (imv_attestation_state_t*)state;
450 pts = attestation_state->get_pts(attestation_state);
451
452 /* parse received PA-TNC message and automatically handle any errors */
453 result = imv_attestation->receive_message(imv_attestation, connection_id,
454 chunk_create(msg, msg_len), msg_type,
455 &pa_tnc_msg);
456
457 /* no parsed PA-TNC attributes available if an error occurred */
458 if (!pa_tnc_msg)
459 {
460 return result;
461 }
462
463 attr_list = linked_list_create();
464
465 /* analyze PA-TNC attributes */
466 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
467 while (enumerator->enumerate(enumerator, &attr))
468 {
469 if (attr->get_vendor_id(attr) == PEN_IETF)
470 {
471 if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
472 {
473 ietf_attr_pa_tnc_error_t *error_attr;
474 pen_t error_vendor_id;
475 pa_tnc_error_code_t error_code;
476 chunk_t msg_info, attr_info;
477 u_int32_t offset;
478
479 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
480 error_vendor_id = error_attr->get_vendor_id(error_attr);
481 error_code = error_attr->get_error_code(error_attr);
482 msg_info = error_attr->get_msg_info(error_attr);
483
484 if (error_vendor_id == PEN_IETF)
485 {
486 DBG1(DBG_IMV, "received PA-TNC error '%N' "
487 "concerning message %#B",
488 pa_tnc_error_code_names, error_code, &msg_info);
489
490 switch (error_code)
491 {
492 case PA_ERROR_INVALID_PARAMETER:
493 offset = error_attr->get_offset(error_attr);
494 DBG1(DBG_IMV, " occurred at offset of %u bytes",
495 offset);
496 break;
497 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
498 attr_info = error_attr->get_attr_info(error_attr);
499 DBG1(DBG_IMV, " unsupported attribute %#B",
500 &attr_info);
501 break;
502 default:
503 break;
504 }
505 }
506 else if (error_vendor_id == PEN_TCG)
507 {
508 DBG1(DBG_IMV, "received TCG-PTS error '%N'",
509 pts_error_code_names, error_code);
510 DBG1(DBG_IMV, "error information: %B", &msg_info);
511 }
512 fatal_error = TRUE;
513 }
514 else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION)
515 {
516 ietf_attr_product_info_t *attr_cast;
517 char *platform_info;
518
519 attr_cast = (ietf_attr_product_info_t*)attr;
520 platform_info = attr_cast->get_info(attr_cast, NULL, NULL);
521 pts->set_platform_info(pts, platform_info);
522 }
523 }
524 else if (attr->get_vendor_id(attr) == PEN_TCG)
525 {
526 switch (attr->get_type(attr))
527 {
528 case TCG_PTS_PROTO_CAPS:
529 {
530 tcg_pts_attr_proto_caps_t *attr_cast;
531 pts_proto_caps_flag_t flags;
532
533 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
534 flags = attr_cast->get_flags(attr_cast);
535 pts->set_proto_caps(pts, flags);
536 break;
537 }
538 case TCG_PTS_MEAS_ALGO_SELECTION:
539 {
540 tcg_pts_attr_meas_algo_t *attr_cast;
541 pts_meas_algorithms_t selected_algorithm;
542
543 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
544 selected_algorithm = attr_cast->get_algorithms(attr_cast);
545 if (!(selected_algorithm & supported_algorithms))
546 {
547 DBG1(DBG_IMV, "PTS-IMC selected unsupported "
548 "measurement algorithm");
549 return TNC_RESULT_FATAL;
550 }
551 pts->set_meas_algorithm(pts, selected_algorithm);
552 break;
553 }
554 case TCG_PTS_DH_NONCE_PARAMS_RESP:
555 {
556 tcg_pts_attr_dh_nonce_params_resp_t *attr_cast;
557 int nonce_len, min_nonce_len;
558 pts_dh_group_t dh_group;
559 pts_meas_algorithms_t offered_algorithms, selected_algorithm;
560 chunk_t responder_value, responder_nonce;
561
562 attr_cast = (tcg_pts_attr_dh_nonce_params_resp_t*)attr;
563 responder_nonce = attr_cast->get_responder_nonce(attr_cast);
564
565 /* check compliance of responder nonce length */
566 min_nonce_len = lib->settings->get_int(lib->settings,
567 "libimcv.plugins.imv-attestation.min_nonce_len", 0);
568 nonce_len = responder_nonce.len;
569 if (nonce_len <= NONCE_LEN_LIMIT ||
570 (min_nonce_len > 0 && nonce_len < min_nonce_len))
571 {
572 attr_info = attr->get_value(attr);
573 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
574 TCG_PTS_BAD_NONCE_LENGTH, attr_info);
575 attr_list->insert_last(attr_list, attr);
576 break;
577 }
578
579 dh_group = attr_cast->get_dh_group(attr_cast);
580 if (!(dh_group & supported_dh_groups))
581 {
582 DBG1(DBG_IMV, "PTS-IMC selected unsupported DH group");
583 return TNC_RESULT_FATAL;
584 }
585
586 offered_algorithms = attr_cast->get_hash_algo_set(attr_cast);
587 selected_algorithm = pts_meas_algo_select(supported_algorithms,
588 offered_algorithms);
589 if (selected_algorithm == PTS_MEAS_ALGO_NONE)
590 {
591 attr = pts_hash_alg_error_create(supported_algorithms);
592 attr_list->insert_last(attr_list, attr);
593 break;
594 }
595 pts->set_dh_hash_algorithm(pts, selected_algorithm);
596
597 if (!pts->create_dh_nonce(pts, dh_group, nonce_len))
598 {
599 return TNC_RESULT_FATAL;
600 }
601
602 responder_value = attr_cast->get_responder_value(attr_cast);
603 pts->set_peer_public_value(pts, responder_value,
604 responder_nonce);
605
606 /* Calculate secret assessment value */
607 if (!pts->calculate_secret(pts))
608 {
609 return TNC_RESULT_FATAL;
610 }
611 break;
612 }
613 case TCG_PTS_TPM_VERSION_INFO:
614 {
615 tcg_pts_attr_tpm_version_info_t *attr_cast;
616 chunk_t tpm_version_info;
617
618 attr_cast = (tcg_pts_attr_tpm_version_info_t*)attr;
619 tpm_version_info = attr_cast->get_tpm_version_info(attr_cast);
620 pts->set_tpm_version_info(pts, tpm_version_info);
621 break;
622 }
623 case TCG_PTS_AIK:
624 {
625 tcg_pts_attr_aik_t *attr_cast;
626 certificate_t *aik, *issuer;
627 enumerator_t *e;
628 bool trusted = FALSE;
629
630 attr_cast = (tcg_pts_attr_aik_t*)attr;
631 aik = attr_cast->get_aik(attr_cast);
632 if (!aik)
633 {
634 /* TODO generate error attribute */
635 break;
636 }
637 if (aik->get_type(aik) == CERT_X509)
638 {
639 DBG1(DBG_IMV, "verifying AIK certificate");
640 e = pts_credmgr->create_trusted_enumerator(pts_credmgr,
641 KEY_ANY, aik->get_issuer(aik), FALSE);
642 while (e->enumerate(e, &issuer))
643 {
644 if (aik->issued_by(aik, issuer))
645 {
646 trusted = TRUE;
647 break;
648 }
649 }
650 e->destroy(e);
651 DBG1(DBG_IMV, "AIK certificate is %strusted",
652 trusted ? "" : "not ");
653 }
654 pts->set_aik(pts, aik);
655 break;
656 }
657
658 /* PTS-based Attestation Evidence */
659 case TCG_PTS_SIMPLE_COMP_EVID:
660 {
661 tcg_pts_attr_simple_comp_evid_t *attr_cast;
662 pts_attr_simple_comp_evid_flag_t flags;
663 u_int32_t depth, comp_vendor_id, extended_pcr;
664 u_int8_t family, measurement_type;
665 pts_qualifier_t qualifier;
666 pts_funct_comp_name_t name;
667 pts_meas_algorithms_t hash_algorithm;
668 pts_pcr_transform_t transformation;
669 chunk_t measurement_time, policy_uri, pcr_before, pcr_after, measurement;
670
671 attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
672 attr_info = attr->get_value(attr);
673
674 flags = attr_cast->get_flags(attr_cast);
675 depth = attr_cast->get_sub_component_depth(attr_cast);
676 /* TODO: Implement checking of components with its sub-components */
677 if (depth != 0)
678 {
679 DBG1(DBG_IMV, "Current version of Attestation IMV does not support"
680 "sub component measurement deeper than zero");
681 }
682 comp_vendor_id = attr_cast->get_spec_comp_funct_name_vendor_id(attr_cast);
683 if (comp_vendor_id != PEN_TCG)
684 {
685 DBG1(DBG_IMV, "Current version of Attestation IMV supports"
686 "only functional component namings by TCG ");
687 break;
688 }
689 family = attr_cast->get_family(attr_cast);
690 if (family)
691 {
692 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
693 TCG_PTS_INVALID_NAME_FAM, attr_info);
694 attr_list->insert_last(attr_list, attr);
695 break;
696 }
697 qualifier = attr_cast->get_qualifier(attr_cast);
698 /* Check if Unknown or Wildcard was set for qualifier */
699 if (qualifier.kernel && qualifier.sub_component &&
700 (qualifier.type & PTS_FUNC_COMP_TYPE_ALL))
701 {
702 DBG1(DBG_IMV, "Wildcard was set for the qualifier"
703 "of functional component");
704 return TNC_RESULT_FATAL;
705 }
706 else if (!qualifier.kernel && !qualifier.sub_component &&
707 (qualifier.type & PTS_FUNC_COMP_TYPE_UNKNOWN))
708 {
709 DBG1(DBG_IMV, "Unknown feature was set for the qualifier"
710 "of functional component");
711 return TNC_RESULT_FATAL;
712 }
713 else
714 {
715 /* TODO: Implement what todo with received qualifier */
716 }
717
718 name = attr_cast->get_comp_funct_name(attr_cast);
719 measurement_type = attr_cast->get_measurement_type(attr_cast);
720 hash_algorithm = attr_cast->get_hash_algorithm(attr_cast);
721 transformation = attr_cast->get_pcr_trans(attr_cast);
722 measurement_time = attr_cast->get_measurement_time(attr_cast);
723
724 /* Call getters of optional fields when corresponding flag is set */
725 if (flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR)
726 {
727 extended_pcr = attr_cast->get_extended_pcr(attr_cast);
728 pcr_before = attr_cast->get_pcr_before_value(attr_cast);
729 pcr_after = attr_cast->get_pcr_after_value(attr_cast);
730 measurement = attr_cast->get_comp_measurement(attr_cast);
731 }
732 if (!(flags & PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID))
733 {
734 policy_uri = attr_cast->get_policy_uri(attr_cast);
735 }
736
737 /** TODO: Implement saving the PCR number, Hash Algo = communicated one,
738 * PCR transform (truncate SHA256, SHA384), PCR before and after values
739 */
740 break;
741 }
742
743 case TCG_PTS_SIMPLE_EVID_FINAL:
744 {
745 tcg_pts_attr_simple_evid_final_t *attr_cast;
746 pts_simple_evid_final_flag_t flags;
747 chunk_t pcr_comp = chunk_empty;
748 chunk_t tpm_quote_sign = chunk_empty;
749 chunk_t evid_sign = chunk_empty;
750
751 /** TODO: Ignoring Composite Hash Algorithm field
752 * No flag defined which indicates the precense of it
753 */
754 attr_cast = (tcg_pts_attr_simple_evid_final_t*)attr;
755 flags = attr_cast->get_flags(attr_cast);
756
757 if ((flags >> 6) & PTS_SIMPLE_EVID_FINAL_FLAG_NO)
758 {
759 pcr_comp = attr_cast->get_pcr_comp(attr_cast);
760 tpm_quote_sign = attr_cast->get_tpm_quote_sign(attr_cast);
761
762 /** TODO: Construct PCR Composite */
763 }
764 if (flags & PTS_SIMPLE_EVID_FINAL_FLAG_EVID)
765 {
766 /** TODO: What to do with Evidence Signature */
767 evid_sign = attr_cast->get_evid_sign(attr_cast);
768 }
769
770 break;
771 }
772
773 case TCG_PTS_FILE_MEAS:
774 {
775 tcg_pts_attr_file_meas_t *attr_cast;
776 u_int16_t request_id;
777 int file_count, file_id;
778 pts_meas_algorithms_t algo;
779 pts_file_meas_t *measurements;
780 char *platform_info;
781 enumerator_t *e_hash;
782 bool is_dir;
783
784 platform_info = pts->get_platform_info(pts);
785 if (!pts_db || !platform_info)
786 {
787 break;
788 }
789
790 attr_cast = (tcg_pts_attr_file_meas_t*)attr;
791 measurements = attr_cast->get_measurements(attr_cast);
792 algo = pts->get_meas_algorithm(pts);
793 request_id = measurements->get_request_id(measurements);
794 file_count = measurements->get_file_count(measurements);
795
796 DBG1(DBG_IMV, "measurement request %d returned %d file%s:",
797 request_id, file_count, (file_count == 1) ? "":"s");
798
799 if (!attestation_state->check_off_request(attestation_state,
800 request_id, &file_id, &is_dir))
801 {
802 DBG1(DBG_IMV, " no entry found for this request");
803 break;
804 }
805
806 /* check hashes from database against measurements */
807 e_hash = pts_db->create_hash_enumerator(pts_db,
808 platform_info, algo, file_id, is_dir);
809 if (!measurements->verify(measurements, e_hash, is_dir))
810 {
811 measurement_error = TRUE;
812 }
813 e_hash->destroy(e_hash);
814 break;
815 }
816 case TCG_PTS_UNIX_FILE_META:
817 {
818 tcg_pts_attr_file_meta_t *attr_cast;
819 int file_count;
820 pts_file_meta_t *metadata;
821 enumerator_t *e;
822 pts_file_metadata_t *entry;
823
824 attr_cast = (tcg_pts_attr_file_meta_t*)attr;
825 metadata = attr_cast->get_metadata(attr_cast);
826 file_count = metadata->get_file_count(metadata);
827
828 DBG1(DBG_IMV, "metadata request returned %d file%s:",
829 file_count, (file_count == 1) ? "":"s");
830
831 e = metadata->create_enumerator(metadata);
832 while(e->enumerate(e, &entry))
833 {
834 DBG1(DBG_IMV, "File name: %s", entry->filename);
835 DBG1(DBG_IMV, " type: %d", entry->type);
836 DBG1(DBG_IMV, " size: %d", entry->filesize);
837 DBG1(DBG_IMV, " create time: %s", ctime(&entry->create_time));
838 DBG1(DBG_IMV, " last modified: %s", ctime(&entry->last_modify_time));
839 DBG1(DBG_IMV, " last accessed: %s", ctime(&entry->last_access_time));
840 DBG1(DBG_IMV, " owner id: %d", entry->owner_id);
841 DBG1(DBG_IMV, " group id: %d", entry->group_id);
842 }
843
844 e->destroy(e);
845
846 break;
847 }
848
849 /* TODO: Not implemented yet */
850 case TCG_PTS_INTEG_MEAS_LOG:
851 /* Attributes using XML */
852 case TCG_PTS_TEMPL_REF_MANI_SET_META:
853 case TCG_PTS_VERIFICATION_RESULT:
854 case TCG_PTS_INTEG_REPORT:
855 /* On Windows only*/
856 case TCG_PTS_WIN_FILE_META:
857 case TCG_PTS_REGISTRY_VALUE:
858 /* Received on IMC side only*/
859 case TCG_PTS_REQ_PROTO_CAPS:
860 case TCG_PTS_DH_NONCE_PARAMS_REQ:
861 case TCG_PTS_DH_NONCE_FINISH:
862 case TCG_PTS_MEAS_ALGO:
863 case TCG_PTS_GET_TPM_VERSION_INFO:
864 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
865 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
866 case TCG_PTS_GET_AIK:
867 case TCG_PTS_REQ_FUNCT_COMP_EVID:
868 case TCG_PTS_GEN_ATTEST_EVID:
869 case TCG_PTS_REQ_FILE_META:
870 case TCG_PTS_REQ_FILE_MEAS:
871 case TCG_PTS_REQ_INTEG_MEAS_LOG:
872 default:
873 DBG1(DBG_IMV, "received unsupported attribute '%N'",
874 tcg_attr_names, attr->get_type(attr));
875 break;
876 }
877 }
878 }
879 enumerator->destroy(enumerator);
880 pa_tnc_msg->destroy(pa_tnc_msg);
881
882
883 if (fatal_error)
884 {
885 state->set_recommendation(state,
886 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
887 TNC_IMV_EVALUATION_RESULT_ERROR);
888 return imv_attestation->provide_recommendation(imv_attestation,
889 connection_id);
890 }
891
892 if (attr_list->get_count(attr_list))
893 {
894 pa_tnc_msg = pa_tnc_msg_create();
895
896 enumerator = attr_list->create_enumerator(attr_list);
897 while (enumerator->enumerate(enumerator, &attr))
898 {
899 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
900 }
901 enumerator->destroy(enumerator);
902
903 pa_tnc_msg->build(pa_tnc_msg);
904 result = imv_attestation->send_message(imv_attestation, connection_id,
905 pa_tnc_msg->get_encoding(pa_tnc_msg));
906
907 pa_tnc_msg->destroy(pa_tnc_msg);
908 attr_list->destroy(attr_list);
909
910 return result;
911 }
912 DESTROY_IF(attr_list);
913
914 if (attestation_state->get_handshake_state(attestation_state) &
915 IMV_ATTESTATION_STATE_END)
916 {
917 if (attestation_state->get_request_count(attestation_state))
918 {
919 DBG1(DBG_IMV, "failure due to %d pending file measurements",
920 attestation_state->get_request_count(attestation_state));
921 measurement_error = TRUE;
922 }
923 if (measurement_error)
924 {
925 state->set_recommendation(state,
926 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
927 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR);
928 }
929 else
930 {
931 state->set_recommendation(state,
932 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
933 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
934 }
935 return imv_attestation->provide_recommendation(imv_attestation,
936 connection_id);
937 }
938
939 return send_message(connection_id);
940 }
941
942 /**
943 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
944 */
945 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
946 TNC_ConnectionID connection_id)
947 {
948 if (!imv_attestation)
949 {
950 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
951 return TNC_RESULT_NOT_INITIALIZED;
952 }
953 return imv_attestation->provide_recommendation(imv_attestation, connection_id);
954 }
955
956 /**
957 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
958 */
959 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
960 TNC_ConnectionID connection_id)
961 {
962 imv_state_t *state;
963 imv_attestation_state_t *attestation_state;
964
965 if (!imv_attestation)
966 {
967 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
968 return TNC_RESULT_NOT_INITIALIZED;
969 }
970 /* get current IMV state */
971 if (!imv_attestation->get_state(imv_attestation, connection_id, &state))
972 {
973 return TNC_RESULT_FATAL;
974 }
975 attestation_state = (imv_attestation_state_t*)state;
976
977 /* Check if IMV has to initiate the PA-TNC exchange */
978 if (attestation_state->get_handshake_state(attestation_state) ==
979 IMV_ATTESTATION_STATE_INIT)
980 {
981 return send_message(connection_id);
982 }
983 return TNC_RESULT_SUCCESS;
984 }
985
986 /**
987 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
988 */
989 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
990 {
991 if (!imv_attestation)
992 {
993 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
994 return TNC_RESULT_NOT_INITIALIZED;
995 }
996 if (pts_creds)
997 {
998 pts_credmgr->remove_set(pts_credmgr, pts_creds->get_set(pts_creds));
999 pts_creds->destroy(pts_creds);
1000 }
1001 DESTROY_IF(pts_db);
1002 DESTROY_IF(pts_credmgr);
1003
1004 libpts_deinit();
1005
1006 imv_attestation->destroy(imv_attestation);
1007 imv_attestation = NULL;
1008
1009 return TNC_RESULT_SUCCESS;
1010 }
1011
1012 /**
1013 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
1014 */
1015 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
1016 TNC_TNCS_BindFunctionPointer bind_function)
1017 {
1018 if (!imv_attestation)
1019 {
1020 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
1021 return TNC_RESULT_NOT_INITIALIZED;
1022 }
1023 return imv_attestation->bind_functions(imv_attestation, bind_function);
1024 }