9b60bc07c8ba73f0030615535cc2b440208b004a
[strongswan.git] / src / libimcv / plugins / imc_attestation / imc_attestation.c
1 /*
2 * Copyright (C) 2011 Sansar Choinyambuu
3 * HSR Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "imc_attestation_state.h"
17
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>
22 #include <ietf/ietf_attr_product_info.h>
23
24 #include <tcg/pts/pts_error.h>
25
26 #include <tcg/tcg_pts_attr_proto_caps.h>
27 #include <tcg/tcg_pts_attr_meas_algo.h>
28 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
29 #include <tcg/tcg_pts_attr_tpm_version_info.h>
30 #include <tcg/tcg_pts_attr_get_aik.h>
31 #include <tcg/tcg_pts_attr_aik.h>
32 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
33 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
34 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
35 #include <tcg/tcg_pts_attr_simple_evid_final.h>
36 #include <tcg/tcg_pts_attr_req_file_meas.h>
37 #include <tcg/tcg_pts_attr_file_meas.h>
38
39 #include <tncif_pa_subtypes.h>
40
41 #include <pen/pen.h>
42 #include <debug.h>
43 #include <utils/linked_list.h>
44
45 /* IMC definitions */
46
47 static const char imc_name[] = "Attestation";
48
49 #define IMC_VENDOR_ID PEN_TCG
50 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
51
52 static imc_agent_t *imc_attestation;
53
54 /**
55 * Supported PTS measurement algorithms
56 */
57 static pts_meas_algorithms_t supported_algorithms = 0;
58
59 /**
60 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
61 */
62 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
63 TNC_Version min_version,
64 TNC_Version max_version,
65 TNC_Version *actual_version)
66 {
67 if (imc_attestation)
68 {
69 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
70 return TNC_RESULT_ALREADY_INITIALIZED;
71 }
72 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
73 imc_id, actual_version);
74 if (!imc_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
75 {
76 return TNC_RESULT_FATAL;
77 }
78 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
79 {
80 DBG1(DBG_IMC, "no common IF-IMC version");
81 return TNC_RESULT_NO_COMMON_VERSION;
82 }
83 return TNC_RESULT_SUCCESS;
84 }
85
86 /**
87 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
88 */
89 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
90 TNC_ConnectionID connection_id,
91 TNC_ConnectionState new_state)
92 {
93 imc_state_t *state;
94 /* TODO: Not used so far */
95 //imc_attestation_state_t *attestation_state;
96
97 if (!imc_attestation)
98 {
99 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
100 return TNC_RESULT_NOT_INITIALIZED;
101 }
102 switch (new_state)
103 {
104 case TNC_CONNECTION_STATE_CREATE:
105 state = imc_attestation_state_create(connection_id);
106 return imc_attestation->create_state(imc_attestation, state);
107 case TNC_CONNECTION_STATE_DELETE:
108 return imc_attestation->delete_state(imc_attestation, connection_id);
109 case TNC_CONNECTION_STATE_HANDSHAKE:
110 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
111 case TNC_CONNECTION_STATE_ACCESS_NONE:
112 default:
113 return imc_attestation->change_state(imc_attestation, connection_id,
114 new_state, NULL);
115 }
116 }
117
118
119 /**
120 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
121 */
122 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
123 TNC_ConnectionID connection_id)
124 {
125 imc_state_t *state;
126 imc_attestation_state_t *attestation_state;
127 pts_t *pts;
128 char *platform_info;
129 TNC_Result result = TNC_RESULT_SUCCESS;
130
131 if (!imc_attestation)
132 {
133 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
134 return TNC_RESULT_NOT_INITIALIZED;
135 }
136
137 /* get current IMC state */
138 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
139 {
140 return TNC_RESULT_FATAL;
141 }
142 attestation_state = (imc_attestation_state_t*)state;
143 pts = attestation_state->get_pts(attestation_state);
144
145 platform_info = pts->get_platform_info(pts);
146 if (platform_info)
147 {
148 pa_tnc_msg_t *pa_tnc_msg;
149 pa_tnc_attr_t *attr;
150
151 pa_tnc_msg = pa_tnc_msg_create();
152 attr = ietf_attr_product_info_create(0, 0, platform_info);
153 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
154 pa_tnc_msg->build(pa_tnc_msg);
155 result = imc_attestation->send_message(imc_attestation, connection_id,
156 pa_tnc_msg->get_encoding(pa_tnc_msg));
157 pa_tnc_msg->destroy(pa_tnc_msg);
158 }
159
160 return result;
161 }
162
163 /**
164 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
165 */
166 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
167 TNC_ConnectionID connection_id,
168 TNC_BufferReference msg,
169 TNC_UInt32 msg_len,
170 TNC_MessageType msg_type)
171 {
172 pa_tnc_msg_t *pa_tnc_msg;
173 pa_tnc_attr_t *attr;
174 linked_list_t *attr_list;
175 imc_state_t *state;
176 imc_attestation_state_t *attestation_state;
177 enumerator_t *enumerator;
178 pts_t *pts;
179 TNC_Result result;
180 bool fatal_error = FALSE;
181
182 if (!imc_attestation)
183 {
184 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
185 return TNC_RESULT_NOT_INITIALIZED;
186 }
187
188 /* get current IMC state */
189 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
190 {
191 return TNC_RESULT_FATAL;
192 }
193 attestation_state = (imc_attestation_state_t*)state;
194 pts = attestation_state->get_pts(attestation_state);
195
196 /* parse received PA-TNC message and automatically handle any errors */
197 result = imc_attestation->receive_message(imc_attestation, connection_id,
198 chunk_create(msg, msg_len), msg_type,
199 &pa_tnc_msg);
200
201 /* no parsed PA-TNC attributes available if an error occurred */
202 if (!pa_tnc_msg)
203 {
204 return result;
205 }
206
207 attr_list = linked_list_create();
208
209 /* analyze PA-TNC attributes */
210 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
211 while (enumerator->enumerate(enumerator, &attr))
212 {
213 if (attr->get_vendor_id(attr) == PEN_IETF &&
214 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
215 {
216 ietf_attr_pa_tnc_error_t *error_attr;
217 pa_tnc_error_code_t error_code;
218 chunk_t msg_info, attr_info;
219 u_int32_t offset;
220
221 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
222 error_code = error_attr->get_error_code(error_attr);
223 msg_info = error_attr->get_msg_info(error_attr);
224
225 DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
226 pa_tnc_error_code_names, error_code, &msg_info);
227 switch (error_code)
228 {
229 case PA_ERROR_INVALID_PARAMETER:
230 offset = error_attr->get_offset(error_attr);
231 DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
232 break;
233 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
234 attr_info = error_attr->get_attr_info(error_attr);
235 DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
236 break;
237 default:
238 break;
239 }
240 fatal_error = TRUE;
241 }
242 else if (attr->get_vendor_id(attr) == PEN_TCG)
243 {
244 switch (attr->get_type(attr))
245 {
246 case TCG_PTS_REQ_PROTO_CAPS:
247 {
248 tcg_pts_attr_proto_caps_t *attr_cast;
249 pts_proto_caps_flag_t imc_flags, imv_flags;
250
251 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
252 imv_flags = attr_cast->get_flags(attr_cast);
253 imc_flags = pts->get_proto_caps(pts);
254 pts->set_proto_caps(pts, imc_flags & imv_flags);
255
256 /* Send PTS Protocol Capabilities attribute */
257 attr = tcg_pts_attr_proto_caps_create(imc_flags & imv_flags,
258 FALSE);
259 attr_list->insert_last(attr_list, attr);
260 break;
261 }
262 case TCG_PTS_MEAS_ALGO:
263 {
264 tcg_pts_attr_meas_algo_t *attr_cast;
265 pts_meas_algorithms_t selected_algorithm;
266
267 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
268 selected_algorithm = attr_cast->get_algorithms(attr_cast);
269
270 if ((supported_algorithms & PTS_MEAS_ALGO_SHA384) &&
271 (selected_algorithm & PTS_MEAS_ALGO_SHA384))
272 {
273 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA384);
274 }
275 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA256) &&
276 (selected_algorithm & PTS_MEAS_ALGO_SHA256))
277 {
278 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA256);
279 }
280
281 else if ((supported_algorithms & PTS_MEAS_ALGO_SHA1) &&
282 (selected_algorithm & PTS_MEAS_ALGO_SHA1))
283 {
284 pts->set_meas_algorithm(pts, PTS_MEAS_ALGO_SHA1);
285 }
286 else
287 {
288 attr = pts_hash_alg_error_create(supported_algorithms);
289 attr_list->insert_last(attr_list, attr);
290 break;
291 }
292
293 /* Send Measurement Algorithm Selection attribute */
294 selected_algorithm = pts->get_meas_algorithm(pts);
295 attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
296 TRUE);
297 attr_list->insert_last(attr_list, attr);
298 break;
299 }
300
301 case TCG_PTS_GET_TPM_VERSION_INFO:
302 {
303 chunk_t tpm_version_info, attr_info;
304
305 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
306 {
307 attr_info = attr->get_value(attr);
308 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
309 TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
310 attr_list->insert_last(attr_list, attr);
311 break;
312 }
313
314 /* Send TPM Version Info attribute */
315 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
316 attr_list->insert_last(attr_list, attr);
317 break;
318 }
319
320 case TCG_PTS_GET_AIK:
321 {
322 certificate_t *aik;
323
324 aik = pts->get_aik(pts);
325 if (!aik)
326 {
327 DBG1(DBG_IMC, "no AIK certificate or public key available");
328 break;
329 }
330
331 /* Send AIK attribute */
332 attr = tcg_pts_attr_aik_create(aik);
333 attr_list->insert_last(attr_list, attr);
334 break;
335 }
336
337 /* PTS-based Attestation Evidence */
338 case TCG_PTS_REQ_FUNCT_COMP_EVID:
339 break;
340 case TCG_PTS_GEN_ATTEST_EVID:
341 break;
342 case TCG_PTS_REQ_FILE_MEAS:
343 {
344 tcg_pts_attr_req_file_meas_t *attr_cast;
345 char *pathname;
346 u_int16_t request_id;
347 bool is_directory;
348 pts_file_meas_t *measurements;
349
350 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
351 is_directory = attr_cast->get_directory_flag(attr_cast);
352 request_id = attr_cast->get_request_id(attr_cast);
353 pathname = attr_cast->get_pathname(attr_cast);
354
355 /* Do PTS File Measurements and send them to PTS-IMV */
356 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
357 request_id, is_directory ? "directory" : "file",
358 pathname);
359 measurements = pts->do_measurements(pts, request_id,
360 pathname, is_directory);
361 if (!measurements)
362 {
363 /* TODO handle error codes from measurements */
364 return TNC_RESULT_FATAL;
365 }
366 attr = tcg_pts_attr_file_meas_create(measurements);
367 attr->set_noskip_flag(attr, TRUE);
368 attr_list->insert_last(attr_list, attr);
369 break;
370 }
371 /* TODO: Not implemented yet */
372 case TCG_PTS_DH_NONCE_PARAMS_REQ:
373 case TCG_PTS_DH_NONCE_FINISH:
374 case TCG_PTS_REQ_FILE_META:
375 case TCG_PTS_REQ_INTEG_MEAS_LOG:
376 /* Attributes using XML */
377 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
378 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
379 /* On Windows only*/
380 case TCG_PTS_REQ_REGISTRY_VALUE:
381 /* Received on IMV side only*/
382 case TCG_PTS_PROTO_CAPS:
383 case TCG_PTS_DH_NONCE_PARAMS_RESP:
384 case TCG_PTS_MEAS_ALGO_SELECTION:
385 case TCG_PTS_TPM_VERSION_INFO:
386 case TCG_PTS_TEMPL_REF_MANI_SET_META:
387 case TCG_PTS_AIK:
388 case TCG_PTS_SIMPLE_COMP_EVID:
389 case TCG_PTS_SIMPLE_EVID_FINAL:
390 case TCG_PTS_VERIFICATION_RESULT:
391 case TCG_PTS_INTEG_REPORT:
392 case TCG_PTS_UNIX_FILE_META:
393 case TCG_PTS_FILE_MEAS:
394 case TCG_PTS_INTEG_MEAS_LOG:
395 default:
396 DBG1(DBG_IMC, "received unsupported attribute '%N'",
397 tcg_attr_names, attr->get_type(attr));
398 break;
399 }
400 }
401 }
402 enumerator->destroy(enumerator);
403 pa_tnc_msg->destroy(pa_tnc_msg);
404
405 result = TNC_RESULT_SUCCESS;
406
407 if (attr_list->get_count(attr_list))
408 {
409 pa_tnc_msg = pa_tnc_msg_create();
410
411 enumerator = attr_list->create_enumerator(attr_list);
412 while (enumerator->enumerate(enumerator, &attr))
413 {
414 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
415 }
416 enumerator->destroy(enumerator);
417
418 pa_tnc_msg->build(pa_tnc_msg);
419 result = imc_attestation->send_message(imc_attestation, connection_id,
420 pa_tnc_msg->get_encoding(pa_tnc_msg));
421
422 attr_list->destroy(attr_list);
423 pa_tnc_msg->destroy(pa_tnc_msg);
424 }
425
426 return result;
427 }
428
429 /**
430 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
431 */
432 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
433 TNC_ConnectionID connection_id)
434 {
435 if (!imc_attestation)
436 {
437 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
438 return TNC_RESULT_NOT_INITIALIZED;
439 }
440 return TNC_RESULT_SUCCESS;
441 }
442
443 /**
444 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
445 */
446 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
447 {
448 if (!imc_attestation)
449 {
450 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
451 return TNC_RESULT_NOT_INITIALIZED;
452 }
453 imc_attestation->destroy(imc_attestation);
454 imc_attestation = NULL;
455
456 return TNC_RESULT_SUCCESS;
457 }
458
459 /**
460 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
461 */
462 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
463 TNC_TNCC_BindFunctionPointer bind_function)
464 {
465 if (!imc_attestation)
466 {
467 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
468 return TNC_RESULT_NOT_INITIALIZED;
469 }
470 return imc_attestation->bind_functions(imc_attestation, bind_function);
471 }