improved performance of database access by caching primary keys
[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 hash_algo = pts->get_meas_algorithm(pts);
148 hash_size = pts_meas_algo_hash_size(hash_algo);
149 pcr_len = pts->get_pcr_len(pts);
150 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
151
152 /* get and check the measurement data */
153 measurement = chunk_from_hex(
154 chunk_create(meas_hex, strlen(meas_hex)), NULL);
155 pcr_before = chunk_from_hex(
156 chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL);
157 pcr_after = chunk_from_hex(
158 chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL);
159 if (pcr_before.len != pcr_len || pcr_after.len != pcr_len ||
160 measurement.len != hash_size)
161 {
162 DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size");
163 free(measurement.ptr);
164 free(pcr_before.ptr);
165 free(pcr_after.ptr);
166 return FAILED;
167 }
168
169 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
170 this->depth, extended_pcr,
171 hash_algo, pcr_transform,
172 this->measurement_time, measurement);
173 evid->set_pcr_info(evid, pcr_before, pcr_after);
174
175 return (this->seq_no < 2) ? NEED_MORE : SUCCESS;
176 }
177
178 METHOD(pts_component_t, verify, status_t,
179 pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
180 {
181 bool has_pcr_info;
182 u_int32_t extended_pcr, vid, name;
183 enum_name_t *names;
184 pts_meas_algorithms_t algo;
185 pts_pcr_transform_t transform;
186 time_t measurement_time;
187 chunk_t measurement, pcr_before, pcr_after;
188
189 measurement = evidence->get_measurement(evidence, &extended_pcr,
190 &algo, &transform, &measurement_time);
191
192 if (!this->keyid.ptr)
193 {
194 if (!pts->get_aik_keyid(pts, &this->keyid))
195 {
196 return FAILED;
197 }
198 this->keyid = chunk_clone(this->keyid);
199
200 if (!this->pts_db)
201 {
202 DBG1(DBG_PTS, "pts database not available");
203 return FAILED;
204 }
205 if (this->pts_db->get_comp_measurement_count(this->pts_db,
206 this->name, this->keyid, algo,
207 &this->cid, &this->kid, &this->count) != SUCCESS)
208 {
209 return FAILED;
210 }
211 vid = this->name->get_vendor_id(this->name);
212 name = this->name->get_name(this->name);
213 names = pts_components->get_comp_func_names(pts_components, vid);
214
215 if (this->count)
216 {
217 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
218 "measurements", this->count, pen_names, vid, names, name);
219 }
220 else
221 {
222 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
223 "measurements", pen_names, vid, names, name);
224 this->is_registering = TRUE;
225 }
226 }
227
228 if (this->is_registering)
229 {
230 if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
231 this->cid, this->kid, ++this->seq_no,
232 extended_pcr, algo) != SUCCESS)
233 {
234 return FAILED;
235 }
236 this->count = this->seq_no + 1;
237 }
238 else
239 {
240 if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
241 this->cid, this->kid, ++this->seq_no,
242 extended_pcr, algo) != SUCCESS)
243 {
244 return FAILED;
245 }
246 }
247
248 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
249 if (has_pcr_info)
250 {
251 if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
252 {
253 return FAILED;
254 }
255 }
256
257 return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
258 }
259
260 METHOD(pts_component_t, check_off_registrations, bool,
261 pts_ita_comp_tboot_t *this)
262 {
263 u_int32_t vid, name;
264 enum_name_t *names;
265
266 if (!this->is_registering)
267 {
268 return FALSE;
269 }
270
271 /* Finalize registration */
272 this->is_registering = FALSE;
273
274 vid = this->name->get_vendor_id(this->name);
275 name = this->name->get_name(this->name);
276 names = pts_components->get_comp_func_names(pts_components, vid);
277 DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
278 "measurements", this->seq_no, pen_names, vid, names, name);
279 return TRUE;
280 }
281
282 METHOD(pts_component_t, destroy, void,
283 pts_ita_comp_tboot_t *this)
284 {
285 int count;
286 u_int32_t vid, name;
287 enum_name_t *names;
288
289 if (this->is_registering)
290 {
291 count = this->pts_db->delete_comp_measurements(this->pts_db,
292 this->cid, this->kid);
293 vid = this->name->get_vendor_id(this->name);
294 name = this->name->get_name(this->name);
295 names = pts_components->get_comp_func_names(pts_components, vid);
296 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
297 "evidence measurements", count, pen_names, vid, names, name);
298 }
299 this->name->destroy(this->name);
300 free(this->keyid.ptr);
301 free(this);
302 }
303
304 /**
305 * See header
306 */
307 pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth,
308 pts_database_t *pts_db)
309 {
310 pts_ita_comp_tboot_t *this;
311
312 INIT(this,
313 .public = {
314 .get_comp_func_name = _get_comp_func_name,
315 .get_evidence_flags = _get_evidence_flags,
316 .get_depth = _get_depth,
317 .measure = _measure,
318 .verify = _verify,
319 .check_off_registrations = _check_off_registrations,
320 .destroy = _destroy,
321 },
322 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT,
323 qualifier),
324 .depth = depth,
325 .pts_db = pts_db,
326 );
327
328 return &this->public;
329 }
330