send TCG_PTS_TPM_VERS_NOT_SUPPORTED error code
[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/pts/pts_error.h>
24
25 #include <tcg/tcg_pts_attr_proto_caps.h>
26 #include <tcg/tcg_pts_attr_meas_algo.h>
27 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
28 #include <tcg/tcg_pts_attr_tpm_version_info.h>
29 #include <tcg/tcg_pts_attr_get_aik.h>
30 #include <tcg/tcg_pts_attr_aik.h>
31 #include <tcg/tcg_pts_attr_req_funct_comp_evid.h>
32 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
33 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
34 #include <tcg/tcg_pts_attr_simple_evid_final.h>
35 #include <tcg/tcg_pts_attr_req_file_meas.h>
36 #include <tcg/tcg_pts_attr_file_meas.h>
37
38 #include <tncif_pa_subtypes.h>
39
40 #include <pen/pen.h>
41 #include <debug.h>
42 #include <utils/linked_list.h>
43
44 /* IMC definitions */
45
46 static const char imc_name[] = "Attestation";
47
48 #define IMC_VENDOR_ID PEN_TCG
49 #define IMC_SUBTYPE PA_SUBTYPE_TCG_PTS
50
51 static imc_agent_t *imc_attestation;
52
53 /**
54 * Supported PTS measurement algorithms
55 */
56 static pts_meas_algorithms_t supported_algorithms = 0;
57
58 /**
59 * see section 3.7.1 of TCG TNC IF-IMC Specification 1.2
60 */
61 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
62 TNC_Version min_version,
63 TNC_Version max_version,
64 TNC_Version *actual_version)
65 {
66 if (imc_attestation)
67 {
68 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
69 return TNC_RESULT_ALREADY_INITIALIZED;
70 }
71 imc_attestation = imc_agent_create(imc_name, IMC_VENDOR_ID, IMC_SUBTYPE,
72 imc_id, actual_version);
73 if (!imc_attestation || !pts_meas_probe_algorithms(&supported_algorithms))
74 {
75 return TNC_RESULT_FATAL;
76 }
77 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
78 {
79 DBG1(DBG_IMC, "no common IF-IMC version");
80 return TNC_RESULT_NO_COMMON_VERSION;
81 }
82 return TNC_RESULT_SUCCESS;
83 }
84
85 /**
86 * see section 3.7.2 of TCG TNC IF-IMC Specification 1.2
87 */
88 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
89 TNC_ConnectionID connection_id,
90 TNC_ConnectionState new_state)
91 {
92 imc_state_t *state;
93 /* TODO: Not used so far */
94 //imc_attestation_state_t *attestation_state;
95
96 if (!imc_attestation)
97 {
98 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
99 return TNC_RESULT_NOT_INITIALIZED;
100 }
101 switch (new_state)
102 {
103 case TNC_CONNECTION_STATE_CREATE:
104 state = imc_attestation_state_create(connection_id);
105 return imc_attestation->create_state(imc_attestation, state);
106 case TNC_CONNECTION_STATE_DELETE:
107 return imc_attestation->delete_state(imc_attestation, connection_id);
108 case TNC_CONNECTION_STATE_HANDSHAKE:
109 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
110 case TNC_CONNECTION_STATE_ACCESS_NONE:
111 default:
112 return imc_attestation->change_state(imc_attestation, connection_id,
113 new_state, NULL);
114 }
115 }
116
117
118 /**
119 * see section 3.7.3 of TCG TNC IF-IMC Specification 1.2
120 */
121 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
122 TNC_ConnectionID connection_id)
123 {
124 if (!imc_attestation)
125 {
126 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
127 return TNC_RESULT_NOT_INITIALIZED;
128 }
129 return TNC_RESULT_SUCCESS;
130 }
131
132 /**
133 * see section 3.7.4 of TCG TNC IF-IMC Specification 1.2
134 */
135 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
136 TNC_ConnectionID connection_id,
137 TNC_BufferReference msg,
138 TNC_UInt32 msg_len,
139 TNC_MessageType msg_type)
140 {
141 pa_tnc_msg_t *pa_tnc_msg;
142 pa_tnc_attr_t *attr;
143 linked_list_t *attr_list;
144 imc_state_t *state;
145 imc_attestation_state_t *attestation_state;
146 enumerator_t *enumerator;
147 pts_t *pts;
148 TNC_Result result;
149 bool fatal_error = FALSE;
150
151 if (!imc_attestation)
152 {
153 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
154 return TNC_RESULT_NOT_INITIALIZED;
155 }
156
157 /* get current IMC state */
158 if (!imc_attestation->get_state(imc_attestation, connection_id, &state))
159 {
160 return TNC_RESULT_FATAL;
161 }
162 attestation_state = (imc_attestation_state_t*)state;
163 pts = attestation_state->get_pts(attestation_state);
164
165 /* parse received PA-TNC message and automatically handle any errors */
166 result = imc_attestation->receive_message(imc_attestation, connection_id,
167 chunk_create(msg, msg_len), msg_type,
168 &pa_tnc_msg);
169
170 /* no parsed PA-TNC attributes available if an error occurred */
171 if (!pa_tnc_msg)
172 {
173 return result;
174 }
175
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 = tcg_pts_attr_proto_caps_create(imc_flags & imv_flags,
227 FALSE);
228 attr_list->insert_last(attr_list, attr);
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 attr = pts_hash_alg_error_create(supported_algorithms);
258 attr_list->insert_last(attr_list, attr);
259 break;
260 }
261
262 /* Send Measurement Algorithm Selection attribute */
263 selected_algorithm = pts->get_meas_algorithm(pts);
264 attr = tcg_pts_attr_meas_algo_create(selected_algorithm,
265 TRUE);
266 attr_list->insert_last(attr_list, attr);
267 break;
268 }
269
270 case TCG_PTS_GET_TPM_VERSION_INFO:
271 {
272 chunk_t tpm_version_info, attr_info;
273
274 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
275 {
276 attr_info = attr->get_value(attr);
277 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
278 TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
279 attr_list->insert_last(attr_list, attr);
280 break;
281 }
282
283 /* Send TPM Version Info attribute */
284 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
285 attr_list->insert_last(attr_list, attr);
286 break;
287 }
288
289 case TCG_PTS_GET_AIK:
290 {
291 chunk_t aik;
292 bool is_naked_key;
293
294 if (!pts->get_aik(pts, &aik, &is_naked_key))
295 {
296 DBG1(DBG_IMC, "Obtaining AIK Certificate failed");
297 break;
298 }
299
300 /* Send AIK attribute */
301 attr = tcg_pts_attr_aik_create(is_naked_key, aik);
302 attr_list->insert_last(attr_list, attr);
303 break;
304 }
305
306 /* PTS-based Attestation Evidence */
307 case TCG_PTS_REQ_FUNCT_COMP_EVID:
308 break;
309 case TCG_PTS_GEN_ATTEST_EVID:
310 break;
311 case TCG_PTS_REQ_FILE_MEAS:
312 {
313 tcg_pts_attr_req_file_meas_t *attr_cast;
314 char *pathname;
315 u_int16_t request_id;
316 bool is_directory;
317 pts_file_meas_t *measurements;
318
319 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
320 is_directory = attr_cast->get_directory_flag(attr_cast);
321 request_id = attr_cast->get_request_id(attr_cast);
322 pathname = attr_cast->get_pathname(attr_cast);
323
324 /* Do PTS File Measurements and send them to PTS-IMV */
325 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
326 request_id, is_directory ? "directory" : "file",
327 pathname);
328 measurements = pts->do_measurements(pts, request_id,
329 pathname, is_directory);
330 if (!measurements)
331 {
332 /* TODO handle error codes from measurements */
333 return TNC_RESULT_FATAL;
334 }
335 attr = tcg_pts_attr_file_meas_create(measurements);
336 attr->set_noskip_flag(attr, TRUE);
337 attr_list->insert_last(attr_list, attr);
338 break;
339 }
340 /* TODO: Not implemented yet */
341 case TCG_PTS_DH_NONCE_PARAMS_REQ:
342 case TCG_PTS_DH_NONCE_FINISH:
343 case TCG_PTS_REQ_FILE_META:
344 case TCG_PTS_REQ_INTEG_MEAS_LOG:
345 /* Attributes using XML */
346 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
347 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
348 /* On Windows only*/
349 case TCG_PTS_REQ_REGISTRY_VALUE:
350 /* Received on IMV side only*/
351 case TCG_PTS_PROTO_CAPS:
352 case TCG_PTS_DH_NONCE_PARAMS_RESP:
353 case TCG_PTS_MEAS_ALGO_SELECTION:
354 case TCG_PTS_TPM_VERSION_INFO:
355 case TCG_PTS_TEMPL_REF_MANI_SET_META:
356 case TCG_PTS_AIK:
357 case TCG_PTS_SIMPLE_COMP_EVID:
358 case TCG_PTS_SIMPLE_EVID_FINAL:
359 case TCG_PTS_VERIFICATION_RESULT:
360 case TCG_PTS_INTEG_REPORT:
361 case TCG_PTS_UNIX_FILE_META:
362 case TCG_PTS_FILE_MEAS:
363 case TCG_PTS_INTEG_MEAS_LOG:
364 default:
365 DBG1(DBG_IMC, "received unsupported attribute '%N'",
366 tcg_attr_names, attr->get_type(attr));
367 break;
368 }
369 }
370 }
371 enumerator->destroy(enumerator);
372 pa_tnc_msg->destroy(pa_tnc_msg);
373
374 result = TNC_RESULT_SUCCESS;
375
376 if (attr_list->get_count(attr_list))
377 {
378 pa_tnc_msg = pa_tnc_msg_create();
379
380 enumerator = attr_list->create_enumerator(attr_list);
381 while (enumerator->enumerate(enumerator, &attr))
382 {
383 pa_tnc_msg->add_attribute(pa_tnc_msg, attr);
384 }
385 enumerator->destroy(enumerator);
386
387 pa_tnc_msg->build(pa_tnc_msg);
388 result = imc_attestation->send_message(imc_attestation, connection_id,
389 pa_tnc_msg->get_encoding(pa_tnc_msg));
390
391 attr_list->destroy(attr_list);
392 pa_tnc_msg->destroy(pa_tnc_msg);
393 }
394
395 return result;
396 }
397
398 /**
399 * see section 3.7.5 of TCG TNC IF-IMC Specification 1.2
400 */
401 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
402 TNC_ConnectionID connection_id)
403 {
404 if (!imc_attestation)
405 {
406 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
407 return TNC_RESULT_NOT_INITIALIZED;
408 }
409 return TNC_RESULT_SUCCESS;
410 }
411
412 /**
413 * see section 3.7.6 of TCG TNC IF-IMC Specification 1.2
414 */
415 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
416 {
417 if (!imc_attestation)
418 {
419 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
420 return TNC_RESULT_NOT_INITIALIZED;
421 }
422 imc_attestation->destroy(imc_attestation);
423 imc_attestation = NULL;
424
425 return TNC_RESULT_SUCCESS;
426 }
427
428 /**
429 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.2
430 */
431 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
432 TNC_TNCC_BindFunctionPointer bind_function)
433 {
434 if (!imc_attestation)
435 {
436 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
437 return TNC_RESULT_NOT_INITIALIZED;
438 }
439 return imc_attestation->bind_functions(imc_attestation, bind_function);
440 }