]>
Commit | Line | Data |
---|---|---|
051dfbd6 | 1 | /* |
d647a8f9 | 2 | * Copyright (C) 2011-2020 Andreas Steffen |
051dfbd6 AS |
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 "ita_comp_tboot.h" | |
17 | #include "ita_comp_func_name.h" | |
18 | ||
d6fb2cc6 | 19 | #include "imcv.h" |
051dfbd6 AS |
20 | #include "pts/components/pts_component.h" |
21 | ||
f05b4272 | 22 | #include <utils/debug.h> |
051dfbd6 AS |
23 | #include <pen/pen.h> |
24 | ||
25 | typedef struct pts_ita_comp_tboot_t pts_ita_comp_tboot_t; | |
26 | ||
27 | /** | |
28 | * Private data of a pts_ita_comp_tboot_t object. | |
29 | * | |
30 | */ | |
31 | struct pts_ita_comp_tboot_t { | |
32 | ||
33 | /** | |
cb3ecd5a | 34 | * Public pts_component_t interface. |
051dfbd6 AS |
35 | */ |
36 | pts_component_t public; | |
37 | ||
38 | /** | |
39 | * Component Functional Name | |
40 | */ | |
41 | pts_comp_func_name_t *name; | |
cb3ecd5a | 42 | |
824a7824 SC |
43 | /** |
44 | * Sub-component depth | |
45 | */ | |
b12c53ce | 46 | uint32_t depth; |
824a7824 | 47 | |
db087023 AS |
48 | /** |
49 | * PTS measurement database | |
50 | */ | |
51 | pts_database_t *pts_db; | |
52 | ||
b138bbee AS |
53 | /** |
54 | * Primary key for AIK database entry | |
55 | */ | |
56 | int aik_id; | |
57 | ||
f2a521e7 | 58 | /** |
4932278e | 59 | * Primary key for Component Functional Name database entry |
f2a521e7 | 60 | */ |
4932278e AS |
61 | int cid; |
62 | ||
db087023 | 63 | /** |
f05b4272 | 64 | * Component is registering measurements |
db087023 AS |
65 | */ |
66 | bool is_registering; | |
67 | ||
cb3ecd5a | 68 | /** |
86a6f698 | 69 | * Time of TBOOT measurement |
cb3ecd5a | 70 | */ |
86a6f698 | 71 | time_t measurement_time; |
cb3ecd5a | 72 | |
f2a521e7 AS |
73 | /** |
74 | * Expected measurement count | |
75 | */ | |
76 | int count; | |
77 | ||
cb3ecd5a | 78 | /** |
86a6f698 | 79 | * Measurement sequence number |
cb3ecd5a | 80 | */ |
86a6f698 | 81 | int seq_no; |
cb3ecd5a | 82 | |
af8354da AS |
83 | /** |
84 | * Reference count | |
85 | */ | |
86 | refcount_t ref; | |
87 | ||
051dfbd6 AS |
88 | }; |
89 | ||
90 | METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, | |
91 | pts_ita_comp_tboot_t *this) | |
92 | { | |
93 | return this->name; | |
94 | } | |
95 | ||
b12c53ce | 96 | METHOD(pts_component_t, get_evidence_flags, uint8_t, |
a1ac4d5e AS |
97 | pts_ita_comp_tboot_t *this) |
98 | { | |
8d851141 | 99 | return PTS_REQ_FUNC_COMP_EVID_PCR; |
a1ac4d5e AS |
100 | } |
101 | ||
b12c53ce | 102 | METHOD(pts_component_t, get_depth, uint32_t, |
824a7824 SC |
103 | pts_ita_comp_tboot_t *this) |
104 | { | |
105 | return this->depth; | |
106 | } | |
107 | ||
cb3ecd5a | 108 | METHOD(pts_component_t, measure, status_t, |
b12c53ce | 109 | pts_ita_comp_tboot_t *this, uint8_t qualifier, pts_t *pts, |
af8354da | 110 | pts_comp_evidence_t **evidence) |
e0bfc4d6 | 111 | |
051dfbd6 | 112 | { |
4c020862 AS |
113 | size_t pcr_len; |
114 | pts_pcr_t *pcrs; | |
115 | pts_pcr_transform_t pcr_transform; | |
116 | pts_meas_algorithms_t hash_algo; | |
cb3ecd5a AS |
117 | pts_comp_evidence_t *evid; |
118 | char *meas_hex, *pcr_before_hex, *pcr_after_hex; | |
119 | chunk_t measurement, pcr_before, pcr_after; | |
b12c53ce | 120 | uint32_t extended_pcr; |
f05b4272 | 121 | |
86a6f698 | 122 | switch (this->seq_no++) |
cb3ecd5a AS |
123 | { |
124 | case 0: | |
125 | /* dummy data since currently the TBOOT log is not retrieved */ | |
126 | time(&this->measurement_time); | |
127 | meas_hex = lib->settings->get_str(lib->settings, | |
50fdff70 | 128 | "%s.plugins.imc-attestation.pcr17_meas", NULL, lib->ns); |
cb3ecd5a | 129 | pcr_before_hex = lib->settings->get_str(lib->settings, |
50fdff70 | 130 | "%s.plugins.imc-attestation.pcr17_before", NULL, lib->ns); |
cb3ecd5a | 131 | pcr_after_hex = lib->settings->get_str(lib->settings, |
50fdff70 | 132 | "%s.plugins.imc-attestation.pcr17_after", NULL, lib->ns); |
86a6f698 | 133 | extended_pcr = PCR_TBOOT_POLICY; |
cb3ecd5a | 134 | break; |
86a6f698 | 135 | case 1: |
cb3ecd5a AS |
136 | /* dummy data since currently the TBOOT log is not retrieved */ |
137 | meas_hex = lib->settings->get_str(lib->settings, | |
50fdff70 | 138 | "%s.plugins.imc-attestation.pcr18_meas", NULL, lib->ns); |
cb3ecd5a | 139 | pcr_before_hex = lib->settings->get_str(lib->settings, |
50fdff70 | 140 | "%s.plugins.imc-attestation.pcr18_before", NULL, lib->ns); |
cb3ecd5a | 141 | pcr_after_hex = lib->settings->get_str(lib->settings, |
50fdff70 | 142 | "%s.plugins.imc-attestation.pcr18_after", NULL, lib->ns); |
86a6f698 | 143 | extended_pcr = PCR_TBOOT_MLE; |
cb3ecd5a AS |
144 | break; |
145 | default: | |
146 | return FAILED; | |
147 | } | |
148 | ||
3092bf10 AS |
149 | if (meas_hex == NULL || pcr_before_hex == NULL || pcr_after_hex == NULL) |
150 | { | |
151 | return FAILED; | |
152 | } | |
153 | ||
4c020862 AS |
154 | hash_algo = PTS_MEAS_ALGO_SHA1; |
155 | pcr_len = HASH_SIZE_SHA1; | |
eeefca6b | 156 | pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); |
51b00052 | 157 | |
eeefca6b | 158 | /* get and check the measurement data */ |
cb3ecd5a AS |
159 | measurement = chunk_from_hex( |
160 | chunk_create(meas_hex, strlen(meas_hex)), NULL); | |
161 | pcr_before = chunk_from_hex( | |
162 | chunk_create(pcr_before_hex, strlen(pcr_before_hex)), NULL); | |
163 | pcr_after = chunk_from_hex( | |
164 | chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL); | |
eeefca6b | 165 | if (pcr_before.len != pcr_len || pcr_after.len != pcr_len || |
4c020862 | 166 | measurement.len != pcr_len) |
eeefca6b | 167 | { |
ab957aac | 168 | DBG1(DBG_PTS, "TBOOT measurement or PCR data have the wrong size"); |
eeefca6b AS |
169 | free(measurement.ptr); |
170 | free(pcr_before.ptr); | |
171 | free(pcr_after.ptr); | |
172 | return FAILED; | |
173 | } | |
cb3ecd5a | 174 | |
4c020862 | 175 | pcrs = pts->get_pcrs(pts); |
d647a8f9 AS |
176 | if (!pcrs) |
177 | { | |
178 | return FAILED; | |
179 | } | |
4c020862 | 180 | pcrs->set(pcrs, extended_pcr, pcr_after); |
56fd3baa | 181 | evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), |
4c020862 AS |
182 | this->depth, extended_pcr, hash_algo, pcr_transform, |
183 | this->measurement_time, measurement); | |
cb3ecd5a AS |
184 | evid->set_pcr_info(evid, pcr_before, pcr_after); |
185 | ||
f2a521e7 | 186 | return (this->seq_no < 2) ? NEED_MORE : SUCCESS; |
051dfbd6 AS |
187 | } |
188 | ||
cb3ecd5a | 189 | METHOD(pts_component_t, verify, status_t, |
b12c53ce | 190 | pts_ita_comp_tboot_t *this, uint8_t qualifier,pts_t *pts, |
af8354da | 191 | pts_comp_evidence_t *evidence) |
051dfbd6 | 192 | { |
cb3ecd5a | 193 | bool has_pcr_info; |
b12c53ce | 194 | uint32_t extended_pcr, vid, name; |
f2a521e7 | 195 | enum_name_t *names; |
cb3ecd5a AS |
196 | pts_meas_algorithms_t algo; |
197 | pts_pcr_transform_t transform; | |
4c020862 | 198 | pts_pcr_t *pcrs; |
cb3ecd5a | 199 | time_t measurement_time; |
f2a521e7 | 200 | chunk_t measurement, pcr_before, pcr_after; |
ddafcda4 | 201 | status_t status; |
824a7824 | 202 | |
b138bbee | 203 | this->aik_id = pts->get_aik_id(pts); |
4c020862 | 204 | pcrs = pts->get_pcrs(pts); |
d647a8f9 AS |
205 | if (!pcrs) |
206 | { | |
207 | return FAILED; | |
208 | } | |
cb3ecd5a | 209 | measurement = evidence->get_measurement(evidence, &extended_pcr, |
86a6f698 | 210 | &algo, &transform, &measurement_time); |
cb3ecd5a | 211 | |
b138bbee AS |
212 | status = this->pts_db->get_comp_measurement_count(this->pts_db, |
213 | this->name, this->aik_id, algo, | |
214 | &this->cid, &this->count); | |
215 | if (status != SUCCESS) | |
f2a521e7 | 216 | { |
b138bbee AS |
217 | return status; |
218 | } | |
219 | vid = this->name->get_vendor_id(this->name); | |
220 | name = this->name->get_name(this->name); | |
d6fb2cc6 | 221 | names = imcv_pts_components->get_comp_func_names(imcv_pts_components, vid); |
f2a521e7 | 222 | |
b138bbee AS |
223 | if (this->count) |
224 | { | |
225 | DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence " | |
226 | "measurements", this->count, pen_names, vid, names, name); | |
227 | } | |
228 | else | |
229 | { | |
230 | DBG1(DBG_PTS, "registering %N '%N' functional component evidence " | |
231 | "measurements", pen_names, vid, names, name); | |
232 | this->is_registering = TRUE; | |
db087023 | 233 | } |
f2a521e7 | 234 | |
db087023 | 235 | if (this->is_registering) |
f275b543 | 236 | { |
ddafcda4 | 237 | status = this->pts_db->insert_comp_measurement(this->pts_db, |
b138bbee | 238 | measurement, this->cid, this->aik_id, |
ddafcda4 AS |
239 | ++this->seq_no, extended_pcr, algo); |
240 | if (status != SUCCESS) | |
db087023 | 241 | { |
ddafcda4 | 242 | return status; |
db087023 AS |
243 | } |
244 | this->count = this->seq_no + 1; | |
245 | } | |
246 | else | |
247 | { | |
ddafcda4 | 248 | status = this->pts_db->check_comp_measurement(this->pts_db, |
08feb454 | 249 | measurement, this->cid, this->aik_id, |
ddafcda4 AS |
250 | ++this->seq_no, extended_pcr, algo); |
251 | if (status != SUCCESS) | |
db087023 | 252 | { |
ddafcda4 | 253 | return status; |
db087023 | 254 | } |
f275b543 AS |
255 | } |
256 | ||
cb3ecd5a AS |
257 | has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); |
258 | if (has_pcr_info) | |
259 | { | |
161a0157 | 260 | if (!chunk_equals_const(pcr_before, pcrs->get(pcrs, extended_pcr))) |
19c956b6 | 261 | { |
ab957aac | 262 | DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", |
4c020862 AS |
263 | extended_pcr); |
264 | } | |
265 | if (pcrs->set(pcrs, extended_pcr, pcr_after)) | |
266 | { | |
267 | return SUCCESS; | |
19c956b6 | 268 | } |
cb3ecd5a AS |
269 | } |
270 | ||
ddafcda4 | 271 | return SUCCESS; |
051dfbd6 AS |
272 | } |
273 | ||
ddafcda4 | 274 | METHOD(pts_component_t, finalize, bool, |
b12c53ce | 275 | pts_ita_comp_tboot_t *this, uint8_t qualifier, bio_writer_t *result) |
db087023 | 276 | { |
975472e4 | 277 | char result_buf[BUF_LEN]; |
ddafcda4 AS |
278 | |
279 | if (this->is_registering) | |
db087023 | 280 | { |
ddafcda4 AS |
281 | /* close registration */ |
282 | this->is_registering = FALSE; | |
283 | ||
975472e4 AS |
284 | snprintf(result_buf, BUF_LEN, "registered %d evidence measurements", |
285 | this->seq_no); | |
ddafcda4 AS |
286 | } |
287 | else if (this->seq_no < this->count) | |
288 | { | |
975472e4 AS |
289 | snprintf(result_buf, BUF_LEN, "%d of %d evidence measurements " |
290 | "missing", this->count - this->seq_no, this->count); | |
db087023 AS |
291 | return FALSE; |
292 | } | |
975472e4 AS |
293 | else |
294 | { | |
295 | snprintf(result_buf, BUF_LEN, "%d evidence measurements are ok", | |
296 | this->count); | |
297 | } | |
298 | DBG1(DBG_PTS, "%s", result_buf); | |
299 | result->write_data(result, chunk_from_str(result_buf)); | |
db087023 | 300 | |
db087023 AS |
301 | return TRUE; |
302 | } | |
303 | ||
af8354da AS |
304 | METHOD(pts_component_t, get_ref, pts_component_t*, |
305 | pts_ita_comp_tboot_t *this) | |
306 | { | |
307 | ref_get(&this->ref); | |
308 | return &this->public; | |
309 | } | |
310 | ||
051dfbd6 | 311 | METHOD(pts_component_t, destroy, void, |
824a7824 | 312 | pts_ita_comp_tboot_t *this) |
051dfbd6 | 313 | { |
db087023 | 314 | int count; |
b12c53ce | 315 | uint32_t vid, name; |
64d4be9b | 316 | enum_name_t *names; |
db087023 | 317 | |
af8354da | 318 | if (ref_put(&this->ref)) |
db087023 | 319 | { |
af8354da AS |
320 | if (this->is_registering) |
321 | { | |
322 | count = this->pts_db->delete_comp_measurements(this->pts_db, | |
b138bbee | 323 | this->cid, this->aik_id); |
af8354da AS |
324 | vid = this->name->get_vendor_id(this->name); |
325 | name = this->name->get_name(this->name); | |
d6fb2cc6 AS |
326 | names = imcv_pts_components->get_comp_func_names(imcv_pts_components, |
327 | vid); | |
af8354da AS |
328 | DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " |
329 | "evidence measurements", count, pen_names, vid, names, name); | |
330 | } | |
331 | this->name->destroy(this->name); | |
af8354da | 332 | free(this); |
db087023 | 333 | } |
051dfbd6 AS |
334 | } |
335 | ||
336 | /** | |
337 | * See header | |
338 | */ | |
b12c53ce | 339 | pts_component_t *pts_ita_comp_tboot_create(uint32_t depth, |
db087023 | 340 | pts_database_t *pts_db) |
051dfbd6 AS |
341 | { |
342 | pts_ita_comp_tboot_t *this; | |
343 | ||
344 | INIT(this, | |
345 | .public = { | |
346 | .get_comp_func_name = _get_comp_func_name, | |
a1ac4d5e | 347 | .get_evidence_flags = _get_evidence_flags, |
824a7824 | 348 | .get_depth = _get_depth, |
051dfbd6 AS |
349 | .measure = _measure, |
350 | .verify = _verify, | |
ddafcda4 | 351 | .finalize = _finalize, |
af8354da | 352 | .get_ref = _get_ref, |
051dfbd6 AS |
353 | .destroy = _destroy, |
354 | }, | |
355 | .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT, | |
af8354da AS |
356 | PTS_ITA_QUALIFIER_FLAG_KERNEL | |
357 | PTS_ITA_QUALIFIER_TYPE_TRUSTED), | |
824a7824 | 358 | .depth = depth, |
db087023 | 359 | .pts_db = pts_db, |
af8354da | 360 | .ref = 1, |
051dfbd6 AS |
361 | ); |
362 | ||
363 | return &this->public; | |
364 | } |