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