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
16 #include "imc_attestation_state.h"
18 #include <imc/imc_agent.h>
19 #include <pa_tnc/pa_tnc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ietf/ietf_attr_pa_tnc_error.h>
23 #include <tcg/tcg_pts_attr_proto_caps.h>
24 #include <tcg/tcg_pts_attr_meas_algo.h>
25 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
26 #include <tcg/tcg_pts_attr_tpm_version_info.h>
27 #include <tcg/tcg_pts_attr_get_aik.h>
28 #include <tcg/tcg_pts_attr_aik.h>
29 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
30 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
31 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
32 #include <tcg/tcg_pts_attr_simple_evid_final.h>
33 #include <tcg/tcg_pts_attr_req_file_meas.h>
34 #include <tcg/tcg_pts_attr_file_meas.h>
36 #include <tncif_pa_subtypes.h>
40 #include <utils/linked_list.h>
41 #include <crypto/hashers/hasher.h>
45 static const char imc_name
[] = "Attestation";
47 #define IMC_VENDOR_ID PEN_TCG
48 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
50 static imc_agent_t
*imc_attestation
;
53 * Supported PTS measurement algorithms
55 static pts_meas_algorithms_t supported_algorithms
= 0;
58 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
60 TNC_Result
TNC_IMC_Initialize(TNC_IMCID imc_id
,
61 TNC_Version min_version
,
62 TNC_Version max_version
,
63 TNC_Version
*actual_version
)
67 DBG1(DBG_IMC
, "IMC \"%s\" has already been initialized", imc_name
);
68 return TNC_RESULT_ALREADY_INITIALIZED
;
70 imc_attestation
= imc_agent_create(imc_name
, IMC_VENDOR_ID
, IMC_SUBTYPE
,
71 imc_id
, actual_version
);
72 if (!imc_attestation
|| !pts_meas_probe_algorithms(&supported_algorithms
))
74 return TNC_RESULT_FATAL
;
76 if (min_version
> TNC_IFIMC_VERSION_1
|| max_version
< TNC_IFIMC_VERSION_1
)
78 DBG1(DBG_IMC
, "no common IF-IMC version");
79 return TNC_RESULT_NO_COMMON_VERSION
;
81 return TNC_RESULT_SUCCESS
;
85 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
87 TNC_Result
TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id
,
88 TNC_ConnectionID connection_id
,
89 TNC_ConnectionState new_state
)
92 /* TODO: Not used so far */
93 //imc_attestation_state_t *attestation_state;
97 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
98 return TNC_RESULT_NOT_INITIALIZED
;
102 case TNC_CONNECTION_STATE_CREATE
:
103 state
= imc_attestation_state_create(connection_id
);
104 return imc_attestation
->create_state(imc_attestation
, state
);
105 case TNC_CONNECTION_STATE_DELETE
:
106 return imc_attestation
->delete_state(imc_attestation
, connection_id
);
107 case TNC_CONNECTION_STATE_HANDSHAKE
:
108 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
109 case TNC_CONNECTION_STATE_ACCESS_NONE
:
111 return imc_attestation
->change_state(imc_attestation
, connection_id
,
118 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
120 TNC_Result
TNC_IMC_BeginHandshake(TNC_IMCID imc_id
,
121 TNC_ConnectionID connection_id
)
123 if (!imc_attestation
)
125 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
126 return TNC_RESULT_NOT_INITIALIZED
;
128 return TNC_RESULT_SUCCESS
;
132 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
134 TNC_Result
TNC_IMC_ReceiveMessage(TNC_IMCID imc_id
,
135 TNC_ConnectionID connection_id
,
136 TNC_BufferReference msg
,
138 TNC_MessageType msg_type
)
140 pa_tnc_msg_t
*pa_tnc_msg
, *msg_to_send
;
141 pa_tnc_attr_t
*attr
, *attr_to_send
;
142 linked_list_t
*attr_list
;
144 imc_attestation_state_t
*attestation_state
;
145 enumerator_t
*enumerator
;
148 bool fatal_error
= FALSE
;
150 if (!imc_attestation
)
152 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
153 return TNC_RESULT_NOT_INITIALIZED
;
156 /* get current IMC state */
157 if (!imc_attestation
->get_state(imc_attestation
, connection_id
, &state
))
159 return TNC_RESULT_FATAL
;
161 attestation_state
= (imc_attestation_state_t
*)state
;
162 pts
= attestation_state
->get_pts(attestation_state
);
164 /* parse received PA-TNC message and automatically handle any errors */
165 result
= imc_attestation
->receive_message(imc_attestation
, connection_id
,
166 chunk_create(msg
, msg_len
), msg_type
,
169 /* no parsed PA-TNC attributes available if an error occurred */
175 msg_to_send
= pa_tnc_msg_create();
176 attr_list
= linked_list_create();
178 /* analyze PA-TNC attributes */
179 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
180 while (enumerator
->enumerate(enumerator
, &attr
))
182 if (attr
->get_vendor_id(attr
) == PEN_IETF
&&
183 attr
->get_type(attr
) == IETF_ATTR_PA_TNC_ERROR
)
185 ietf_attr_pa_tnc_error_t
*error_attr
;
186 pa_tnc_error_code_t error_code
;
187 chunk_t msg_info
, attr_info
;
190 error_attr
= (ietf_attr_pa_tnc_error_t
*)attr
;
191 error_code
= error_attr
->get_error_code(error_attr
);
192 msg_info
= error_attr
->get_msg_info(error_attr
);
194 DBG1(DBG_IMC
, "received PA-TNC error '%N' concerning message %#B",
195 pa_tnc_error_code_names
, error_code
, &msg_info
);
198 case PA_ERROR_INVALID_PARAMETER
:
199 offset
= error_attr
->get_offset(error_attr
);
200 DBG1(DBG_IMC
, " occurred at offset of %u bytes", offset
);
202 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
203 attr_info
= error_attr
->get_attr_info(error_attr
);
204 DBG1(DBG_IMC
, " unsupported attribute %#B", &attr_info
);
211 else if (attr
->get_vendor_id(attr
) == PEN_TCG
)
213 switch(attr
->get_type(attr
))
215 case TCG_PTS_REQ_PROTO_CAPS
:
217 tcg_pts_attr_proto_caps_t
*attr_cast
;
218 pts_proto_caps_flag_t imc_flags
, imv_flags
;
220 attr_cast
= (tcg_pts_attr_proto_caps_t
*)attr
;
221 imv_flags
= attr_cast
->get_flags(attr_cast
);
222 imc_flags
= pts
->get_proto_caps(pts
);
223 pts
->set_proto_caps(pts
, imc_flags
& imv_flags
);
225 /* Send PTS Protocol Capabilities attribute */
226 attr_to_send
= tcg_pts_attr_proto_caps_create(imc_flags
& imv_flags
, FALSE
);
227 attr_to_send
= (pa_tnc_attr_t
*)attr_to_send
;
228 attr_list
->insert_last(attr_list
,attr_to_send
);
231 case TCG_PTS_MEAS_ALGO
:
233 tcg_pts_attr_meas_algo_t
*attr_cast
;
234 pts_meas_algorithms_t selected_algorithm
;
236 attr_cast
= (tcg_pts_attr_meas_algo_t
*)attr
;
237 selected_algorithm
= attr_cast
->get_algorithms(attr_cast
);
239 if ((supported_algorithms
& PTS_MEAS_ALGO_SHA256
) &&
240 (selected_algorithm
& PTS_MEAS_ALGO_SHA256
))
242 pts
->set_meas_algorithm(pts
, PTS_MEAS_ALGO_SHA256
);
244 else if ((supported_algorithms
& PTS_MEAS_ALGO_SHA384
) &&
245 (selected_algorithm
& PTS_MEAS_ALGO_SHA384
))
247 pts
->set_meas_algorithm(pts
, PTS_MEAS_ALGO_SHA384
);
250 else if ((supported_algorithms
& PTS_MEAS_ALGO_SHA1
) &&
251 (selected_algorithm
& PTS_MEAS_ALGO_SHA1
))
253 pts
->set_meas_algorithm(pts
, PTS_MEAS_ALGO_SHA1
);
257 /* TODO send a TCG_PTS_H_ALG_NOT_SUPPORTED error */
259 /* Send Measurement Algorithm Selection attribute */
260 selected_algorithm
= pts
->get_meas_algorithm(pts
);
261 attr_to_send
= tcg_pts_attr_meas_algo_create(selected_algorithm
, TRUE
);
262 attr_to_send
= (pa_tnc_attr_t
*)attr_to_send
;
263 attr_list
->insert_last(attr_list
,attr_to_send
);
267 case TCG_PTS_GET_TPM_VERSION_INFO
:
269 chunk_t tpm_version_info
;
271 if (!pts
->get_tpm_version_info(pts
, &tpm_version_info
))
273 /* TODO return TCG_PTS_TPM_VERS_NOT_SUPPORTED error attribute */
276 /* Send TPM Version Info attribute */
277 attr_to_send
= tcg_pts_attr_tpm_version_info_create(tpm_version_info
);
278 attr_to_send
= (pa_tnc_attr_t
*)attr_to_send
;
279 attr_list
->insert_last(attr_list
,attr_to_send
);
283 case TCG_PTS_GET_AIK
:
285 /* TODO: Implement AIK retrieve */
289 /* PTS-based Attestation Evidence */
290 case TCG_PTS_REQ_FUNCT_COMP_EVID
:
292 case TCG_PTS_GEN_ATTEST_EVID
:
294 case TCG_PTS_REQ_FILE_MEAS
:
296 tcg_pts_attr_req_file_meas_t
*attr_cast
;
297 tcg_pts_attr_file_meas_t
*attr_file_meas
;
300 u_int16_t request_id
;
302 pts_meas_algorithms_t selected_algorithm
;
305 linked_list_t
*file_measurements
;
307 attr_cast
= (tcg_pts_attr_req_file_meas_t
*)attr
;
308 directory_flag
= attr_cast
->get_directory_flag(attr_cast
);
309 request_id
= attr_cast
->get_request_id(attr_cast
);
310 delimiter
= attr_cast
->get_delimiter(attr_cast
);
311 path
= attr_cast
->get_file_path(attr_cast
);
313 DBG3(DBG_IMC
,"The Requested File/Directory to be measured: %s", path
.ptr
);
315 /* Send File Measurement attribute */
316 selected_algorithm
= pts
->get_meas_algorithm(pts
);
317 meas_len
= HASH_SIZE_SHA1
;
318 if (selected_algorithm
& PTS_MEAS_ALGO_SHA384
)
320 meas_len
= HASH_SIZE_SHA384
;
322 else if(selected_algorithm
& PTS_MEAS_ALGO_SHA256
)
324 meas_len
= HASH_SIZE_SHA512
;
328 * Hash the file or directory and add them as attribute
331 attr_to_send
= directory_flag ?
332 tcg_pts_attr_file_meas_create(0, request_id
, meas_len
) :
333 tcg_pts_attr_file_meas_create(1, request_id
, meas_len
);
334 attr_to_send
->set_noskip_flag(attr_to_send
, TRUE
);
335 attr_file_meas
= (tcg_pts_attr_file_meas_t
*)attr_to_send
;
339 if(pts
->hash_file(pts
,path
.ptr
,file_hash
) != true)
341 DBG1(DBG_IMC
, "Hashing the given file has failed");
342 return TNC_RESULT_FATAL
;
344 attr_file_meas
->add_file_meas(attr_file_meas
,
345 chunk_create(file_hash
,strlen(file_hash
)),
350 enumerator_t
*meas_enumerator
;
351 file_meas_entry_t
*meas_entry
;
352 u_int64_t num_of_files
= 0 ;
353 if(pts
->hash_directory(pts
, path
.ptr
, file_measurements
) != true)
355 DBG1(DBG_IMC
, "Hashing the files in a given directory has failed");
356 return TNC_RESULT_FATAL
;
359 meas_enumerator
= file_measurements
->create_enumerator(file_measurements
);
360 while (meas_enumerator
->enumerate(meas_enumerator
, &meas_entry
))
363 attr_file_meas
->add_file_meas(attr_file_meas
,
364 meas_entry
->measurement
,
365 meas_entry
->file_name
);
368 attr_file_meas
->set_number_of_files(attr_file_meas
,
370 meas_enumerator
->destroy(meas_enumerator
);
371 file_measurements
->destroy(file_measurements
);
375 attr_to_send
= (pa_tnc_attr_t
*)attr_file_meas
;
376 attr_list
->insert_last(attr_list
,attr_to_send
);
380 /* TODO: Not implemented yet */
381 case TCG_PTS_DH_NONCE_PARAMS_REQ
:
382 case TCG_PTS_DH_NONCE_FINISH
:
383 case TCG_PTS_REQ_FILE_META
:
384 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
385 /* Attributes using XML */
386 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
387 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
389 case TCG_PTS_REQ_REGISTRY_VALUE
:
390 /* Received on IMV side only*/
391 case TCG_PTS_PROTO_CAPS
:
392 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
393 case TCG_PTS_MEAS_ALGO_SELECTION
:
394 case TCG_PTS_TPM_VERSION_INFO
:
395 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
397 case TCG_PTS_SIMPLE_COMP_EVID
:
398 case TCG_PTS_SIMPLE_EVID_FINAL
:
399 case TCG_PTS_VERIFICATION_RESULT
:
400 case TCG_PTS_INTEG_REPORT
:
401 case TCG_PTS_UNIX_FILE_META
:
402 case TCG_PTS_FILE_MEAS
:
403 case TCG_PTS_INTEG_MEAS_LOG
:
405 DBG1(DBG_IMC
, "received unsupported attribute '%N'",
406 tcg_attr_names
, attr
->get_type(attr
));
413 enumerator
->destroy(enumerator
);
414 pa_tnc_msg
->destroy(pa_tnc_msg
);
416 if(attr_list
->get_count(attr_list
))
418 enumerator_t
*attr_enumerator
= attr_list
->create_enumerator(attr_list
);
419 while (attr_enumerator
->enumerate(attr_enumerator
, &attr_to_send
))
421 msg_to_send
->add_attribute(msg_to_send
, attr_to_send
);
423 attr_enumerator
->destroy(attr_enumerator
);
426 msg_to_send
->build(msg_to_send
);
427 result
= imc_attestation
->send_message(imc_attestation
, connection_id
,
428 msg_to_send
->get_encoding(msg_to_send
));
430 attr_list
->destroy(attr_list
);
431 msg_to_send
->destroy(msg_to_send
);
433 return TNC_RESULT_SUCCESS
;
437 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
439 TNC_Result
TNC_IMC_BatchEnding(TNC_IMCID imc_id
,
440 TNC_ConnectionID connection_id
)
442 if (!imc_attestation
)
444 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
445 return TNC_RESULT_NOT_INITIALIZED
;
447 return TNC_RESULT_SUCCESS
;
451 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
453 TNC_Result
TNC_IMC_Terminate(TNC_IMCID imc_id
)
455 if (!imc_attestation
)
457 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
458 return TNC_RESULT_NOT_INITIALIZED
;
460 imc_attestation
->destroy(imc_attestation
);
461 imc_attestation
= NULL
;
463 return TNC_RESULT_SUCCESS
;
467 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
469 TNC_Result
TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id
,
470 TNC_TNCC_BindFunctionPointer bind_function
)
472 if (!imc_attestation
)
474 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
475 return TNC_RESULT_NOT_INITIALIZED
;
477 return imc_attestation
->bind_functions(imc_attestation
, bind_function
);