libimcv: Allow pts_t.set_peer_public_value() to fail
[strongswan.git] / src / libimcv / 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/pts/tcg_pts_attr_proto_caps.h>
29 #include <tcg/pts/tcg_pts_attr_meas_algo.h>
30 #include <tcg/pts/tcg_pts_attr_dh_nonce_params_req.h>
31 #include <tcg/pts/tcg_pts_attr_dh_nonce_params_resp.h>
32 #include <tcg/pts/tcg_pts_attr_dh_nonce_finish.h>
33 #include <tcg/pts/tcg_pts_attr_get_tpm_version_info.h>
34 #include <tcg/pts/tcg_pts_attr_tpm_version_info.h>
35 #include <tcg/pts/tcg_pts_attr_get_aik.h>
36 #include <tcg/pts/tcg_pts_attr_aik.h>
37 #include <tcg/pts/tcg_pts_attr_req_func_comp_evid.h>
38 #include <tcg/pts/tcg_pts_attr_gen_attest_evid.h>
39 #include <tcg/pts/tcg_pts_attr_simple_comp_evid.h>
40 #include <tcg/pts/tcg_pts_attr_simple_evid_final.h>
41 #include <tcg/pts/tcg_pts_attr_req_file_meas.h>
42 #include <tcg/pts/tcg_pts_attr_file_meas.h>
43 #include <tcg/pts/tcg_pts_attr_req_file_meta.h>
44 #include <tcg/pts/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 "%s.plugins.imc-attestation.nonce_len",
113 DEFAULT_NONCE_LEN, lib->ns);
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 if (!pts->get_my_public_value(pts, &responder_value,
141 &responder_nonce))
142 {
143 return FALSE;
144 }
145
146 /* Send DH Nonce Parameters Response attribute */
147 attr = tcg_pts_attr_dh_nonce_params_resp_create(selected_dh_group,
148 supported_algorithms, responder_nonce, responder_value);
149 msg->add_attribute(msg, attr);
150 break;
151 }
152 case TCG_PTS_DH_NONCE_FINISH:
153 {
154 tcg_pts_attr_dh_nonce_finish_t *attr_cast;
155 pts_meas_algorithms_t selected_algorithm;
156 chunk_t initiator_nonce, initiator_value;
157 int nonce_len;
158
159 attr_cast = (tcg_pts_attr_dh_nonce_finish_t*)attr;
160 selected_algorithm = attr_cast->get_hash_algo(attr_cast);
161 if (!(selected_algorithm & supported_algorithms))
162 {
163 DBG1(DBG_IMC, "PTS-IMV selected unsupported DH hash algorithm");
164 return FALSE;
165 }
166 pts->set_dh_hash_algorithm(pts, selected_algorithm);
167
168 initiator_value = attr_cast->get_initiator_value(attr_cast);
169 initiator_nonce = attr_cast->get_initiator_nonce(attr_cast);
170
171 nonce_len = lib->settings->get_int(lib->settings,
172 "%s.plugins.imc-attestation.nonce_len",
173 DEFAULT_NONCE_LEN, lib->ns);
174 if (nonce_len != initiator_nonce.len)
175 {
176 DBG1(DBG_IMC, "initiator and responder DH nonces "
177 "have differing lengths");
178 return FALSE;
179 }
180
181
182 if (!pts->set_peer_public_value(pts, initiator_value,
183 initiator_nonce) ||
184 !pts->calculate_secret(pts))
185 {
186 return FALSE;
187 }
188 break;
189 }
190 case TCG_PTS_GET_TPM_VERSION_INFO:
191 {
192 chunk_t tpm_version_info, attr_info;
193 pen_type_t error_code = { PEN_TCG, TCG_PTS_TPM_VERS_NOT_SUPPORTED };
194
195 if (!pts->get_tpm_version_info(pts, &tpm_version_info))
196 {
197 attr_info = attr->get_value(attr);
198 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
199 msg->add_attribute(msg, attr);
200 break;
201 }
202
203 /* Send TPM Version Info attribute */
204 attr = tcg_pts_attr_tpm_version_info_create(tpm_version_info);
205 msg->add_attribute(msg, attr);
206 break;
207 }
208 case TCG_PTS_GET_AIK:
209 {
210 certificate_t *aik;
211
212 aik = pts->get_aik(pts);
213 if (!aik)
214 {
215 DBG1(DBG_IMC, "no AIK certificate or public key available");
216 break;
217 }
218
219 /* Send AIK attribute */
220 attr = tcg_pts_attr_aik_create(aik);
221 msg->add_attribute(msg, attr);
222 break;
223 }
224 case TCG_PTS_REQ_FILE_MEAS:
225 {
226 tcg_pts_attr_req_file_meas_t *attr_cast;
227 char *pathname;
228 u_int16_t request_id;
229 bool is_directory;
230 u_int32_t delimiter;
231 pts_file_meas_t *measurements;
232 pen_type_t error_code;
233
234 attr_info = attr->get_value(attr);
235 attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
236 is_directory = attr_cast->get_directory_flag(attr_cast);
237 request_id = attr_cast->get_request_id(attr_cast);
238 delimiter = attr_cast->get_delimiter(attr_cast);
239 pathname = attr_cast->get_pathname(attr_cast);
240 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
241
242 if (valid_path && pts_error)
243 {
244 error_code = pen_type_create(PEN_TCG, pts_error);
245 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
246 msg->add_attribute(msg, attr);
247 break;
248 }
249 else if (!valid_path)
250 {
251 break;
252 }
253
254 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
255 {
256 error_code = pen_type_create(PEN_TCG,
257 TCG_PTS_INVALID_DELIMITER);
258 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
259 msg->add_attribute(msg, attr);
260 break;
261 }
262
263 /* Do PTS File Measurements and send them to PTS-IMV */
264 DBG2(DBG_IMC, "measurement request %d for %s '%s'",
265 request_id, is_directory ? "directory" : "file",
266 pathname);
267 measurements = pts_file_meas_create_from_path(request_id,
268 pathname, is_directory, TRUE,
269 pts->get_meas_algorithm(pts));
270 if (!measurements)
271 {
272 /* TODO handle error codes from measurements */
273 return FALSE;
274 }
275 attr = tcg_pts_attr_file_meas_create(measurements);
276 attr->set_noskip_flag(attr, TRUE);
277 msg->add_attribute(msg, attr);
278 break;
279 }
280 case TCG_PTS_REQ_FILE_META:
281 {
282 tcg_pts_attr_req_file_meta_t *attr_cast;
283 char *pathname;
284 bool is_directory;
285 u_int8_t delimiter;
286 pts_file_meta_t *metadata;
287 pen_type_t error_code;
288
289 attr_info = attr->get_value(attr);
290 attr_cast = (tcg_pts_attr_req_file_meta_t*)attr;
291 is_directory = attr_cast->get_directory_flag(attr_cast);
292 delimiter = attr_cast->get_delimiter(attr_cast);
293 pathname = attr_cast->get_pathname(attr_cast);
294
295 valid_path = pts->is_path_valid(pts, pathname, &pts_error);
296 if (valid_path && pts_error)
297 {
298 error_code = pen_type_create(PEN_TCG, pts_error);
299 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
300 msg->add_attribute(msg, attr);
301 break;
302 }
303 else if (!valid_path)
304 {
305 break;
306 }
307 if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF)
308 {
309 error_code = pen_type_create(PEN_TCG,
310 TCG_PTS_INVALID_DELIMITER);
311 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
312 msg->add_attribute(msg, attr);
313 break;
314 }
315 /* Get File Metadata and send them to PTS-IMV */
316 DBG2(DBG_IMC, "metadata request for %s '%s'",
317 is_directory ? "directory" : "file",
318 pathname);
319 metadata = pts->get_metadata(pts, pathname, is_directory);
320
321 if (!metadata)
322 {
323 /* TODO handle error codes from measurements */
324 return FALSE;
325 }
326 attr = tcg_pts_attr_unix_file_meta_create(metadata);
327 attr->set_noskip_flag(attr, TRUE);
328 msg->add_attribute(msg, attr);
329 break;
330 }
331 case TCG_PTS_REQ_FUNC_COMP_EVID:
332 {
333 tcg_pts_attr_req_func_comp_evid_t *attr_cast;
334 pts_proto_caps_flag_t negotiated_caps;
335 pts_comp_func_name_t *name;
336 pts_comp_evidence_t *evid;
337 pts_component_t *comp;
338 pen_type_t error_code;
339 u_int32_t depth;
340 u_int8_t flags;
341 status_t status;
342 enumerator_t *e;
343
344 attr_info = attr->get_value(attr);
345 attr_cast = (tcg_pts_attr_req_func_comp_evid_t*)attr;
346
347 DBG1(DBG_IMC, "evidence requested for %d functional components",
348 attr_cast->get_count(attr_cast));
349
350 e = attr_cast->create_enumerator(attr_cast);
351 while (e->enumerate(e, &flags, &depth, &name))
352 {
353 name->log(name, "* ");
354 negotiated_caps = pts->get_proto_caps(pts);
355
356 if (flags & PTS_REQ_FUNC_COMP_EVID_TTC)
357 {
358 error_code = pen_type_create(PEN_TCG,
359 TCG_PTS_UNABLE_DET_TTC);
360 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
361 msg->add_attribute(msg, attr);
362 break;
363 }
364 if (flags & PTS_REQ_FUNC_COMP_EVID_VER &&
365 !(negotiated_caps & PTS_PROTO_CAPS_V))
366 {
367 error_code = pen_type_create(PEN_TCG,
368 TCG_PTS_UNABLE_LOCAL_VAL);
369 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
370 msg->add_attribute(msg, attr);
371 break;
372 }
373 if (flags & PTS_REQ_FUNC_COMP_EVID_CURR &&
374 !(negotiated_caps & PTS_PROTO_CAPS_C))
375 {
376 error_code = pen_type_create(PEN_TCG,
377 TCG_PTS_UNABLE_CUR_EVID);
378 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
379 msg->add_attribute(msg, attr);
380 break;
381 }
382 if (flags & PTS_REQ_FUNC_COMP_EVID_PCR &&
383 !(negotiated_caps & PTS_PROTO_CAPS_T))
384 {
385 error_code = pen_type_create(PEN_TCG,
386 TCG_PTS_UNABLE_DET_PCR);
387 attr = ietf_attr_pa_tnc_error_create(error_code, attr_info);
388 msg->add_attribute(msg, attr);
389 break;
390 }
391 if (depth > 0)
392 {
393 DBG1(DBG_IMC, "the Attestation IMC currently does not "
394 "support sub component measurements");
395 return FALSE;
396 }
397 comp = attestation_state->create_component(attestation_state,
398 name, depth);
399 if (!comp)
400 {
401 DBG2(DBG_IMC, " not registered: no evidence provided");
402 continue;
403 }
404
405 /* do the component evidence measurement[s] and cache them */
406 do
407 {
408 status = comp->measure(comp, name->get_qualifier(name),
409 pts, &evid);
410 if (status == FAILED)
411 {
412 break;
413 }
414 attestation_state->add_evidence(attestation_state, evid);
415 }
416 while (status == NEED_MORE);
417 }
418 e->destroy(e);
419 break;
420 }
421 case TCG_PTS_GEN_ATTEST_EVID:
422 {
423 pts_simple_evid_final_flag_t flags;
424 pts_meas_algorithms_t comp_hash_algorithm;
425 pts_comp_evidence_t *evid;
426 chunk_t pcr_composite, quote_sig;
427 bool use_quote2;
428
429 /* Send cached Component Evidence entries */
430 while (attestation_state->next_evidence(attestation_state, &evid))
431 {
432 attr = tcg_pts_attr_simple_comp_evid_create(evid);
433 msg->add_attribute(msg, attr);
434 }
435
436 use_quote2 = lib->settings->get_bool(lib->settings,
437 "%s.plugins.imc-attestation.use_quote2", TRUE,
438 lib->ns);
439 if (!pts->quote_tpm(pts, use_quote2, &pcr_composite, &quote_sig))
440 {
441 DBG1(DBG_IMC, "error occurred during TPM quote operation");
442 return FALSE;
443 }
444
445 /* Send Simple Evidence Final attribute */
446 flags = use_quote2 ? PTS_SIMPLE_EVID_FINAL_QUOTE_INFO2 :
447 PTS_SIMPLE_EVID_FINAL_QUOTE_INFO;
448 comp_hash_algorithm = PTS_MEAS_ALGO_SHA1;
449
450 attr = tcg_pts_attr_simple_evid_final_create(flags,
451 comp_hash_algorithm, pcr_composite, quote_sig);
452 msg->add_attribute(msg, attr);
453 break;
454 }
455 case TCG_SEG_MAX_ATTR_SIZE_REQ:
456 case TCG_SEG_NEXT_SEG_REQ:
457 break;
458
459 /* TODO: Not implemented yet */
460 case TCG_PTS_REQ_INTEG_MEAS_LOG:
461 /* Attributes using XML */
462 case TCG_PTS_REQ_TEMPL_REF_MANI_SET_META:
463 case TCG_PTS_UPDATE_TEMPL_REF_MANI:
464 /* On Windows only*/
465 case TCG_PTS_REQ_REGISTRY_VALUE:
466 /* Received on IMV side only*/
467 case TCG_PTS_PROTO_CAPS:
468 case TCG_PTS_DH_NONCE_PARAMS_RESP:
469 case TCG_PTS_MEAS_ALGO_SELECTION:
470 case TCG_PTS_TPM_VERSION_INFO:
471 case TCG_PTS_TEMPL_REF_MANI_SET_META:
472 case TCG_PTS_AIK:
473 case TCG_PTS_SIMPLE_COMP_EVID:
474 case TCG_PTS_SIMPLE_EVID_FINAL:
475 case TCG_PTS_VERIFICATION_RESULT:
476 case TCG_PTS_INTEG_REPORT:
477 case TCG_PTS_UNIX_FILE_META:
478 case TCG_PTS_FILE_MEAS:
479 case TCG_PTS_INTEG_MEAS_LOG:
480 default:
481 DBG1(DBG_IMC, "received unsupported attribute '%N/%N'",
482 pen_names, PEN_TCG, tcg_attr_names, attr_type.type);
483 break;
484 }
485 return TRUE;
486 }