2 * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen
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>
28 #include <tcg/pts/tcg_pts_attr_proto_caps.h>
29 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
30 #include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
31 #include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
32 #include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
33 #include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
34 #include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
35 #include <tcg/pts/tcg_pts_attr_get_aik.h>
36 #include <tcg/pts/tcg_pts_attr_aik.h>
37 #include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
38 #include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
39 #include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
40 #include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
41 #include <tcg/pts/tcg_pts_attr_req_file_meas.h>
42 #include <tcg/pts/tcg_pts_attr_file_meas.h>
43 #include <tcg/pts/tcg_pts_attr_req_file_meta.h>
44 #include <tcg/pts/tcg_pts_attr_unix_file_meta.h>
46 #include <utils/debug.h>
47 #include <utils/lexparser.h>
49 #define DEFAULT_NONCE_LEN 20
51 bool imc_attestation_process(pa_tnc_attr_t
*attr
, imc_msg_t
*msg
,
52 imc_attestation_state_t
*attestation_state
,
53 pts_meas_algorithms_t supported_algorithms
,
54 pts_dh_group_t supported_dh_groups
)
58 pts_error_code_t pts_error
;
62 pts
= attestation_state
->get_pts(attestation_state
);
63 attr_type
= attr
->get_type(attr
);
65 switch (attr_type
.type
)
67 case TCG_PTS_REQ_PROTO_CAPS
:
69 tcg_pts_attr_proto_caps_t
*attr_cast
;
70 pts_proto_caps_flag_t imc_caps
, imv_caps
;
72 attr_cast
= (tcg_pts_attr_proto_caps_t
*)attr
;
73 imv_caps
= attr_cast
->get_flags(attr_cast
);
74 imc_caps
= pts
->get_proto_caps(pts
);
75 pts
->set_proto_caps(pts
, imc_caps
& imv_caps
);
77 /* Send PTS Protocol Capabilities attribute */
78 attr
= tcg_pts_attr_proto_caps_create(imc_caps
& imv_caps
, FALSE
);
79 msg
->add_attribute(msg
, attr
);
82 case TCG_PTS_MEAS_ALGO
:
84 tcg_pts_attr_meas_algo_t
*attr_cast
;
85 pts_meas_algorithms_t offered_algorithms
, selected_algorithm
;
87 attr_cast
= (tcg_pts_attr_meas_algo_t
*)attr
;
88 offered_algorithms
= attr_cast
->get_algorithms(attr_cast
);
89 selected_algorithm
= pts_meas_algo_select(supported_algorithms
,
91 if (selected_algorithm
== PTS_MEAS_ALGO_NONE
)
93 attr
= pts_hash_alg_error_create(supported_algorithms
);
94 msg
->add_attribute(msg
, attr
);
98 /* Send Measurement Algorithm Selection attribute */
99 pts
->set_meas_algorithm(pts
, selected_algorithm
);
100 attr
= tcg_pts_attr_meas_algo_create(selected_algorithm
, TRUE
);
101 msg
->add_attribute(msg
, attr
);
104 case TCG_PTS_DH_NONCE_PARAMS_REQ
:
106 tcg_pts_attr_dh_nonce_params_req_t
*attr_cast
;
107 pts_dh_group_t offered_dh_groups
, selected_dh_group
;
108 chunk_t responder_value
, responder_nonce
;
109 int nonce_len
, min_nonce_len
;
111 nonce_len
= lib
->settings
->get_int(lib
->settings
,
112 "%s.plugins.imc-attestation.nonce_len",
113 DEFAULT_NONCE_LEN
, lib
->ns
);
115 attr_cast
= (tcg_pts_attr_dh_nonce_params_req_t
*)attr
;
116 min_nonce_len
= attr_cast
->get_min_nonce_len(attr_cast
);
117 if (nonce_len
< PTS_MIN_NONCE_LEN
||
118 (min_nonce_len
> 0 && nonce_len
< min_nonce_len
))
120 attr
= pts_dh_nonce_error_create(nonce_len
, PTS_MAX_NONCE_LEN
);
121 msg
->add_attribute(msg
, attr
);
125 offered_dh_groups
= attr_cast
->get_dh_groups(attr_cast
);
126 selected_dh_group
= pts_dh_group_select(supported_dh_groups
,
128 if (selected_dh_group
== PTS_DH_GROUP_NONE
)
130 attr
= pts_dh_group_error_create(supported_dh_groups
);
131 msg
->add_attribute(msg
, attr
);
135 /* Create own DH factor and nonce */
136 if (!pts
->create_dh_nonce(pts
, selected_dh_group
, nonce_len
))
140 pts
->get_my_public_value(pts
, &responder_value
, &responder_nonce
);
142 /* Send DH Nonce Parameters Response attribute */
143 attr
= tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group
,
144 supported_algorithms
, responder_nonce
, responder_value
);
145 msg
->add_attribute(msg
, attr
);
148 case TCG_PTS_DH_NONCE_FINISH
:
150 tcg_pts_attr_dh_nonce_finish_t
*attr_cast
;
151 pts_meas_algorithms_t selected_algorithm
;
152 chunk_t initiator_nonce
, initiator_value
;
155 attr_cast
= (tcg_pts_attr_dh_nonce_finish_t
*)attr
;
156 selected_algorithm
= attr_cast
->get_hash_algo(attr_cast
);
157 if (!(selected_algorithm
& supported_algorithms
))
159 DBG1(DBG_IMC
, "PTS-IMV selected unsupported DH hash algorithm");
162 pts
->set_dh_hash_algorithm(pts
, selected_algorithm
);
164 initiator_value
= attr_cast
->get_initiator_value(attr_cast
);
165 initiator_nonce
= attr_cast
->get_initiator_nonce(attr_cast
);
167 nonce_len
= lib
->settings
->get_int(lib
->settings
,
168 "%s.plugins.imc-attestation.nonce_len",
169 DEFAULT_NONCE_LEN
, lib
->ns
);
170 if (nonce_len
!= initiator_nonce
.len
)
172 DBG1(DBG_IMC
, "initiator and responder DH nonces "
173 "have differing lengths");
177 pts
->set_peer_public_value(pts
, initiator_value
, initiator_nonce
);
178 if (!pts
->calculate_secret(pts
))
184 case TCG_PTS_GET_TPM_VERSION_INFO
:
186 chunk_t tpm_version_info
, attr_info
;
187 pen_type_t error_code
= { PEN_TCG
, TCG_PTS_TPM_VERS_NOT_SUPPORTED
};
189 if (!pts
->get_tpm_version_info(pts
, &tpm_version_info
))
191 attr_info
= attr
->get_value(attr
);
192 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
193 msg
->add_attribute(msg
, attr
);
197 /* Send TPM Version Info attribute */
198 attr
= tcg_pts_attr_tpm_version_info_create(tpm_version_info
);
199 msg
->add_attribute(msg
, attr
);
202 case TCG_PTS_GET_AIK
:
206 aik
= pts
->get_aik(pts
);
209 DBG1(DBG_IMC
, "no AIK certificate or public key available");
213 /* Send AIK attribute */
214 attr
= tcg_pts_attr_aik_create(aik
);
215 msg
->add_attribute(msg
, attr
);
218 case TCG_PTS_REQ_FILE_MEAS
:
220 tcg_pts_attr_req_file_meas_t
*attr_cast
;
222 u_int16_t request_id
;
225 pts_file_meas_t
*measurements
;
226 pen_type_t error_code
;
228 attr_info
= attr
->get_value(attr
);
229 attr_cast
= (tcg_pts_attr_req_file_meas_t
*)attr
;
230 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
231 request_id
= attr_cast
->get_request_id(attr_cast
);
232 delimiter
= attr_cast
->get_delimiter(attr_cast
);
233 pathname
= attr_cast
->get_pathname(attr_cast
);
234 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
236 if (valid_path
&& pts_error
)
238 error_code
= pen_type_create(PEN_TCG
, pts_error
);
239 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
240 msg
->add_attribute(msg
, attr
);
243 else if (!valid_path
)
248 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
250 error_code
= pen_type_create(PEN_TCG
,
251 TCG_PTS_INVALID_DELIMITER
);
252 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
253 msg
->add_attribute(msg
, attr
);
257 /* Do PTS File Measurements and send them to PTS-IMV */
258 DBG2(DBG_IMC
, "measurement request %d for %s '%s'",
259 request_id
, is_directory ?
"directory" : "file",
261 measurements
= pts_file_meas_create_from_path(request_id
,
262 pathname
, is_directory
, TRUE
,
263 pts
->get_meas_algorithm(pts
));
266 /* TODO handle error codes from measurements */
269 attr
= tcg_pts_attr_file_meas_create(measurements
);
270 attr
->set_noskip_flag(attr
, TRUE
);
271 msg
->add_attribute(msg
, attr
);
274 case TCG_PTS_REQ_FILE_META
:
276 tcg_pts_attr_req_file_meta_t
*attr_cast
;
280 pts_file_meta_t
*metadata
;
281 pen_type_t error_code
;
283 attr_info
= attr
->get_value(attr
);
284 attr_cast
= (tcg_pts_attr_req_file_meta_t
*)attr
;
285 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
286 delimiter
= attr_cast
->get_delimiter(attr_cast
);
287 pathname
= attr_cast
->get_pathname(attr_cast
);
289 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
290 if (valid_path
&& pts_error
)
292 error_code
= pen_type_create(PEN_TCG
, pts_error
);
293 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
294 msg
->add_attribute(msg
, attr
);
297 else if (!valid_path
)
301 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
303 error_code
= pen_type_create(PEN_TCG
,
304 TCG_PTS_INVALID_DELIMITER
);
305 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
306 msg
->add_attribute(msg
, attr
);
309 /* Get File Metadata and send them to PTS-IMV */
310 DBG2(DBG_IMC
, "metadata request for %s '%s'",
311 is_directory ?
"directory" : "file",
313 metadata
= pts
->get_metadata(pts
, pathname
, is_directory
);
317 /* TODO handle error codes from measurements */
320 attr
= tcg_pts_attr_unix_file_meta_create(metadata
);
321 attr
->set_noskip_flag(attr
, TRUE
);
322 msg
->add_attribute(msg
, attr
);
325 case TCG_PTS_REQ_FUNC_COMP_EVID
:
327 tcg_pts_attr_req_func_comp_evid_t
*attr_cast
;
328 pts_proto_caps_flag_t negotiated_caps
;
329 pts_comp_func_name_t
*name
;
330 pts_comp_evidence_t
*evid
;
331 pts_component_t
*comp
;
332 pen_type_t error_code
;
338 attr_info
= attr
->get_value(attr
);
339 attr_cast
= (tcg_pts_attr_req_func_comp_evid_t
*)attr
;
341 DBG1(DBG_IMC
, "evidence requested for %d functional components",
342 attr_cast
->get_count(attr_cast
));
344 e
= attr_cast
->create_enumerator(attr_cast
);
345 while (e
->enumerate(e
, &flags
, &depth
, &name
))
347 name
->log(name
, "* ");
348 negotiated_caps
= pts
->get_proto_caps(pts
);
350 if (flags
& PTS_REQ_FUNC_COMP_EVID_TTC
)
352 error_code
= pen_type_create(PEN_TCG
,
353 TCG_PTS_UNABLE_DET_TTC
);
354 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
355 msg
->add_attribute(msg
, attr
);
358 if (flags
& PTS_REQ_FUNC_COMP_EVID_VER
&&
359 !(negotiated_caps
& PTS_PROTO_CAPS_V
))
361 error_code
= pen_type_create(PEN_TCG
,
362 TCG_PTS_UNABLE_LOCAL_VAL
);
363 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
364 msg
->add_attribute(msg
, attr
);
367 if (flags
& PTS_REQ_FUNC_COMP_EVID_CURR
&&
368 !(negotiated_caps
& PTS_PROTO_CAPS_C
))
370 error_code
= pen_type_create(PEN_TCG
,
371 TCG_PTS_UNABLE_CUR_EVID
);
372 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
373 msg
->add_attribute(msg
, attr
);
376 if (flags
& PTS_REQ_FUNC_COMP_EVID_PCR
&&
377 !(negotiated_caps
& PTS_PROTO_CAPS_T
))
379 error_code
= pen_type_create(PEN_TCG
,
380 TCG_PTS_UNABLE_DET_PCR
);
381 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
382 msg
->add_attribute(msg
, attr
);
387 DBG1(DBG_IMC
, "the Attestation IMC currently does not "
388 "support sub component measurements");
391 comp
= attestation_state
->create_component(attestation_state
,
395 DBG2(DBG_IMC
, " not registered: no evidence provided");
399 /* do the component evidence measurement[s] and cache them */
402 status
= comp
->measure(comp
, name
->get_qualifier(name
),
404 if (status
== FAILED
)
408 attestation_state
->add_evidence(attestation_state
, evid
);
410 while (status
== NEED_MORE
);
415 case TCG_PTS_GEN_ATTEST_EVID
:
417 pts_simple_evid_final_flag_t flags
;
418 pts_meas_algorithms_t comp_hash_algorithm
;
419 pts_comp_evidence_t
*evid
;
420 chunk_t pcr_composite
, quote_sig
;
423 /* Send cached Component Evidence entries */
424 while (attestation_state
->next_evidence(attestation_state
, &evid
))
426 attr
= tcg_pts_attr_simple_comp_evid_create(evid
);
427 msg
->add_attribute(msg
, attr
);
430 use_quote2
= lib
->settings
->get_bool(lib
->settings
,
431 "%s.plugins.imc-attestation.use_quote2", TRUE
,
433 if (!pts
->quote_tpm(pts
, use_quote2
, &pcr_composite
, "e_sig
))
435 DBG1(DBG_IMC
, "error occurred during TPM quote operation");
439 /* Send Simple Evidence Final attribute */
440 flags
= use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2
:
441 PTS_SIMPLE_EVID_FINAL_QUOTE_INFO
;
442 comp_hash_algorithm
= PTS_MEAS_ALGO_SHA1
;
444 attr
= tcg_pts_attr_simple_evid_final_create(flags
,
445 comp_hash_algorithm
, pcr_composite
, quote_sig
);
446 msg
->add_attribute(msg
, attr
);
449 /* TODO: Not implemented yet */
450 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
451 /* Attributes using XML */
452 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
453 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
455 case TCG_PTS_REQ_REGISTRY_VALUE
:
456 /* Received on IMV side only*/
457 case TCG_PTS_PROTO_CAPS
:
458 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
459 case TCG_PTS_MEAS_ALGO_SELECTION
:
460 case TCG_PTS_TPM_VERSION_INFO
:
461 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
463 case TCG_PTS_SIMPLE_COMP_EVID
:
464 case TCG_PTS_SIMPLE_EVID_FINAL
:
465 case TCG_PTS_VERIFICATION_RESULT
:
466 case TCG_PTS_INTEG_REPORT
:
467 case TCG_PTS_UNIX_FILE_META
:
468 case TCG_PTS_FILE_MEAS
:
469 case TCG_PTS_INTEG_MEAS_LOG
:
471 DBG1(DBG_IMC
, "received unsupported attribute '%N'",
472 tcg_attr_names
, attr
->get_type(attr
));