transfer IMA file measurements via PA-TNC
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_tboot.c
1 /*
2 * Copyright (C) 2011-2012 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 #include "ita_comp_tboot.h"
17 #include "ita_comp_func_name.h"
18
19 #include "libpts.h"
20 #include "pts/components/pts_component.h"
21
22 #include <debug.h>
23 #include <pen/pen.h>
24
25 typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t;
26
27 /**
28 * Private data of a pts_ita_comp_tboot_t object.
29 *
30 */
31 struct pts_ita_comp_tboot_t {
32
33 /**
34 * Public pts_component_t interface.
35 */
36 pts_component_t public;
37
38 /**
39 * Component Functional Name
40 */
41 pts_comp_func_name_t *name;
42
43 /**
44 * AIK keyid
45 */
46 chunk_t keyid;
47
48 /**
49 * Sub-component depth
50 */
51 u_int32_t depth;
52
53 /**
54 * PTS measurement database
55 */
56 pts_database_t *pts_db;
57
58 /**
59 * Primary key for Component Functional Name database entry
60 */
61 int cid;
62
63 /**
64 * Primary key for AIK database entry
65 */
66 int kid;
67
68 /**
69 * Component is registering measurements
70 */
71 bool is_registering;
72
73 /**
74 * Time of TBOOT measurement
75 */
76 time_t measurement_time;
77
78 /**
79 * Expected measurement count
80 */
81 int count;
82
83 /**
84 * Measurement sequence number
85 */
86 int seq_no;
87
88 };
89
90 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
91 pts_ita_comp_tboot_t *this)
92 {
93 return this->name;
94 }
95
96 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
97 pts_ita_comp_tboot_t *this)
98 {
99 return PTS_REQ_FUNC_COMP_EVID_PCR;
100 }
101
102 METHOD(pts_component_t, get_depth, u_int32_t,
103 pts_ita_comp_tboot_t *this)
104 {
105 return this->depth;
106 }
107
108 METHOD(pts_component_t, measure, status_t,
109 pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t **evidence,
110 pts_file_meas_t **measurements)
111
112 {
113 pts_comp_evidence_t *evid;
114 char *meas_hex, *pcr_before_hex, *pcr_after_hex;
115 chunk_t measurement, pcr_before, pcr_after;
116 size_t hash_size, pcr_len;
117 u_int32_t extended_pcr;
118 pts_pcr_transform_t pcr_transform;
119 pts_meas_algorithms_t hash_algo;
120
121 switch (this->seq_no++)
122 {
123 case 0:
124 /* dummy data since currently the TBOOT log is not retrieved */
125 time(&this->measurement_time);
126 meas_hex = lib->settings->get_str(lib->settings,
127 "libimcv.plugins.imc-attestation.pcr17_meas", NULL);
128 pcr_before_hex = lib->settings->get_str(lib->settings,
129 "libimcv.plugins.imc-attestation.pcr17_before", NULL);
130 pcr_after_hex = lib->settings->get_str(lib->settings,
131 "libimcv.plugins.imc-attestation.pcr17_after", NULL);
132 extended_pcr = PCR_TBOOT_POLICY;
133 break;
134 case 1:
135 /* dummy data since currently the TBOOT log is not retrieved */
136 meas_hex = lib->settings->get_str(lib->settings,
137 "libimcv.plugins.imc-attestation.pcr18_meas", NULL);
138 pcr_before_hex = lib->settings->get_str(lib->settings,
139 "libimcv.plugins.imc-attestation.pcr18_before", NULL);
140 pcr_after_hex = lib->settings->get_str(lib->settings,
141 "libimcv.plugins.imc-attestation.pcr18_after", NULL);
142 extended_pcr = PCR_TBOOT_MLE;
143 break;
144 default:
145 return FAILED;
146 }
147
148 if (meas_hex == NULL || pcr_before_hex == NULL || pcr_after_hex == NULL)
149 {
150 return FAILED;
151 }
152
153 hash_algo = pts->get_meas_algorithm(pts);
154 hash_size = pts_meas_algo_hash_size(hash_algo);
155 pcr_len = pts->get_pcr_len(pts);
156 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
157
158 /* get and check the measurement data */
159 measurement = chunk_from_hex(
160 chunk_create(meas_hex, strlen(meas_hex)), NULL);
161 pcr_before = chunk_from_hex(
162 chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL);
163 pcr_after = chunk_from_hex(
164 chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL);
165 if (pcr_before.len != pcr_len || pcr_after.len != pcr_len ||
166 measurement.len != hash_size)
167 {
168 DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size");
169 free(measurement.ptr);
170 free(pcr_before.ptr);
171 free(pcr_after.ptr);
172 return FAILED;
173 }
174
175 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
176 this->depth, extended_pcr,
177 hash_algo, pcr_transform,
178 this->measurement_time, measurement);
179 evid->set_pcr_info(evid, pcr_before, pcr_after);
180
181 return (this->seq_no < 2) ? NEED_MORE : SUCCESS;
182 }
183
184 METHOD(pts_component_t, verify, status_t,
185 pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
186 {
187 bool has_pcr_info;
188 u_int32_t extended_pcr, vid, name;
189 enum_name_t *names;
190 pts_meas_algorithms_t algo;
191 pts_pcr_transform_t transform;
192 time_t measurement_time;
193 chunk_t measurement, pcr_before, pcr_after;
194 status_t status;
195
196 measurement = evidence->get_measurement(evidence, &extended_pcr,
197 &algo, &transform, &measurement_time);
198
199 if (!this->keyid.ptr)
200 {
201 if (!pts->get_aik_keyid(pts, &this->keyid))
202 {
203 return FAILED;
204 }
205 this->keyid = chunk_clone(this->keyid);
206
207 if (!this->pts_db)
208 {
209 DBG1(DBG_PTS, "pts database not available");
210 return FAILED;
211 }
212 status = this->pts_db->get_comp_measurement_count(this->pts_db,
213 this->name, this->keyid, algo, &this->cid,
214 &this->kid, &this->count);
215 if (status != SUCCESS)
216 {
217 return status;
218 }
219 vid = this->name->get_vendor_id(this->name);
220 name = this->name->get_name(this->name);
221 names = pts_components->get_comp_func_names(pts_components, vid);
222
223 if (this->count)
224 {
225 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
226 "measurements", this->count, pen_names, vid, names, name);
227 }
228 else
229 {
230 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
231 "measurements", pen_names, vid, names, name);
232 this->is_registering = TRUE;
233 }
234 }
235
236 if (this->is_registering)
237 {
238 status = this->pts_db->insert_comp_measurement(this->pts_db,
239 measurement, this->cid, this->kid,
240 ++this->seq_no, extended_pcr, algo);
241 if (status != SUCCESS)
242 {
243 return status;
244 }
245 this->count = this->seq_no + 1;
246 }
247 else
248 {
249 status = this->pts_db->check_comp_measurement(this->pts_db,
250 measurement, this->cid, this->kid,
251 ++this->seq_no, extended_pcr, algo);
252 if (status != SUCCESS)
253 {
254 return status;
255 }
256 }
257
258 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
259 if (has_pcr_info)
260 {
261 if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
262 {
263 return FAILED;
264 }
265 }
266
267 return SUCCESS;
268 }
269
270 METHOD(pts_component_t, finalize, bool,
271 pts_ita_comp_tboot_t *this)
272 {
273 u_int32_t vid, name;
274 enum_name_t *names;
275
276 vid = this->name->get_vendor_id(this->name);
277 name = this->name->get_name(this->name);
278 names = pts_components->get_comp_func_names(pts_components, vid);
279
280 if (this->is_registering)
281 {
282 /* close registration */
283 this->is_registering = FALSE;
284
285 DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
286 "measurements", this->seq_no, pen_names, vid, names, name);
287 }
288 else if (this->seq_no < this->count)
289 {
290 DBG1(DBG_PTS, "%d of %d %N '%N' functional component evidence "
291 "measurements missing", this->count - this->seq_no,
292 this->count, pen_names, vid, names, name);
293 return FALSE;
294 }
295
296 return TRUE;
297 }
298
299 METHOD(pts_component_t, destroy, void,
300 pts_ita_comp_tboot_t *this)
301 {
302 int count;
303 u_int32_t vid, name;
304 enum_name_t *names;
305
306 if (this->is_registering)
307 {
308 count = this->pts_db->delete_comp_measurements(this->pts_db,
309 this->cid, this->kid);
310 vid = this->name->get_vendor_id(this->name);
311 name = this->name->get_name(this->name);
312 names = pts_components->get_comp_func_names(pts_components, vid);
313 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
314 "evidence measurements", count, pen_names, vid, names, name);
315 }
316 this->name->destroy(this->name);
317 free(this->keyid.ptr);
318 free(this);
319 }
320
321 /**
322 * See header
323 */
324 pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
325 pts_database_t *pts_db)
326 {
327 pts_ita_comp_tboot_t *this;
328
329 INIT(this,
330 .public = {
331 .get_comp_func_name = _get_comp_func_name,
332 .get_evidence_flags = _get_evidence_flags,
333 .get_depth = _get_depth,
334 .measure = _measure,
335 .verify = _verify,
336 .finalize = _finalize,
337 .destroy = _destroy,
338 },
339 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
340 qualifier),
341 .depth = depth,
342 .pts_db = pts_db,
343 );
344
345 return &this->public;
346 }
347