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 if (!pts
->get_my_public_value(pts
, &responder_value
,
146 /* Send DH Nonce Parameters Response attribute */
147 attr
= tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group
,
148 supported_algorithms
, responder_nonce
, responder_value
);
149 msg
->add_attribute(msg
, attr
);
152 case TCG_PTS_DH_NONCE_FINISH
:
154 tcg_pts_attr_dh_nonce_finish_t
*attr_cast
;
155 pts_meas_algorithms_t selected_algorithm
;
156 chunk_t initiator_nonce
, initiator_value
;
159 attr_cast
= (tcg_pts_attr_dh_nonce_finish_t
*)attr
;
160 selected_algorithm
= attr_cast
->get_hash_algo(attr_cast
);
161 if (!(selected_algorithm
& supported_algorithms
))
163 DBG1(DBG_IMC
, "PTS-IMV selected unsupported DH hash algorithm");
166 pts
->set_dh_hash_algorithm(pts
, selected_algorithm
);
168 initiator_value
= attr_cast
->get_initiator_value(attr_cast
);
169 initiator_nonce
= attr_cast
->get_initiator_nonce(attr_cast
);
171 nonce_len
= lib
->settings
->get_int(lib
->settings
,
172 "%s.plugins.imc-attestation.nonce_len",
173 DEFAULT_NONCE_LEN
, lib
->ns
);
174 if (nonce_len
!= initiator_nonce
.len
)
176 DBG1(DBG_IMC
, "initiator and responder DH nonces "
177 "have differing lengths");
182 if (!pts
->set_peer_public_value(pts
, initiator_value
,
184 !pts
->calculate_secret(pts
))
190 case TCG_PTS_GET_TPM_VERSION_INFO
:
192 chunk_t tpm_version_info
, attr_info
;
193 pen_type_t error_code
= { PEN_TCG
, TCG_PTS_TPM_VERS_NOT_SUPPORTED
};
195 if (!pts
->get_tpm_version_info(pts
, &tpm_version_info
))
197 attr_info
= attr
->get_value(attr
);
198 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
199 msg
->add_attribute(msg
, attr
);
203 /* Send TPM Version Info attribute */
204 attr
= tcg_pts_attr_tpm_version_info_create(tpm_version_info
);
205 msg
->add_attribute(msg
, attr
);
208 case TCG_PTS_GET_AIK
:
212 aik
= pts
->get_aik(pts
);
215 DBG1(DBG_IMC
, "no AIK certificate or public key available");
219 /* Send AIK attribute */
220 attr
= tcg_pts_attr_aik_create(aik
);
221 msg
->add_attribute(msg
, attr
);
224 case TCG_PTS_REQ_FILE_MEAS
:
226 tcg_pts_attr_req_file_meas_t
*attr_cast
;
228 u_int16_t request_id
;
231 pts_file_meas_t
*measurements
;
232 pen_type_t error_code
;
234 attr_info
= attr
->get_value(attr
);
235 attr_cast
= (tcg_pts_attr_req_file_meas_t
*)attr
;
236 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
237 request_id
= attr_cast
->get_request_id(attr_cast
);
238 delimiter
= attr_cast
->get_delimiter(attr_cast
);
239 pathname
= attr_cast
->get_pathname(attr_cast
);
240 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
242 if (valid_path
&& pts_error
)
244 error_code
= pen_type_create(PEN_TCG
, pts_error
);
245 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
246 msg
->add_attribute(msg
, attr
);
249 else if (!valid_path
)
254 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
256 error_code
= pen_type_create(PEN_TCG
,
257 TCG_PTS_INVALID_DELIMITER
);
258 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
259 msg
->add_attribute(msg
, attr
);
263 /* Do PTS File Measurements and send them to PTS-IMV */
264 DBG2(DBG_IMC
, "measurement request %d for %s '%s'",
265 request_id
, is_directory ?
"directory" : "file",
267 measurements
= pts_file_meas_create_from_path(request_id
,
268 pathname
, is_directory
, TRUE
,
269 pts
->get_meas_algorithm(pts
));
272 /* TODO handle error codes from measurements */
275 attr
= tcg_pts_attr_file_meas_create(measurements
);
276 attr
->set_noskip_flag(attr
, TRUE
);
277 msg
->add_attribute(msg
, attr
);
280 case TCG_PTS_REQ_FILE_META
:
282 tcg_pts_attr_req_file_meta_t
*attr_cast
;
286 pts_file_meta_t
*metadata
;
287 pen_type_t error_code
;
289 attr_info
= attr
->get_value(attr
);
290 attr_cast
= (tcg_pts_attr_req_file_meta_t
*)attr
;
291 is_directory
= attr_cast
->get_directory_flag(attr_cast
);
292 delimiter
= attr_cast
->get_delimiter(attr_cast
);
293 pathname
= attr_cast
->get_pathname(attr_cast
);
295 valid_path
= pts
->is_path_valid(pts
, pathname
, &pts_error
);
296 if (valid_path
&& pts_error
)
298 error_code
= pen_type_create(PEN_TCG
, pts_error
);
299 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
300 msg
->add_attribute(msg
, attr
);
303 else if (!valid_path
)
307 if (delimiter
!= SOLIDUS_UTF
&& delimiter
!= REVERSE_SOLIDUS_UTF
)
309 error_code
= pen_type_create(PEN_TCG
,
310 TCG_PTS_INVALID_DELIMITER
);
311 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
312 msg
->add_attribute(msg
, attr
);
315 /* Get File Metadata and send them to PTS-IMV */
316 DBG2(DBG_IMC
, "metadata request for %s '%s'",
317 is_directory ?
"directory" : "file",
319 metadata
= pts
->get_metadata(pts
, pathname
, is_directory
);
323 /* TODO handle error codes from measurements */
326 attr
= tcg_pts_attr_unix_file_meta_create(metadata
);
327 attr
->set_noskip_flag(attr
, TRUE
);
328 msg
->add_attribute(msg
, attr
);
331 case TCG_PTS_REQ_FUNC_COMP_EVID
:
333 tcg_pts_attr_req_func_comp_evid_t
*attr_cast
;
334 pts_proto_caps_flag_t negotiated_caps
;
335 pts_comp_func_name_t
*name
;
336 pts_comp_evidence_t
*evid
;
337 pts_component_t
*comp
;
338 pen_type_t error_code
;
344 attr_info
= attr
->get_value(attr
);
345 attr_cast
= (tcg_pts_attr_req_func_comp_evid_t
*)attr
;
347 DBG1(DBG_IMC
, "evidence requested for %d functional components",
348 attr_cast
->get_count(attr_cast
));
350 e
= attr_cast
->create_enumerator(attr_cast
);
351 while (e
->enumerate(e
, &flags
, &depth
, &name
))
353 name
->log(name
, "* ");
354 negotiated_caps
= pts
->get_proto_caps(pts
);
356 if (flags
& PTS_REQ_FUNC_COMP_EVID_TTC
)
358 error_code
= pen_type_create(PEN_TCG
,
359 TCG_PTS_UNABLE_DET_TTC
);
360 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
361 msg
->add_attribute(msg
, attr
);
364 if (flags
& PTS_REQ_FUNC_COMP_EVID_VER
&&
365 !(negotiated_caps
& PTS_PROTO_CAPS_V
))
367 error_code
= pen_type_create(PEN_TCG
,
368 TCG_PTS_UNABLE_LOCAL_VAL
);
369 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
370 msg
->add_attribute(msg
, attr
);
373 if (flags
& PTS_REQ_FUNC_COMP_EVID_CURR
&&
374 !(negotiated_caps
& PTS_PROTO_CAPS_C
))
376 error_code
= pen_type_create(PEN_TCG
,
377 TCG_PTS_UNABLE_CUR_EVID
);
378 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
379 msg
->add_attribute(msg
, attr
);
382 if (flags
& PTS_REQ_FUNC_COMP_EVID_PCR
&&
383 !(negotiated_caps
& PTS_PROTO_CAPS_T
))
385 error_code
= pen_type_create(PEN_TCG
,
386 TCG_PTS_UNABLE_DET_PCR
);
387 attr
= ietf_attr_pa_tnc_error_create(error_code
, attr_info
);
388 msg
->add_attribute(msg
, attr
);
393 DBG1(DBG_IMC
, "the Attestation IMC currently does not "
394 "support sub component measurements");
397 comp
= attestation_state
->create_component(attestation_state
,
401 DBG2(DBG_IMC
, " not registered: no evidence provided");
405 /* do the component evidence measurement[s] and cache them */
408 status
= comp
->measure(comp
, name
->get_qualifier(name
),
410 if (status
== FAILED
)
414 attestation_state
->add_evidence(attestation_state
, evid
);
416 while (status
== NEED_MORE
);
421 case TCG_PTS_GEN_ATTEST_EVID
:
423 pts_simple_evid_final_flag_t flags
;
424 pts_meas_algorithms_t comp_hash_algorithm
;
425 pts_comp_evidence_t
*evid
;
426 chunk_t pcr_composite
, quote_sig
;
429 /* Send cached Component Evidence entries */
430 while (attestation_state
->next_evidence(attestation_state
, &evid
))
432 attr
= tcg_pts_attr_simple_comp_evid_create(evid
);
433 msg
->add_attribute(msg
, attr
);
436 use_quote2
= lib
->settings
->get_bool(lib
->settings
,
437 "%s.plugins.imc-attestation.use_quote2", TRUE
,
439 if (!pts
->quote_tpm(pts
, use_quote2
, &pcr_composite
, "e_sig
))
441 DBG1(DBG_IMC
, "error occurred during TPM quote operation");
445 /* Send Simple Evidence Final attribute */
446 flags
= use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2
:
447 PTS_SIMPLE_EVID_FINAL_QUOTE_INFO
;
448 comp_hash_algorithm
= PTS_MEAS_ALGO_SHA1
;
450 attr
= tcg_pts_attr_simple_evid_final_create(flags
,
451 comp_hash_algorithm
, pcr_composite
, quote_sig
);
452 msg
->add_attribute(msg
, attr
);
455 case TCG_SEG_MAX_ATTR_SIZE_REQ
:
456 case TCG_SEG_NEXT_SEG_REQ
:
459 /* TODO: Not implemented yet */
460 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
461 /* Attributes using XML */
462 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
463 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
465 case TCG_PTS_REQ_REGISTRY_VALUE
:
466 /* Received on IMV side only*/
467 case TCG_PTS_PROTO_CAPS
:
468 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
469 case TCG_PTS_MEAS_ALGO_SELECTION
:
470 case TCG_PTS_TPM_VERSION_INFO
:
471 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
473 case TCG_PTS_SIMPLE_COMP_EVID
:
474 case TCG_PTS_SIMPLE_EVID_FINAL
:
475 case TCG_PTS_VERIFICATION_RESULT
:
476 case TCG_PTS_INTEG_REPORT
:
477 case TCG_PTS_UNIX_FILE_META
:
478 case TCG_PTS_FILE_MEAS
:
479 case TCG_PTS_INTEG_MEAS_LOG
:
481 DBG1(DBG_IMC
, "received unsupported attribute '%N/%N'",
482 pen_names
, PEN_TCG
, tcg_attr_names
, attr_type
.type
);