Request missing SWID tags in a directed PA-TNC message
[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 u_int32_t pcr_count;
44
45 /**
46 * Highest extended PCR register
47 */
48 u_int32_t pcr_max;
49
50 /**
51 * Bitmap of extended PCR registers
52 */
53 u_int8_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, u_int32_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, u_int32_t pcr)
70 {
71 u_int32_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 u_int32_t pcr;
110 /** back reference to parent */
111 private_pts_pcr_t *pcrs;
112 } pcr_enumerator_t;
113
114 /**
115 * Implementation of enumerator.enumerate
116 */
117 static bool pcr_enumerator_enumerate(pcr_enumerator_t *this, ...)
118 {
119 u_int32_t *pcr, i, f;
120 va_list args;
121
122 va_start(args, this);
123 pcr = va_arg(args, u_int32_t*);
124 va_end(args);
125
126 while (this->pcr <= this->pcrs->pcr_max)
127 {
128 /* Determine PCR selection flag */
129 i = this->pcr / 8;
130 f = 1 << (this->pcr - 8*i);
131
132 /* Assign current PCR to output argument and increase */
133 *pcr = this->pcr++;
134
135 /* return if PCR is selected */
136 if (this->pcrs->pcr_select[i] & f)
137 {
138 return TRUE;
139 }
140 }
141 return FALSE;
142 }
143
144 METHOD(pts_pcr_t, create_enumerator, enumerator_t*,
145 private_pts_pcr_t *this)
146 {
147 pcr_enumerator_t *enumerator;
148
149 INIT(enumerator,
150 .public = {
151 .enumerate = (void*)pcr_enumerator_enumerate,
152 .destroy = (void*)free,
153 },
154 .pcrs = this,
155 );
156
157 return (enumerator_t*)enumerator;
158 }
159
160 METHOD(pts_pcr_t, get, chunk_t,
161 private_pts_pcr_t *this, u_int32_t pcr)
162 {
163 return (pcr < PTS_PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty;
164 }
165
166 METHOD(pts_pcr_t, set, bool,
167 private_pts_pcr_t *this, u_int32_t pcr, chunk_t value)
168 {
169 if (value.len != PTS_PCR_LEN)
170 {
171 DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr);
172 return FALSE;
173 }
174 if (select_pcr(this, pcr))
175 {
176 memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN);
177 return TRUE;
178 }
179 return FALSE;
180 }
181
182 METHOD(pts_pcr_t, extend, chunk_t,
183 private_pts_pcr_t *this, u_int32_t pcr, chunk_t measurement)
184 {
185 if (measurement.len != PTS_PCR_LEN)
186 {
187 DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr);
188 return chunk_empty;
189 }
190 if (!select_pcr(this, pcr))
191 {
192 return chunk_empty;
193 }
194 if (!this->hasher->get_hash(this->hasher, this->pcrs[pcr] , NULL) ||
195 !this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr))
196 {
197 DBG1(DBG_PTS, "PCR %2u: not extended due to hasher problem", pcr);
198 return chunk_empty;
199 }
200 return this->pcrs[pcr];
201 }
202
203 METHOD(pts_pcr_t, get_composite, chunk_t,
204 private_pts_pcr_t *this)
205 {
206 chunk_t composite;
207 enumerator_t *enumerator;
208 u_int16_t selection_size;
209 u_int32_t pcr_field_size, pcr;
210 u_char *pos;
211
212 selection_size = get_selection_size(this);
213 pcr_field_size = this->pcr_count * PTS_PCR_LEN;
214
215 composite = chunk_alloc(2 + selection_size + 4 + pcr_field_size);
216 pos = composite.ptr;
217 htoun16(pos, selection_size);
218 pos += 2;
219 memcpy(pos, this->pcr_select, selection_size);
220 pos += selection_size;
221 htoun32(pos, pcr_field_size);
222 pos += 4;
223
224 enumerator = create_enumerator(this);
225 while (enumerator->enumerate(enumerator, &pcr))
226 {
227 memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN);
228 pos += PTS_PCR_LEN;
229 }
230 enumerator->destroy(enumerator);
231
232 DBG3(DBG_PTS, "constructed PCR Composite: %B", &composite);
233 return composite;
234 }
235
236 METHOD(pts_pcr_t, destroy, void,
237 private_pts_pcr_t *this)
238 {
239 u_int32_t i;
240
241 for (i = 0; i < PTS_PCR_MAX_NUM; i++)
242 {
243 free(this->pcrs[i].ptr);
244 }
245 this->hasher->destroy(this->hasher);
246 free(this);
247 }
248
249 /**
250 * See header
251 */
252 pts_pcr_t *pts_pcr_create(void)
253 {
254 private_pts_pcr_t *this;
255 hasher_t *hasher;
256 u_int32_t i;
257
258 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
259 if (!hasher)
260 {
261 DBG1(DBG_PTS, "%N hasher could not be created",
262 hash_algorithm_short_names, HASH_SHA1);
263 return NULL;
264 }
265
266 INIT(this,
267 .public = {
268 .get_count = _get_count,
269 .select_pcr = _select_pcr,
270 .get_selection_size = _get_selection_size,
271 .create_enumerator = _create_enumerator,
272 .get = _get,
273 .set = _set,
274 .extend = _extend,
275 .get_composite = _get_composite,
276 .destroy = _destroy,
277 },
278 .hasher = hasher,
279 );
280
281 for (i = 0; i < PTS_PCR_MAX_NUM; i++)
282 {
283 this->pcrs[i] = chunk_alloc(PTS_PCR_LEN);
284 memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN);
285 }
286
287 return &this->public;
288 }
289