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