]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libimcv/pts/pts_pcr.c
9f098c08eb0b19ada9810c0295ffb78e13cd9ed0
[thirdparty/strongswan.git] / src / libimcv / pts / pts_pcr.c
1 /*
2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pts_pcr.h"
17
18 #include <utils/debug.h>
19
20 #include <stdarg.h>
21
22 typedef struct private_pts_pcr_t private_pts_pcr_t;
23
24 /**
25 * Private data of a pts_pcr_t object.
26 *
27 */
28 struct private_pts_pcr_t {
29
30 /**
31 * Public pts_pcr_t interface.
32 */
33 pts_pcr_t public;
34
35 /**
36 * Shadow PCR registers
37 */
38 chunk_t pcrs[PTS_PCR_MAX_NUM];
39
40 /**
41 * Number of extended PCR registers
42 */
43 uint32_t pcr_count;
44
45 /**
46 * Highest extended PCR register
47 */
48 uint32_t pcr_max;
49
50 /**
51 * Bitmap of extended PCR registers
52 */
53 uint8_t pcr_select[PTS_PCR_MAX_NUM / 8];
54
55 /**
56 * Hasher used to extend shadow PCRs
57 */
58 hasher_t *hasher;
59
60 };
61
62 METHOD(pts_pcr_t, get_count, uint32_t,
63 private_pts_pcr_t *this)
64 {
65 return this->pcr_count;
66 }
67
68 METHOD(pts_pcr_t, select_pcr, bool,
69 private_pts_pcr_t *this, uint32_t pcr)
70 {
71 uint32_t i, f;
72
73 if (pcr >= PTS_PCR_MAX_NUM)
74 {
75 DBG1(DBG_PTS, "PCR %2u: number is larger than maximum of %u",
76 pcr, PTS_PCR_MAX_NUM-1);
77 return FALSE;
78 }
79
80 /* Determine PCR selection flag */
81 i = pcr / 8;
82 f = 1 << (pcr - 8*i);
83
84 /* Has this PCR already been selected? */
85 if (!(this->pcr_select[i] & f))
86 {
87 this->pcr_select[i] |= f;
88 this->pcr_max = max(this->pcr_max, pcr);
89 this->pcr_count++;
90 }
91 return TRUE;
92 }
93
94 METHOD(pts_pcr_t, get_selection_size, size_t,
95 private_pts_pcr_t *this)
96 {
97
98 /**
99 * A TPM v1.2 has 24 PCR Registers so the bitmask field length
100 * used by TrouSerS is at least 3 bytes
101 */
102 return PTS_PCR_MAX_NUM / 8;
103 }
104
105 typedef struct {
106 /** implements enumerator_t */
107 enumerator_t public;
108 /** current PCR */
109 uint32_t pcr;
110 /** back reference to parent */
111 private_pts_pcr_t *pcrs;
112 } pcr_enumerator_t;
113
114 METHOD(enumerator_t, pcr_enumerator_enumerate, bool,
115 pcr_enumerator_t *this, va_list args)
116 {
117 uint32_t i, f, *pcr;
118
119 VA_ARGS_VGET(args, pcr);
120
121 while (this->pcr <= this->pcrs->pcr_max)
122 {
123 /* Determine PCR selection flag */
124 i = this->pcr / 8;
125 f = 1 << (this->pcr - 8*i);
126
127 /* Assign current PCR to output argument and increase */
128 *pcr = this->pcr++;
129
130 /* return if PCR is selected */
131 if (this->pcrs->pcr_select[i] & f)
132 {
133 return TRUE;
134 }
135 }
136 return FALSE;
137 }
138
139 METHOD(pts_pcr_t, create_enumerator, enumerator_t*,
140 private_pts_pcr_t *this)
141 {
142 pcr_enumerator_t *enumerator;
143
144 INIT(enumerator,
145 .public = {
146 .enumerate = enumerator_enumerate_default,
147 .venumerate = _pcr_enumerator_enumerate,
148 .destroy = (void*)free,
149 },
150 .pcrs = this,
151 );
152
153 return (enumerator_t*)enumerator;
154 }
155
156 METHOD(pts_pcr_t, get, chunk_t,
157 private_pts_pcr_t *this, uint32_t pcr)
158 {
159 return (pcr < PTS_PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty;
160 }
161
162 METHOD(pts_pcr_t, set, bool,
163 private_pts_pcr_t *this, uint32_t pcr, chunk_t value)
164 {
165 if (value.len != PTS_PCR_LEN)
166 {
167 DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr);
168 return FALSE;
169 }
170 if (select_pcr(this, pcr))
171 {
172 memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN);
173 return TRUE;
174 }
175 return FALSE;
176 }
177
178 METHOD(pts_pcr_t, extend, chunk_t,
179 private_pts_pcr_t *this, uint32_t pcr, chunk_t measurement)
180 {
181 if (measurement.len != PTS_PCR_LEN)
182 {
183 DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr);
184 return chunk_empty;
185 }
186 if (!select_pcr(this, pcr))
187 {
188 return chunk_empty;
189 }
190 if (!this->hasher->get_hash(this->hasher, this->pcrs[pcr] , NULL) ||
191 !this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr))
192 {
193 DBG1(DBG_PTS, "PCR %2u: not extended due to hasher problem", pcr);
194 return chunk_empty;
195 }
196 return this->pcrs[pcr];
197 }
198
199 METHOD(pts_pcr_t, get_composite, tpm_tss_pcr_composite_t*,
200 private_pts_pcr_t *this)
201 {
202 tpm_tss_pcr_composite_t *pcr_composite;
203 enumerator_t *enumerator;
204 uint16_t selection_size;
205 uint32_t pcr_field_size, pcr;
206 u_char *pos;
207
208 selection_size = get_selection_size(this);
209 pcr_field_size = this->pcr_count * PTS_PCR_LEN;
210
211 INIT(pcr_composite,
212 .pcr_select = chunk_alloc(selection_size),
213 .pcr_composite = chunk_alloc(pcr_field_size),
214 );
215
216 memcpy(pcr_composite->pcr_select.ptr, this->pcr_select, selection_size);
217 pos = pcr_composite->pcr_composite.ptr;
218
219 enumerator = create_enumerator(this);
220 while (enumerator->enumerate(enumerator, &pcr))
221 {
222 memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN);
223 pos += PTS_PCR_LEN;
224 }
225 enumerator->destroy(enumerator);
226
227 return pcr_composite;
228 }
229
230 METHOD(pts_pcr_t, destroy, void,
231 private_pts_pcr_t *this)
232 {
233 uint32_t i;
234
235 for (i = 0; i < PTS_PCR_MAX_NUM; i++)
236 {
237 free(this->pcrs[i].ptr);
238 }
239 this->hasher->destroy(this->hasher);
240 free(this);
241 }
242
243 /**
244 * See header
245 */
246 pts_pcr_t *pts_pcr_create(void)
247 {
248 private_pts_pcr_t *this;
249 hasher_t *hasher;
250 uint32_t i;
251
252 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
253 if (!hasher)
254 {
255 DBG1(DBG_PTS, "%N hasher could not be created",
256 hash_algorithm_short_names, HASH_SHA1);
257 return NULL;
258 }
259
260 INIT(this,
261 .public = {
262 .get_count = _get_count,
263 .select_pcr = _select_pcr,
264 .get_selection_size = _get_selection_size,
265 .create_enumerator = _create_enumerator,
266 .get = _get,
267 .set = _set,
268 .extend = _extend,
269 .get_composite = _get_composite,
270 .destroy = _destroy,
271 },
272 .hasher = hasher,
273 );
274
275 for (i = 0; i < PTS_PCR_MAX_NUM; i++)
276 {
277 this->pcrs[i] = chunk_alloc(PTS_PCR_LEN);
278 memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN);
279 }
280
281 return &this->public;
282 }
283