1e0f3606f475bdc0aeeffc3a3b6d13e4b7a85931
[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 #define _GNU_SOURCE
17
18 #include "imc_attestation_state.h"
19
20 #include <imc/imc_agent.h>
21 #include <pa_tnc/pa_tnc_msg.h>
22 #include <ietf/ietf_attr.h>
23 #include <ietf/ietf_attr_pa_tnc_error.h>
24 #include <ietf/ietf_attr_product_info.h>
25
26 #include <libpts.h>
27
28 #include <pts/pts_error.h>
29
30 #include <tcg/tcg_pts_attr_proto_caps.h>
31 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
32 #include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
33 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
34 #include <tcg/tcg_pts_attr_meas_algo.h>
35 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
36 #include <tcg/tcg_pts_attr_tpm_version_info.h>
37 #include <tcg/tcg_pts_attr_get_aik.h>
38 #include <tcg/tcg_pts_attr_aik.h>
39 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
40 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
41 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
42 #include <tcg/tcg_pts_attr_simple_evid_final.h>
43 #include <tcg/tcg_pts_attr_req_file_meas.h>
44 #include <tcg/tcg_pts_attr_file_meas.h>
45 #include <tcg/tcg_pts_attr_req_file_meta.h>
46 #include <tcg/tcg_pts_attr_unix_file_meta.h>
47
48 #include <tncif_pa_subtypes.h>
49
50 #include <pen/pen.h>
51 #include <debug.h>
52 #include <utils/linked_list.h>
53
54 /* IMC definitions */
55
56 static const char imc_name[] = "Attestation";
57
58 #define IMC_VENDOR_ID PEN_TCG
59 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
60 #define EXTEND_PCR 16
61
62 static imc_agent_t *imc_attestation;
63
64 /**
65 * Supported PTS measurement algorithms
66 */
67 static pts_meas_algorithms_t supported_algorithms = 0;
68
69 /**
70 * Supported PTS Diffie Hellman Groups
71 */
72 static pts_dh_group_t supported_dh_groups = 0;
73
74 /**
75 * High Entropy Random Data
76 * used in calculation of shared secret for the assessment session
77 */
78 static char *responder_nonce = NULL;
79
80 /**
81 * List of buffered Simple Component Evidences
82 * To be sent on reception of Generate Attestation Evidence attribute
83 */
84 static linked_list_t *evidences = NULL;
85
86 /**
87 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
88 */
89 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
90 TNC_Version min_version,
91 TNC_Version max_version,
92 TNC_Version *actual_version)
93 {
94 rng_t *rng;
95
96 if (imc_attestation)
97 {
98 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
99 return TNC_RESULT_ALREADY_INITIALIZED;
100 }
101 if (!pts_meas_probe_algorithms(&supported_algorithms))
102 {
103 return TNC_RESULT_FATAL;
104 }
105 if (!pts_probe_dh_groups(&supported_dh_groups))
106 {
107 return TNC_RESULT_FATAL;
108 }
109 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
110 imc_id, actual_version);
111 if (!imc_attestation)
112 {
113 return TNC_RESULT_FATAL;
114 }
115
116 libpts_init();
117
118 /* create a responder nonce */
119 responder_nonce = (char*)malloc(NONCE_LEN);
120 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
121 if (rng)
122 {
123 rng->get_bytes(rng, NONCE_LEN, responder_nonce);
124 rng->destroy(rng);
125 }
126
127 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
128 {
129 DBG1(DBG_IMC, "no common IF-IMC version");
130 return TNC_RESULT_NO_COMMON_VERSION;
131 }
132 return TNC_RESULT_SUCCESS;
133 }
134
135 /**
136 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
137 */
138 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
139 TNC_ConnectionID connection_id,
140 TNC_ConnectionState new_state)
141 {
142 imc_state_t *state;
143 /* TODO: Not used so far */
144 //imc_attestation_state_t *attestation_state;
145
146 if (!imc_attestation)
147 {
148 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
149 return TNC_RESULT_NOT_INITIALIZED;
150 }
151 switch (new_state)
152 {
153 case TNC_CONNECTION_STATE_CREATE:
154 state = imc_attestation_state_create(connection_id);
155 return imc_attestation->create_state(imc_attestation, state);
156 case TNC_CONNECTION_STATE_DELETE:
157 return imc_attestation->delete_state(imc_attestation, connection_id);
158 case TNC_CONNECTION_STATE_HANDSHAKE:
159 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
160 case TNC_CONNECTION_STATE_ACCESS_NONE:
161 default:
162 return imc_attestation->change_state(imc_attestation, connection_id,
163 new_state, NULL);
164 }
165 }
166
167
168 /**
169 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
170 */
171 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
172 TNC_ConnectionID connection_id)
173 {
174 imc_state_t *state;
175 imc_attestation_state_t *attestation_state;
176 pts_t *pts;
177 char *platform_info;
178 TNC_Result result = TNC_RESULT_SUCCESS;
179
180 if (!imc_attestation)
181 {
182 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
183 return TNC_RESULT_NOT_INITIALIZED;
184 }
185
186 /* get current IMC state */
187 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
188 {
189 return TNC_RESULT_FATAL;
190 }
191 attestation_state = (imc_attestation_state_t*)state;
192 pts = attestation_state->get_pts(attestation_state);
193
194 platform_info = pts->get_platform_info(pts);
195 if (platform_info)
196 {
197 pa_tnc_msg_t *pa_tnc_msg;
198 pa_tnc_attr_t *attr;
199
200 pa_tnc_msg = pa_tnc_msg_create();
201 attr = ietf_attr_product_info_create(0, 0, platform_info);
202 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
203 pa_tnc_msg->build(pa_tnc_msg);
204 result = imc_attestation->send_message(imc_attestation, connection_id,
205 pa_tnc_msg->get_encoding(pa_tnc_msg));
206 pa_tnc_msg->destroy(pa_tnc_msg);
207 }
208
209 evidences = linked_list_create();
210
211 return result;
212 }
213
214 /**
215 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
216 */
217 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
218 TNC_ConnectionID connection_id,
219 TNC_BufferReference msg,
220 TNC_UInt32 msg_len,
221 TNC_MessageType msg_type)
222 {
223 pa_tnc_msg_t *pa_tnc_msg;
224 pa_tnc_attr_t *attr;
225 linked_list_t *attr_list;
226 imc_state_t *state;
227 imc_attestation_state_t *attestation_state;
228 enumerator_t *enumerator;
229 pts_t *pts;
230 TNC_Result result;
231 bool fatal_error = FALSE;
232 chunk_t attr_info;
233 pts_error_code_t pts_error;
234 bool valid_path;
235
236 if (!imc_attestation)
237 {
238 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
239 return TNC_RESULT_NOT_INITIALIZED;
240 }
241
242 /* get current IMC state */
243 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
244 {
245 return TNC_RESULT_FATAL;
246 }
247 attestation_state = (imc_attestation_state_t*)state;
248 pts = attestation_state->get_pts(attestation_state);
249
250 /* parse received PA-TNC message and automatically handle any errors */
251 result = imc_attestation->receive_message(imc_attestation, connection_id,
252 chunk_create(msg, msg_len), msg_type,
253 &pa_tnc_msg);
254
255 /* no parsed PA-TNC attributes available if an error occurred */
256 if (!pa_tnc_msg)
257 {
258 return result;
259 }
260
261 attr_list = linked_list_create();
262
263 /* analyze PA-TNC attributes */
264 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
265 while (enumerator->enumerate(enumerator, &attr))
266 {
267 if (attr->get_vendor_id(attr) == PEN_IETF &&
268 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
269 {
270 ietf_attr_pa_tnc_error_t *error_attr;
271 pa_tnc_error_code_t error_code;
272 chunk_t msg_info, attr_info;
273 u_int32_t offset;
274
275 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
276 error_code = error_attr->get_error_code(error_attr);
277 msg_info = error_attr->get_msg_info(error_attr);
278
279 DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
280 pa_tnc_error_code_names, error_code, &msg_info);
281 switch (error_code)
282 {
283 case PA_ERROR_INVALID_PARAMETER:
284 offset = error_attr->get_offset(error_attr);
285 DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
286 break;
287 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
288 attr_info = error_attr->get_attr_info(error_attr);
289 DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
290 break;
291 default:
292 break;
293 }
294 fatal_error = TRUE;
295 }
296 else if (attr->get_vendor_id(attr) == PEN_TCG)
297 {
298 switch (attr->get_type(attr))
299 {
300 case TCG_PTS_REQ_PROTO_CAPS:
301 {
302 tcg_pts_attr_proto_caps_t *attr_cast;
303 pts_proto_caps_flag_t imc_caps, imv_caps;
304
305 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
306 imv_caps = attr_cast->get_flags(attr_cast);
307 imc_caps = pts->get_proto_caps(pts);
308 pts->set_proto_caps(pts, imc_caps & imv_caps);
309
310 /* Send PTS Protocol Capabilities attribute */
311 attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps,
312 FALSE);
313 attr_list->insert_last(attr_list, attr);
314 break;
315 }
316 case TCG_PTS_MEAS_ALGO:
317 {
318 tcg_pts_attr_meas_algo_t *attr_cast;
319 pts_meas_algorithms_t offered_algorithms, selected_algorithm;
320
321 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
322 offered_algorithms = attr_cast->get_algorithms(attr_cast);
323
324 if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
325 (offered_algorithms & PTS_MEAS_ALGO_SHA384))
326 {
327 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
328 }
329 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
330 (offered_algorithms & PTS_MEAS_ALGO_SHA256))
331 {
332 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
333 }
334
335 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
336 (offered_algorithms & PTS_MEAS_ALGO_SHA1))
337 {
338 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
339 }
340 else
341 {
342 attr = pts_hash_alg_error_create(supported_algorithms);
343 attr_list->insert_last(attr_list, attr);
344 break;
345 }
346
347 /* Send Measurement Algorithm Selection attribute */
348 selected_algorithm = pts->get_meas_algorithm(pts);
349 attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
350 TRUE);
351 attr_list->insert_last(attr_list, attr);
352 break;
353 }
354 case TCG_PTS_DH_NONCE_PARAMS_REQ:
355 {
356 tcg_pts_attr_dh_nonce_params_req_t *attr_cast;
357 u_int8_t min_nonce_len;
358 pts_dh_group_t offered_dh_groups, selected_dh_group;
359 chunk_t responder_pub_val;
360
361 attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr;
362 min_nonce_len = attr_cast->get_min_nonce_len(attr_cast);
363 if (NONCE_LEN < min_nonce_len || NONCE_LEN <= 16)
364 {
365 attr_info = attr->get_value(attr);
366 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
367 TCG_PTS_BAD_NONCE_LENGTH, attr_info);
368 attr_list->insert_last(attr_list, attr);
369 break;
370 }
371
372 offered_dh_groups = attr_cast->get_dh_groups(attr_cast);
373
374 if ((supported_dh_groups & PTS_DH_GROUP_IKE20) &&
375 (offered_dh_groups & PTS_DH_GROUP_IKE20))
376 {
377 pts->set_dh_group(pts, PTS_DH_GROUP_IKE20);
378 }
379 else if ((supported_dh_groups & PTS_DH_GROUP_IKE19) &&
380 (offered_dh_groups & PTS_DH_GROUP_IKE19))
381 {
382 pts->set_dh_group(pts, PTS_DH_GROUP_IKE19);
383 }
384 else if ((supported_dh_groups & PTS_DH_GROUP_IKE14) &&
385 (offered_dh_groups & PTS_DH_GROUP_IKE14))
386 {
387 pts->set_dh_group(pts, PTS_DH_GROUP_IKE14);
388 }
389 else if ((supported_dh_groups & PTS_DH_GROUP_IKE5) &&
390 (offered_dh_groups & PTS_DH_GROUP_IKE5))
391 {
392 pts->set_dh_group(pts, PTS_DH_GROUP_IKE5);
393 }
394 else if ((supported_dh_groups & PTS_DH_GROUP_IKE2) &&
395 (offered_dh_groups & PTS_DH_GROUP_IKE2))
396 {
397 pts->set_dh_group(pts, PTS_DH_GROUP_IKE2);
398 }
399 else
400 {
401 attr_info = attr->get_value(attr);
402 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
403 TCG_PTS_DH_GRPS_NOT_SUPPORTED, attr_info);
404 attr_list->insert_last(attr_list, attr);
405 break;
406 }
407
408 /* Send DH Nonce Parameters Response attribute */
409 selected_dh_group = pts->get_dh_group(pts);
410 if (!pts->create_dh(pts, selected_dh_group))
411 {
412 return TNC_RESULT_FATAL;
413 }
414 pts->get_my_pub_val(pts, &responder_pub_val);
415
416 attr = tcg_pts_attr_dh_nonce_params_resp_create(NONCE_LEN,
417 selected_dh_group, supported_algorithms,
418 chunk_create(responder_nonce, NONCE_LEN),
419 responder_pub_val);
420 attr_list->insert_last(attr_list, attr);
421 break;
422 }
423 case TCG_PTS_DH_NONCE_FINISH:
424 {
425 tcg_pts_attr_dh_nonce_finish_t *attr_cast;
426 u_int8_t nonce_len;
427 pts_meas_algorithms_t selected_algorithm;
428 chunk_t initiator_nonce, initiator_pub_val, responder_non;
429
430 attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
431 nonce_len = attr_cast->get_nonce_len(attr_cast);
432 if (nonce_len < 0 || nonce_len <= 16)
433 {
434 attr_info = attr->get_value(attr);
435 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
436 TCG_PTS_BAD_NONCE_LENGTH, attr_info);
437 attr_list->insert_last(attr_list, attr);
438 break;
439 }
440
441 selected_algorithm = attr_cast->get_hash_algo(attr_cast);
442 initiator_pub_val = attr_cast->get_initiator_pub_val(attr_cast);
443 initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
444 responder_non = chunk_create(responder_nonce, NONCE_LEN);
445
446 DBG3(DBG_IMC, "Initiator nonce: %B", &initiator_nonce);
447 DBG3(DBG_IMC, "Responder nonce: %B", &responder_non);
448
449 pts->set_other_pub_val(pts, initiator_pub_val);
450 if (!pts->calculate_secret(pts, initiator_nonce,
451 responder_non, selected_algorithm))
452 {
453 return TNC_RESULT_FATAL;
454 }
455
456 break;
457 }
458 <<<<<<< HEAD
459 case TCG_PTS_MEAS_ALGO:
460 {
461 tcg_pts_attr_meas_algo_t *attr_cast;
462 pts_meas_algorithms_t offered_algorithms, selected_algorithm;
463
464 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
465 offered_algorithms = attr_cast->get_algorithms(attr_cast);
466
467 if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
468 (offered_algorithms & PTS_MEAS_ALGO_SHA384))
469 {
470 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
471 }
472 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
473 (offered_algorithms & PTS_MEAS_ALGO_SHA256))
474 {
475 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
476 }
477
478 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
479 (offered_algorithms & PTS_MEAS_ALGO_SHA1))
480 {
481 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
482 }
483 else
484 {
485 attr = pts_hash_alg_error_create(supported_algorithms);
486 attr_list->insert_last(attr_list, attr);
487 break;
488 }
489
490 /* Send Measurement Algorithm Selection attribute */
491 selected_algorithm = pts->get_meas_algorithm(pts);
492 attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
493 TRUE);
494 attr_list->insert_last(attr_list, attr);
495 break;
496 }
497 case TCG_PTS_GET_TPM_VERSION_INFO:
498 {
499 chunk_t tpm_version_info, attr_info;
500
501 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
502 {
503 attr_info = attr->get_value(attr);
504 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
505 TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
506 attr_list->insert_last(attr_list, attr);
507 break;
508 }
509
510 /* Send TPM Version Info attribute */
511 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
512 attr_list->insert_last(attr_list, attr);
513 break;
514 }
515 case TCG_PTS_GET_AIK:
516 {
517 certificate_t *aik;
518
519 aik = pts->get_aik(pts);
520 if (!aik)
521 {
522 DBG1(DBG_IMC, "no AIK certificate or public key available");
523 break;
524 }
525
526 /* Send AIK attribute */
527 attr = tcg_pts_attr_aik_create(aik);
528 attr_list->insert_last(attr_list, attr);
529 break;
530 }
531 case TCG_PTS_REQ_FUNCT_COMP_EVID:
532 {
533 tcg_pts_attr_req_funct_comp_evid_t *attr_cast;
534 pts_proto_caps_flag_t negotiated_caps;
535 pts_attr_req_funct_comp_evid_flag_t flags;
536 u_int32_t sub_comp_depth;
537 u_int32_t comp_name_vendor_id;
538 u_int8_t family;
539 pts_qualifier_t qualifier;
540 pts_funct_comp_name_t name;
541
542 attr_info = attr->get_value(attr);
543 attr_cast = (tcg_pts_attr_req_funct_comp_evid_t*)attr;
544 negotiated_caps = pts->get_proto_caps(pts);
545 flags = attr_cast->get_flags(attr_cast);
546
547 if (flags & PTS_REQ_FUNC_COMP_FLAG_TTC)
548 {
549 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
550 TCG_PTS_UNABLE_DET_TTC, attr_info);
551 attr_list->insert_last(attr_list, attr);
552 break;
553 }
554 if (flags & PTS_REQ_FUNC_COMP_FLAG_VER &&
555 !(negotiated_caps & PTS_PROTO_CAPS_V))
556 {
557 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
558 TCG_PTS_UNABLE_LOCAL_VAL, attr_info);
559 attr_list->insert_last(attr_list, attr);
560 break;
561 }
562 if (flags & PTS_REQ_FUNC_COMP_FLAG_CURR &&
563 !(negotiated_caps & PTS_PROTO_CAPS_C))
564 {
565 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
566 TCG_PTS_UNABLE_CUR_EVID, attr_info);
567 attr_list->insert_last(attr_list, attr);
568 break;
569 }
570 if (flags & PTS_REQ_FUNC_COMP_FLAG_PCR &&
571 !(negotiated_caps & PTS_PROTO_CAPS_T))
572 {
573 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
574 TCG_PTS_UNABLE_DET_PCR, attr_info);
575 attr_list->insert_last(attr_list, attr);
576 break;
577 }
578
579 sub_comp_depth = attr_cast->get_sub_component_depth(attr_cast);
580 /* TODO: Implement checking of components with its sub-components */
581 if (sub_comp_depth != 0)
582 {
583 DBG1(DBG_IMC, "Current version of Attestation IMC does not support"
584 "sub component measurement deeper than zero. "
585 "Measuring top level component only.");
586 }
587
588 comp_name_vendor_id = attr_cast->get_comp_funct_name_vendor_id(attr_cast);
589 if (comp_name_vendor_id != PEN_TCG)
590 {
591 DBG1(DBG_IMC, "Current version of Attestation IMC supports"
592 "only functional component namings by TCG ");
593 break;
594 }
595
596 family = attr_cast->get_family(attr_cast);
597 if (family)
598 {
599 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
600 TCG_PTS_INVALID_NAME_FAM, attr_info);
601 attr_list->insert_last(attr_list, attr);
602 break;
603 }
604
605 qualifier = attr_cast->get_qualifier(attr_cast);
606 /* Check if Unknown or Wildcard was set for qualifier */
607 if (qualifier.kernel && qualifier.sub_component &&
608 (qualifier.type & PTS_FUNC_COMP_TYPE_ALL))
609 {
610 DBG2(DBG_IMC, "Wildcard was set for the qualifier of functional"
611 " component. Identifying the component with name binary enumeration");
612 }
613 else if (!qualifier.kernel && !qualifier.sub_component &&
614 (qualifier.type & PTS_FUNC_COMP_TYPE_UNKNOWN))
615 {
616 DBG2(DBG_IMC, "Unknown was set for the qualifier of functional"
617 " component. Identifying the component with name binary enumeration");
618 }
619 else
620 {
621 /* TODO: Implement what todo with received qualifier */
622 }
623
624 name = attr_cast->get_comp_funct_name(attr_cast);
625 switch (name)
626 {
627 case PTS_FUNC_COMP_NAME_BIOS:
628 {
629 tcg_pts_attr_simple_comp_evid_params_t params;
630 pts_qualifier_t qualifier;
631 time_t measurement_time_t;
632 struct tm *time_now;
633 char *utc_time;
634 hasher_t *hasher;
635 u_char hash_output[HASH_SIZE_SHA384];
636 hash_algorithm_t hash_alg;
637
638 /* TODO: Implement BIOS measurement */
639 DBG1(DBG_IMC, "Experimental implementation:"
640 " Extend TPM with etc/tnc_config file");
641
642 params.flags = PTS_SIMPLE_COMP_EVID_FLAG_PCR | PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID;
643 params.depth = 0;
644 params.vendor_id = PEN_TCG;
645
646 qualifier.kernel = FALSE;
647 qualifier.sub_component = FALSE;
648 qualifier.type = PTS_FUNC_COMP_TYPE_TNC;
649 params.qualifier = qualifier;
650
651 params.name = PTS_FUNC_COMP_NAME_BIOS;
652 params.extended_pcr = EXTEND_PCR;
653 params.hash_algorithm = pts->get_meas_algorithm(pts);
654
655 if (!(params.flags & PTS_SIMPLE_COMP_EVID_FLAG_PCR))
656 {
657 params.transformation = PTS_PCR_TRANSFORM_NO;
658 }
659 else if (pts->get_meas_algorithm(pts) & PTS_MEAS_ALGO_SHA1)
660 {
661 params.transformation = PTS_PCR_TRANSFORM_MATCH;
662 }
663 else if (pts->get_meas_algorithm(pts) & PTS_MEAS_ALGO_SHA256)
664 {
665 params.transformation = PTS_PCR_TRANSFORM_LONG;
666 }
667
668 /* Create a hasher */
669 hash_alg = pts_meas_to_hash_algorithm(pts->get_meas_algorithm(pts));
670 hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
671 if (!hasher)
672 {
673 DBG1(DBG_IMC, " hasher %N not available",
674 hash_algorithm_names, hash_alg);
675 return TNC_RESULT_FATAL;
676 }
677
678 if (!pts->hash_file(pts, hasher, "/etc/tnc_config", hash_output))
679 {
680 hasher->destroy(hasher);
681 return TNC_RESULT_FATAL;
682 }
683
684 measurement_time_t = time(NULL);
685 if (!measurement_time_t)
686 {
687 params.measurement_time = chunk_create("0000-00-00T00:00:00Z", 20);
688 }
689 else
690 {
691 time_now = localtime(&measurement_time_t);
692 if (asprintf(&utc_time, "%d-%2.2d-%2.2dT%2.2d:%2.2d:%2.2dZ",
693 time_now->tm_year + 1900,
694 time_now->tm_mon + 1,
695 time_now->tm_mday,
696 time_now->tm_hour,
697 time_now->tm_min,
698 time_now->tm_sec) < 0)
699 {
700 DBG1(DBG_IMC, "Couldn not format local time to UTC");
701 return TNC_RESULT_FATAL;
702 }
703 params.measurement_time = chunk_create(utc_time, 20);
704 }
705
706 params.measurement = chunk_create(hash_output, hasher->get_hash_size(hasher));
707 hasher->destroy(hasher);
708
709 params.policy_uri = chunk_empty;
710 if (!pts->read_pcr(pts, EXTEND_PCR, &params.pcr_before))
711 {
712 DBG1(DBG_IMC, "Error occured while reading PCR: %d", EXTEND_PCR);
713 return TNC_RESULT_FATAL;
714 }
715 if (!pts->extend_pcr(pts, EXTEND_PCR,
716 params.measurement, &params.pcr_after))
717 {
718 DBG1(DBG_IMC, "Error occured while extending PCR: %d", EXTEND_PCR);
719 return TNC_RESULT_FATAL;
720 }
721
722 /* Buffer Simple Component Evidence attribute */
723 attr = tcg_pts_attr_simple_comp_evid_create(params);
724 evidences->insert_last(evidences, attr);
725
726 break;
727 }
728 case PTS_FUNC_COMP_NAME_IGNORE:
729 case PTS_FUNC_COMP_NAME_CRTM:
730 case PTS_FUNC_COMP_NAME_PLATFORM_EXT:
731 case PTS_FUNC_COMP_NAME_BOARD:
732 case PTS_FUNC_COMP_NAME_INIT_LOADER:
733 case PTS_FUNC_COMP_NAME_OPT_ROMS:
734 default:
735 {
736 DBG1(DBG_IMC, "Unsupported Functional Component Name");
737 break;
738 }
739 }
740
741 break;
742 }
743 case TCG_PTS_GEN_ATTEST_EVID:
744 {
745 enumerator_t *e;
746 pts_simple_evid_final_flag_t flags;
747
748 /* Send buffered Simple Component Evidences */
749 e = evidences->create_enumerator(evidences);
750 while (e->enumerate(e, &attr))
751 {
752 attr_list->insert_last(attr_list, attr);
753 }
754
755 /* TODO: TPM quote operation over included PCR's */
756 /* Send Simple Evidence Final attribute */
757 flags = PTS_SIMPLE_EVID_FINAL_FLAG_NO;
758 attr = tcg_pts_attr_simple_evid_final_create(flags, 0,
759 chunk_empty, chunk_empty, chunk_empty);
760 attr_list->insert_last(attr_list, attr);
761
762 e->destroy(e);
763 DESTROY_IF(evidences);
764
765 break;
766 }
767 case TCG_PTS_REQ_FILE_META:
768 {
769 tcg_pts_attr_req_file_meta_t *attr_cast;
770 char *pathname;
771 bool is_directory;
772 u_int8_t delimiter;
773 pts_file_meta_t *metadata;
774
775 attr_info = attr->get_value(attr);
776 attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
777 is_directory = attr_cast->get_directory_flag(attr_cast);
778 delimiter = attr_cast->get_delimiter(attr_cast);
779 pathname = attr_cast->get_pathname(attr_cast);
780
781 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
782 if (valid_path && pts_error)
783 {
784 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
785 pts_error, attr_info);
786 attr_list->insert_last(attr_list, attr);
787 break;
788 }
789 else if (!valid_path)
790 {
791 break;
792 }
793 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
794 {
795 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
796 TCG_PTS_INVALID_DELIMITER, attr_info);
797 attr_list->insert_last(attr_list, attr);
798 break;
799 }
800 /* Get File Metadata and send them to PTS-IMV */
801 DBG2(DBG_IMC, "metadata request for %s '%s'",
802 is_directory ? "directory" : "file",
803 pathname);
804 metadata = pts->get_metadata(pts, pathname, is_directory);
805
806 if (!metadata)
807 {
808 /* TODO handle error codes from measurements */
809 return TNC_RESULT_FATAL;
810 }
811 attr = tcg_pts_attr_unix_file_meta_create(metadata);
812 attr->set_noskip_flag(attr, TRUE);
813 attr_list->insert_last(attr_list, attr);
814
815 break;
816 }
817 case TCG_PTS_REQ_FILE_MEAS:
818 {
819 tcg_pts_attr_req_file_meas_t *attr_cast;
820 char *pathname;
821 u_int16_t request_id;
822 bool is_directory;
823 u_int32_t delimiter;
824 pts_file_meas_t *measurements;
825
826 attr_info = attr->get_value(attr);
827 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
828 is_directory = attr_cast->get_directory_flag(attr_cast);
829 request_id = attr_cast->get_request_id(attr_cast);
830 delimiter = attr_cast->get_delimiter(attr_cast);
831 pathname = attr_cast->get_pathname(attr_cast);
832 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
833
834 if (valid_path && pts_error)
835 {
836 attr_info = attr->get_value(attr);
837 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
838 pts_error, attr_info);
839 attr_list->insert_last(attr_list, attr);
840 break;
841 }
842 else if (!valid_path)
843 {
844 break;
845 }
846
847 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
848 {
849 attr_info = attr->get_value(attr);
850 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
851 TCG_PTS_INVALID_DELIMITER, attr_info);
852 attr_list->insert_last(attr_list, attr);
853 break;
854 }
855
856 /* Do PTS File Measurements and send them to PTS-IMV */
857 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
858 request_id, is_directory ? "directory" : "file",
859 pathname);
860 measurements = pts->do_measurements(pts, request_id,
861 pathname, is_directory);
862 if (!measurements)
863 {
864 /* TODO handle error codes from measurements */
865 return TNC_RESULT_FATAL;
866 }
867 attr = tcg_pts_attr_file_meas_create(measurements);
868 attr->set_noskip_flag(attr, TRUE);
869 attr_list->insert_last(attr_list, attr);
870 break;
871 }
872 /* TODO: Not implemented yet */
873 case TCG_PTS_REQ_INTEG_MEAS_LOG:
874 /* Attributes using XML */
875 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
876 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
877 /* On Windows only*/
878 case TCG_PTS_REQ_REGISTRY_VALUE:
879 /* Received on IMV side only*/
880 case TCG_PTS_PROTO_CAPS:
881 case TCG_PTS_DH_NONCE_PARAMS_RESP:
882 case TCG_PTS_MEAS_ALGO_SELECTION:
883 case TCG_PTS_TPM_VERSION_INFO:
884 case TCG_PTS_TEMPL_REF_MANI_SET_META:
885 case TCG_PTS_AIK:
886 case TCG_PTS_SIMPLE_COMP_EVID:
887 case TCG_PTS_SIMPLE_EVID_FINAL:
888 case TCG_PTS_VERIFICATION_RESULT:
889 case TCG_PTS_INTEG_REPORT:
890 case TCG_PTS_UNIX_FILE_META:
891 case TCG_PTS_FILE_MEAS:
892 case TCG_PTS_INTEG_MEAS_LOG:
893 default:
894 DBG1(DBG_IMC, "received unsupported attribute '%N'",
895 tcg_attr_names, attr->get_type(attr));
896 break;
897 }
898 }
899 }
900 enumerator->destroy(enumerator);
901 pa_tnc_msg->destroy(pa_tnc_msg);
902
903 result = TNC_RESULT_SUCCESS;
904
905 if (attr_list->get_count(attr_list))
906 {
907 pa_tnc_msg = pa_tnc_msg_create();
908
909 enumerator = attr_list->create_enumerator(attr_list);
910 while (enumerator->enumerate(enumerator, &attr))
911 {
912 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
913 }
914 enumerator->destroy(enumerator);
915
916 pa_tnc_msg->build(pa_tnc_msg);
917 result = imc_attestation->send_message(imc_attestation, connection_id,
918 pa_tnc_msg->get_encoding(pa_tnc_msg));
919 pa_tnc_msg->destroy(pa_tnc_msg);
920 }
921 attr_list->destroy(attr_list);
922
923 return result;
924 }
925
926 /**
927 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
928 */
929 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
930 TNC_ConnectionID connection_id)
931 {
932 if (!imc_attestation)
933 {
934 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
935 return TNC_RESULT_NOT_INITIALIZED;
936 }
937 return TNC_RESULT_SUCCESS;
938 }
939
940 /**
941 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
942 */
943 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
944 {
945 if (!imc_attestation)
946 {
947 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
948 return TNC_RESULT_NOT_INITIALIZED;
949 }
950
951 free(responder_nonce);
952 DESTROY_IF(evidences);
953 libpts_deinit();
954
955 imc_attestation->destroy(imc_attestation);
956 imc_attestation = NULL;
957
958 return TNC_RESULT_SUCCESS;
959 }
960
961 /**
962 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
963 */
964 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
965 TNC_TNCC_BindFunctionPointer bind_function)
966 {
967 if (!imc_attestation)
968 {
969 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
970 return TNC_RESULT_NOT_INITIALIZED;
971 }
972 return imc_attestation->bind_functions(imc_attestation, bind_function);
973 }