increased number of PCR registers used by IMA
[strongswan.git] / src / libpts / pts / components / ita / ita_comp_ima.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_ima.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 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 #define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
33 #define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
34 #define IMA_PCR_MAX 16
35
36 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t;
37
38 /**
39 * Private data of a pts_ita_comp_ima_t object.
40 *
41 */
42 struct pts_ita_comp_ima_t {
43
44 /**
45 * Public pts_component_t interface.
46 */
47 pts_component_t public;
48
49 /**
50 * Component Functional Name
51 */
52 pts_comp_func_name_t *name;
53
54 /**
55 * Sub-component depth
56 */
57 u_int32_t depth;
58
59 /**
60 * PTS measurement database
61 */
62 pts_database_t *pts_db;
63
64 /**
65 * AIK keyid
66 */
67 chunk_t keyid;
68
69 /**
70 * Component is registering measurements
71 */
72 bool is_registering;
73
74 /**
75 * IMA BIOS measurement time
76 */
77 time_t bios_measurement_time;
78
79 /**
80 * IMA BIOS measurements
81 */
82 linked_list_t *list;
83
84 /**
85 * Expected measurement count
86 */
87 int count;
88
89 /**
90 * Measurement sequence number
91 */
92 int seq_no;
93
94 /**
95 * Shadow PCR registers
96 */
97 chunk_t pcrs[IMA_PCR_MAX];
98 };
99
100 typedef struct entry_t entry_t;
101
102 /**
103 * Linux IMA measurement entry
104 */
105 struct entry_t {
106
107 /**
108 * PCR register
109 */
110 u_int32_t pcr;
111
112 /**
113 * SHA1 measurement hash
114 */
115 chunk_t measurement;
116 };
117
118 /**
119 * Free an entry_t object
120 */
121 static void free_entry(entry_t *this)
122 {
123 free(this->measurement.ptr);
124 free(this);
125 }
126
127 /**
128 * Load a PCR measurement file and determine the creation date
129 */
130 static bool load_measurements(char *file, linked_list_t *list, time_t *created)
131 {
132 u_int32_t pcr, num, len;
133 entry_t *entry;
134 struct stat st;
135 ssize_t res;
136 int fd;
137
138 fd = open(file, O_RDONLY);
139 if (fd == -1)
140 {
141 DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno));
142 return FALSE;
143 }
144
145 if (fstat(fd, &st) == -1)
146 {
147 DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file,
148 strerror(errno));
149 close(fd);
150 return FALSE;
151 }
152 *created = st.st_ctime;
153
154 while (TRUE)
155 {
156 res = read(fd, &pcr, 4);
157 if (res == 0)
158 {
159 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
160 file, list->get_count(list));
161 close(fd);
162 return TRUE;
163 }
164
165 entry = malloc_thing(entry_t);
166 entry->pcr = pcr;
167 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
168
169 if (res != 4)
170 {
171 break;
172 }
173 if (read(fd, &num, 4) != 4)
174 {
175 break;
176 }
177 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
178 {
179 break;
180 }
181 if (read(fd, &len, 4) != 4)
182 {
183 break;
184 }
185 if (lseek(fd, len, SEEK_CUR) == -1)
186 {
187 break;
188 }
189 list->insert_last(list, entry);
190 }
191
192 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s",
193 file, strerror(errno));
194 close(fd);
195 return FALSE;
196 }
197
198 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
199 pts_ita_comp_ima_t *this)
200 {
201 return this->name;
202 }
203
204 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
205 pts_ita_comp_ima_t *this)
206 {
207 return PTS_REQ_FUNC_COMP_EVID_PCR;
208 }
209
210 METHOD(pts_component_t, get_depth, u_int32_t,
211 pts_ita_comp_ima_t *this)
212 {
213 return this->depth;
214 }
215
216 METHOD(pts_component_t, measure, status_t,
217 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
218 {
219 pts_comp_evidence_t *evid;
220 chunk_t pcr_before, pcr_after;
221 pts_pcr_transform_t pcr_transform;
222 pts_meas_algorithms_t hash_algo;
223 size_t pcr_len;
224 entry_t *entry;
225 hasher_t *hasher;
226
227 hash_algo = PTS_MEAS_ALGO_SHA1;
228 pcr_len = pts->get_pcr_len(pts);
229 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
230
231 if (this->list->get_count(this->list) == 0)
232 {
233 if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list,
234 &this->bios_measurement_time))
235 {
236 return FAILED;
237 }
238 }
239
240 if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS)
241 {
242 DBG1(DBG_PTS, "could not retrieve measurement entry");
243 return FAILED;
244 }
245
246 pcr_before = chunk_clone(this->pcrs[entry->pcr]);
247
248 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
249 hasher->get_hash(hasher, pcr_before, NULL);
250 hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr);
251 hasher->destroy(hasher);
252
253 pcr_after = chunk_clone(this->pcrs[entry->pcr]);
254
255 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
256 this->depth, entry->pcr, hash_algo, pcr_transform,
257 this->bios_measurement_time, entry->measurement);
258 evid->set_pcr_info(evid, pcr_before, pcr_after);
259
260 free(entry);
261
262 return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS;
263 }
264
265 METHOD(pts_component_t, verify, status_t,
266 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence)
267 {
268 bool has_pcr_info;
269 u_int32_t extended_pcr, vid, name;
270 enum_name_t *names;
271 pts_meas_algorithms_t algo;
272 pts_pcr_transform_t transform;
273 time_t measurement_time;
274 chunk_t measurement, pcr_before, pcr_after;
275
276 measurement = evidence->get_measurement(evidence, &extended_pcr,
277 &algo, &transform, &measurement_time);
278
279 if (!this->keyid.ptr)
280 {
281 if (!pts->get_aik_keyid(pts, &this->keyid))
282 {
283 return FAILED;
284 }
285 this->keyid = chunk_clone(this->keyid);
286
287 if (!this->pts_db)
288 {
289 DBG1(DBG_PTS, "pts database not available");
290 return FAILED;
291 }
292 if (this->pts_db->get_comp_measurement_count(this->pts_db, this->name,
293 this->keyid, algo, &this->count) != SUCCESS)
294 {
295 return FAILED;
296 }
297 vid = this->name->get_vendor_id(this->name);
298 name = this->name->get_name(this->name);
299 names = pts_components->get_comp_func_names(pts_components, vid);
300
301 if (this->count)
302 {
303 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence "
304 "measurements", this->count, pen_names, vid, names, name);
305 }
306 else
307 {
308 DBG1(DBG_PTS, "registering %N '%N' functional component evidence "
309 "measurements", pen_names, vid, names, name);
310 this->is_registering = TRUE;
311 }
312 }
313
314 if (this->is_registering)
315 {
316 if (this->pts_db->insert_comp_measurement(this->pts_db, measurement,
317 this->name, this->keyid, ++this->seq_no,
318 extended_pcr, algo) != SUCCESS)
319 {
320 return FAILED;
321 }
322 this->count = this->seq_no + 1;
323 }
324 else
325 {
326 if (this->pts_db->check_comp_measurement(this->pts_db, measurement,
327 this->name, this->keyid, ++this->seq_no,
328 extended_pcr, algo) != SUCCESS)
329 {
330 return FAILED;
331 }
332 }
333
334 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
335 if (has_pcr_info)
336 {
337 if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
338 {
339 return FAILED;
340 }
341 }
342
343 return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
344 }
345
346 METHOD(pts_component_t, check_off_registrations, bool,
347 pts_ita_comp_ima_t *this)
348 {
349 u_int32_t vid, name;
350 enum_name_t *names;
351
352 if (!this->is_registering)
353 {
354 return FALSE;
355 }
356
357 /* Finalize registration */
358 this->is_registering = FALSE;
359
360 vid = this->name->get_vendor_id(this->name);
361 name = this->name->get_name(this->name);
362 names = pts_components->get_comp_func_names(pts_components, vid);
363 DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence "
364 "measurements", this->seq_no, pen_names, vid, names, name);
365 return TRUE;
366 }
367
368 METHOD(pts_component_t, destroy, void,
369 pts_ita_comp_ima_t *this)
370 {
371 int i, count;
372 u_int32_t vid, name;
373 enum_name_t *names;
374
375 for (i = 0; i < IMA_PCR_MAX; i++)
376 {
377 free(this->pcrs[i].ptr);
378 }
379 if (this->is_registering)
380 {
381 count = this->pts_db->delete_comp_measurements(this->pts_db, this->name,
382 this->keyid);
383 vid = this->name->get_vendor_id(this->name);
384 name = this->name->get_name(this->name);
385 names = pts_components->get_comp_func_names(pts_components, vid);
386 DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component "
387 "evidence measurements", count, pen_names, vid, names, name);
388 }
389 this->list->destroy_function(this->list, (void *)free_entry);
390 this->name->destroy(this->name);
391 free(this->keyid.ptr);
392 free(this);
393 }
394
395 /**
396 * See header
397 */
398 pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth,
399 pts_database_t *pts_db)
400 {
401 pts_ita_comp_ima_t *this;
402 int i;
403
404 INIT(this,
405 .public = {
406 .get_comp_func_name = _get_comp_func_name,
407 .get_evidence_flags = _get_evidence_flags,
408 .get_depth = _get_depth,
409 .measure = _measure,
410 .verify = _verify,
411 .check_off_registrations = _check_off_registrations,
412 .destroy = _destroy,
413 },
414 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
415 qualifier),
416 .depth = depth,
417 .pts_db = pts_db,
418 .list = linked_list_create(),
419 );
420
421 for (i = 0; i < IMA_PCR_MAX; i++)
422 {
423 this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1);
424 memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1);
425 }
426 return &this->public;
427 }
428