bound functional component measurements to AIK
[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 8
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 * AIK keyid
61 */
62 chunk_t keyid;
63
64 /**
65 * IMA BIOS measurement time
66 */
67 time_t bios_measurement_time;
68
69 /**
70 * IMA BIOS measurements
71 */
72 linked_list_t *list;
73
74 /**
75 * Expected measurement count
76 */
77 int count;
78
79 /**
80 * Measurement sequence number
81 */
82 int seq_no;
83
84 /**
85 * Shadow PCR registers
86 */
87 chunk_t pcrs[IMA_PCR_MAX];
88 };
89
90 typedef struct entry_t entry_t;
91
92 /**
93 * Linux IMA measurement entry
94 */
95 struct entry_t {
96
97 /**
98 * PCR register
99 */
100 u_int32_t pcr;
101
102 /**
103 * SHA1 measurement hash
104 */
105 chunk_t measurement;
106 };
107
108 /**
109 * Free an entry_t object
110 */
111 static void free_entry(entry_t *this)
112 {
113 free(this->measurement.ptr);
114 free(this);
115 }
116
117 /**
118 * Load a PCR measurement file and determine the creation date
119 */
120 static bool load_measurements(char *file, linked_list_t *list, time_t *created)
121 {
122 u_int32_t pcr, num, len;
123 entry_t *entry;
124 struct stat st;
125 ssize_t res;
126 int fd;
127
128 fd = open(file, O_RDONLY);
129 if (fd == -1)
130 {
131 DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno));
132 return FALSE;
133 }
134
135 if (fstat(fd, &st) == -1)
136 {
137 DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file,
138 strerror(errno));
139 close(fd);
140 return FALSE;
141 }
142 *created = st.st_ctime;
143
144 while (TRUE)
145 {
146 res = read(fd, &pcr, 4);
147 if (res == 0)
148 {
149 DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)",
150 file, list->get_count(list));
151 close(fd);
152 return TRUE;
153 }
154
155 entry = malloc_thing(entry_t);
156 entry->pcr = pcr;
157 entry->measurement = chunk_alloc(HASH_SIZE_SHA1);
158
159 if (res != 4)
160 {
161 break;
162 }
163 if (read(fd, &num, 4) != 4)
164 {
165 break;
166 }
167 if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1)
168 {
169 break;
170 }
171 if (read(fd, &len, 4) != 4)
172 {
173 break;
174 }
175 if (lseek(fd, len, SEEK_CUR) == -1)
176 {
177 break;
178 }
179 list->insert_last(list, entry);
180 }
181
182 DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s",
183 file, strerror(errno));
184 close(fd);
185 return FALSE;
186 }
187
188 METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*,
189 pts_ita_comp_ima_t *this)
190 {
191 return this->name;
192 }
193
194 METHOD(pts_component_t, get_evidence_flags, u_int8_t,
195 pts_ita_comp_ima_t *this)
196 {
197 return PTS_REQ_FUNC_COMP_EVID_PCR;
198 }
199
200 METHOD(pts_component_t, get_depth, u_int32_t,
201 pts_ita_comp_ima_t *this)
202 {
203 return this->depth;
204 }
205
206 METHOD(pts_component_t, measure, status_t,
207 pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence)
208 {
209 pts_comp_evidence_t *evid;
210 chunk_t pcr_before, pcr_after;
211 pts_pcr_transform_t pcr_transform;
212 pts_meas_algorithms_t hash_algo;
213 size_t pcr_len;
214 entry_t *entry;
215 hasher_t *hasher;
216
217 hash_algo = PTS_MEAS_ALGO_SHA1;
218 pcr_len = pts->get_pcr_len(pts);
219 pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len);
220
221 if (this->list->get_count(this->list) == 0)
222 {
223 if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list,
224 &this->bios_measurement_time))
225 {
226 return FAILED;
227 }
228 }
229
230 if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS)
231 {
232 DBG1(DBG_PTS, "could not retrieve measurement entry");
233 return FAILED;
234 }
235
236 pcr_before = chunk_clone(this->pcrs[entry->pcr]);
237
238 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
239 hasher->get_hash(hasher, pcr_before, NULL);
240 hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr);
241 hasher->destroy(hasher);
242
243 pcr_after = chunk_clone(this->pcrs[entry->pcr]);
244
245 evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name),
246 this->depth, entry->pcr, hash_algo, pcr_transform,
247 this->bios_measurement_time, entry->measurement);
248 evid->set_pcr_info(evid, pcr_before, pcr_after);
249
250 free(entry);
251
252 return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS;
253 }
254
255 METHOD(pts_component_t, verify, status_t,
256 pts_ita_comp_ima_t *this, pts_t *pts, pts_database_t *pts_db,
257 pts_comp_evidence_t *evidence)
258 {
259 bool has_pcr_info;
260 u_int32_t extended_pcr, vid, name;
261 enum_name_t *names;
262 pts_meas_algorithms_t algo;
263 pts_pcr_transform_t transform;
264 time_t measurement_time;
265 chunk_t measurement, pcr_before, pcr_after;
266
267 measurement = evidence->get_measurement(evidence, &extended_pcr,
268 &algo, &transform, &measurement_time);
269
270 if (!this->keyid.ptr)
271 {
272 if (!pts->get_aik_keyid(pts, &this->keyid))
273 {
274 return FAILED;
275 }
276 this->keyid = chunk_clone(this->keyid);
277
278 if (!pts_db)
279 {
280 DBG1(DBG_PTS, "pts database not available");
281 return FAILED;
282 }
283 if (!pts_db->get_comp_measurement_count(pts_db, this->name, this->keyid,
284 algo, &this->count))
285 {
286 return FAILED;
287 }
288 vid = this->name->get_vendor_id(this->name);
289 name = this->name->get_name(this->name);
290 names = pts_components->get_comp_func_names(pts_components, vid);
291
292 if (this->count == 0)
293 {
294 DBG1(DBG_PTS, "no %N '%N' functional component evidence measurements "
295 "available", pen_names, vid, names, name);
296 return FAILED;
297 }
298 DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence measurements",
299 this->count, pen_names, vid, names, name);
300 }
301
302 if (pts_db->check_comp_measurement(pts_db, measurement, this->name,
303 this->keyid, ++this->seq_no, extended_pcr, algo) != SUCCESS)
304 {
305 return FAILED;
306 }
307
308 has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after);
309 if (has_pcr_info)
310 {
311 if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after))
312 {
313 return FAILED;
314 }
315 }
316
317 return (this->seq_no < this->count) ? NEED_MORE : SUCCESS;
318 }
319
320 METHOD(pts_component_t, destroy, void,
321 pts_ita_comp_ima_t *this)
322 {
323 int i;
324
325 for (i = 0; i < IMA_PCR_MAX; i++)
326 {
327 free(this->pcrs[i].ptr);
328 }
329 this->list->destroy_function(this->list, (void *)free_entry);
330 this->name->destroy(this->name);
331 free(this->keyid.ptr);
332 free(this);
333 }
334
335 /**
336 * See header
337 */
338 pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth)
339 {
340 pts_ita_comp_ima_t *this;
341 int i;
342
343 INIT(this,
344 .public = {
345 .get_comp_func_name = _get_comp_func_name,
346 .get_evidence_flags = _get_evidence_flags,
347 .get_depth = _get_depth,
348 .measure = _measure,
349 .verify = _verify,
350 .destroy = _destroy,
351 },
352 .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA,
353 qualifier),
354 .depth = depth,
355 .list = linked_list_create(),
356 );
357
358 for (i = 0; i < IMA_PCR_MAX; i++)
359 {
360 this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1);
361 memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1);
362 }
363 return &this->public;
364 }
365