transfer IMA file measurements via PA-TNC
[strongswan.git] / src / libpts / plugins / imc_attestation / imc_attestation_process.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 #define _GNU_SOURCE
17
18 #include <stdio.h>
19 /* for isdigit */
20 #include <ctype.h>
21
22 #include "imc_attestation_process.h"
23
24 #include <ietf/ietf_attr_pa_tnc_error.h>
25
26 #include <libpts.h>
27 #include <pts/pts.h>
28
29 #include <tcg/tcg_pts_attr_proto_caps.h>
30 #include <tcg/tcg_pts_attr_meas_algo.h>
31 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
32 #include <tcg/tcg_pts_attr_dh_nonce_params_resp.h>
33 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
34 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
35 #include <tcg/tcg_pts_attr_tpm_version_info.h>
36 #include <tcg/tcg_pts_attr_get_aik.h>
37 #include <tcg/tcg_pts_attr_aik.h>
38 #include <tcg/tcg_pts_attr_req_func_comp_evid.h>
39 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
40 #include <tcg/tcg_pts_attr_simple_comp_evid.h>
41 #include <tcg/tcg_pts_attr_simple_evid_final.h>
42 #include <tcg/tcg_pts_attr_req_file_meas.h>
43 #include <tcg/tcg_pts_attr_file_meas.h>
44 #include <tcg/tcg_pts_attr_req_file_meta.h>
45 #include <tcg/tcg_pts_attr_unix_file_meta.h>
46
47 #include <debug.h>
48 #include <utils/lexparser.h>
49
50 #define DEFAULT_NONCE_LEN 20
51
52 bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list,
53 imc_attestation_state_t *attestation_state,
54 pts_meas_algorithms_t supported_algorithms,
55 pts_dh_group_t supported_dh_groups)
56 {
57 chunk_t attr_info;
58 pts_t *pts;
59 pts_error_code_t pts_error;
60 bool valid_path;
61
62 pts = attestation_state->get_pts(attestation_state);
63 switch (attr->get_type(attr))
64 {
65 case TCG_PTS_REQ_PROTO_CAPS:
66 {
67 tcg_pts_attr_proto_caps_t *attr_cast;
68 pts_proto_caps_flag_t imc_caps, imv_caps;
69
70 attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
71 imv_caps = attr_cast->get_flags(attr_cast);
72 imc_caps = pts->get_proto_caps(pts);
73 pts->set_proto_caps(pts, imc_caps & imv_caps);
74
75 /* Send PTS Protocol Capabilities attribute */
76 attr = tcg_pts_attr_proto_caps_create(imc_caps & imv_caps, FALSE);
77 attr_list->insert_last(attr_list, attr);
78 break;
79 }
80 case TCG_PTS_MEAS_ALGO:
81 {
82 tcg_pts_attr_meas_algo_t *attr_cast;
83 pts_meas_algorithms_t offered_algorithms, selected_algorithm;
84
85 attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
86 offered_algorithms = attr_cast->get_algorithms(attr_cast);
87 selected_algorithm = pts_meas_algo_select(supported_algorithms,
88 offered_algorithms);
89 if (selected_algorithm == PTS_MEAS_ALGO_NONE)
90 {
91 attr = pts_hash_alg_error_create(supported_algorithms);
92 attr_list->insert_last(attr_list, attr);
93 break;
94 }
95
96 /* Send Measurement Algorithm Selection attribute */
97 pts->set_meas_algorithm(pts, selected_algorithm);
98 attr = tcg_pts_attr_meas_algo_create(selected_algorithm, TRUE);
99 attr_list->insert_last(attr_list, attr);
100 break;
101 }
102 case TCG_PTS_DH_NONCE_PARAMS_REQ:
103 {
104 tcg_pts_attr_dh_nonce_params_req_t *attr_cast;
105 pts_dh_group_t offered_dh_groups, selected_dh_group;
106 chunk_t responder_value, responder_nonce;
107 int nonce_len, min_nonce_len;
108
109 nonce_len = lib->settings->get_int(lib->settings,
110 "libimcv.plugins.imc-attestation.nonce_len",
111 DEFAULT_NONCE_LEN);
112
113 attr_cast = (tcg_pts_attr_dh_nonce_params_req_t*)attr;
114 min_nonce_len = attr_cast->get_min_nonce_len(attr_cast);
115 if (nonce_len < PTS_MIN_NONCE_LEN ||
116 (min_nonce_len > 0 && nonce_len < min_nonce_len))
117 {
118 attr = pts_dh_nonce_error_create(nonce_len, PTS_MAX_NONCE_LEN);
119 attr_list->insert_last(attr_list, attr);
120 break;
121 }
122
123 offered_dh_groups = attr_cast->get_dh_groups(attr_cast);
124 selected_dh_group = pts_dh_group_select(supported_dh_groups,
125 offered_dh_groups);
126 if (selected_dh_group == PTS_DH_GROUP_NONE)
127 {
128 attr = pts_dh_group_error_create(supported_dh_groups);
129 attr_list->insert_last(attr_list, attr);
130 break;
131 }
132
133 /* Create own DH factor and nonce */
134 if (!pts->create_dh_nonce(pts, selected_dh_group, nonce_len))
135 {
136 return FALSE;
137 }
138 pts->get_my_public_value(pts, &responder_value, &responder_nonce);
139
140 /* Send DH Nonce Parameters Response attribute */
141 attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group,
142 supported_algorithms, responder_nonce, responder_value);
143 attr_list->insert_last(attr_list, attr);
144 break;
145 }
146 case TCG_PTS_DH_NONCE_FINISH:
147 {
148 tcg_pts_attr_dh_nonce_finish_t *attr_cast;
149 pts_meas_algorithms_t selected_algorithm;
150 chunk_t initiator_nonce, initiator_value;
151 int nonce_len;
152
153 attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
154 selected_algorithm = attr_cast->get_hash_algo(attr_cast);
155 if (!(selected_algorithm & supported_algorithms))
156 {
157 DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm");
158 return FALSE;
159 }
160 pts->set_dh_hash_algorithm(pts, selected_algorithm);
161
162 initiator_value = attr_cast->get_initiator_value(attr_cast);
163 initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
164
165 nonce_len = lib->settings->get_int(lib->settings,
166 "libimcv.plugins.imc-attestation.nonce_len",
167 DEFAULT_NONCE_LEN);
168 if (nonce_len != initiator_nonce.len)
169 {
170 DBG1(DBG_IMC, "initiator and responder DH nonces "
171 "have differing lengths");
172 return FALSE;
173 }
174
175 pts->set_peer_public_value(pts, initiator_value, initiator_nonce);
176 if (!pts->calculate_secret(pts))
177 {
178 return FALSE;
179 }
180 break;
181 }
182 case TCG_PTS_GET_TPM_VERSION_INFO:
183 {
184 chunk_t tpm_version_info, attr_info;
185
186 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
187 {
188 attr_info = attr->get_value(attr);
189 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
190 TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info);
191 attr_list->insert_last(attr_list, attr);
192 break;
193 }
194
195 /* Send TPM Version Info attribute */
196 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
197 attr_list->insert_last(attr_list, attr);
198 break;
199 }
200 case TCG_PTS_GET_AIK:
201 {
202 certificate_t *aik;
203
204 aik = pts->get_aik(pts);
205 if (!aik)
206 {
207 DBG1(DBG_IMC, "no AIK certificate or public key available");
208 break;
209 }
210
211 /* Send AIK attribute */
212 attr = tcg_pts_attr_aik_create(aik);
213 attr_list->insert_last(attr_list, attr);
214 break;
215 }
216 case TCG_PTS_REQ_FILE_MEAS:
217 {
218 tcg_pts_attr_req_file_meas_t *attr_cast;
219 char *pathname;
220 u_int16_t request_id;
221 bool is_directory;
222 u_int32_t delimiter;
223 pts_file_meas_t *measurements;
224
225 attr_info = attr->get_value(attr);
226 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
227 is_directory = attr_cast->get_directory_flag(attr_cast);
228 request_id = attr_cast->get_request_id(attr_cast);
229 delimiter = attr_cast->get_delimiter(attr_cast);
230 pathname = attr_cast->get_pathname(attr_cast);
231 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
232
233 if (valid_path && pts_error)
234 {
235 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
236 pts_error, attr_info);
237 attr_list->insert_last(attr_list, attr);
238 break;
239 }
240 else if (!valid_path)
241 {
242 break;
243 }
244
245 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
246 {
247 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
248 TCG_PTS_INVALID_DELIMITER, attr_info);
249 attr_list->insert_last(attr_list, attr);
250 break;
251 }
252
253 /* Do PTS File Measurements and send them to PTS-IMV */
254 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
255 request_id, is_directory ? "directory" : "file",
256 pathname);
257 measurements = pts->do_measurements(pts, request_id,
258 pathname, is_directory);
259 if (!measurements)
260 {
261 /* TODO handle error codes from measurements */
262 return FALSE;
263 }
264 attr = tcg_pts_attr_file_meas_create(measurements);
265 attr->set_noskip_flag(attr, TRUE);
266 attr_list->insert_last(attr_list, attr);
267 break;
268 }
269 case TCG_PTS_REQ_FILE_META:
270 {
271 tcg_pts_attr_req_file_meta_t *attr_cast;
272 char *pathname;
273 bool is_directory;
274 u_int8_t delimiter;
275 pts_file_meta_t *metadata;
276
277 attr_info = attr->get_value(attr);
278 attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
279 is_directory = attr_cast->get_directory_flag(attr_cast);
280 delimiter = attr_cast->get_delimiter(attr_cast);
281 pathname = attr_cast->get_pathname(attr_cast);
282
283 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
284 if (valid_path && pts_error)
285 {
286 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
287 pts_error, attr_info);
288 attr_list->insert_last(attr_list, attr);
289 break;
290 }
291 else if (!valid_path)
292 {
293 break;
294 }
295 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
296 {
297 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
298 TCG_PTS_INVALID_DELIMITER, attr_info);
299 attr_list->insert_last(attr_list, attr);
300 break;
301 }
302 /* Get File Metadata and send them to PTS-IMV */
303 DBG2(DBG_IMC, "metadata request for %s '%s'",
304 is_directory ? "directory" : "file",
305 pathname);
306 metadata = pts->get_metadata(pts, pathname, is_directory);
307
308 if (!metadata)
309 {
310 /* TODO handle error codes from measurements */
311 return FALSE;
312 }
313 attr = tcg_pts_attr_unix_file_meta_create(metadata);
314 attr->set_noskip_flag(attr, TRUE);
315 attr_list->insert_last(attr_list, attr);
316
317 break;
318 }
319 case TCG_PTS_REQ_FUNC_COMP_EVID:
320 {
321 tcg_pts_attr_req_func_comp_evid_t *attr_cast;
322 pts_proto_caps_flag_t negotiated_caps;
323 pts_file_meas_t *measurements;
324 pts_comp_func_name_t *name;
325 pts_comp_evidence_t *evid;
326 pts_component_t *comp;
327 u_int32_t depth;
328 u_int8_t flags;
329 status_t status;
330 enumerator_t *e;
331
332 attr_info = attr->get_value(attr);
333 attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr;
334
335 DBG1(DBG_IMC, "evidence requested for %d functional components",
336 attr_cast->get_count(attr_cast));
337
338 e = attr_cast->create_enumerator(attr_cast);
339 while (e->enumerate(e, &flags, &depth, &name))
340 {
341 name->log(name, "* ");
342 negotiated_caps = pts->get_proto_caps(pts);
343
344 if (flags & PTS_REQ_FUNC_COMP_EVID_TTC)
345 {
346 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
347 TCG_PTS_UNABLE_DET_TTC, attr_info);
348 attr_list->insert_last(attr_list, attr);
349 break;
350 }
351 if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
352 !(negotiated_caps & PTS_PROTO_CAPS_V))
353 {
354 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
355 TCG_PTS_UNABLE_LOCAL_VAL, attr_info);
356 attr_list->insert_last(attr_list, attr);
357 break;
358 }
359 if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
360 !(negotiated_caps & PTS_PROTO_CAPS_C))
361 {
362 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
363 TCG_PTS_UNABLE_CUR_EVID, attr_info);
364 attr_list->insert_last(attr_list, attr);
365 break;
366 }
367 if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
368 !(negotiated_caps & PTS_PROTO_CAPS_T))
369 {
370 attr = ietf_attr_pa_tnc_error_create(PEN_TCG,
371 TCG_PTS_UNABLE_DET_PCR, attr_info);
372 attr_list->insert_last(attr_list, attr);
373 break;
374 }
375 if (depth > 0)
376 {
377 DBG1(DBG_IMC, "the Attestation IMC currently does not "
378 "support sub component measurements");
379 return FALSE;
380 }
381 comp = pts_components->create(pts_components, name, depth, NULL);
382 if (!comp)
383 {
384 DBG2(DBG_IMC, " not registered: no evidence provided");
385 continue;
386 }
387
388 /* do the component evidence measurement[s] */
389 do
390 {
391 status = comp->measure(comp, pts, &evid, &measurements);
392 if (status == FAILED)
393 {
394 break;
395 }
396 attestation_state->add_evidence(attestation_state, evid);
397 if (measurements)
398 {
399 DBG2(DBG_IMC, "collected %d file measurements",
400 measurements->get_file_count(measurements));
401 attr = tcg_pts_attr_file_meas_create(measurements);
402 attr_list->insert_last(attr_list, attr);
403 }
404 }
405 while (status == NEED_MORE);
406 comp->destroy(comp);
407 }
408 e->destroy(e);
409 break;
410 }
411 case TCG_PTS_GEN_ATTEST_EVID:
412 {
413 pts_simple_evid_final_flag_t flags;
414 pts_meas_algorithms_t comp_hash_algorithm;
415 pts_comp_evidence_t *evid;
416 chunk_t pcr_composite, quote_sig;
417 bool use_quote2;
418
419 /* Send buffered Simple Component Evidences */
420 while (attestation_state->next_evidence(attestation_state, &evid))
421 {
422 pts->select_pcr(pts, evid->get_extended_pcr(evid));
423
424 /* Send Simple Component Evidence */
425 attr = tcg_pts_attr_simple_comp_evid_create(evid);
426 attr_list->insert_last(attr_list, attr);
427 }
428
429 use_quote2 = lib->settings->get_bool(lib->settings,
430 "libimcv.plugins.imc-attestation.use_quote2", TRUE);
431 if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
432 {
433 DBG1(DBG_IMC, "error occurred during TPM quote operation");
434 return FALSE;
435 }
436
437 /* Send Simple Evidence Final attribute */
438 flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
439 PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
440 comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
441
442 attr = tcg_pts_attr_simple_evid_final_create(flags,
443 comp_hash_algorithm, pcr_composite, quote_sig);
444 attr_list->insert_last(attr_list, attr);
445 break;
446 }
447 /* TODO: Not implemented yet */
448 case TCG_PTS_REQ_INTEG_MEAS_LOG:
449 /* Attributes using XML */
450 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
451 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
452 /* On Windows only*/
453 case TCG_PTS_REQ_REGISTRY_VALUE:
454 /* Received on IMV side only*/
455 case TCG_PTS_PROTO_CAPS:
456 case TCG_PTS_DH_NONCE_PARAMS_RESP:
457 case TCG_PTS_MEAS_ALGO_SELECTION:
458 case TCG_PTS_TPM_VERSION_INFO:
459 case TCG_PTS_TEMPL_REF_MANI_SET_META:
460 case TCG_PTS_AIK:
461 case TCG_PTS_SIMPLE_COMP_EVID:
462 case TCG_PTS_SIMPLE_EVID_FINAL:
463 case TCG_PTS_VERIFICATION_RESULT:
464 case TCG_PTS_INTEG_REPORT:
465 case TCG_PTS_UNIX_FILE_META:
466 case TCG_PTS_FILE_MEAS:
467 case TCG_PTS_INTEG_MEAS_LOG:
468 default:
469 DBG1(DBG_IMC, "received unsupported attribute '%N'",
470 tcg_attr_names, attr->get_type(attr));
471 break;
472 }
473 return TRUE;
474 }