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