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