imc/imv->send_message() uses attr_list
[strongswan.git] / src / libpts / plugins / imv_attestation / imv_attestation_build.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 "imv_attestation_build.h"
17 #include "imv_attestation_state.h"
18
19 #include <libpts.h>
20 #include <tcg/tcg_pts_attr_proto_caps.h>
21 #include <tcg/tcg_pts_attr_meas_algo.h>
22 #include <tcg/tcg_pts_attr_dh_nonce_params_req.h>
23 #include <tcg/tcg_pts_attr_dh_nonce_finish.h>
24 #include <tcg/tcg_pts_attr_get_tpm_version_info.h>
25 #include <tcg/tcg_pts_attr_get_aik.h>
26 #include <tcg/tcg_pts_attr_req_func_comp_evid.h>
27 #include <tcg/tcg_pts_attr_gen_attest_evid.h>
28 #include <tcg/tcg_pts_attr_req_file_meas.h>
29 #include <tcg/tcg_pts_attr_req_file_meta.h>
30
31 #include <debug.h>
32
33 bool imv_attestation_build(linked_list_t *attr_list,
34 imv_attestation_state_t *attestation_state,
35 pts_meas_algorithms_t supported_algorithms,
36 pts_dh_group_t supported_dh_groups,
37 pts_database_t *pts_db)
38 {
39 imv_attestation_handshake_state_t handshake_state;
40 pts_t *pts;
41 pa_tnc_attr_t *attr = NULL;
42
43 handshake_state = attestation_state->get_handshake_state(attestation_state);
44 pts = attestation_state->get_pts(attestation_state);
45
46 /**
47 * Skip DH Nonce Parameters Request attribute when
48 * DH Nonce Exchange is not selected by PTS-IMC side
49 */
50 if (handshake_state == IMV_ATTESTATION_STATE_NONCE_REQ &&
51 !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
52 {
53 DBG2(DBG_IMV, "PTS-IMC does not support DH Nonce negotiation - "
54 "advancing to TPM Initialization");
55 handshake_state = IMV_ATTESTATION_STATE_TPM_INIT;
56 }
57
58 /**
59 * Skip TPM Version Info and AIK attributes when
60 * no TPM is available on the PTS-IMC side
61 */
62 if (handshake_state == IMV_ATTESTATION_STATE_TPM_INIT &&
63 !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T))
64 {
65 DBG2(DBG_IMV, "PTS-IMC made no TPM available - "
66 "advancing to File Measurements");
67 handshake_state = IMV_ATTESTATION_STATE_MEAS;
68 }
69
70 switch (handshake_state)
71 {
72 case IMV_ATTESTATION_STATE_INIT:
73 {
74 pts_proto_caps_flag_t flags;
75
76 /* Send Request Protocol Capabilities attribute */
77 flags = pts->get_proto_caps(pts);
78 attr = tcg_pts_attr_proto_caps_create(flags, TRUE);
79 attr->set_noskip_flag(attr, TRUE);
80 attr_list->insert_last(attr_list, attr);
81
82 /* Send Measurement Algorithms attribute */
83 attr = tcg_pts_attr_meas_algo_create(supported_algorithms, FALSE);
84 attr->set_noskip_flag(attr, TRUE);
85 attr_list->insert_last(attr_list, attr);
86
87 attestation_state->set_handshake_state(attestation_state,
88 IMV_ATTESTATION_STATE_NONCE_REQ);
89 break;
90 }
91 case IMV_ATTESTATION_STATE_NONCE_REQ:
92 {
93 int min_nonce_len;
94
95 /* Send DH nonce parameters request attribute */
96 min_nonce_len = lib->settings->get_int(lib->settings,
97 "libimcv.plugins.imv-attestation.min_nonce_len", 0);
98 attr = tcg_pts_attr_dh_nonce_params_req_create(min_nonce_len,
99 supported_dh_groups);
100 attr->set_noskip_flag(attr, TRUE);
101 attr_list->insert_last(attr_list, attr);
102
103 attestation_state->set_handshake_state(attestation_state,
104 IMV_ATTESTATION_STATE_TPM_INIT);
105 break;
106 }
107 case IMV_ATTESTATION_STATE_TPM_INIT:
108 {
109 pts_meas_algorithms_t selected_algorithm;
110 chunk_t initiator_value, initiator_nonce;
111
112 if ((pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
113 {
114 /* Send DH nonce finish attribute */
115 selected_algorithm = pts->get_meas_algorithm(pts);
116 pts->get_my_public_value(pts, &initiator_value, &initiator_nonce);
117 attr = tcg_pts_attr_dh_nonce_finish_create(selected_algorithm,
118 initiator_value, initiator_nonce);
119 attr->set_noskip_flag(attr, TRUE);
120 attr_list->insert_last(attr_list, attr);
121 }
122
123 /* Send Get TPM Version attribute */
124 attr = tcg_pts_attr_get_tpm_version_info_create();
125 attr->set_noskip_flag(attr, TRUE);
126 attr_list->insert_last(attr_list, attr);
127
128 /* Send Get AIK attribute */
129 attr = tcg_pts_attr_get_aik_create();
130 attr->set_noskip_flag(attr, TRUE);
131 attr_list->insert_last(attr_list, attr);
132
133 attestation_state->set_handshake_state(attestation_state,
134 IMV_ATTESTATION_STATE_MEAS);
135 break;
136 }
137 case IMV_ATTESTATION_STATE_MEAS:
138 {
139 enumerator_t *enumerator;
140 u_int32_t delimiter = SOLIDUS_UTF;
141 char *platform_info, *pathname;
142 u_int16_t request_id;
143 int id, type;
144 bool is_dir;
145
146 attestation_state->set_handshake_state(attestation_state,
147 IMV_ATTESTATION_STATE_COMP_EVID);
148
149 /* Get Platform and OS of the PTS-IMC */
150 platform_info = pts->get_platform_info(pts);
151
152 if (!pts_db || !platform_info)
153 {
154 DBG1(DBG_IMV, "%s%s%s not available",
155 (pts_db) ? "" : "pts database",
156 (!pts_db && !platform_info) ? "and" : "",
157 (platform_info) ? "" : "platform info");
158 break;
159 }
160 DBG1(DBG_IMV, "platform is '%s'", platform_info);
161
162 /* Send Request File Metadata attribute */
163 enumerator = pts_db->create_file_meta_enumerator(pts_db,
164 platform_info);
165 if (!enumerator)
166 {
167 break;
168 }
169 while (enumerator->enumerate(enumerator, &type, &pathname))
170 {
171 is_dir = (type != 0);
172 DBG2(DBG_IMV, "metadata request for %s '%s'",
173 is_dir ? "directory" : "file", pathname);
174 attr = tcg_pts_attr_req_file_meta_create(is_dir, delimiter,
175 pathname);
176 attr->set_noskip_flag(attr, TRUE);
177 attr_list->insert_last(attr_list, attr);
178 }
179 enumerator->destroy(enumerator);
180
181 /* Send Request File Measurement attribute */
182 enumerator = pts_db->create_file_meas_enumerator(pts_db,
183 platform_info);
184 if (!enumerator)
185 {
186 break;
187 }
188 while (enumerator->enumerate(enumerator, &id, &type, &pathname))
189 {
190 is_dir = (type != 0);
191 request_id = attestation_state->add_file_meas_request(
192 attestation_state, id, is_dir);
193 DBG2(DBG_IMV, "measurement request %d for %s '%s'",
194 request_id, is_dir ? "directory" : "file", pathname);
195 attr = tcg_pts_attr_req_file_meas_create(is_dir, request_id,
196 delimiter, pathname);
197 attr->set_noskip_flag(attr, TRUE);
198 attr_list->insert_last(attr_list, attr);
199 }
200 enumerator->destroy(enumerator);
201 break;
202 }
203 case IMV_ATTESTATION_STATE_COMP_EVID:
204 {
205 tcg_pts_attr_req_func_comp_evid_t *attr_cast;
206 enumerator_t *enumerator;
207 pts_component_t *comp;
208 pts_comp_func_name_t *comp_name;
209 chunk_t keyid;
210 int kid, vid, name, qualifier;
211 u_int8_t flags;
212 u_int32_t depth;
213 bool first = TRUE, first_component = TRUE;
214
215 attestation_state->set_handshake_state(attestation_state,
216 IMV_ATTESTATION_STATE_END);
217
218 if (!(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_T) ||
219 !(pts->get_proto_caps(pts) & PTS_PROTO_CAPS_D))
220 {
221 DBG2(DBG_IMV, "PTS-IMC made no TPM available - "
222 "skipping Component Measurements");
223 break;
224 }
225 if (!pts->get_aik_keyid(pts, &keyid))
226 {
227 DBG1(DBG_IMV, "retrieval of AIK keyid failed");
228 return FALSE;
229 }
230 if (!pts_db)
231 {
232 DBG1(DBG_IMV, "pts database not available");
233 break;
234 }
235 if (pts_db->check_aik_keyid(pts_db, keyid, &kid) != SUCCESS)
236 {
237 return FALSE;
238 }
239 enumerator = pts_db->create_comp_evid_enumerator(pts_db, kid);
240 if (!enumerator)
241 {
242 break;
243 }
244 while (enumerator->enumerate(enumerator, &vid, &name,
245 &qualifier, &depth))
246 {
247 if (first)
248 {
249 DBG2(DBG_IMV, "evidence request by");
250 first = FALSE;
251 }
252 comp_name = pts_comp_func_name_create(vid, name, qualifier);
253 comp_name->log(comp_name, " ");
254
255 comp = pts_components->create(pts_components, comp_name,
256 depth, pts_db);
257 if (!comp)
258 {
259 DBG2(DBG_IMV, " not registered: removed from request");
260 comp_name->destroy(comp_name);
261 continue;
262 }
263 attestation_state->add_component(attestation_state, comp);
264 if (first_component)
265 {
266 attr = tcg_pts_attr_req_func_comp_evid_create();
267 attr->set_noskip_flag(attr, TRUE);
268 first_component = FALSE;
269 }
270 flags = comp->get_evidence_flags(comp);
271 /* TODO check flags against negotiated_caps */
272 attr_cast = (tcg_pts_attr_req_func_comp_evid_t *)attr;
273 attr_cast->add_component(attr_cast, flags, depth, comp_name);
274 }
275 enumerator->destroy(enumerator);
276
277 if (attr)
278 {
279 /* Send Request Functional Component Evidence attribute */
280 attr_list->insert_last(attr_list, attr);
281
282 /* Send Generate Attestation Evidence attribute */
283 attr = tcg_pts_attr_gen_attest_evid_create();
284 attr->set_noskip_flag(attr, TRUE);
285 attr_list->insert_last(attr_list, attr);
286
287 attestation_state->set_handshake_state(attestation_state,
288 IMV_ATTESTATION_STATE_EVID_FINAL);
289 }
290 break;
291 }
292 case IMV_ATTESTATION_STATE_EVID_FINAL:
293 attestation_state->set_handshake_state(attestation_state,
294 IMV_ATTESTATION_STATE_END);
295 break;
296 case IMV_ATTESTATION_STATE_END:
297 break;
298 }
299 return TRUE;
300 }