libpts: Move settings to <ns>.plugins with fallback to libimcv
[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 <utils/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 * Reference count
90 */
91 refcount_t ref;
92
93 };
94
95 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
96 pts_ita_comp_tboot_t *this)
97 {
98 return this->name;
99 }
100
101 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
102 pts_ita_comp_tboot_t *this)
103 {
104 return PTS_REQ_FUNC_COMP_EVID_PCR;
105 }
106
107 METHOD(pts_component_t, get_depth, u_int32_t,
108 pts_ita_comp_tboot_t *this)
109 {
110 return this->depth;
111 }
112
113 METHOD(pts_component_t, measure, status_t,
114 pts_ita_comp_tboot_t *this, u_int8_t qualifier, pts_t *pts,
115 pts_comp_evidence_t **evidence)
116
117 {
118 size_t pcr_len;
119 pts_pcr_t *pcrs;
120 pts_pcr_transform_t pcr_transform;
121 pts_meas_algorithms_t hash_algo;
122 pts_comp_evidence_t *evid;
123 char *meas_hex, *pcr_before_hex, *pcr_after_hex;
124 chunk_t measurement, pcr_before, pcr_after;
125 u_int32_t extended_pcr;
126
127 switch (this->seq_no++)
128 {
129 case 0:
130 /* dummy data since currently the TBOOT log is not retrieved */
131 time(&this->measurement_time);
132 meas_hex = lib->settings->get_str(lib->settings,
133 "%s.plugins.imc-attestation.pcr17_meas", NULL, lib->ns);
134 pcr_before_hex = lib->settings->get_str(lib->settings,
135 "%s.plugins.imc-attestation.pcr17_before", NULL, lib->ns);
136 pcr_after_hex = lib->settings->get_str(lib->settings,
137 "%s.plugins.imc-attestation.pcr17_after", NULL, lib->ns);
138 extended_pcr = PCR_TBOOT_POLICY;
139 break;
140 case 1:
141 /* dummy data since currently the TBOOT log is not retrieved */
142 meas_hex = lib->settings->get_str(lib->settings,
143 "%s.plugins.imc-attestation.pcr18_meas", NULL, lib->ns);
144 pcr_before_hex = lib->settings->get_str(lib->settings,
145 "%s.plugins.imc-attestation.pcr18_before", NULL, lib->ns);
146 pcr_after_hex = lib->settings->get_str(lib->settings,
147 "%s.plugins.imc-attestation.pcr18_after", NULL, lib->ns);
148 extended_pcr = PCR_TBOOT_MLE;
149 break;
150 default:
151 return FAILED;
152 }
153
154 if (meas_hex == NULL || pcr_before_hex == NULL || pcr_after_hex == NULL)
155 {
156 return FAILED;
157 }
158
159 hash_algo = PTS_MEAS_ALGO_SHA1;
160 pcr_len = HASH_SIZE_SHA1;
161 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
162
163 /* get and check the measurement data */
164 measurement = chunk_from_hex(
165 chunk_create(meas_hex, strlen(meas_hex)), NULL);
166 pcr_before = chunk_from_hex(
167 chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL);
168 pcr_after = chunk_from_hex(
169 chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL);
170 if (pcr_before.len != pcr_len || pcr_after.len != pcr_len ||
171 measurement.len != pcr_len)
172 {
173 DBG1(DBG_PTS, "TBOOT measurement or PCR data have the wrong size");
174 free(measurement.ptr);
175 free(pcr_before.ptr);
176 free(pcr_after.ptr);
177 return FAILED;
178 }
179
180 pcrs = pts->get_pcrs(pts);
181 pcrs->set(pcrs, extended_pcr, pcr_after);
182 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
183 this->depth, extended_pcr, hash_algo, pcr_transform,
184 this->measurement_time, measurement);
185 evid->set_pcr_info(evid, pcr_before, pcr_after);
186
187 return (this->seq_no < 2) ? NEED_MORE : SUCCESS;
188 }
189
190 METHOD(pts_component_t, verify, status_t,
191 pts_ita_comp_tboot_t *this, u_int8_t qualifier,pts_t *pts,
192 pts_comp_evidence_t *evidence)
193 {
194 bool has_pcr_info;
195 u_int32_t extended_pcr, vid, name;
196 enum_name_t *names;
197 pts_meas_algorithms_t algo;
198 pts_pcr_transform_t transform;
199 pts_pcr_t *pcrs;
200 time_t measurement_time;
201 chunk_t measurement, pcr_before, pcr_after;
202 status_t status;
203
204 pcrs = pts->get_pcrs(pts);
205 measurement = evidence->get_measurement(evidence, &extended_pcr,
206 &algo, &transform, &measurement_time);
207
208 if (!this->keyid.ptr)
209 {
210 if (!pts->get_aik_keyid(pts, &this->keyid))
211 {
212 return FAILED;
213 }
214 this->keyid = chunk_clone(this->keyid);
215
216 if (!this->pts_db)
217 {
218 DBG1(DBG_PTS, "pts database not available");
219 return FAILED;
220 }
221 status = this->pts_db->get_comp_measurement_count(this->pts_db,
222 this->name, this->keyid, algo, &this->cid,
223 &this->kid, &this->count);
224 if (status != SUCCESS)
225 {
226 return status;
227 }
228 vid = this->name->get_vendor_id(this->name);
229 name = this->name->get_name(this->name);
230 names = pts_components->get_comp_func_names(pts_components, vid);
231
232 if (this->count)
233 {
234 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
235 "measurements", this->count, pen_names, vid, names, name);
236 }
237 else
238 {
239 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
240 "measurements", pen_names, vid, names, name);
241 this->is_registering = TRUE;
242 }
243 }
244
245 if (this->is_registering)
246 {
247 status = this->pts_db->insert_comp_measurement(this->pts_db,
248 measurement, this->cid, this->kid,
249 ++this->seq_no, extended_pcr, algo);
250 if (status != SUCCESS)
251 {
252 return status;
253 }
254 this->count = this->seq_no + 1;
255 }
256 else
257 {
258 status = this->pts_db->check_comp_measurement(this->pts_db,
259 measurement, this->cid, this->kid,
260 ++this->seq_no, extended_pcr, algo);
261 if (status != SUCCESS)
262 {
263 return status;
264 }
265 }
266
267 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
268 if (has_pcr_info)
269 {
270 if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
271 {
272 DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
273 extended_pcr);
274 }
275 if (pcrs->set(pcrs, extended_pcr, pcr_after))
276 {
277 return SUCCESS;
278 }
279 }
280
281 return SUCCESS;
282 }
283
284 METHOD(pts_component_t, finalize, bool,
285 pts_ita_comp_tboot_t *this, u_int8_t qualifier)
286 {
287 u_int32_t vid, name;
288 enum_name_t *names;
289
290 vid = this->name->get_vendor_id(this->name);
291 name = this->name->get_name(this->name);
292 names = pts_components->get_comp_func_names(pts_components, vid);
293
294 if (this->is_registering)
295 {
296 /* close registration */
297 this->is_registering = FALSE;
298
299 DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
300 "measurements", this->seq_no, pen_names, vid, names, name);
301 }
302 else if (this->seq_no < this->count)
303 {
304 DBG1(DBG_PTS, "%d of %d %N '%N' functional component evidence "
305 "measurements missing", this->count - this->seq_no,
306 this->count, pen_names, vid, names, name);
307 return FALSE;
308 }
309
310 return TRUE;
311 }
312
313 METHOD(pts_component_t, get_ref, pts_component_t*,
314 pts_ita_comp_tboot_t *this)
315 {
316 ref_get(&this->ref);
317 return &this->public;
318 }
319
320 METHOD(pts_component_t, destroy, void,
321 pts_ita_comp_tboot_t *this)
322 {
323 int count;
324 u_int32_t vid, name;
325 enum_name_t *names;
326
327 if (ref_put(&this->ref))
328 {
329 if (this->is_registering)
330 {
331 count = this->pts_db->delete_comp_measurements(this->pts_db,
332 this->cid, this->kid);
333 vid = this->name->get_vendor_id(this->name);
334 name = this->name->get_name(this->name);
335 names = pts_components->get_comp_func_names(pts_components, vid);
336 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
337 "evidence measurements", count, pen_names, vid, names, name);
338 }
339 this->name->destroy(this->name);
340 free(this->keyid.ptr);
341 free(this);
342 }
343 }
344
345 /**
346 * See header
347 */
348 pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth,
349 pts_database_t *pts_db)
350 {
351 pts_ita_comp_tboot_t *this;
352
353 INIT(this,
354 .public = {
355 .get_comp_func_name = _get_comp_func_name,
356 .get_evidence_flags = _get_evidence_flags,
357 .get_depth = _get_depth,
358 .measure = _measure,
359 .verify = _verify,
360 .finalize = _finalize,
361 .get_ref = _get_ref,
362 .destroy = _destroy,
363 },
364 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
365 PTS_ITA_QUALIFIER_FLAG_KERNEL |
366 PTS_ITA_QUALIFIER_TYPE_TRUSTED),
367 .depth = depth,
368 .pts_db = pts_db,
369 .ref = 1,
370 );
371
372 return &this->public;
373 }
374