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