Use global status variable for IMA runtime
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_tboot.c
1 /*
2 * Copyright (C) 2011-2014 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 * Sub-component depth
45 */
46 u_int32_t depth;
47
48 /**
49 * PTS measurement database
50 */
51 pts_database_t *pts_db;
52
53 /**
54 * Primary key for AIK database entry
55 */
56 int aik_id;
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 this->aik_id = pts->get_aik_id(pts);
205 pcrs = pts->get_pcrs(pts);
206 measurement = evidence->get_measurement(evidence, &extended_pcr,
207 &algo, &transform, &measurement_time);
208
209 status = this->pts_db->get_comp_measurement_count(this->pts_db,
210 this->name, this->aik_id, algo,
211 &this->cid, &this->count);
212 if (status != SUCCESS)
213 {
214 return status;
215 }
216 vid = this->name->get_vendor_id(this->name);
217 name = this->name->get_name(this->name);
218 names = pts_components->get_comp_func_names(pts_components, vid);
219
220 if (this->count)
221 {
222 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
223 "measurements", this->count, pen_names, vid, names, name);
224 }
225 else
226 {
227 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
228 "measurements", pen_names, vid, names, name);
229 this->is_registering = TRUE;
230 }
231
232 if (this->is_registering)
233 {
234 status = this->pts_db->insert_comp_measurement(this->pts_db,
235 measurement, this->cid, this->aik_id,
236 ++this->seq_no, extended_pcr, algo);
237 if (status != SUCCESS)
238 {
239 return status;
240 }
241 this->count = this->seq_no + 1;
242 }
243 else
244 {
245 status = this->pts_db->check_comp_measurement(this->pts_db,
246 measurement, this->cid, this->kid,
247 ++this->seq_no, extended_pcr, algo);
248 if (status != SUCCESS)
249 {
250 return status;
251 }
252 }
253
254 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
255 if (has_pcr_info)
256 {
257 if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr)))
258 {
259 DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value",
260 extended_pcr);
261 }
262 if (pcrs->set(pcrs, extended_pcr, pcr_after))
263 {
264 return SUCCESS;
265 }
266 }
267
268 return SUCCESS;
269 }
270
271 METHOD(pts_component_t, finalize, bool,
272 pts_ita_comp_tboot_t *this, u_int8_t qualifier, bio_writer_t *result)
273 {
274 char result_buf[BUF_LEN];
275
276 if (this->is_registering)
277 {
278 /* close registration */
279 this->is_registering = FALSE;
280
281 snprintf(result_buf, BUF_LEN, "registered %d evidence measurements",
282 this->seq_no);
283 }
284 else if (this->seq_no < this->count)
285 {
286 snprintf(result_buf, BUF_LEN, "%d of %d evidence measurements "
287 "missing", this->count - this->seq_no, this->count);
288 return FALSE;
289 }
290 else
291 {
292 snprintf(result_buf, BUF_LEN, "%d evidence measurements are ok",
293 this->count);
294 }
295 DBG1(DBG_PTS, "%s", result_buf);
296 result->write_data(result, chunk_from_str(result_buf));
297
298 return TRUE;
299 }
300
301 METHOD(pts_component_t, get_ref, pts_component_t*,
302 pts_ita_comp_tboot_t *this)
303 {
304 ref_get(&this->ref);
305 return &this->public;
306 }
307
308 METHOD(pts_component_t, destroy, void,
309 pts_ita_comp_tboot_t *this)
310 {
311 int count;
312 u_int32_t vid, name;
313 enum_name_t *names;
314
315 if (ref_put(&this->ref))
316 {
317 if (this->is_registering)
318 {
319 count = this->pts_db->delete_comp_measurements(this->pts_db,
320 this->cid, this->aik_id);
321 vid = this->name->get_vendor_id(this->name);
322 name = this->name->get_name(this->name);
323 names = pts_components->get_comp_func_names(pts_components, vid);
324 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
325 "evidence measurements", count, pen_names, vid, names, name);
326 }
327 this->name->destroy(this->name);
328 free(this);
329 }
330 }
331
332 /**
333 * See header
334 */
335 pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth,
336 pts_database_t *pts_db)
337 {
338 pts_ita_comp_tboot_t *this;
339
340 INIT(this,
341 .public = {
342 .get_comp_func_name = _get_comp_func_name,
343 .get_evidence_flags = _get_evidence_flags,
344 .get_depth = _get_depth,
345 .measure = _measure,
346 .verify = _verify,
347 .finalize = _finalize,
348 .get_ref = _get_ref,
349 .destroy = _destroy,
350 },
351 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
352 PTS_ITA_QUALIFIER_FLAG_KERNEL |
353 PTS_ITA_QUALIFIER_TYPE_TRUSTED),
354 .depth = depth,
355 .pts_db = pts_db,
356 .ref = 1,
357 );
358
359 return &this->public;
360 }
361