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 "imv_attestation_state.h"
17 #include "imv_attestation_process.h"
18 #include "imv_attestation_build.h"
20 #include <imv/imv_agent.h>
21 #include <pa_tnc/pa_tnc_msg.h>
22 #include <ietf/ietf_attr.h>
23 #include <ietf/ietf_attr_pa_tnc_error.h>
24 #include <ietf/ietf_attr_product_info.h>
29 #include <pts/pts_database.h>
30 #include <pts/pts_creds.h>
32 #include <tcg/tcg_attr.h>
34 #include <tncif_pa_subtypes.h>
38 #include <credentials/credential_manager.h>
39 #include <utils/linked_list.h>
43 static const char imv_name
[] = "Attestation";
45 #define IMV_VENDOR_ID PEN_TCG
46 #define IMV_SUBTYPE PA_SUBTYPE_TCG_PTS
48 static imv_agent_t
*imv_attestation
;
51 * Supported PTS measurement algorithms
53 static pts_meas_algorithms_t supported_algorithms
= PTS_MEAS_ALGO_NONE
;
56 * Supported PTS Diffie Hellman Groups
58 static pts_dh_group_t supported_dh_groups
= PTS_DH_GROUP_NONE
;
61 * PTS file measurement database
63 static pts_database_t
*pts_db
;
68 static pts_creds_t
*pts_creds
;
71 * PTS credential manager
73 static credential_manager_t
*pts_credmgr
;
76 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
78 TNC_Result
TNC_IMV_Initialize(TNC_IMVID imv_id
,
79 TNC_Version min_version
,
80 TNC_Version max_version
,
81 TNC_Version
*actual_version
)
83 char *hash_alg
, *dh_group
, *uri
, *cadir
;
87 DBG1(DBG_IMV
, "IMV \"%s\" has already been initialized", imv_name
);
88 return TNC_RESULT_ALREADY_INITIALIZED
;
90 if (!pts_meas_algo_probe(&supported_algorithms
) ||
91 !pts_dh_group_probe(&supported_dh_groups
))
93 return TNC_RESULT_FATAL
;
95 imv_attestation
= imv_agent_create(imv_name
, IMV_VENDOR_ID
, IMV_SUBTYPE
,
96 imv_id
, actual_version
);
99 return TNC_RESULT_FATAL
;
104 if (min_version
> TNC_IFIMV_VERSION_1
|| max_version
< TNC_IFIMV_VERSION_1
)
106 DBG1(DBG_IMV
, "no common IF-IMV version");
107 return TNC_RESULT_NO_COMMON_VERSION
;
110 hash_alg
= lib
->settings
->get_str(lib
->settings
,
111 "libimcv.plugins.imv-attestation.hash_algorithm", "sha256");
112 dh_group
= lib
->settings
->get_str(lib
->settings
,
113 "libimcv.plugins.imv-attestation.dh_group", "ecp256");
115 if (!pts_meas_algo_update(hash_alg
, &supported_algorithms
) ||
116 !pts_dh_group_update(dh_group
, &supported_dh_groups
))
118 return TNC_RESULT_FATAL
;
121 /* create a PTS credential manager */
122 pts_credmgr
= credential_manager_create();
124 /* create PTS credential set */
125 cadir
= lib
->settings
->get_str(lib
->settings
,
126 "libimcv.plugins.imv-attestation.cadir", NULL
);
127 pts_creds
= pts_creds_create(cadir
);
130 pts_credmgr
->add_set(pts_credmgr
, pts_creds
->get_set(pts_creds
));
133 /* attach file measurement database */
134 uri
= lib
->settings
->get_str(lib
->settings
,
135 "libimcv.plugins.imv-attestation.database", NULL
);
136 pts_db
= pts_database_create(uri
);
138 return TNC_RESULT_SUCCESS
;
142 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
144 TNC_Result
TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id
,
145 TNC_ConnectionID connection_id
,
146 TNC_ConnectionState new_state
)
150 if (!imv_attestation
)
152 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
153 return TNC_RESULT_NOT_INITIALIZED
;
157 case TNC_CONNECTION_STATE_CREATE
:
158 state
= imv_attestation_state_create(connection_id
);
159 return imv_attestation
->create_state(imv_attestation
, state
);
160 case TNC_CONNECTION_STATE_DELETE
:
161 return imv_attestation
->delete_state(imv_attestation
, connection_id
);
162 case TNC_CONNECTION_STATE_HANDSHAKE
:
164 return imv_attestation
->change_state(imv_attestation
, connection_id
,
169 static TNC_Result
send_message(TNC_ConnectionID connection_id
)
174 imv_attestation_state_t
*attestation_state
;
176 linked_list_t
*attr_list
;
177 enumerator_t
*enumerator
;
179 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
181 return TNC_RESULT_FATAL
;
183 attestation_state
= (imv_attestation_state_t
*)state
;
184 attr_list
= linked_list_create();
186 if (imv_attestation_build(attr_list
, attestation_state
, supported_algorithms
,
187 supported_dh_groups
, pts_db
))
189 if (attr_list
->get_count(attr_list
))
191 msg
= pa_tnc_msg_create();
193 /* move PA-TNC attributes to PA-TNC message */
194 enumerator
= attr_list
->create_enumerator(attr_list
);
195 while (enumerator
->enumerate(enumerator
, &attr
))
197 msg
->add_attribute(msg
, attr
);
199 enumerator
->destroy(enumerator
);
202 result
= imv_attestation
->send_message(imv_attestation
,
203 connection_id
, FALSE
, 0, TNC_IMCID_ANY
,
204 msg
->get_encoding(msg
));
209 result
= TNC_RESULT_SUCCESS
;
211 attr_list
->destroy(attr_list
);
215 attr_list
->destroy_offset(attr_list
, offsetof(pa_tnc_attr_t
, destroy
));
216 result
= TNC_RESULT_FATAL
;
222 static TNC_Result
receive_message(TNC_IMVID imv_id
,
223 TNC_ConnectionID connection_id
,
224 TNC_UInt32 msg_flags
,
226 TNC_VendorID msg_vid
,
227 TNC_MessageSubtype msg_subtype
,
228 TNC_UInt32 src_imc_id
,
229 TNC_UInt32 dst_imv_id
)
231 pa_tnc_msg_t
*pa_tnc_msg
;
233 linked_list_t
*attr_list
;
235 imv_attestation_state_t
*attestation_state
;
237 enumerator_t
*enumerator
;
240 if (!imv_attestation
)
242 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
243 return TNC_RESULT_NOT_INITIALIZED
;
246 /* get current IMV state */
247 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
249 return TNC_RESULT_FATAL
;
251 attestation_state
= (imv_attestation_state_t
*)state
;
252 pts
= attestation_state
->get_pts(attestation_state
);
254 /* parse received PA-TNC message and automatically handle any errors */
255 result
= imv_attestation
->receive_message(imv_attestation
, state
, msg
,
256 msg_vid
, msg_subtype
, src_imc_id
, dst_imv_id
, &pa_tnc_msg
);
258 /* no parsed PA-TNC attributes available if an error occurred */
264 /* preprocess any IETF standard error attributes */
265 result
= pa_tnc_msg
->process_ietf_std_errors(pa_tnc_msg
) ?
266 TNC_RESULT_FATAL
: TNC_RESULT_SUCCESS
;
268 attr_list
= linked_list_create();
270 /* analyze PA-TNC attributes */
271 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
272 while (enumerator
->enumerate(enumerator
, &attr
))
274 if (attr
->get_vendor_id(attr
) == PEN_IETF
)
276 if (attr
->get_type(attr
) == IETF_ATTR_PA_TNC_ERROR
)
278 ietf_attr_pa_tnc_error_t
*error_attr
;
279 pen_t error_vendor_id
;
280 pa_tnc_error_code_t error_code
;
283 error_attr
= (ietf_attr_pa_tnc_error_t
*)attr
;
284 error_vendor_id
= error_attr
->get_vendor_id(error_attr
);
286 if (error_vendor_id
== PEN_TCG
)
288 error_code
= error_attr
->get_error_code(error_attr
);
289 msg_info
= error_attr
->get_msg_info(error_attr
);
291 DBG1(DBG_IMV
, "received TCG-PTS error '%N'",
292 pts_error_code_names
, error_code
);
293 DBG1(DBG_IMV
, "error information: %B", &msg_info
);
295 result
= TNC_RESULT_FATAL
;
298 else if (attr
->get_type(attr
) == IETF_ATTR_PRODUCT_INFORMATION
)
300 ietf_attr_product_info_t
*attr_cast
;
303 attr_cast
= (ietf_attr_product_info_t
*)attr
;
304 platform_info
= attr_cast
->get_info(attr_cast
, NULL
, NULL
);
305 pts
->set_platform_info(pts
, platform_info
);
308 else if (attr
->get_vendor_id(attr
) == PEN_TCG
)
310 if (!imv_attestation_process(attr
, attr_list
, attestation_state
,
311 supported_algorithms
,supported_dh_groups
, pts_db
, pts_credmgr
))
313 result
= TNC_RESULT_FATAL
;
318 enumerator
->destroy(enumerator
);
319 pa_tnc_msg
->destroy(pa_tnc_msg
);
321 if (result
!= TNC_RESULT_SUCCESS
)
323 attr_list
->destroy_offset(attr_list
, offsetof(pa_tnc_attr_t
, destroy
));
324 state
->set_recommendation(state
,
325 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
326 TNC_IMV_EVALUATION_RESULT_ERROR
);
327 return imv_attestation
->provide_recommendation(imv_attestation
,
331 if (attr_list
->get_count(attr_list
))
333 pa_tnc_msg
= pa_tnc_msg_create();
335 /* move PA-TNC attributes to PA-TNC message */
336 enumerator
= attr_list
->create_enumerator(attr_list
);
337 while (enumerator
->enumerate(enumerator
, &attr
))
339 pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
);
341 enumerator
->destroy(enumerator
);
343 pa_tnc_msg
->build(pa_tnc_msg
);
344 result
= imv_attestation
->send_message(imv_attestation
, connection_id
,
345 FALSE
, 0, TNC_IMCID_ANY
,
346 pa_tnc_msg
->get_encoding(pa_tnc_msg
));
348 pa_tnc_msg
->destroy(pa_tnc_msg
);
349 attr_list
->destroy(attr_list
);
353 attr_list
->destroy(attr_list
);
355 /* check the IMV state for the next PA-TNC attributes to send */
356 result
= send_message(connection_id
);
358 if (attestation_state
->get_handshake_state(attestation_state
) ==
359 IMV_ATTESTATION_STATE_END
)
361 if (attestation_state
->get_file_meas_request_count(attestation_state
))
363 DBG1(DBG_IMV
, "failure due to %d pending file measurements",
364 attestation_state
->get_file_meas_request_count(attestation_state
));
365 attestation_state
->set_measurement_error(attestation_state
);
367 if (attestation_state
->get_component_count(attestation_state
))
369 DBG1(DBG_IMV
, "failure due to %d components waiting for evidence",
370 attestation_state
->get_component_count(attestation_state
));
371 attestation_state
->set_measurement_error(attestation_state
);
373 if (attestation_state
->get_measurement_error(attestation_state
))
375 state
->set_recommendation(state
,
376 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
377 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
);
381 state
->set_recommendation(state
,
382 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
383 TNC_IMV_EVALUATION_RESULT_COMPLIANT
);
385 return imv_attestation
->provide_recommendation(imv_attestation
,
393 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
395 TNC_Result
TNC_IMV_ReceiveMessage(TNC_IMVID imv_id
,
396 TNC_ConnectionID connection_id
,
397 TNC_BufferReference msg
,
399 TNC_MessageType msg_type
)
401 TNC_VendorID msg_vid
;
402 TNC_MessageSubtype msg_subtype
;
404 msg_vid
= msg_type
>> 8;
405 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
407 return receive_message(imv_id
, connection_id
, 0, chunk_create(msg
, msg_len
),
408 msg_vid
, msg_subtype
, 0, TNC_IMVID_ANY
);
412 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
414 TNC_Result
TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id
,
415 TNC_ConnectionID connection_id
,
416 TNC_UInt32 msg_flags
,
417 TNC_BufferReference msg
,
419 TNC_VendorID msg_vid
,
420 TNC_MessageSubtype msg_subtype
,
421 TNC_UInt32 src_imc_id
,
422 TNC_UInt32 dst_imv_id
)
424 return receive_message(imv_id
, connection_id
, msg_flags
,
425 chunk_create(msg
, msg_len
), msg_vid
, msg_subtype
,
426 src_imc_id
, dst_imv_id
);
430 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
432 TNC_Result
TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id
,
433 TNC_ConnectionID connection_id
)
435 if (!imv_attestation
)
437 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
438 return TNC_RESULT_NOT_INITIALIZED
;
440 return imv_attestation
->provide_recommendation(imv_attestation
,
445 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
447 TNC_Result
TNC_IMV_BatchEnding(TNC_IMVID imv_id
,
448 TNC_ConnectionID connection_id
)
451 imv_attestation_state_t
*attestation_state
;
453 if (!imv_attestation
)
455 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
456 return TNC_RESULT_NOT_INITIALIZED
;
458 /* get current IMV state */
459 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
461 return TNC_RESULT_FATAL
;
463 attestation_state
= (imv_attestation_state_t
*)state
;
465 /* Check if IMV has to initiate the PA-TNC exchange */
466 if (attestation_state
->get_handshake_state(attestation_state
) ==
467 IMV_ATTESTATION_STATE_INIT
)
469 return send_message(connection_id
);
471 return TNC_RESULT_SUCCESS
;
475 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
477 TNC_Result
TNC_IMV_Terminate(TNC_IMVID imv_id
)
479 if (!imv_attestation
)
481 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
482 return TNC_RESULT_NOT_INITIALIZED
;
486 pts_credmgr
->remove_set(pts_credmgr
, pts_creds
->get_set(pts_creds
));
487 pts_creds
->destroy(pts_creds
);
490 DESTROY_IF(pts_credmgr
);
494 imv_attestation
->destroy(imv_attestation
);
495 imv_attestation
= NULL
;
497 return TNC_RESULT_SUCCESS
;
501 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
503 TNC_Result
TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id
,
504 TNC_TNCS_BindFunctionPointer bind_function
)
506 if (!imv_attestation
)
508 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
509 return TNC_RESULT_NOT_INITIALIZED
;
511 return imv_attestation
->bind_functions(imv_attestation
, bind_function
);