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_selection.h>
25 #include <tcg/tcg_pts_attr_tpm_version_info.h>
26 #include <tcg/tcg_pts_attr_aik.h>
27 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
28 #include <tcg/tcg_pts_attr_simple_evid_final.h>
29 #include <tcg/tcg_pts_attr_file_meas.h>
31 #include <tncif_pa_subtypes.h>
35 #include <utils/linked_list.h>
37 #include <trousers/tss.h>
38 #include <trousers/trousers.h>
39 #include <openssl/sha.h>
44 static const char imc_name
[] = "Attestation";
46 #define IMC_VENDOR_ID PEN_TCG
47 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
48 #define IMC_ATTESTATION_MAX_FILE_SIZE 32768
50 static imc_agent_t
*imc_attestation
;
54 * Selected Measurement Algorithm, which is selected during
55 * the PTS Measurement Algorithm attributes exchange
56 * Default value is SHA256
58 static pts_meas_algorithms_t selected_algorithm
= PTS_MEAS_ALGO_SHA256
;
61 * List of files and directories to measure
63 static linked_list_t
*files
, *directories
;
66 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
68 TNC_Result
TNC_IMC_Initialize(TNC_IMCID imc_id
,
69 TNC_Version min_version
,
70 TNC_Version max_version
,
71 TNC_Version
*actual_version
)
75 DBG1(DBG_IMC
, "IMC \"%s\" has already been initialized", imc_name
);
76 return TNC_RESULT_ALREADY_INITIALIZED
;
78 imc_attestation
= imc_agent_create(imc_name
, IMC_VENDOR_ID
, IMC_SUBTYPE
,
79 imc_id
, actual_version
);
82 return TNC_RESULT_FATAL
;
84 if (min_version
> TNC_IFIMC_VERSION_1
|| max_version
< TNC_IFIMC_VERSION_1
)
86 DBG1(DBG_IMC
, "no common IF-IMC version");
87 return TNC_RESULT_NO_COMMON_VERSION
;
89 return TNC_RESULT_SUCCESS
;
93 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
95 TNC_Result
TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id
,
96 TNC_ConnectionID connection_id
,
97 TNC_ConnectionState new_state
)
100 /* TODO: Not used so far */
101 //imc_attestation_state_t *attestation_state;
103 if (!imc_attestation
)
105 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
106 return TNC_RESULT_NOT_INITIALIZED
;
110 case TNC_CONNECTION_STATE_CREATE
:
111 state
= imc_attestation_state_create(connection_id
);
112 return imc_attestation
->create_state(imc_attestation
, state
);
113 case TNC_CONNECTION_STATE_DELETE
:
114 return imc_attestation
->delete_state(imc_attestation
, connection_id
);
115 case TNC_CONNECTION_STATE_HANDSHAKE
:
116 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
117 case TNC_CONNECTION_STATE_ACCESS_NONE
:
119 return imc_attestation
->change_state(imc_attestation
, connection_id
,
125 * Get the TPM Version Information
127 static TSS_RESULT
get_tpm_version_info(BYTE
*tpm_version_info
)
129 TSS_HCONTEXT hContext
;
133 /* TODO: Needed for parsing version info on IMV side */
134 //TPM_CAP_VERSION_INFO versionInfo;
137 uiResult
= Tspi_Context_Create(&hContext
);
138 if (uiResult
!= TSS_SUCCESS
) {
139 DBG1(DBG_IMC
,"Error 0x%x on Tspi_Context_Create\n", uiResult
);
142 uiResult
= Tspi_Context_Connect(hContext
, NULL
);
143 if (uiResult
!= TSS_SUCCESS
) {
144 DBG1(DBG_IMC
,"Error 0x%x on Tspi_Context_Connect\n", uiResult
);
147 uiResult
= Tspi_Context_GetTpmObject (hContext
, &hTPM
);
148 if (uiResult
!= TSS_SUCCESS
) {
149 DBG1(DBG_IMC
,"Error 0x%x on Tspi_Context_GetTpmObject\n", uiResult
);
153 uiResult
= Tspi_TPM_GetCapability(hTPM
, TSS_TPMCAP_VERSION_VAL
, 0, NULL
, &uiResultLen
,
155 if (uiResult
!= TSS_SUCCESS
) {
156 DBG1(DBG_IMC
,"Error 0x%x on Tspi_TPM_GetCapability\n", uiResult
);
162 * Get Hash Measurement of a file
163 * Uses openssl's sha.h
165 static TNC_Result
hash_file(char *path
, unsigned char *out
)
171 file
= fopen(path
, "rb");
173 DBG1(DBG_IMC
,"File can not be opened %s\n", path
);
174 return TNC_RESULT_FATAL
;
177 buffer
= malloc(IMC_ATTESTATION_MAX_FILE_SIZE
);
180 DBG1(DBG_IMC
,"Buffer couldn't be allocated memory");
184 switch(selected_algorithm
)
186 case PTS_MEAS_ALGO_SHA1
:
191 while((bytesRead
= fread(buffer
, 1, IMC_ATTESTATION_MAX_FILE_SIZE
, file
)))
193 SHA1_Update(&sha1
, buffer
, bytesRead
);
195 SHA1_Final(out
, &sha1
);
198 case PTS_MEAS_ALGO_SHA256
:
201 SHA256_Init(&sha256
);
203 while((bytesRead
= fread(buffer
, 1, IMC_ATTESTATION_MAX_FILE_SIZE
, file
)))
205 SHA256_Update(&sha256
, buffer
, bytesRead
);
207 SHA256_Final(out
, &sha256
);
210 case PTS_MEAS_ALGO_SHA384
:
213 SHA384_Init(&sha384);
215 while((bytesRead = fread(buffer, 1, IMC_ATTESTATION_MAX_FILE_SIZE, file)))
217 SHA384_Update(&sha384, buffer, bytesRead);
219 SHA384_Final(out, &sha384);
224 DBG1(DBG_IMC
,"Unsupported Selected Hashing Algorithm \n");
225 return TNC_RESULT_FATAL
;
230 return TNC_RESULT_SUCCESS
;
234 return TNC_RESULT_FATAL
;
237 static TNC_Result
send_message(TNC_ConnectionID connection_id
)
242 imc_attestation_state_t
*attestation_state
;
243 imc_attestation_handshake_state_t handshake_state
;
246 if (!imc_attestation
->get_state(imc_attestation
, connection_id
, &state
))
248 return TNC_RESULT_FATAL
;
250 attestation_state
= (imc_attestation_state_t
*)state
;
251 handshake_state
= attestation_state
->get_handshake_state(attestation_state
);
253 /* Switch on the attribute type IMC has received */
254 switch (handshake_state
)
256 case IMC_ATTESTATION_STATE_REQ_PROTO_CAP
:
258 pts_proto_caps_flag_t flags
;
259 flags
= PTS_PROTO_CAPS_T
| PTS_PROTO_CAPS_VER
;
260 attr
= tcg_pts_attr_proto_caps_create(flags
);
263 case IMC_ATTESTATION_STATE_REQ_MEAS_ALGO
:
265 pts_meas_algorithms_t algorithm
;
266 algorithm
= PTS_MEAS_ALGO_SHA1
;
267 /* Save the selected algorithm for further attributes creation */
268 selected_algorithm
= algorithm
;
269 attr
= tcg_pts_attr_meas_algo_selection_create(algorithm
);
272 case IMC_ATTESTATION_STATE_GET_TPM_INFO
:
275 BYTE
*tpm_version_info
;
277 uiResult
= get_tpm_version_info(tpm_version_info
);
278 if (uiResult
!= TSS_SUCCESS
) {
279 DBG1(DBG_IMC
,"Error 0x%x on get_tpm_version_info\n", uiResult
);
283 attr
= tcg_pts_attr_tpm_version_info_create(
284 chunk_create((char *)tpm_version_info
,
285 strlen(tpm_version_info
)));
288 /* TODO: working on */
289 /*case IMC_ATTESTATION_STATE_REQ_FILE_MEAS:
291 enumerator_t *enumerator;
292 measurement_req_entry_t *entry;
294 enumerator = enumerator_create_single(file_list, NULL);
295 while (enumerator->enumerate(enumerator, &entry))
297 attr = tcg_pts_attr_req_file_meas_create(false,
298 entry.request_id, delimiter,
299 chunk_create(entry.path,strlen(entry.path)));
300 attr->set_noskip_flag(attr, TRUE);
301 msg->add_attribute(msg, attr);
304 enumerator = enumerator_create_single(file_list, NULL);
305 while (enumerator->enumerate(enumerator, &entry))
307 attr = tcg_pts_attr_req_file_meas_create(false,
308 entry.request_id, delimiter,
309 chunk_create(entry.path,strlen(entry.path)));
310 attr->set_noskip_flag(attr, TRUE);
311 msg->add_attribute(msg, attr);
315 case IMC_ATTESTATION_STATE_GET_AIK
:
316 case IMC_ATTESTATION_STATE_REQ_FUNCT_COMP_EVID
:
317 case IMC_ATTESTATION_STATE_GEN_ATTEST_EVID
:
318 case IMC_ATTESTATION_STATE_REQ_FILE_METADATA
:
319 case IMC_ATTESTATION_STATE_REQ_IML
:
320 case IMC_ATTESTATION_STATE_INIT
:
321 DBG1(DBG_IMC
, "Attestation IMC has nothing to send: \"%s\"", handshake_state
);
322 return TNC_RESULT_FATAL
;
324 DBG1(DBG_IMC
, "Attestation IMC is in unknown state: \"%s\"", handshake_state
);
325 return TNC_RESULT_FATAL
;
329 attr
->set_noskip_flag(attr
, TRUE
);
330 msg
= pa_tnc_msg_create();
331 msg
->add_attribute(msg
, attr
);
333 result
= imc_attestation
->send_message(imc_attestation
, connection_id
,
334 msg
->get_encoding(msg
));
341 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
343 TNC_Result
TNC_IMC_BeginHandshake(TNC_IMCID imc_id
,
344 TNC_ConnectionID connection_id
)
346 if (!imc_attestation
)
348 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
349 return TNC_RESULT_NOT_INITIALIZED
;
351 return send_message(connection_id
);
355 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
357 TNC_Result
TNC_IMC_ReceiveMessage(TNC_IMCID imc_id
,
358 TNC_ConnectionID connection_id
,
359 TNC_BufferReference msg
,
361 TNC_MessageType msg_type
)
363 pa_tnc_msg_t
*pa_tnc_msg
;
365 enumerator_t
*enumerator
;
367 bool fatal_error
= FALSE
;
369 if (!imc_attestation
)
371 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
372 return TNC_RESULT_NOT_INITIALIZED
;
375 /* parse received PA-TNC message and automatically handle any errors */
376 result
= imc_attestation
->receive_message(imc_attestation
, connection_id
,
377 chunk_create(msg
, msg_len
), msg_type
,
380 /* no parsed PA-TNC attributes available if an error occurred */
386 /* analyze PA-TNC attributes */
387 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
388 while (enumerator
->enumerate(enumerator
, &attr
))
390 if (attr
->get_vendor_id(attr
) == PEN_IETF
&&
391 attr
->get_type(attr
) == IETF_ATTR_PA_TNC_ERROR
)
393 ietf_attr_pa_tnc_error_t
*error_attr
;
394 pa_tnc_error_code_t error_code
;
395 chunk_t msg_info
, attr_info
;
398 error_attr
= (ietf_attr_pa_tnc_error_t
*)attr
;
399 error_code
= error_attr
->get_error_code(error_attr
);
400 msg_info
= error_attr
->get_msg_info(error_attr
);
402 DBG1(DBG_IMC
, "received PA-TNC error '%N' concerning message %#B",
403 pa_tnc_error_code_names
, error_code
, &msg_info
);
406 case PA_ERROR_INVALID_PARAMETER
:
407 offset
= error_attr
->get_offset(error_attr
);
408 DBG1(DBG_IMC
, " occurred at offset of %u bytes", offset
);
410 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
411 attr_info
= error_attr
->get_attr_info(error_attr
);
412 DBG1(DBG_IMC
, " unsupported attribute %#B", &attr_info
);
419 else if (attr
->get_vendor_id(attr
) == PEN_TCG
)
422 * Handle TCG PTS attributes
424 switch(attr
->get_type(attr
))
426 case TCG_PTS_REQ_PROTO_CAPS
:
428 case TCG_PTS_MEAS_ALGO
:
430 case TCG_PTS_GET_TPM_VERSION_INFO
:
432 case TCG_PTS_GET_AIK
:
435 /* PTS-based Attestation Evidence */
436 case TCG_PTS_REQ_FUNCT_COMP_EVID
:
438 case TCG_PTS_GEN_ATTEST_EVID
:
440 case TCG_PTS_REQ_FILE_MEAS
:
443 /* TODO: Not implemented yet */
444 case TCG_PTS_DH_NONCE_PARAMS_REQ
:
445 case TCG_PTS_DH_NONCE_FINISH
:
446 case TCG_PTS_REQ_FILE_META
:
447 case TCG_PTS_REQ_INTEG_MEAS_LOG
:
448 /* Attributes using XML */
449 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META
:
450 case TCG_PTS_UPDATE_TEMPL_REF_MANI
:
452 case TCG_PTS_REQ_REGISTRY_VALUE
:
453 /* Received on IMV side only*/
454 case TCG_PTS_PROTO_CAPS
:
455 case TCG_PTS_DH_NONCE_PARAMS_RESP
:
456 case TCG_PTS_MEAS_ALGO_SELECTION
:
457 case TCG_PTS_TPM_VERSION_INFO
:
458 case TCG_PTS_TEMPL_REF_MANI_SET_META
:
460 case TCG_PTS_SIMPLE_COMP_EVID
:
461 case TCG_PTS_SIMPLE_EVID_FINAL
:
462 case TCG_PTS_VERIFICATION_RESULT
:
463 case TCG_PTS_INTEG_REPORT
:
464 case TCG_PTS_UNIX_FILE_META
:
465 case TCG_PTS_FILE_MEAS
:
466 case TCG_PTS_INTEG_MEAS_LOG
:
468 DBG1(DBG_IMC
, "received unsupported attribute '%N'",
469 tcg_attr_names
, attr
->get_type(attr
));
476 enumerator
->destroy(enumerator
);
477 pa_tnc_msg
->destroy(pa_tnc_msg
);
479 /* if no error occurred then always return the same response */
480 return fatal_error ? TNC_RESULT_FATAL
: send_message(connection_id
);
484 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
486 TNC_Result
TNC_IMC_BatchEnding(TNC_IMCID imc_id
,
487 TNC_ConnectionID connection_id
)
489 if (!imc_attestation
)
491 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
492 return TNC_RESULT_NOT_INITIALIZED
;
494 return TNC_RESULT_SUCCESS
;
498 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
500 TNC_Result
TNC_IMC_Terminate(TNC_IMCID imc_id
)
502 if (!imc_attestation
)
504 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
505 return TNC_RESULT_NOT_INITIALIZED
;
507 imc_attestation
->destroy(imc_attestation
);
508 imc_attestation
= NULL
;
510 return TNC_RESULT_SUCCESS
;
514 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
516 TNC_Result
TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id
,
517 TNC_TNCC_BindFunctionPointer bind_function
)
519 if (!imc_attestation
)
521 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
522 return TNC_RESULT_NOT_INITIALIZED
;
524 return imc_attestation
->bind_functions(imc_attestation
, bind_function
);