2 * Copyright (C) 2011 Sansar Choinyambuu
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
22 #include "imc_attestation_process.h"
24 #include <ietf/ietf_attr_pa_tnc_error.h>
27 #include <tcg/tcg_pts_attr_proto_caps.h>
28 #include <tcg/tcg_pts_attr_meas_algo.h>
29 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
30 #include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
31 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
32 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
33 #include <tcg/tcg_pts_attr_tpm_version_info.h>
34 #include <tcg/tcg_pts_attr_get_aik.h>
35 #include <tcg/tcg_pts_attr_aik.h>
36 #include <tcg/tcg_pts_attr_req_func_comp_evid.h>
37 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
38 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
39 #include <tcg/tcg_pts_attr_simple_evid_final.h>
40 #include <tcg/tcg_pts_attr_req_file_meas.h>
41 #include <tcg/tcg_pts_attr_file_meas.h>
42 #include <tcg/tcg_pts_attr_req_file_meta.h>
43 #include <tcg/tcg_pts_attr_unix_file_meta.h>
46 #include <utils/lexparser.h>
48 #define DEFAULT_NONCE_LEN 20
51 * Set parameters of Simple Component Evidence
53 static bool set_simple_comp_evid_params(pts_t
*pts
, pts_comp_func_name_t
*name
,
54 u_int8_t sequence
, tcg_pts_attr_simple_comp_evid_params_t
*out
)
56 tcg_pts_attr_simple_comp_evid_params_t params
;
57 time_t measurement_time_t
;
62 params
.pcr_info_included
= TRUE
;
63 params
.flags
= PTS_SIMPLE_COMP_EVID_FLAG_NO_VALID
;
66 /* The measurements done by tboot and trustedGRUB are SHA1 hashes */
67 params
.hash_algorithm
= TRUSTED_HASH_ALGO
;
68 params
.transformation
= PTS_PCR_TRANSFORM_NO
;
70 measurement_time_t
= time(NULL
);
71 if (!measurement_time_t
)
73 params
.measurement_time
= chunk_create("0000-00-00T00:00:00Z", 20);
74 params
.measurement_time
= chunk_clone(params
.measurement_time
);
78 time_now
= localtime(&measurement_time_t
);
79 if (asprintf(&utc_time
,
80 "%d-%.2d-%.2dT%.2d:%.2d:%.2dZ",
81 time_now
->tm_year
+ 1900,
86 time_now
->tm_sec
) < 0)
88 DBG1(DBG_IMC
, "could not format local time to UTC");
91 params
.measurement_time
= chunk_create(utc_time
, 20);
92 params
.measurement_time
= chunk_clone(params
.measurement_time
);
96 params
.policy_uri
= chunk_empty
;
98 /* Provisional/temporal implementation for components except tboot */
99 if (params
.name
->get_name(params
.name
) == PTS_ITA_COMP_FUNC_NAME_TGRUB
)
101 params
.extended_pcr
= PCR_DEBUG
;
103 params
.measurement
= chunk_alloc(HASH_SIZE_SHA1
);
104 memset(params
.measurement
.ptr
, 0, HASH_SIZE_SHA1
);
106 params
.pcr_before
= chunk_alloc(PCR_LEN
);
107 memset(params
.pcr_before
.ptr
, 0, PCR_LEN
);
109 if(!pts
->read_pcr(pts
, params
.extended_pcr
, ¶ms
.pcr_after
))
111 DBG1(DBG_IMC
, "error occured while reading PCR: %d",
112 params
.extended_pcr
);
116 /* Set parameters which varies from component to component */
117 else if (params
.name
->get_name(params
.name
) == PTS_ITA_COMP_FUNC_NAME_TBOOT
)
119 char *measurement
, *pcr_before
, *pcr_after
;
123 params
.extended_pcr
= PCR_TBOOT_POLICY
;
124 measurement
= lib
->settings
->get_str(lib
->settings
,
125 "libimcv.plugins.imc-attestation.pcr17_meas", NULL
);
126 pcr_before
= lib
->settings
->get_str(lib
->settings
,
127 "libimcv.plugins.imc-attestation.pcr17_before", NULL
);
128 pcr_after
= lib
->settings
->get_str(lib
->settings
,
129 "libimcv.plugins.imc-attestation.pcr17_after", NULL
);
133 params
.extended_pcr
= PCR_TBOOT_MLE
;
134 measurement
= lib
->settings
->get_str(lib
->settings
,
135 "libimcv.plugins.imc-attestation.pcr18_meas", NULL
);
136 pcr_before
= lib
->settings
->get_str(lib
->settings
,
137 "libimcv.plugins.imc-attestation.pcr18_before", NULL
);
138 pcr_after
= lib
->settings
->get_str(lib
->settings
,
139 "libimcv.plugins.imc-attestation.pcr18_after", NULL
);
142 if (!measurement
|| !pcr_before
|| !pcr_after
)
144 DBG1(DBG_IMC
, "tboot: configure measurement, before and after value"
145 " for PCR%d", params
.extended_pcr
);
149 params
.measurement
= chunk_from_hex(
150 chunk_create(measurement
, strlen(measurement
)), NULL
);
151 params
.pcr_before
= chunk_from_hex(
152 chunk_create(pcr_before
, strlen(pcr_before
)), NULL
);
153 params
.pcr_after
= chunk_from_hex(
154 chunk_create(pcr_after
, strlen(pcr_after
)), NULL
);
159 DBG1(DBG_IMC
, "unsupported Functional Component Name: Vendor ID: %d"
160 " Name: %d, Qualifier: %d",
161 params
.name
->get_vendor_id(params
.name
),
162 params
.name
->get_name(params
.name
),
163 params
.name
->get_qualifier(params
.name
));
171 bool imc_attestation_process(pa_tnc_attr_t
*attr
, linked_list_t
*attr_list
,
172 imc_attestation_state_t
*attestation_state
,
173 pts_meas_algorithms_t supported_algorithms
,
174 pts_dh_group_t supported_dh_groups
,
175 linked_list_t
*evidences
)
179 pts_error_code_t pts_error
;
182 pts
= attestation_state
->get_pts(attestation_state
);
183 switch (attr
->get_type(attr
))
185 case TCG_PTS_REQ_PROTO_CAPS
:
187 tcg_pts_attr_proto_caps_t
*attr_cast
;
188 pts_proto_caps_flag_t imc_caps
, imv_caps
;
190 attr_cast
= (tcg_pts_attr_proto_caps_t
*)attr
;
191 imv_caps
= attr_cast
->get_flags(attr_cast
);
192 imc_caps
= pts
->get_proto_caps(pts
);
193 pts
->set_proto_caps(pts
, imc_caps
& imv_caps
);
195 /* Send PTS Protocol Capabilities attribute */
196 attr
= tcg_pts_attr_proto_caps_create(imc_caps
& imv_caps
, FALSE
);
197 attr_list
->insert_last(attr_list
, attr
);
200 case TCG_PTS_MEAS_ALGO
:
202 tcg_pts_attr_meas_algo_t
*attr_cast
;
203 pts_meas_algorithms_t offered_algorithms
, selected_algorithm
;
205 attr_cast
= (tcg_pts_attr_meas_algo_t
*)attr
;
206 offered_algorithms
= attr_cast
->get_algorithms(attr_cast
);
207 selected_algorithm
= pts_meas_algo_select(supported_algorithms
,
209 if (selected_algorithm
== PTS_MEAS_ALGO_NONE
)
211 attr
= pts_hash_alg_error_create(supported_algorithms
);
212 attr_list
->insert_last(attr_list
, attr
);
216 /* Send Measurement Algorithm Selection attribute */
217 pts
->set_meas_algorithm(pts
, selected_algorithm
);
218 attr
= tcg_pts_attr_meas_algo_create(selected_algorithm
, TRUE
);
219 attr_list
->insert_last(attr_list
, attr
);
222 case TCG_PTS_DH_NONCE_PARAMS_REQ
:
224 tcg_pts_attr_dh_nonce_params_req_t
*attr_cast
;
225 pts_dh_group_t offered_dh_groups
, selected_dh_group
;
226 chunk_t responder_value
, responder_nonce
;
227 int nonce_len
, min_nonce_len
;
229 nonce_len
= lib
->settings
->get_int(lib
->settings
,
230 "libimcv.plugins.imc-attestation.nonce_len",
233 attr_cast
= (tcg_pts_attr_dh_nonce_params_req_t
*)attr
;
234 min_nonce_len
= attr_cast
->get_min_nonce_len(attr_cast
);
235 if (nonce_len
< PTS_MIN_NONCE_LEN
||
236 (min_nonce_len
> 0 && nonce_len
< min_nonce_len
))
238 attr
= pts_dh_nonce_error_create(nonce_len
, PTS_MAX_NONCE_LEN
);
239 attr_list
->insert_last(attr_list
, attr
);
243 offered_dh_groups
= attr_cast
->get_dh_groups(attr_cast
);
244 selected_dh_group
= pts_dh_group_select(supported_dh_groups
,
246 if (selected_dh_group
== PTS_DH_GROUP_NONE
)
248 attr
= pts_dh_group_error_create(supported_dh_groups
);
249 attr_list
->insert_last(attr_list
, attr
);
253 /* Create own DH factor and nonce */
254 if (!pts
->create_dh_nonce(pts
, selected_dh_group
, nonce_len
))
258 pts
->get_my_public_value(pts
, &responder_value
, &responder_nonce
);
260 /* Send DH Nonce Parameters Response attribute */
261 attr
= tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group
,
262 supported_algorithms
, responder_nonce
, responder_value
);
263 attr_list
->insert_last(attr_list
, attr
);
266 case TCG_PTS_DH_NONCE_FINISH
:
268 tcg_pts_attr_dh_nonce_finish_t
*attr_cast
;
269 pts_meas_algorithms_t selected_algorithm
;
270 chunk_t initiator_nonce
, initiator_value
;
273 attr_cast
= (tcg_pts_attr_dh_nonce_finish_t
*)attr
;
274 selected_algorithm
= attr_cast
->get_hash_algo(attr_cast
);
275 if (!(selected_algorithm
& supported_algorithms
))
277 DBG1(DBG_IMC
, "PTS-IMV selected unsupported DH hash algorithm");
280 pts
->set_dh_hash_algorithm(pts
, selected_algorithm
);
282 initiator_value
= attr_cast
->get_initiator_value(attr_cast
);
283 initiator_nonce
= attr_cast
->get_initiator_nonce(attr_cast
);
285 nonce_len
= lib
->settings
->get_int(lib
->settings
,
286 "libimcv.plugins.imc-attestation.nonce_len",
288 if (nonce_len
!= initiator_nonce
.len
)
290 DBG1(DBG_IMC
, "initiator and responder DH nonces "
291 "have differing lengths");
295 pts
->set_peer_public_value(pts
, initiator_value
, initiator_nonce
);
296 if (!pts
->calculate_secret(pts
))
302 case TCG_PTS_GET_TPM_VERSION_INFO
:
304 chunk_t tpm_version_info
, attr_info
;
306 if (!pts
->get_tpm_version_info(pts
, &tpm_version_info
))
308 attr_info
= attr
->get_value(attr
);
309 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
310 TCG_PTS_TPM_VERS_NOT_SUPPORTED
, attr_info
);
311 attr_list
->insert_last(attr_list
, attr
);
315 /* Send TPM Version Info attribute */
316 attr
= tcg_pts_attr_tpm_version_info_create(tpm_version_info
);
317 attr_list
->insert_last(attr_list
, attr
);
320 case TCG_PTS_GET_AIK
:
324 aik
= pts
->get_aik(pts
);
327 DBG1(DBG_IMC
, "no AIK certificate or public key available");
331 /* Send AIK attribute */
332 attr
= tcg_pts_attr_aik_create(aik
);
333 attr_list
->insert_last(attr_list
, attr
);
336 case TCG_PTS_REQ_FILE_MEAS
:
338 tcg_pts_attr_req_file_meas_t
*attr_cast
;
340 u_int16_t request_id
;
343 pts_file_meas_t
*measurements
;
345 attr_info
= attr
->get_value(attr
);
346 attr_cast
= (tcg_pts_attr_req_file_meas_t
*)attr
;
347 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
348 request_id
= attr_cast
->get_request_id(attr_cast
);
349 delimiter
= attr_cast
->get_delimiter(attr_cast
);
350 pathname
= attr_cast
->get_pathname(attr_cast
);
351 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
353 if (valid_path
&& pts_error
)
355 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
356 pts_error
, attr_info
);
357 attr_list
->insert_last(attr_list
, attr
);
360 else if (!valid_path
)
365 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
367 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
368 TCG_PTS_INVALID_DELIMITER
, attr_info
);
369 attr_list
->insert_last(attr_list
, attr
);
373 /* Do PTS File Measurements and send them to PTS-IMV */
374 DBG2(DBG_IMC
, "measurement request %d for %s '%s'",
375 request_id
, is_directory ?
"directory" : "file",
377 measurements
= pts
->do_measurements(pts
, request_id
,
378 pathname
, is_directory
);
381 /* TODO handle error codes from measurements */
384 attr
= tcg_pts_attr_file_meas_create(measurements
);
385 attr
->set_noskip_flag(attr
, TRUE
);
386 attr_list
->insert_last(attr_list
, attr
);
389 case TCG_PTS_REQ_FILE_META
:
391 tcg_pts_attr_req_file_meta_t
*attr_cast
;
395 pts_file_meta_t
*metadata
;
397 attr_info
= attr
->get_value(attr
);
398 attr_cast
= (tcg_pts_attr_req_file_meta_t
*)attr
;
399 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
400 delimiter
= attr_cast
->get_delimiter(attr_cast
);
401 pathname
= attr_cast
->get_pathname(attr_cast
);
403 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
404 if (valid_path
&& pts_error
)
406 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
407 pts_error
, attr_info
);
408 attr_list
->insert_last(attr_list
, attr
);
411 else if (!valid_path
)
415 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
417 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
418 TCG_PTS_INVALID_DELIMITER
, attr_info
);
419 attr_list
->insert_last(attr_list
, attr
);
422 /* Get File Metadata and send them to PTS-IMV */
423 DBG2(DBG_IMC
, "metadata request for %s '%s'",
424 is_directory ?
"directory" : "file",
426 metadata
= pts
->get_metadata(pts
, pathname
, is_directory
);
430 /* TODO handle error codes from measurements */
433 attr
= tcg_pts_attr_unix_file_meta_create(metadata
);
434 attr
->set_noskip_flag(attr
, TRUE
);
435 attr_list
->insert_last(attr_list
, attr
);
439 case TCG_PTS_REQ_FUNC_COMP_EVID
:
441 tcg_pts_attr_req_func_comp_evid_t
*attr_cast
;
442 pts_proto_caps_flag_t negotiated_caps
;
443 pts_comp_func_name_t
*name
;
448 attr_info
= attr
->get_value(attr
);
449 attr_cast
= (tcg_pts_attr_req_func_comp_evid_t
*)attr
;
451 DBG1(DBG_IMC
, "IMV requests evidence for %d functional components",
452 attr_cast
->get_count(attr_cast
));
454 e
= attr_cast
->create_enumerator(attr_cast
);
455 while (e
->enumerate(e
, &flags
, &depth
, &name
))
457 negotiated_caps
= pts
->get_proto_caps(pts
);
459 DBG1(DBG_IMC
, "Requested Evidence flags: %d, depth: %d,"
460 " vendor_id: %d, qualifier %d, name: %d",
461 flags
, depth
, name
->get_vendor_id(name
),
462 name
->get_qualifier(name
), name
->get_name(name
));
464 if (flags
& PTS_REQ_FUNC_COMP_FLAG_TTC
)
466 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
467 TCG_PTS_UNABLE_DET_TTC
, attr_info
);
468 attr_list
->insert_last(attr_list
, attr
);
471 if (flags
& PTS_REQ_FUNC_COMP_FLAG_VER
&&
472 !(negotiated_caps
& PTS_PROTO_CAPS_V
))
474 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
475 TCG_PTS_UNABLE_LOCAL_VAL
, attr_info
);
476 attr_list
->insert_last(attr_list
, attr
);
479 if (flags
& PTS_REQ_FUNC_COMP_FLAG_CURR
&&
480 !(negotiated_caps
& PTS_PROTO_CAPS_C
))
482 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
483 TCG_PTS_UNABLE_CUR_EVID
, attr_info
);
484 attr_list
->insert_last(attr_list
, attr
);
487 if (flags
& PTS_REQ_FUNC_COMP_FLAG_PCR
&&
488 !(negotiated_caps
& PTS_PROTO_CAPS_T
))
490 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
491 TCG_PTS_UNABLE_DET_PCR
, attr_info
);
492 attr_list
->insert_last(attr_list
, attr
);
497 DBG1(DBG_IMC
, "current version of Attestation IMC does not "
498 "support sub component measurement deeper than "
499 "zero. Measuring top level component only.");
502 if (name
->get_vendor_id(name
) != PEN_ITA
)
504 DBG1(DBG_IMC
, "current version of Attestation IMC supports"
505 "only functional component namings by ITA");
509 /* Check if Unknown or Wildcard was set for qualifier */
510 if (name
->get_qualifier(name
) & PTS_QUALIFIER_WILDCARD
)
512 DBG2(DBG_IMC
, "wildcard was set for the qualifier of functional"
513 " component. Identifying the component with "
514 "name binary enumeration");
516 else if (name
->get_qualifier(name
) & PTS_QUALIFIER_UNKNOWN
)
518 DBG2(DBG_IMC
, "unknown was set for the qualifier of functional"
519 " component. Identifying the component with "
520 "name binary enumeration");
522 else if ((name
->get_qualifier(name
) >> PTS_ITA_QUALIFIER_TYPE_SIZE
)
523 & PTS_ITA_QUALIFIER_TYPE_TRUSTED
)
525 tcg_pts_attr_simple_comp_evid_params_t params
;
527 if (name
->get_name(name
) == PTS_ITA_COMP_FUNC_NAME_TBOOT
)
530 for (i
= 1; i
<= TBOOT_SEQUENCE_COUNT
; i
++)
532 /* Set parameters of Simple Component Evidence */
533 if (!set_simple_comp_evid_params(pts
, name
, i
, ¶ms
))
535 DBG1(DBG_IMC
, "error occured while setting "
536 " parameters for Simple Component Evidence");
539 /* Buffer Simple Component Evidence attribute */
540 attr
= tcg_pts_attr_simple_comp_evid_create(params
);
541 evidences
->insert_last(evidences
, attr
);
548 /* Set parameters of Simple Component Evidence */
549 if (!set_simple_comp_evid_params(pts
, name
, 0, ¶ms
))
551 DBG1(DBG_IMC
, "error occured while setting parameters"
552 "for Simple Component Evidence");
556 /* Buffer Simple Component Evidence attribute */
557 attr
= tcg_pts_attr_simple_comp_evid_create(params
);
558 evidences
->insert_last(evidences
, attr
);
565 DBG1(DBG_IMC
, "Functional Component with unsupported type: %d"
566 "was requested for evidence",
567 (name
->get_qualifier(name
) >> PTS_ITA_QUALIFIER_TYPE_SIZE
));
574 case TCG_PTS_GEN_ATTEST_EVID
:
577 pts_simple_evid_final_flag_t flags
;
578 pts_meas_algorithms_t composite_algorithm
= 0;
579 chunk_t pcr_composite
, quote_signature
;
580 u_int32_t num_of_evidences
, i
= 0;
584 /* Send buffered Simple Component Evidences */
585 num_of_evidences
= evidences
->get_count(evidences
);
586 pcrs
= (u_int32_t
*)malloc(sizeof(u_int32_t
)*num_of_evidences
);
588 e
= evidences
->create_enumerator(evidences
);
589 while (e
->enumerate(e
, &attr
))
591 tcg_pts_attr_simple_comp_evid_t
*attr_cast
;
592 u_int32_t extended_pcr
;
594 attr_cast
= (tcg_pts_attr_simple_comp_evid_t
*)attr
;
595 extended_pcr
= attr_cast
->get_extended_pcr(attr_cast
);
597 /* Add extended PCR number to PCR list to quote */
598 /* Duplicated PCR numbers have no influence */
599 pcrs
[i
] = extended_pcr
;
601 /* Send Simple Compoenent Evidence */
602 attr_list
->insert_last(attr_list
, attr
);
605 use_quote2
= (lib
->settings
->get_int(lib
->settings
,
606 "libimcv.plugins.imc-attestation.quote_version", 1) == 1) ?
610 if (!pts
->quote_tpm(pts
, use_quote2
, pcrs
, num_of_evidences
,
611 &pcr_composite
, "e_signature
))
613 DBG1(DBG_IMC
, "error occured during TPM quote operation");
615 DESTROY_IF(evidences
);
619 /* Send Simple Evidence Final attribute */
620 flags
= use_quote2 ? PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2
:
621 PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO
;
622 composite_algorithm
|= PTS_MEAS_ALGO_SHA1
;
624 attr
= tcg_pts_attr_simple_evid_final_create(FALSE
, flags
,
625 composite_algorithm
, pcr_composite
,
626 quote_signature
, chunk_empty
);
627 attr_list
->insert_last(attr_list
, attr
);
630 DESTROY_IF(evidences
);
634 /* TODO: Not implemented yet */
635 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
636 /* Attributes using XML */
637 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
638 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
640 case TCG_PTS_REQ_REGISTRY_VALUE
:
641 /* Received on IMV side only*/
642 case TCG_PTS_PROTO_CAPS
:
643 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
644 case TCG_PTS_MEAS_ALGO_SELECTION
:
645 case TCG_PTS_TPM_VERSION_INFO
:
646 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
648 case TCG_PTS_SIMPLE_COMP_EVID
:
649 case TCG_PTS_SIMPLE_EVID_FINAL
:
650 case TCG_PTS_VERIFICATION_RESULT
:
651 case TCG_PTS_INTEG_REPORT
:
652 case TCG_PTS_UNIX_FILE_META
:
653 case TCG_PTS_FILE_MEAS
:
654 case TCG_PTS_INTEG_MEAS_LOG
:
656 DBG1(DBG_IMC
, "received unsupported attribute '%N'",
657 tcg_attr_names
, attr
->get_type(attr
));