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