9639c263ba4b308e637e9bdb03f4cff018277007
[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 selected_dh_group = 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 selected_dh_group = 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 selected_dh_group = 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 selected_dh_group = 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 selected_dh_group = 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 /* Create own DH factor */
409 if (!pts->create_dh(pts, selected_dh_group))
410 {
411 goto err;
412 }
413 pts->get_my_public_value(pts, &responder_pub_val);
414
415 /* Send DH Nonce Parameters Response attribute */
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_peer_public_value(pts, initiator_pub_val);
450 if (!pts->calculate_secret(pts, initiator_nonce,
451 responder_non, selected_algorithm))
452 {
453 goto err;
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 goto err;
676 }
677
678 if (!pts->hash_file(pts, hasher, "/etc/tnc_config", hash_output))
679 {
680 hasher->destroy(hasher);
681 goto err;
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 hasher->destroy(hasher);
702 goto err;
703 }
704 params.measurement_time = chunk_create(utc_time, 20);
705 params.measurement_time = chunk_clone(params.measurement_time);
706 free(utc_time);
707
708 }
709
710 params.measurement = chunk_create(hash_output, hasher->get_hash_size(hasher));
711 hasher->destroy(hasher);
712
713 params.policy_uri = chunk_empty;
714 if (!pts->read_pcr(pts, EXTEND_PCR, &params.pcr_before))
715 {
716 DBG1(DBG_IMC, "Error occured while reading PCR: %d", EXTEND_PCR);
717 goto err;
718 }
719
720 if (!pts->extend_pcr(pts, EXTEND_PCR,
721 params.measurement, &params.pcr_after))
722 {
723 DBG1(DBG_IMC, "Error occured while extending PCR: %d", EXTEND_PCR);
724 goto err;
725 }
726
727 /* Buffer Simple Component Evidence attribute */
728 attr = tcg_pts_attr_simple_comp_evid_create(params);
729 evidences->insert_last(evidences, attr);
730
731 break;
732 }
733 case PTS_FUNC_COMP_NAME_IGNORE:
734 case PTS_FUNC_COMP_NAME_CRTM:
735 case PTS_FUNC_COMP_NAME_PLATFORM_EXT:
736 case PTS_FUNC_COMP_NAME_BOARD:
737 case PTS_FUNC_COMP_NAME_INIT_LOADER:
738 case PTS_FUNC_COMP_NAME_OPT_ROMS:
739 default:
740 {
741 DBG1(DBG_IMC, "Unsupported Functional Component Name");
742 break;
743 }
744 }
745
746 break;
747 }
748 case TCG_PTS_GEN_ATTEST_EVID:
749 {
750 enumerator_t *e;
751 pts_simple_evid_final_flag_t flags;
752 chunk_t pcr_composite, quote_signature;
753 linked_list_t *pcrs;
754
755 /* Send buffered Simple Component Evidences */
756 pcrs = linked_list_create();
757
758 e = evidences->create_enumerator(evidences);
759 while (e->enumerate(e, &attr))
760 {
761 tcg_pts_attr_simple_comp_evid_t *attr_cast;
762 u_int32_t extended_pcr;
763
764 attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr;
765 extended_pcr = attr_cast->get_extended_pcr(attr_cast);
766
767 /* Add extended PCR number to PCR list to quote */
768 /* Duplicated PCR numbers have no influence */
769 pcrs->insert_last(pcrs, &extended_pcr);
770 /* Send Simple Compoenent Evidence */
771 attr_list->insert_last(attr_list, attr);
772 }
773
774 /* Quote */
775 if (!pts->quote_tpm(pts, pcrs, &pcr_composite, &quote_signature))
776 {
777 DBG1(DBG_IMC, "Error occured while TPM quote operation");
778 DESTROY_IF(e);
779 DESTROY_IF(pcrs);
780 DESTROY_IF(evidences);
781 goto err;
782 }
783
784 /* Send Simple Evidence Final attribute */
785 flags = PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO;
786
787 attr = tcg_pts_attr_simple_evid_final_create(flags, 0,
788 pcr_composite, quote_signature, chunk_empty);
789 attr_list->insert_last(attr_list, attr);
790
791 DESTROY_IF(e);
792 DESTROY_IF(pcrs);
793 DESTROY_IF(evidences);
794
795 break;
796 }
797 case TCG_PTS_REQ_FILE_META:
798 {
799 tcg_pts_attr_req_file_meta_t *attr_cast;
800 char *pathname;
801 bool is_directory;
802 u_int8_t delimiter;
803 pts_file_meta_t *metadata;
804
805 attr_info = attr->get_value(attr);
806 attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
807 is_directory = attr_cast->get_directory_flag(attr_cast);
808 delimiter = attr_cast->get_delimiter(attr_cast);
809 pathname = attr_cast->get_pathname(attr_cast);
810
811 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
812 if (valid_path && pts_error)
813 {
814 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
815 pts_error, attr_info);
816 attr_list->insert_last(attr_list, attr);
817 break;
818 }
819 else if (!valid_path)
820 {
821 break;
822 }
823 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
824 {
825 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
826 TCG_PTS_INVALID_DELIMITER, attr_info);
827 attr_list->insert_last(attr_list, attr);
828 break;
829 }
830 /* Get File Metadata and send them to PTS-IMV */
831 DBG2(DBG_IMC, "metadata request for %s '%s'",
832 is_directory ? "directory" : "file",
833 pathname);
834 metadata = pts->get_metadata(pts, pathname, is_directory);
835
836 if (!metadata)
837 {
838 /* TODO handle error codes from measurements */
839 goto err;
840 }
841 attr = tcg_pts_attr_unix_file_meta_create(metadata);
842 attr->set_noskip_flag(attr, TRUE);
843 attr_list->insert_last(attr_list, attr);
844
845 break;
846 }
847 case TCG_PTS_REQ_FILE_MEAS:
848 {
849 tcg_pts_attr_req_file_meas_t *attr_cast;
850 char *pathname;
851 u_int16_t request_id;
852 bool is_directory;
853 u_int32_t delimiter;
854 pts_file_meas_t *measurements;
855
856 attr_info = attr->get_value(attr);
857 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
858 is_directory = attr_cast->get_directory_flag(attr_cast);
859 request_id = attr_cast->get_request_id(attr_cast);
860 delimiter = attr_cast->get_delimiter(attr_cast);
861 pathname = attr_cast->get_pathname(attr_cast);
862 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
863
864 if (valid_path && pts_error)
865 {
866 attr_info = attr->get_value(attr);
867 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
868 pts_error, attr_info);
869 attr_list->insert_last(attr_list, attr);
870 break;
871 }
872 else if (!valid_path)
873 {
874 break;
875 }
876
877 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
878 {
879 attr_info = attr->get_value(attr);
880 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
881 TCG_PTS_INVALID_DELIMITER, attr_info);
882 attr_list->insert_last(attr_list, attr);
883 break;
884 }
885
886 /* Do PTS File Measurements and send them to PTS-IMV */
887 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
888 request_id, is_directory ? "directory" : "file",
889 pathname);
890 measurements = pts->do_measurements(pts, request_id,
891 pathname, is_directory);
892 if (!measurements)
893 {
894 /* TODO handle error codes from measurements */
895 goto err;
896 }
897 attr = tcg_pts_attr_file_meas_create(measurements);
898 attr->set_noskip_flag(attr, TRUE);
899 attr_list->insert_last(attr_list, attr);
900 break;
901 }
902 /* TODO: Not implemented yet */
903 case TCG_PTS_REQ_INTEG_MEAS_LOG:
904 /* Attributes using XML */
905 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
906 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
907 /* On Windows only*/
908 case TCG_PTS_REQ_REGISTRY_VALUE:
909 /* Received on IMV side only*/
910 case TCG_PTS_PROTO_CAPS:
911 case TCG_PTS_DH_NONCE_PARAMS_RESP:
912 case TCG_PTS_MEAS_ALGO_SELECTION:
913 case TCG_PTS_TPM_VERSION_INFO:
914 case TCG_PTS_TEMPL_REF_MANI_SET_META:
915 case TCG_PTS_AIK:
916 case TCG_PTS_SIMPLE_COMP_EVID:
917 case TCG_PTS_SIMPLE_EVID_FINAL:
918 case TCG_PTS_VERIFICATION_RESULT:
919 case TCG_PTS_INTEG_REPORT:
920 case TCG_PTS_UNIX_FILE_META:
921 case TCG_PTS_FILE_MEAS:
922 case TCG_PTS_INTEG_MEAS_LOG:
923 default:
924 DBG1(DBG_IMC, "received unsupported attribute '%N'",
925 tcg_attr_names, attr->get_type(attr));
926 break;
927 }
928 }
929 }
930 enumerator->destroy(enumerator);
931 pa_tnc_msg->destroy(pa_tnc_msg);
932
933 result = TNC_RESULT_SUCCESS;
934
935 if (attr_list->get_count(attr_list))
936 {
937 pa_tnc_msg = pa_tnc_msg_create();
938
939 enumerator = attr_list->create_enumerator(attr_list);
940 while (enumerator->enumerate(enumerator, &attr))
941 {
942 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
943 }
944 enumerator->destroy(enumerator);
945
946 pa_tnc_msg->build(pa_tnc_msg);
947 result = imc_attestation->send_message(imc_attestation, connection_id,
948 pa_tnc_msg->get_encoding(pa_tnc_msg));
949 pa_tnc_msg->destroy(pa_tnc_msg);
950 }
951
952 DESTROY_IF(attr_list);
953 return result;
954
955 err:
956 DESTROY_IF(attr_list);
957 return TNC_RESULT_FATAL;
958 }
959
960 /**
961 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
962 */
963 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
964 TNC_ConnectionID connection_id)
965 {
966 if (!imc_attestation)
967 {
968 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
969 return TNC_RESULT_NOT_INITIALIZED;
970 }
971 return TNC_RESULT_SUCCESS;
972 }
973
974 /**
975 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
976 */
977 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
978 {
979 if (!imc_attestation)
980 {
981 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
982 return TNC_RESULT_NOT_INITIALIZED;
983 }
984
985 free(responder_nonce);
986 DESTROY_IF(evidences);
987 libpts_deinit();
988
989 imc_attestation->destroy(imc_attestation);
990 imc_attestation = NULL;
991
992 return TNC_RESULT_SUCCESS;
993 }
994
995 /**
996 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
997 */
998 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
999 TNC_TNCC_BindFunctionPointer bind_function)
1000 {
1001 if (!imc_attestation)
1002 {
1003 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
1004 return TNC_RESULT_NOT_INITIALIZED;
1005 }
1006 return imc_attestation->bind_functions(imc_attestation, bind_function);
1007 }