2 * Copyright (C) 2011 Andreas Steffen
4 * HSR Hochschule fuer Technik Rapperswil
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>.
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
17 #include "ita_comp_ima.h"
18 #include "ita_comp_func_name.h"
20 #include "pts/components/pts_component.h"
25 #include <sys/types.h>
31 #define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/"
32 #define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements"
34 #define IMA_SEQUENCE 126
36 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t
;
39 * Private data of a pts_ita_comp_ima_t object.
42 struct pts_ita_comp_ima_t
{
45 * Public pts_component_t interface.
47 pts_component_t
public;
50 * Component Functional Name
52 pts_comp_func_name_t
*name
;
60 * IMA BIOS measurement time
62 time_t bios_measurement_time
;
65 * IMA BIOS measurements
70 * Measurement sequence number
75 * Shadow PCR registers
77 chunk_t pcrs
[IMA_PCR_MAX
];
80 typedef struct entry_t entry_t
;
83 * Linux IMA measurement entry
93 * SHA1 measurement hash
99 * Free an entry_t object
101 static void free_entry(entry_t
*this)
103 free(this->measurement
.ptr
);
108 * Load a PCR measurement file and determine the creation date
110 static bool load_measurements(char *file
, linked_list_t
*list
, time_t *created
)
112 u_int32_t pcr
, num
, len
;
118 fd
= open(file
, O_RDONLY
);
121 DBG1(DBG_PTS
, " opening '%s' failed: %s", file
, strerror(errno
));
125 if (fstat(fd
, &st
) == -1)
127 DBG1(DBG_PTS
, " getting statistics of '%s' failed: %s", file
,
132 *created
= st
.st_ctime
;
136 res
= read(fd
, &pcr
, 4);
139 DBG2(DBG_PTS
, "loaded bios measurements '%s' (%d entries)",
140 file
, list
->get_count(list
));
145 entry
= malloc_thing(entry_t
);
147 entry
->measurement
= chunk_alloc(HASH_SIZE_SHA1
);
153 if (read(fd
, &num
, 4) != 4)
157 if (read(fd
, entry
->measurement
.ptr
, HASH_SIZE_SHA1
) != HASH_SIZE_SHA1
)
161 if (read(fd
, &len
, 4) != 4)
165 if (lseek(fd
, len
, SEEK_CUR
) == -1)
169 list
->insert_last(list
, entry
);
172 DBG1(DBG_PTS
, "loading bios measurements '%s' failed: %s",
173 file
, strerror(errno
));
178 METHOD(pts_component_t
, get_comp_func_name
, pts_comp_func_name_t
*,
179 pts_ita_comp_ima_t
*this)
184 METHOD(pts_component_t
, get_evidence_flags
, u_int8_t
,
185 pts_ita_comp_ima_t
*this)
187 return PTS_REQ_FUNC_COMP_EVID_PCR
;
190 METHOD(pts_component_t
, get_depth
, u_int32_t
,
191 pts_ita_comp_ima_t
*this)
196 METHOD(pts_component_t
, measure
, status_t
,
197 pts_ita_comp_ima_t
*this, pts_t
*pts
, pts_comp_evidence_t
**evidence
)
199 pts_comp_evidence_t
*evid
;
200 chunk_t pcr_before
, pcr_after
;
201 pts_pcr_transform_t pcr_transform
;
202 pts_meas_algorithms_t hash_algo
;
207 hash_algo
= PTS_MEAS_ALGO_SHA1
;
208 pcr_len
= pts
->get_pcr_len(pts
);
209 pcr_transform
= pts_meas_algo_to_pcr_transform(hash_algo
, pcr_len
);
211 if (this->list
->get_count(this->list
) == 0)
213 if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH
, this->list
,
214 &this->bios_measurement_time
))
220 if (this->list
->remove_first(this->list
, (void**)&entry
) != SUCCESS
)
222 DBG1(DBG_PTS
, "could not retrieve measurement entry");
226 pcr_before
= chunk_clone(this->pcrs
[entry
->pcr
]);
228 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
229 hasher
->get_hash(hasher
, pcr_before
, NULL
);
230 hasher
->get_hash(hasher
, entry
->measurement
, this->pcrs
[entry
->pcr
].ptr
);
231 hasher
->destroy(hasher
);
233 pcr_after
= chunk_clone(this->pcrs
[entry
->pcr
]);
235 evid
= *evidence
= pts_comp_evidence_create(this->name
->clone(this->name
),
236 this->depth
, entry
->pcr
, hash_algo
, pcr_transform
,
237 this->bios_measurement_time
, entry
->measurement
);
238 evid
->set_pcr_info(evid
, pcr_before
, pcr_after
);
242 return (this->list
->get_count(this->list
)) ? NEED_MORE
: SUCCESS
;
245 METHOD(pts_component_t
, verify
, status_t
,
246 pts_ita_comp_ima_t
*this, pts_t
*pts
, pts_database_t
*pts_db
,
247 pts_comp_evidence_t
*evidence
)
251 u_int32_t extended_pcr
;
252 pts_meas_algorithms_t algo
;
253 pts_pcr_transform_t transform
;
254 time_t measurement_time
;
255 chunk_t measurement
, pcr_before
, pcr_after
;
257 platform_info
= pts
->get_platform_info(pts
);
258 if (!pts_db
|| !platform_info
)
260 DBG1(DBG_PTS
, "%s%s%s not available",
261 (pts_db
) ?
"" : "pts database",
262 (!pts_db
&& !platform_info
) ?
"and" : "",
263 (platform_info
) ?
"" : "platform info");
266 measurement
= evidence
->get_measurement(evidence
, &extended_pcr
,
267 &algo
, &transform
, &measurement_time
);
269 if (pts_db
->check_comp_measurement(pts_db
, measurement
, this->name
,
270 platform_info
, ++this->seq_no
, extended_pcr
, algo
) != SUCCESS
)
275 has_pcr_info
= evidence
->get_pcr_info(evidence
, &pcr_before
, &pcr_after
);
278 if (!pts
->add_pcr(pts
, extended_pcr
, pcr_before
, pcr_after
))
284 return (this->seq_no
< IMA_SEQUENCE
) ? NEED_MORE
: SUCCESS
;
287 METHOD(pts_component_t
, destroy
, void,
288 pts_ita_comp_ima_t
*this)
292 for (i
= 0; i
< IMA_PCR_MAX
; i
++)
294 free(this->pcrs
[i
].ptr
);
296 this->list
->destroy_function(this->list
, (void *)free_entry
);
297 this->name
->destroy(this->name
);
304 pts_component_t
*pts_ita_comp_ima_create(u_int8_t qualifier
, u_int32_t depth
)
306 pts_ita_comp_ima_t
*this;
311 .get_comp_func_name
= _get_comp_func_name
,
312 .get_evidence_flags
= _get_evidence_flags
,
313 .get_depth
= _get_depth
,
318 .name
= pts_comp_func_name_create(PEN_ITA
, PTS_ITA_COMP_FUNC_NAME_IMA
,
321 .list
= linked_list_create(),
324 for (i
= 0; i
< IMA_PCR_MAX
; i
++)
326 this->pcrs
[i
] = chunk_alloc(HASH_SIZE_SHA1
);
327 memset(this->pcrs
[i
].ptr
, 0x00, HASH_SIZE_SHA1
);
329 return &this->public;