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.7.1 of TCG TNC IF-IMV Specification 1.2
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.7.2 of TCG TNC IF-IMV Specification 1.2
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
)
173 imv_attestation_state_t
*attestation_state
;
176 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
178 return TNC_RESULT_FATAL
;
180 attestation_state
= (imv_attestation_state_t
*)state
;
181 msg
= pa_tnc_msg_create();
183 if (imv_attestation_build(msg
, attestation_state
, supported_algorithms
,
184 supported_dh_groups
, pts_db
))
187 result
= imv_attestation
->send_message(imv_attestation
, connection_id
,
188 FALSE
, 0, TNC_IMCID_ANY
,
189 msg
->get_encoding(msg
));
193 result
= TNC_RESULT_FATAL
;
201 * see section 3.7.3 of TCG TNC IF-IMV Specification 1.2
203 TNC_Result
TNC_IMV_ReceiveMessage(TNC_IMVID imv_id
,
204 TNC_ConnectionID connection_id
,
205 TNC_BufferReference msg
,
207 TNC_MessageType msg_type
)
209 pa_tnc_msg_t
*pa_tnc_msg
;
211 linked_list_t
*attr_list
;
213 imv_attestation_state_t
*attestation_state
;
215 enumerator_t
*enumerator
;
218 if (!imv_attestation
)
220 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
221 return TNC_RESULT_NOT_INITIALIZED
;
224 /* get current IMV state */
225 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
227 return TNC_RESULT_FATAL
;
229 attestation_state
= (imv_attestation_state_t
*)state
;
230 pts
= attestation_state
->get_pts(attestation_state
);
232 /* parse received PA-TNC message and automatically handle any errors */
233 result
= imv_attestation
->receive_message(imv_attestation
, connection_id
,
234 chunk_create(msg
, msg_len
), msg_type
,
237 /* no parsed PA-TNC attributes available if an error occurred */
243 attr_list
= linked_list_create();
244 result
= TNC_RESULT_SUCCESS
;
246 /* analyze PA-TNC attributes */
247 enumerator
= pa_tnc_msg
->create_attribute_enumerator(pa_tnc_msg
);
248 while (enumerator
->enumerate(enumerator
, &attr
))
250 if (attr
->get_vendor_id(attr
) == PEN_IETF
)
252 if (attr
->get_type(attr
) == IETF_ATTR_PA_TNC_ERROR
)
254 ietf_attr_pa_tnc_error_t
*error_attr
;
255 pen_t error_vendor_id
;
256 pa_tnc_error_code_t error_code
;
257 chunk_t msg_info
, attr_info
;
260 error_attr
= (ietf_attr_pa_tnc_error_t
*)attr
;
261 error_vendor_id
= error_attr
->get_vendor_id(error_attr
);
262 error_code
= error_attr
->get_error_code(error_attr
);
263 msg_info
= error_attr
->get_msg_info(error_attr
);
265 if (error_vendor_id
== PEN_IETF
)
267 DBG1(DBG_IMV
, "received PA-TNC error '%N' "
268 "concerning message %#B",
269 pa_tnc_error_code_names
, error_code
, &msg_info
);
273 case PA_ERROR_INVALID_PARAMETER
:
274 offset
= error_attr
->get_offset(error_attr
);
275 DBG1(DBG_IMV
, " occurred at offset of %u bytes",
278 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
279 attr_info
= error_attr
->get_attr_info(error_attr
);
280 DBG1(DBG_IMV
, " unsupported attribute %#B",
287 else if (error_vendor_id
== PEN_TCG
)
289 DBG1(DBG_IMV
, "received TCG-PTS error '%N'",
290 pts_error_code_names
, error_code
);
291 DBG1(DBG_IMV
, "error information: %B", &msg_info
);
293 result
= TNC_RESULT_FATAL
;
295 else if (attr
->get_type(attr
) == IETF_ATTR_PRODUCT_INFORMATION
)
297 ietf_attr_product_info_t
*attr_cast
;
300 attr_cast
= (ietf_attr_product_info_t
*)attr
;
301 platform_info
= attr_cast
->get_info(attr_cast
, NULL
, NULL
);
302 pts
->set_platform_info(pts
, platform_info
);
305 else if (attr
->get_vendor_id(attr
) == PEN_TCG
)
307 if (!imv_attestation_process(attr
, attr_list
, attestation_state
,
308 supported_algorithms
,supported_dh_groups
, pts_db
, pts_credmgr
))
310 result
= TNC_RESULT_FATAL
;
315 enumerator
->destroy(enumerator
);
316 pa_tnc_msg
->destroy(pa_tnc_msg
);
318 if (result
!= TNC_RESULT_SUCCESS
)
320 attr_list
->destroy(attr_list
);
321 state
->set_recommendation(state
,
322 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
323 TNC_IMV_EVALUATION_RESULT_ERROR
);
324 return imv_attestation
->provide_recommendation(imv_attestation
,
328 if (attr_list
->get_count(attr_list
))
330 pa_tnc_msg
= pa_tnc_msg_create();
332 enumerator
= attr_list
->create_enumerator(attr_list
);
333 while (enumerator
->enumerate(enumerator
, &attr
))
335 pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
);
337 enumerator
->destroy(enumerator
);
339 pa_tnc_msg
->build(pa_tnc_msg
);
340 result
= imv_attestation
->send_message(imv_attestation
, connection_id
,
341 FALSE
, 0, TNC_IMCID_ANY
,
342 pa_tnc_msg
->get_encoding(pa_tnc_msg
));
344 pa_tnc_msg
->destroy(pa_tnc_msg
);
345 attr_list
->destroy(attr_list
);
349 attr_list
->destroy(attr_list
);
351 if (attestation_state
->get_handshake_state(attestation_state
) ==
352 IMV_ATTESTATION_STATE_END
)
354 if (attestation_state
->get_file_meas_request_count(attestation_state
))
356 DBG1(DBG_IMV
, "failure due to %d pending file measurements",
357 attestation_state
->get_file_meas_request_count(attestation_state
));
358 attestation_state
->set_measurement_error(attestation_state
);
360 if (attestation_state
->get_component_count(attestation_state
))
362 DBG1(DBG_IMV
, "failure due to %d components waiting for evidence",
363 attestation_state
->get_component_count(attestation_state
));
364 attestation_state
->set_measurement_error(attestation_state
);
366 if (attestation_state
->get_measurement_error(attestation_state
))
368 state
->set_recommendation(state
,
369 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
370 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
);
374 state
->set_recommendation(state
,
375 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
376 TNC_IMV_EVALUATION_RESULT_COMPLIANT
);
378 return imv_attestation
->provide_recommendation(imv_attestation
,
382 return send_message(connection_id
);
386 * see section 3.7.4 of TCG TNC IF-IMV Specification 1.2
388 TNC_Result
TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id
,
389 TNC_ConnectionID connection_id
)
391 if (!imv_attestation
)
393 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
394 return TNC_RESULT_NOT_INITIALIZED
;
396 return imv_attestation
->provide_recommendation(imv_attestation
,
401 * see section 3.7.5 of TCG TNC IF-IMV Specification 1.2
403 TNC_Result
TNC_IMV_BatchEnding(TNC_IMVID imv_id
,
404 TNC_ConnectionID connection_id
)
407 imv_attestation_state_t
*attestation_state
;
409 if (!imv_attestation
)
411 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
412 return TNC_RESULT_NOT_INITIALIZED
;
414 /* get current IMV state */
415 if (!imv_attestation
->get_state(imv_attestation
, connection_id
, &state
))
417 return TNC_RESULT_FATAL
;
419 attestation_state
= (imv_attestation_state_t
*)state
;
421 /* Check if IMV has to initiate the PA-TNC exchange */
422 if (attestation_state
->get_handshake_state(attestation_state
) ==
423 IMV_ATTESTATION_STATE_INIT
)
425 return send_message(connection_id
);
427 return TNC_RESULT_SUCCESS
;
431 * see section 3.7.6 of TCG TNC IF-IMV Specification 1.2
433 TNC_Result
TNC_IMV_Terminate(TNC_IMVID imv_id
)
435 if (!imv_attestation
)
437 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
438 return TNC_RESULT_NOT_INITIALIZED
;
442 pts_credmgr
->remove_set(pts_credmgr
, pts_creds
->get_set(pts_creds
));
443 pts_creds
->destroy(pts_creds
);
446 DESTROY_IF(pts_credmgr
);
450 imv_attestation
->destroy(imv_attestation
);
451 imv_attestation
= NULL
;
453 return TNC_RESULT_SUCCESS
;
457 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.2
459 TNC_Result
TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id
,
460 TNC_TNCS_BindFunctionPointer bind_function
)
462 if (!imv_attestation
)
464 DBG1(DBG_IMV
, "IMV \"%s\" has not been initialized", imv_name
);
465 return TNC_RESULT_NOT_INITIALIZED
;
467 return imv_attestation
->bind_functions(imv_attestation
, bind_function
);