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