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>
29 #include <tcg/tcg_pts_attr_proto_caps.h>
30 #include <tcg/tcg_pts_attr_meas_algo.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_get_tpm_version_info.h>
35 #include <tcg/tcg_pts_attr_tpm_version_info.h>
36 #include <tcg/tcg_pts_attr_get_aik.h>
37 #include <tcg/tcg_pts_attr_aik.h>
38 #include <tcg/tcg_pts_attr_req_func_comp_evid.h>
39 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
40 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
41 #include <tcg/tcg_pts_attr_simple_evid_final.h>
42 #include <tcg/tcg_pts_attr_req_file_meas.h>
43 #include <tcg/tcg_pts_attr_file_meas.h>
44 #include <tcg/tcg_pts_attr_req_file_meta.h>
45 #include <tcg/tcg_pts_attr_unix_file_meta.h>
48 #include <utils/lexparser.h>
50 #define DEFAULT_NONCE_LEN 20
52 bool imc_attestation_process(pa_tnc_attr_t
*attr
, linked_list_t
*attr_list
,
53 imc_attestation_state_t
*attestation_state
,
54 pts_meas_algorithms_t supported_algorithms
,
55 pts_dh_group_t supported_dh_groups
)
59 pts_error_code_t pts_error
;
62 pts
= attestation_state
->get_pts(attestation_state
);
63 switch (attr
->get_type(attr
))
65 case TCG_PTS_REQ_PROTO_CAPS
:
67 tcg_pts_attr_proto_caps_t
*attr_cast
;
68 pts_proto_caps_flag_t imc_caps
, imv_caps
;
70 attr_cast
= (tcg_pts_attr_proto_caps_t
*)attr
;
71 imv_caps
= attr_cast
->get_flags(attr_cast
);
72 imc_caps
= pts
->get_proto_caps(pts
);
73 pts
->set_proto_caps(pts
, imc_caps
& imv_caps
);
75 /* Send PTS Protocol Capabilities attribute */
76 attr
= tcg_pts_attr_proto_caps_create(imc_caps
& imv_caps
, FALSE
);
77 attr_list
->insert_last(attr_list
, attr
);
80 case TCG_PTS_MEAS_ALGO
:
82 tcg_pts_attr_meas_algo_t
*attr_cast
;
83 pts_meas_algorithms_t offered_algorithms
, selected_algorithm
;
85 attr_cast
= (tcg_pts_attr_meas_algo_t
*)attr
;
86 offered_algorithms
= attr_cast
->get_algorithms(attr_cast
);
87 selected_algorithm
= pts_meas_algo_select(supported_algorithms
,
89 if (selected_algorithm
== PTS_MEAS_ALGO_NONE
)
91 attr
= pts_hash_alg_error_create(supported_algorithms
);
92 attr_list
->insert_last(attr_list
, attr
);
96 /* Send Measurement Algorithm Selection attribute */
97 pts
->set_meas_algorithm(pts
, selected_algorithm
);
98 attr
= tcg_pts_attr_meas_algo_create(selected_algorithm
, TRUE
);
99 attr_list
->insert_last(attr_list
, attr
);
102 case TCG_PTS_DH_NONCE_PARAMS_REQ
:
104 tcg_pts_attr_dh_nonce_params_req_t
*attr_cast
;
105 pts_dh_group_t offered_dh_groups
, selected_dh_group
;
106 chunk_t responder_value
, responder_nonce
;
107 int nonce_len
, min_nonce_len
;
109 nonce_len
= lib
->settings
->get_int(lib
->settings
,
110 "libimcv.plugins.imc-attestation.nonce_len",
113 attr_cast
= (tcg_pts_attr_dh_nonce_params_req_t
*)attr
;
114 min_nonce_len
= attr_cast
->get_min_nonce_len(attr_cast
);
115 if (nonce_len
< PTS_MIN_NONCE_LEN
||
116 (min_nonce_len
> 0 && nonce_len
< min_nonce_len
))
118 attr
= pts_dh_nonce_error_create(nonce_len
, PTS_MAX_NONCE_LEN
);
119 attr_list
->insert_last(attr_list
, attr
);
123 offered_dh_groups
= attr_cast
->get_dh_groups(attr_cast
);
124 selected_dh_group
= pts_dh_group_select(supported_dh_groups
,
126 if (selected_dh_group
== PTS_DH_GROUP_NONE
)
128 attr
= pts_dh_group_error_create(supported_dh_groups
);
129 attr_list
->insert_last(attr_list
, attr
);
133 /* Create own DH factor and nonce */
134 if (!pts
->create_dh_nonce(pts
, selected_dh_group
, nonce_len
))
138 pts
->get_my_public_value(pts
, &responder_value
, &responder_nonce
);
140 /* Send DH Nonce Parameters Response attribute */
141 attr
= tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group
,
142 supported_algorithms
, responder_nonce
, responder_value
);
143 attr_list
->insert_last(attr_list
, attr
);
146 case TCG_PTS_DH_NONCE_FINISH
:
148 tcg_pts_attr_dh_nonce_finish_t
*attr_cast
;
149 pts_meas_algorithms_t selected_algorithm
;
150 chunk_t initiator_nonce
, initiator_value
;
153 attr_cast
= (tcg_pts_attr_dh_nonce_finish_t
*)attr
;
154 selected_algorithm
= attr_cast
->get_hash_algo(attr_cast
);
155 if (!(selected_algorithm
& supported_algorithms
))
157 DBG1(DBG_IMC
, "PTS-IMV selected unsupported DH hash algorithm");
160 pts
->set_dh_hash_algorithm(pts
, selected_algorithm
);
162 initiator_value
= attr_cast
->get_initiator_value(attr_cast
);
163 initiator_nonce
= attr_cast
->get_initiator_nonce(attr_cast
);
165 nonce_len
= lib
->settings
->get_int(lib
->settings
,
166 "libimcv.plugins.imc-attestation.nonce_len",
168 if (nonce_len
!= initiator_nonce
.len
)
170 DBG1(DBG_IMC
, "initiator and responder DH nonces "
171 "have differing lengths");
175 pts
->set_peer_public_value(pts
, initiator_value
, initiator_nonce
);
176 if (!pts
->calculate_secret(pts
))
182 case TCG_PTS_GET_TPM_VERSION_INFO
:
184 chunk_t tpm_version_info
, attr_info
;
186 if (!pts
->get_tpm_version_info(pts
, &tpm_version_info
))
188 attr_info
= attr
->get_value(attr
);
189 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
190 TCG_PTS_TPM_VERS_NOT_SUPPORTED
, attr_info
);
191 attr_list
->insert_last(attr_list
, attr
);
195 /* Send TPM Version Info attribute */
196 attr
= tcg_pts_attr_tpm_version_info_create(tpm_version_info
);
197 attr_list
->insert_last(attr_list
, attr
);
200 case TCG_PTS_GET_AIK
:
204 aik
= pts
->get_aik(pts
);
207 DBG1(DBG_IMC
, "no AIK certificate or public key available");
211 /* Send AIK attribute */
212 attr
= tcg_pts_attr_aik_create(aik
);
213 attr_list
->insert_last(attr_list
, attr
);
216 case TCG_PTS_REQ_FILE_MEAS
:
218 tcg_pts_attr_req_file_meas_t
*attr_cast
;
220 u_int16_t request_id
;
223 pts_file_meas_t
*measurements
;
225 attr_info
= attr
->get_value(attr
);
226 attr_cast
= (tcg_pts_attr_req_file_meas_t
*)attr
;
227 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
228 request_id
= attr_cast
->get_request_id(attr_cast
);
229 delimiter
= attr_cast
->get_delimiter(attr_cast
);
230 pathname
= attr_cast
->get_pathname(attr_cast
);
231 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
233 if (valid_path
&& pts_error
)
235 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
236 pts_error
, attr_info
);
237 attr_list
->insert_last(attr_list
, attr
);
240 else if (!valid_path
)
245 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
247 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
248 TCG_PTS_INVALID_DELIMITER
, attr_info
);
249 attr_list
->insert_last(attr_list
, attr
);
253 /* Do PTS File Measurements and send them to PTS-IMV */
254 DBG2(DBG_IMC
, "measurement request %d for %s '%s'",
255 request_id
, is_directory ?
"directory" : "file",
257 measurements
= pts
->do_measurements(pts
, request_id
,
258 pathname
, is_directory
);
261 /* TODO handle error codes from measurements */
264 attr
= tcg_pts_attr_file_meas_create(measurements
);
265 attr
->set_noskip_flag(attr
, TRUE
);
266 attr_list
->insert_last(attr_list
, attr
);
269 case TCG_PTS_REQ_FILE_META
:
271 tcg_pts_attr_req_file_meta_t
*attr_cast
;
275 pts_file_meta_t
*metadata
;
277 attr_info
= attr
->get_value(attr
);
278 attr_cast
= (tcg_pts_attr_req_file_meta_t
*)attr
;
279 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
280 delimiter
= attr_cast
->get_delimiter(attr_cast
);
281 pathname
= attr_cast
->get_pathname(attr_cast
);
283 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
284 if (valid_path
&& pts_error
)
286 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
287 pts_error
, attr_info
);
288 attr_list
->insert_last(attr_list
, attr
);
291 else if (!valid_path
)
295 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
297 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
298 TCG_PTS_INVALID_DELIMITER
, attr_info
);
299 attr_list
->insert_last(attr_list
, attr
);
302 /* Get File Metadata and send them to PTS-IMV */
303 DBG2(DBG_IMC
, "metadata request for %s '%s'",
304 is_directory ?
"directory" : "file",
306 metadata
= pts
->get_metadata(pts
, pathname
, is_directory
);
310 /* TODO handle error codes from measurements */
313 attr
= tcg_pts_attr_unix_file_meta_create(metadata
);
314 attr
->set_noskip_flag(attr
, TRUE
);
315 attr_list
->insert_last(attr_list
, attr
);
319 case TCG_PTS_REQ_FUNC_COMP_EVID
:
321 tcg_pts_attr_req_func_comp_evid_t
*attr_cast
;
322 pts_proto_caps_flag_t negotiated_caps
;
323 pts_comp_func_name_t
*name
;
324 pts_comp_evidence_t
*evid
;
325 pts_component_t
*comp
;
331 attr_info
= attr
->get_value(attr
);
332 attr_cast
= (tcg_pts_attr_req_func_comp_evid_t
*)attr
;
334 DBG1(DBG_IMC
, "evidence requested for %d functional components",
335 attr_cast
->get_count(attr_cast
));
337 e
= attr_cast
->create_enumerator(attr_cast
);
338 while (e
->enumerate(e
, &flags
, &depth
, &name
))
340 name
->log(name
, "* ");
341 negotiated_caps
= pts
->get_proto_caps(pts
);
343 if (flags
& PTS_REQ_FUNC_COMP_FLAG_TTC
)
345 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
346 TCG_PTS_UNABLE_DET_TTC
, attr_info
);
347 attr_list
->insert_last(attr_list
, attr
);
350 if (flags
& PTS_REQ_FUNC_COMP_FLAG_VER
&&
351 !(negotiated_caps
& PTS_PROTO_CAPS_V
))
353 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
354 TCG_PTS_UNABLE_LOCAL_VAL
, attr_info
);
355 attr_list
->insert_last(attr_list
, attr
);
358 if (flags
& PTS_REQ_FUNC_COMP_FLAG_CURR
&&
359 !(negotiated_caps
& PTS_PROTO_CAPS_C
))
361 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
362 TCG_PTS_UNABLE_CUR_EVID
, attr_info
);
363 attr_list
->insert_last(attr_list
, attr
);
366 if (flags
& PTS_REQ_FUNC_COMP_FLAG_PCR
&&
367 !(negotiated_caps
& PTS_PROTO_CAPS_T
))
369 attr
= ietf_attr_pa_tnc_error_create(PEN_TCG
,
370 TCG_PTS_UNABLE_DET_PCR
, attr_info
);
371 attr_list
->insert_last(attr_list
, attr
);
376 DBG1(DBG_IMC
, "the Attestation IMC currently does not "
377 "support sub component measurements");
380 name
= name
->clone(name
);
381 comp
= pts_components
->create(pts_components
, name
);
384 DBG2(DBG_IMC
, " not registered: no evidence provided");
389 /* do the component evidence measurement[s] */
392 status
= comp
->measure(comp
, pts
, &evid
);
393 if (status
== FAILED
)
397 attestation_state
->add_evidence(attestation_state
, evid
);
399 while (status
== NEED_MORE
);
405 case TCG_PTS_GEN_ATTEST_EVID
:
407 pts_simple_evid_final_flag_t flags
;
408 pts_meas_algorithms_t composite_algorithm
= 0;
409 pts_comp_evidence_t
*evid
;
410 chunk_t pcr_composite
, quote_signature
;
413 /* Send buffered Simple Component Evidences */
414 while (attestation_state
->next_evidence(attestation_state
, &evid
))
416 pts
->select_pcr(pts
, evid
->get_extended_pcr(evid
));
418 /* Send Simple Component Evidence */
419 attr
= tcg_pts_attr_simple_comp_evid_create(evid
);
420 attr_list
->insert_last(attr_list
, attr
);
423 use_quote2
= lib
->settings
->get_bool(lib
->settings
,
424 "libimcv.plugins.imc-attestation.use_quote2", TRUE
);
427 if (!pts
->quote_tpm(pts
, use_quote2
, &pcr_composite
, "e_signature
))
429 DBG1(DBG_IMC
, "error occured during TPM quote operation");
433 /* Send Simple Evidence Final attribute */
434 flags
= use_quote2 ? PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO2
:
435 PTS_SIMPLE_EVID_FINAL_FLAG_TPM_QUOTE_INFO
;
436 composite_algorithm
|= PTS_MEAS_ALGO_SHA1
;
438 attr
= tcg_pts_attr_simple_evid_final_create(FALSE
, flags
,
439 composite_algorithm
, pcr_composite
,
440 quote_signature
, chunk_empty
);
441 attr_list
->insert_last(attr_list
, attr
);
444 /* TODO: Not implemented yet */
445 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
446 /* Attributes using XML */
447 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
448 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
450 case TCG_PTS_REQ_REGISTRY_VALUE
:
451 /* Received on IMV side only*/
452 case TCG_PTS_PROTO_CAPS
:
453 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
454 case TCG_PTS_MEAS_ALGO_SELECTION
:
455 case TCG_PTS_TPM_VERSION_INFO
:
456 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
458 case TCG_PTS_SIMPLE_COMP_EVID
:
459 case TCG_PTS_SIMPLE_EVID_FINAL
:
460 case TCG_PTS_VERIFICATION_RESULT
:
461 case TCG_PTS_INTEG_REPORT
:
462 case TCG_PTS_UNIX_FILE_META
:
463 case TCG_PTS_FILE_MEAS
:
464 case TCG_PTS_INTEG_MEAS_LOG
:
466 DBG1(DBG_IMC
, "received unsupported attribute '%N'",
467 tcg_attr_names
, attr
->get_type(attr
));