moved pts_meas_algorithms_t to own header file
[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_tpm_version_info.h>
26 #include <tcg/tcg_pts_attr_aik.h>
27 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
28 #include <tcg/tcg_pts_attr_simple_evid_final.h>
29 #include <tcg/tcg_pts_attr_file_meas.h>
30
31 #include <tncif_pa_subtypes.h>
32
33 #include <pen/pen.h>
34 #include <debug.h>
35 #include <utils/linked_list.h>
36
37 #include <trousers/tss.h>
38 #include <trousers/trousers.h>
39 #include <openssl/sha.h>
40
41
42 /* IMC definitions */
43
44 static const char imc_name[] = "Attestation";
45
46 #define IMC_VENDOR_ID PEN_TCG
47 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
48 #define IMC_ATTESTATION_MAX_FILE_SIZE 32768
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 * Selected PTS measurement algorithm after attribute exchange
59 */
60 static pts_meas_algorithms_t selected_algorithm = PTS_MEAS_ALGO_SHA256;
61
62 /**
63 * List of files and directories to measure
64 */
65 static linked_list_t *files, *directories;
66
67 /**
68 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
69 */
70 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
71 TNC_Version min_version,
72 TNC_Version max_version,
73 TNC_Version *actual_version)
74 {
75 if (imc_attestation)
76 {
77 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
78 return TNC_RESULT_ALREADY_INITIALIZED;
79 }
80 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
81 imc_id, actual_version);
82 if (!imc_attestation ||
83 !tcg_pts_probe_meas_algorithms(&supported_algorithms))
84 {
85 return TNC_RESULT_FATAL;
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 * Get the TPM Version Information
129 */
130 static TSS_RESULT get_tpm_version_info(BYTE *tpm_version_info)
131 {
132 TSS_HCONTEXT hContext;
133 TSS_HTPM hTPM;
134 TSS_RESULT uiResult;
135 UINT32 uiResultLen;
136 /* TODO: Needed for parsing version info on IMV side */
137 //TPM_CAP_VERSION_INFO versionInfo;
138 //UINT64 offset = 0;
139
140 uiResult = Tspi_Context_Create(&hContext);
141 if (uiResult != TSS_SUCCESS) {
142 DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_Create\n", uiResult);
143 return uiResult;
144 }
145 uiResult = Tspi_Context_Connect(hContext, NULL);
146 if (uiResult != TSS_SUCCESS) {
147 DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_Connect\n", uiResult);
148 return uiResult;
149 }
150 uiResult = Tspi_Context_GetTpmObject (hContext, &hTPM);
151 if (uiResult != TSS_SUCCESS) {
152 DBG1(DBG_IMC,"Error 0x%x on Tspi_Context_GetTpmObject\n", uiResult);
153 return uiResult;
154 }
155
156 uiResult = Tspi_TPM_GetCapability(hTPM, TSS_TPMCAP_VERSION_VAL, 0, NULL, &uiResultLen,
157 &tpm_version_info);
158 if (uiResult != TSS_SUCCESS) {
159 DBG1(DBG_IMC,"Error 0x%x on Tspi_TPM_GetCapability\n", uiResult);
160 return uiResult;
161 }
162 }
163
164 /**
165 * Get Hash Measurement of a file
166 * Uses openssl's sha.h
167 */
168 static TNC_Result hash_file(char *path, unsigned char *out)
169 {
170 BYTE *buffer;
171 FILE *file;
172 int bytesRead = 0;
173
174 file = fopen(path, "rb");
175 if (!file) {
176 DBG1(DBG_IMC,"File can not be opened %s\n", path);
177 return TNC_RESULT_FATAL;
178 }
179
180 buffer = malloc(IMC_ATTESTATION_MAX_FILE_SIZE);
181 if(!buffer)
182 {
183 DBG1(DBG_IMC,"Buffer couldn't be allocated memory");
184 goto fatal;
185 }
186
187 switch(selected_algorithm)
188 {
189 case PTS_MEAS_ALGO_SHA1:
190 {
191 SHA_CTX sha1;
192 SHA1_Init(&sha1);
193
194 while((bytesRead = fread(buffer, 1, IMC_ATTESTATION_MAX_FILE_SIZE, file)))
195 {
196 SHA1_Update(&sha1, buffer, bytesRead);
197 }
198 SHA1_Final(out, &sha1);
199 break;
200 }
201 case PTS_MEAS_ALGO_SHA256:
202 {
203 SHA256_CTX sha256;
204 SHA256_Init(&sha256);
205
206 while((bytesRead = fread(buffer, 1, IMC_ATTESTATION_MAX_FILE_SIZE, file)))
207 {
208 SHA256_Update(&sha256, buffer, bytesRead);
209 }
210 SHA256_Final(out, &sha256);
211 break;
212 }
213 case PTS_MEAS_ALGO_SHA384:
214 /*{
215 SHA384_CTX sha384;
216 SHA384_Init(&sha384);
217
218 while((bytesRead = fread(buffer, 1, IMC_ATTESTATION_MAX_FILE_SIZE, file)))
219 {
220 SHA384_Update(&sha384, buffer, bytesRead);
221 }
222 SHA384_Final(out, &sha384);
223 break;
224 }
225 */
226 default:
227 DBG1(DBG_IMC,"Unsupported Selected Hashing Algorithm \n");
228 return TNC_RESULT_FATAL;
229 }
230
231 fclose(file);
232 free(buffer);
233 return TNC_RESULT_SUCCESS;
234
235 fatal:
236 fclose(file);
237 return TNC_RESULT_FATAL;
238 }
239
240 static TNC_Result send_message(TNC_ConnectionID connection_id)
241 {
242 pa_tnc_msg_t *msg;
243 pa_tnc_attr_t *attr;
244 imc_state_t *state;
245 imc_attestation_state_t *attestation_state;
246 imc_attestation_handshake_state_t handshake_state;
247 TNC_Result result;
248
249 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
250 {
251 return TNC_RESULT_FATAL;
252 }
253 attestation_state = (imc_attestation_state_t*)state;
254 handshake_state = attestation_state->get_handshake_state(attestation_state);
255
256 /* Switch on the attribute type IMC has received */
257 switch (handshake_state)
258 {
259 case IMC_ATTESTATION_STATE_REQ_PROTO_CAP:
260 {
261 pts_proto_caps_flag_t flags;
262 flags = PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_VER;
263 attr = tcg_pts_attr_proto_caps_create(flags);
264 break;
265 }
266 case IMC_ATTESTATION_STATE_REQ_MEAS_ALGO:
267 {
268 pts_meas_algorithms_t algorithm;
269 algorithm = PTS_MEAS_ALGO_SHA1;
270 /* Save the selected algorithm for further attributes creation */
271 selected_algorithm = algorithm;
272 attr = tcg_pts_attr_meas_algo_create(algorithm, TRUE);
273 break;
274 }
275 case IMC_ATTESTATION_STATE_GET_TPM_INFO:
276 {
277 TSS_RESULT uiResult;
278 BYTE *tpm_version_info;
279
280 uiResult = get_tpm_version_info(tpm_version_info);
281 if (uiResult != TSS_SUCCESS) {
282 DBG1(DBG_IMC,"Error 0x%x on get_tpm_version_info\n", uiResult);
283 return uiResult;
284 }
285
286 attr = tcg_pts_attr_tpm_version_info_create(
287 chunk_create((char *)tpm_version_info,
288 strlen(tpm_version_info)));
289 break;
290 }
291 /* TODO: working on */
292 /*case IMC_ATTESTATION_STATE_REQ_FILE_MEAS:
293 {
294 enumerator_t *enumerator;
295 measurement_req_entry_t *entry;
296
297 enumerator = enumerator_create_single(file_list, NULL);
298 while (enumerator->enumerate(enumerator, &entry))
299 {
300 attr = tcg_pts_attr_req_file_meas_create(false,
301 entry.request_id, delimiter,
302 chunk_create(entry.path,strlen(entry.path)));
303 attr->set_noskip_flag(attr, TRUE);
304 msg->add_attribute(msg, attr);
305 }
306
307 enumerator = enumerator_create_single(file_list, NULL);
308 while (enumerator->enumerate(enumerator, &entry))
309 {
310 attr = tcg_pts_attr_req_file_meas_create(false,
311 entry.request_id, delimiter,
312 chunk_create(entry.path,strlen(entry.path)));
313 attr->set_noskip_flag(attr, TRUE);
314 msg->add_attribute(msg, attr);
315 }
316 break;
317 }*/
318 case IMC_ATTESTATION_STATE_GET_AIK:
319 case IMC_ATTESTATION_STATE_REQ_FUNCT_COMP_EVID:
320 case IMC_ATTESTATION_STATE_GEN_ATTEST_EVID:
321 case IMC_ATTESTATION_STATE_REQ_FILE_METADATA:
322 case IMC_ATTESTATION_STATE_REQ_IML:
323 case IMC_ATTESTATION_STATE_INIT:
324 DBG1(DBG_IMC, "Attestation IMC has nothing to send: \"%s\"", handshake_state);
325 return TNC_RESULT_FATAL;
326 default:
327 DBG1(DBG_IMC, "Attestation IMC is in unknown state: \"%s\"", handshake_state);
328 return TNC_RESULT_FATAL;
329 }
330
331
332 attr->set_noskip_flag(attr, TRUE);
333 msg = pa_tnc_msg_create();
334 msg->add_attribute(msg, attr);
335 msg->build(msg);
336 result = imc_attestation->send_message(imc_attestation, connection_id,
337 msg->get_encoding(msg));
338 msg->destroy(msg);
339
340 return result;
341 }
342
343 /**
344 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
345 */
346 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
347 TNC_ConnectionID connection_id)
348 {
349 if (!imc_attestation)
350 {
351 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
352 return TNC_RESULT_NOT_INITIALIZED;
353 }
354 return send_message(connection_id);
355 }
356
357 /**
358 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
359 */
360 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
361 TNC_ConnectionID connection_id,
362 TNC_BufferReference msg,
363 TNC_UInt32 msg_len,
364 TNC_MessageType msg_type)
365 {
366 pa_tnc_msg_t *pa_tnc_msg;
367 pa_tnc_attr_t *attr;
368 enumerator_t *enumerator;
369 TNC_Result result;
370 bool fatal_error = FALSE;
371
372 if (!imc_attestation)
373 {
374 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
375 return TNC_RESULT_NOT_INITIALIZED;
376 }
377
378 /* parse received PA-TNC message and automatically handle any errors */
379 result = imc_attestation->receive_message(imc_attestation, connection_id,
380 chunk_create(msg, msg_len), msg_type,
381 &pa_tnc_msg);
382
383 /* no parsed PA-TNC attributes available if an error occurred */
384 if (!pa_tnc_msg)
385 {
386 return result;
387 }
388
389 /* analyze PA-TNC attributes */
390 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
391 while (enumerator->enumerate(enumerator, &attr))
392 {
393 if (attr->get_vendor_id(attr) == PEN_IETF &&
394 attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR)
395 {
396 ietf_attr_pa_tnc_error_t *error_attr;
397 pa_tnc_error_code_t error_code;
398 chunk_t msg_info, attr_info;
399 u_int32_t offset;
400
401 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
402 error_code = error_attr->get_error_code(error_attr);
403 msg_info = error_attr->get_msg_info(error_attr);
404
405 DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message %#B",
406 pa_tnc_error_code_names, error_code, &msg_info);
407 switch (error_code)
408 {
409 case PA_ERROR_INVALID_PARAMETER:
410 offset = error_attr->get_offset(error_attr);
411 DBG1(DBG_IMC, " occurred at offset of %u bytes", offset);
412 break;
413 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
414 attr_info = error_attr->get_attr_info(error_attr);
415 DBG1(DBG_IMC, " unsupported attribute %#B", &attr_info);
416 break;
417 default:
418 break;
419 }
420 fatal_error = TRUE;
421 }
422 else if (attr->get_vendor_id(attr) == PEN_TCG)
423 {
424 /**
425 * Handle TCG PTS attributes
426 */
427 switch(attr->get_type(attr))
428 {
429 case TCG_PTS_REQ_PROTO_CAPS:
430 break;
431 case TCG_PTS_MEAS_ALGO:
432 break;
433 case TCG_PTS_GET_TPM_VERSION_INFO:
434 break;
435 case TCG_PTS_GET_AIK:
436 break;
437
438 /* PTS-based Attestation Evidence */
439 case TCG_PTS_REQ_FUNCT_COMP_EVID:
440 break;
441 case TCG_PTS_GEN_ATTEST_EVID:
442 break;
443 case TCG_PTS_REQ_FILE_MEAS:
444 break;
445
446 /* TODO: Not implemented yet */
447 case TCG_PTS_DH_NONCE_PARAMS_REQ:
448 case TCG_PTS_DH_NONCE_FINISH:
449 case TCG_PTS_REQ_FILE_META:
450 case TCG_PTS_REQ_INTEG_MEAS_LOG:
451 /* Attributes using XML */
452 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
453 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
454 /* On Windows only*/
455 case TCG_PTS_REQ_REGISTRY_VALUE:
456 /* Received on IMV side only*/
457 case TCG_PTS_PROTO_CAPS:
458 case TCG_PTS_DH_NONCE_PARAMS_RESP:
459 case TCG_PTS_MEAS_ALGO_SELECTION:
460 case TCG_PTS_TPM_VERSION_INFO:
461 case TCG_PTS_TEMPL_REF_MANI_SET_META:
462 case TCG_PTS_AIK:
463 case TCG_PTS_SIMPLE_COMP_EVID:
464 case TCG_PTS_SIMPLE_EVID_FINAL:
465 case TCG_PTS_VERIFICATION_RESULT:
466 case TCG_PTS_INTEG_REPORT:
467 case TCG_PTS_UNIX_FILE_META:
468 case TCG_PTS_FILE_MEAS:
469 case TCG_PTS_INTEG_MEAS_LOG:
470 default:
471 DBG1(DBG_IMC, "received unsupported attribute '%N'",
472 tcg_attr_names, attr->get_type(attr));
473 break;
474 }
475
476
477 }
478 }
479 enumerator->destroy(enumerator);
480 pa_tnc_msg->destroy(pa_tnc_msg);
481
482 /* if no error occurred then always return the same response */
483 return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id);
484 }
485
486 /**
487 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
488 */
489 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
490 TNC_ConnectionID connection_id)
491 {
492 if (!imc_attestation)
493 {
494 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
495 return TNC_RESULT_NOT_INITIALIZED;
496 }
497 return TNC_RESULT_SUCCESS;
498 }
499
500 /**
501 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
502 */
503 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
504 {
505 if (!imc_attestation)
506 {
507 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
508 return TNC_RESULT_NOT_INITIALIZED;
509 }
510 imc_attestation->destroy(imc_attestation);
511 imc_attestation = NULL;
512
513 return TNC_RESULT_SUCCESS;
514 }
515
516 /**
517 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
518 */
519 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
520 TNC_TNCC_BindFunctionPointer bind_function)
521 {
522 if (!imc_attestation)
523 {
524 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
525 return TNC_RESULT_NOT_INITIALIZED;
526 }
527 return imc_attestation->bind_functions(imc_attestation, bind_function);
528 }