3b23cacb0dc56f932be9f1c8035b2384feebb1d7
[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 <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 u_int32_t delimiter;
349 pts_file_meas_t *measurements;
350 pts_error_code_t pts_error;
351 chunk_t attr_info;
352
353 attr_info = attr->get_value(attr);
354 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
355 is_directory = attr_cast->get_directory_flag(attr_cast);
356 request_id = attr_cast->get_request_id(attr_cast);
357 delimiter = attr_cast->get_delimiter(attr_cast);
358 pathname = attr_cast->get_pathname(attr_cast);
359
360 if (pts->is_path_valid(pts, pathname, &pts_error) && pts_error)
361 {
362 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
363 pts_error, attr_info);
364 attr_list->insert_last(attr_list, attr);
365 break;
366 }
367 else if (!pts->is_path_valid(pts, pathname, &pts_error))
368 {
369 break;
370 }
371
372 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
373 {
374 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
375 TCG_PTS_INVALID_DELIMITER, attr_info);
376 attr_list->insert_last(attr_list, attr);
377 break;
378 }
379
380 /* Do PTS File Measurements and send them to PTS-IMV */
381 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
382 request_id, is_directory ? "directory" : "file",
383 pathname);
384 measurements = pts->do_measurements(pts, request_id,
385 pathname, is_directory);
386 if (!measurements)
387 {
388 /* TODO handle error codes from measurements */
389 return TNC_RESULT_FATAL;
390 }
391 attr = tcg_pts_attr_file_meas_create(measurements);
392 attr->set_noskip_flag(attr, TRUE);
393 attr_list->insert_last(attr_list, attr);
394 break;
395 }
396 /* TODO: Not implemented yet */
397 case TCG_PTS_DH_NONCE_PARAMS_REQ:
398 case TCG_PTS_DH_NONCE_FINISH:
399 case TCG_PTS_REQ_FILE_META:
400 case TCG_PTS_REQ_INTEG_MEAS_LOG:
401 /* Attributes using XML */
402 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
403 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
404 /* On Windows only*/
405 case TCG_PTS_REQ_REGISTRY_VALUE:
406 /* Received on IMV side only*/
407 case TCG_PTS_PROTO_CAPS:
408 case TCG_PTS_DH_NONCE_PARAMS_RESP:
409 case TCG_PTS_MEAS_ALGO_SELECTION:
410 case TCG_PTS_TPM_VERSION_INFO:
411 case TCG_PTS_TEMPL_REF_MANI_SET_META:
412 case TCG_PTS_AIK:
413 case TCG_PTS_SIMPLE_COMP_EVID:
414 case TCG_PTS_SIMPLE_EVID_FINAL:
415 case TCG_PTS_VERIFICATION_RESULT:
416 case TCG_PTS_INTEG_REPORT:
417 case TCG_PTS_UNIX_FILE_META:
418 case TCG_PTS_FILE_MEAS:
419 case TCG_PTS_INTEG_MEAS_LOG:
420 default:
421 DBG1(DBG_IMC, "received unsupported attribute '%N'",
422 tcg_attr_names, attr->get_type(attr));
423 break;
424 }
425 }
426 }
427 enumerator->destroy(enumerator);
428 pa_tnc_msg->destroy(pa_tnc_msg);
429
430 result = TNC_RESULT_SUCCESS;
431
432 if (attr_list->get_count(attr_list))
433 {
434 pa_tnc_msg = pa_tnc_msg_create();
435
436 enumerator = attr_list->create_enumerator(attr_list);
437 while (enumerator->enumerate(enumerator, &attr))
438 {
439 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
440 }
441 enumerator->destroy(enumerator);
442
443 pa_tnc_msg->build(pa_tnc_msg);
444 result = imc_attestation->send_message(imc_attestation, connection_id,
445 pa_tnc_msg->get_encoding(pa_tnc_msg));
446 pa_tnc_msg->destroy(pa_tnc_msg);
447 }
448 attr_list->destroy(attr_list);
449
450 return result;
451 }
452
453 /**
454 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
455 */
456 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
457 TNC_ConnectionID connection_id)
458 {
459 if (!imc_attestation)
460 {
461 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
462 return TNC_RESULT_NOT_INITIALIZED;
463 }
464 return TNC_RESULT_SUCCESS;
465 }
466
467 /**
468 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
469 */
470 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
471 {
472 if (!imc_attestation)
473 {
474 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
475 return TNC_RESULT_NOT_INITIALIZED;
476 }
477 imc_attestation->destroy(imc_attestation);
478 imc_attestation = NULL;
479
480 return TNC_RESULT_SUCCESS;
481 }
482
483 /**
484 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
485 */
486 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
487 TNC_TNCC_BindFunctionPointer bind_function)
488 {
489 if (!imc_attestation)
490 {
491 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
492 return TNC_RESULT_NOT_INITIALIZED;
493 }
494 return imc_attestation->bind_functions(imc_attestation, bind_function);
495 }