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