]>
Commit | Line | Data |
---|---|---|
ff32245b MR |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
97707f12 | 3 | * Copyright (c) 2023 Linaro Limited |
ff32245b MR |
4 | * Copyright (c) 2018 Bootlin |
5 | * Author: Miquel Raynal <[email protected]> | |
6 | */ | |
7 | ||
ff32245b | 8 | #include <dm.h> |
97707f12 EJ |
9 | #include <dm/of_access.h> |
10 | #include <tpm_api.h> | |
ff32245b MR |
11 | #include <tpm-common.h> |
12 | #include <tpm-v2.h> | |
27b462ce | 13 | #include <tpm_tcg2.h> |
97707f12 EJ |
14 | #include <u-boot/sha1.h> |
15 | #include <u-boot/sha256.h> | |
16 | #include <u-boot/sha512.h> | |
17 | #include <version_string.h> | |
18 | #include <asm/io.h> | |
cd93d625 | 19 | #include <linux/bitops.h> |
97707f12 EJ |
20 | #include <linux/unaligned/be_byteshift.h> |
21 | #include <linux/unaligned/generic.h> | |
22 | #include <linux/unaligned/le_byteshift.h> | |
23 | ||
ff32245b | 24 | #include "tpm-utils.h" |
1922df20 | 25 | |
ffdbf775 IA |
26 | static int tpm2_update_active_banks(struct udevice *dev) |
27 | { | |
28 | struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
29 | struct tpml_pcr_selection pcrs; | |
30 | int ret, i; | |
31 | ||
32 | ret = tpm2_get_pcr_info(dev, &pcrs); | |
33 | if (ret) | |
34 | return ret; | |
35 | ||
36 | priv->active_bank_count = 0; | |
37 | for (i = 0; i < pcrs.count; i++) { | |
38 | if (!tpm2_is_active_bank(&pcrs.selection[i])) | |
39 | continue; | |
40 | priv->active_banks[priv->active_bank_count] = pcrs.selection[i].hash; | |
41 | priv->active_bank_count++; | |
42 | } | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
b6228b2e RM |
47 | static void tpm2_print_selected_algorithm_name(u32 selected) |
48 | { | |
49 | size_t i; | |
50 | const char *str; | |
51 | ||
52 | for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { | |
53 | const struct digest_info *algo = &hash_algo_list[i]; | |
54 | ||
55 | if (!(selected & algo->hash_mask)) | |
56 | continue; | |
57 | ||
58 | str = tpm2_algorithm_name(algo->hash_alg); | |
59 | if (str) | |
60 | log_info("%s\n", str); | |
61 | } | |
62 | } | |
63 | ||
64 | int tpm2_scan_masks(struct udevice *dev, u32 log_active, u32 *mask) | |
65 | { | |
66 | struct tpml_pcr_selection pcrs; | |
67 | u32 active = 0; | |
68 | u32 supported = 0; | |
69 | int rc, i; | |
70 | ||
71 | *mask = 0; | |
72 | ||
73 | rc = tpm2_get_pcr_info(dev, &pcrs); | |
74 | if (rc) | |
75 | return rc; | |
76 | ||
77 | for (i = 0; i < pcrs.count; i++) { | |
78 | struct tpms_pcr_selection *sel = &pcrs.selection[i]; | |
79 | size_t j; | |
80 | u32 hash_mask = 0; | |
81 | ||
82 | for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) { | |
83 | if (hash_algo_list[j].hash_alg == sel->hash) | |
84 | hash_mask = hash_algo_list[j].hash_mask; | |
85 | } | |
86 | ||
87 | if (tpm2_algorithm_supported(sel->hash)) | |
88 | supported |= hash_mask; | |
89 | ||
90 | if (tpm2_is_active_bank(sel)) | |
91 | active |= hash_mask; | |
92 | } | |
93 | ||
94 | /* All eventlog algorithm(s) must be supported */ | |
95 | if (log_active & ~supported) { | |
96 | log_err("EventLog contains U-Boot unsupported algorithm(s)\n"); | |
97 | tpm2_print_selected_algorithm_name(log_active & ~supported); | |
98 | rc = -1; | |
99 | } | |
100 | if (log_active && active & ~log_active) { | |
101 | log_warning("TPM active algorithm(s) not exist in eventlog\n"); | |
102 | tpm2_print_selected_algorithm_name(active & ~log_active); | |
103 | *mask = log_active; | |
104 | } | |
105 | ||
106 | /* Any active algorithm(s) which are not supported must be removed */ | |
107 | if (active & ~supported) { | |
108 | log_warning("TPM active algorithm(s) unsupported by u-boot\n"); | |
109 | tpm2_print_selected_algorithm_name(active & ~supported); | |
110 | if (*mask) | |
111 | *mask = active & supported & *mask; | |
112 | else | |
113 | *mask = active & supported; | |
114 | } | |
115 | ||
116 | return rc; | |
117 | } | |
118 | ||
119 | static int tpm2_pcr_allocate(struct udevice *dev, u32 algo_mask) | |
120 | { | |
121 | struct tpml_pcr_selection pcr = { 0 }; | |
122 | u32 pcr_len = 0; | |
123 | int rc; | |
124 | ||
125 | rc = tpm2_get_pcr_info(dev, &pcr); | |
126 | if (rc) | |
127 | return rc; | |
128 | ||
129 | rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len); | |
130 | if (rc) | |
131 | return rc; | |
132 | ||
133 | /* Assume no password */ | |
134 | rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len); | |
135 | if (rc) | |
136 | return rc; | |
137 | ||
138 | /* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */ | |
139 | return tpm2_startup(dev, false, TPM2_SU_CLEAR); | |
140 | } | |
141 | ||
142 | int tpm2_activate_banks(struct udevice *dev, u32 log_active) | |
143 | { | |
144 | u32 algo_mask = 0; | |
145 | int rc; | |
146 | ||
147 | rc = tpm2_scan_masks(dev, log_active, &algo_mask); | |
148 | if (rc) | |
149 | return rc; | |
150 | ||
151 | if (algo_mask) { | |
152 | if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE)) | |
153 | return -1; | |
154 | ||
155 | rc = tpm2_pcr_allocate(dev, algo_mask); | |
156 | if (rc) | |
157 | return rc; | |
158 | ||
159 | log_info("PCR allocate done, shutdown TPM and reboot\n"); | |
160 | do_reset(NULL, 0, 0, NULL); | |
161 | log_err("reset does not work!\n"); | |
162 | return -1; | |
163 | } | |
164 | ||
165 | return 0; | |
166 | } | |
167 | ||
6d8e52a6 | 168 | u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode) |
1922df20 | 169 | { |
6d8e52a6 | 170 | int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN; |
1922df20 MR |
171 | const u8 command_v2[12] = { |
172 | tpm_u16(TPM2_ST_NO_SESSIONS), | |
173 | tpm_u32(12), | |
6d8e52a6 | 174 | tpm_u32(op), |
1922df20 MR |
175 | tpm_u16(mode), |
176 | }; | |
177 | int ret; | |
178 | ||
179 | /* | |
180 | * Note TPM2_Startup command will return RC_SUCCESS the first time, | |
181 | * but will return RC_INITIALIZE otherwise. | |
182 | */ | |
abdc7b8a | 183 | ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
6d8e52a6 | 184 | if ((ret && ret != TPM2_RC_INITIALIZE) || !bon) |
1922df20 MR |
185 | return ret; |
186 | ||
ffdbf775 | 187 | return tpm2_update_active_banks(dev); |
1922df20 | 188 | } |
2dc6d97e | 189 | |
abdc7b8a | 190 | u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test) |
2dc6d97e MR |
191 | { |
192 | const u8 command_v2[12] = { | |
193 | tpm_u16(TPM2_ST_NO_SESSIONS), | |
194 | tpm_u32(11), | |
195 | tpm_u32(TPM2_CC_SELF_TEST), | |
196 | full_test, | |
197 | }; | |
198 | ||
abdc7b8a | 199 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
2dc6d97e | 200 | } |
bad8ff56 | 201 | |
a595be3a IA |
202 | u32 tpm2_auto_start(struct udevice *dev) |
203 | { | |
204 | u32 rc; | |
205 | ||
a595be3a IA |
206 | rc = tpm2_self_test(dev, TPMI_YES); |
207 | ||
208 | if (rc == TPM2_RC_INITIALIZE) { | |
6d8e52a6 | 209 | rc = tpm2_startup(dev, true, TPM2_SU_CLEAR); |
a595be3a IA |
210 | if (rc) |
211 | return rc; | |
212 | ||
213 | rc = tpm2_self_test(dev, TPMI_YES); | |
214 | } | |
ffdbf775 IA |
215 | if (rc) |
216 | return rc; | |
a595be3a | 217 | |
ffdbf775 | 218 | return tpm2_update_active_banks(dev); |
a595be3a IA |
219 | } |
220 | ||
abdc7b8a SG |
221 | u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw, |
222 | const ssize_t pw_sz) | |
bad8ff56 | 223 | { |
1bea7cc4 SG |
224 | /* Length of the message header, up to start of password */ |
225 | uint offset = 27; | |
bad8ff56 MR |
226 | u8 command_v2[COMMAND_BUFFER_SIZE] = { |
227 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
1bea7cc4 | 228 | tpm_u32(offset + pw_sz), /* Length */ |
bad8ff56 MR |
229 | tpm_u32(TPM2_CC_CLEAR), /* Command code */ |
230 | ||
231 | /* HANDLE */ | |
232 | tpm_u32(handle), /* TPM resource handle */ | |
233 | ||
234 | /* AUTH_SESSION */ | |
235 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
236 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
237 | tpm_u16(0), /* Size of <nonce> */ | |
238 | /* <nonce> (if any) */ | |
239 | 0, /* Attributes: Cont/Excl/Rst */ | |
240 | tpm_u16(pw_sz), /* Size of <hmac/password> */ | |
241 | /* STRING(pw) <hmac/password> (if any) */ | |
242 | }; | |
bad8ff56 MR |
243 | int ret; |
244 | ||
245 | /* | |
246 | * Fill the command structure starting from the first buffer: | |
247 | * - the password (if any) | |
248 | */ | |
249 | ret = pack_byte_string(command_v2, sizeof(command_v2), "s", | |
250 | offset, pw, pw_sz); | |
251 | offset += pw_sz; | |
252 | if (ret) | |
253 | return TPM_LIB_ERROR; | |
254 | ||
abdc7b8a | 255 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
bad8ff56 | 256 | } |
6284be5a | 257 | |
eadcbc78 SG |
258 | u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index, |
259 | size_t space_size, u32 nv_attributes, | |
260 | const u8 *nv_policy, size_t nv_policy_size) | |
261 | { | |
262 | /* | |
263 | * Calculate the offset of the nv_policy piece by adding each of the | |
264 | * chunks below. | |
265 | */ | |
1c32eee3 SG |
266 | const int platform_len = sizeof(u32); |
267 | const int session_hdr_len = 13; | |
268 | const int message_len = 14; | |
269 | uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len + | |
270 | message_len; | |
eadcbc78 SG |
271 | u8 command_v2[COMMAND_BUFFER_SIZE] = { |
272 | /* header 10 bytes */ | |
273 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
1c32eee3 | 274 | tpm_u32(offset + nv_policy_size + 2),/* Length */ |
eadcbc78 SG |
275 | tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */ |
276 | ||
1c32eee3 | 277 | /* handles 4 bytes */ |
eadcbc78 SG |
278 | tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ |
279 | ||
280 | /* session header 13 bytes */ | |
281 | tpm_u32(9), /* Header size */ | |
282 | tpm_u32(TPM2_RS_PW), /* Password authorisation */ | |
283 | tpm_u16(0), /* nonce_size */ | |
284 | 0, /* session_attrs */ | |
285 | tpm_u16(0), /* auth_size */ | |
286 | ||
287 | /* message 14 bytes + policy */ | |
1c32eee3 | 288 | tpm_u16(message_len + nv_policy_size), /* size */ |
eadcbc78 SG |
289 | tpm_u32(space_index), |
290 | tpm_u16(TPM2_ALG_SHA256), | |
291 | tpm_u32(nv_attributes), | |
292 | tpm_u16(nv_policy_size), | |
1c32eee3 SG |
293 | /* |
294 | * nv_policy | |
295 | * space_size | |
296 | */ | |
eadcbc78 SG |
297 | }; |
298 | int ret; | |
299 | ||
300 | /* | |
301 | * Fill the command structure starting from the first buffer: | |
302 | * - the password (if any) | |
303 | */ | |
1c32eee3 SG |
304 | ret = pack_byte_string(command_v2, sizeof(command_v2), "sw", |
305 | offset, nv_policy, nv_policy_size, | |
306 | offset + nv_policy_size, space_size); | |
eadcbc78 SG |
307 | if (ret) |
308 | return TPM_LIB_ERROR; | |
309 | ||
310 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); | |
311 | } | |
312 | ||
e926136b IA |
313 | u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm, |
314 | const u8 *digest, u32 digest_len) | |
6284be5a | 315 | { |
1bea7cc4 SG |
316 | /* Length of the message header, up to start of digest */ |
317 | uint offset = 33; | |
6284be5a MR |
318 | u8 command_v2[COMMAND_BUFFER_SIZE] = { |
319 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
1bea7cc4 | 320 | tpm_u32(offset + digest_len), /* Length */ |
6284be5a MR |
321 | tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */ |
322 | ||
323 | /* HANDLE */ | |
324 | tpm_u32(index), /* Handle (PCR Index) */ | |
325 | ||
326 | /* AUTH_SESSION */ | |
327 | tpm_u32(9), /* Authorization size */ | |
328 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
329 | tpm_u16(0), /* Size of <nonce> */ | |
330 | /* <nonce> (if any) */ | |
331 | 0, /* Attributes: Cont/Excl/Rst */ | |
332 | tpm_u16(0), /* Size of <hmac/password> */ | |
333 | /* <hmac/password> (if any) */ | |
1bea7cc4 SG |
334 | |
335 | /* hashes */ | |
6284be5a | 336 | tpm_u32(1), /* Count (number of hashes) */ |
e926136b | 337 | tpm_u16(algorithm), /* Algorithm of the hash */ |
6284be5a MR |
338 | /* STRING(digest) Digest */ |
339 | }; | |
6284be5a MR |
340 | int ret; |
341 | ||
a557d258 SG |
342 | if (!digest) |
343 | return -EINVAL; | |
e7505b3b | 344 | |
0698f133 | 345 | if (!tpm2_check_active_banks(dev)) { |
e7505b3b | 346 | log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n"); |
e7e166da RM |
347 | |
348 | ret = tpm2_pcr_allocate(dev, 0); | |
349 | if (ret) | |
350 | return -EINVAL; | |
e7505b3b | 351 | } |
6284be5a MR |
352 | /* |
353 | * Fill the command structure starting from the first buffer: | |
354 | * - the digest | |
355 | */ | |
356 | ret = pack_byte_string(command_v2, sizeof(command_v2), "s", | |
e926136b | 357 | offset, digest, digest_len); |
6284be5a MR |
358 | if (ret) |
359 | return TPM_LIB_ERROR; | |
360 | ||
abdc7b8a | 361 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
6284be5a | 362 | } |
1c4ea8f4 | 363 | |
6719cbe3 SG |
364 | u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count) |
365 | { | |
366 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
367 | /* header 10 bytes */ | |
368 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
369 | tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */ | |
370 | tpm_u32(TPM2_CC_NV_READ), /* Command code */ | |
371 | ||
372 | /* handles 8 bytes */ | |
373 | tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ | |
374 | tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ | |
375 | ||
376 | /* AUTH_SESSION */ | |
377 | tpm_u32(9), /* Authorization size */ | |
378 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
379 | tpm_u16(0), /* Size of <nonce> */ | |
380 | /* <nonce> (if any) */ | |
381 | 0, /* Attributes: Cont/Excl/Rst */ | |
382 | tpm_u16(0), /* Size of <hmac/password> */ | |
383 | /* <hmac/password> (if any) */ | |
384 | ||
385 | tpm_u16(count), /* Number of bytes */ | |
386 | tpm_u16(0), /* Offset */ | |
387 | }; | |
388 | size_t response_len = COMMAND_BUFFER_SIZE; | |
389 | u8 response[COMMAND_BUFFER_SIZE]; | |
390 | int ret; | |
391 | u16 tag; | |
392 | u32 size, code; | |
393 | ||
394 | ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); | |
395 | if (ret) | |
396 | return log_msg_ret("read", ret); | |
397 | if (unpack_byte_string(response, response_len, "wdds", | |
398 | 0, &tag, 2, &size, 6, &code, | |
399 | 16, data, count)) | |
400 | return TPM_LIB_ERROR; | |
401 | ||
402 | return 0; | |
403 | } | |
404 | ||
405 | u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data, | |
406 | u32 count) | |
407 | { | |
408 | struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
409 | uint offset = 10 + 8 + 4 + 9 + 2; | |
410 | uint len = offset + count + 2; | |
411 | /* Use empty password auth if platform hierarchy is disabled */ | |
412 | u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index : | |
413 | TPM2_RH_PLATFORM; | |
414 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
415 | /* header 10 bytes */ | |
416 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
417 | tpm_u32(len), /* Length */ | |
418 | tpm_u32(TPM2_CC_NV_WRITE), /* Command code */ | |
419 | ||
420 | /* handles 8 bytes */ | |
421 | tpm_u32(auth), /* Primary platform seed */ | |
422 | tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ | |
423 | ||
424 | /* AUTH_SESSION */ | |
425 | tpm_u32(9), /* Authorization size */ | |
426 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
427 | tpm_u16(0), /* Size of <nonce> */ | |
428 | /* <nonce> (if any) */ | |
429 | 0, /* Attributes: Cont/Excl/Rst */ | |
430 | tpm_u16(0), /* Size of <hmac/password> */ | |
431 | /* <hmac/password> (if any) */ | |
432 | ||
433 | tpm_u16(count), | |
434 | }; | |
435 | size_t response_len = COMMAND_BUFFER_SIZE; | |
436 | u8 response[COMMAND_BUFFER_SIZE]; | |
437 | int ret; | |
438 | ||
439 | ret = pack_byte_string(command_v2, sizeof(command_v2), "sw", | |
440 | offset, data, count, | |
441 | offset + count, 0); | |
442 | if (ret) | |
443 | return TPM_LIB_ERROR; | |
444 | ||
445 | return tpm_sendrecv_command(dev, command_v2, response, &response_len); | |
446 | } | |
447 | ||
abdc7b8a | 448 | u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz, |
2957a1e2 RG |
449 | u16 algorithm, void *data, u32 digest_len, |
450 | unsigned int *updates) | |
1c4ea8f4 MR |
451 | { |
452 | u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8)); | |
453 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
454 | tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ | |
455 | tpm_u32(17 + idx_array_sz), /* Length */ | |
456 | tpm_u32(TPM2_CC_PCR_READ), /* Command code */ | |
457 | ||
458 | /* TPML_PCR_SELECTION */ | |
459 | tpm_u32(1), /* Number of selections */ | |
2957a1e2 | 460 | tpm_u16(algorithm), /* Algorithm of the hash */ |
1c4ea8f4 MR |
461 | idx_array_sz, /* Array size for selection */ |
462 | /* bitmap(idx) Selected PCR bitmap */ | |
463 | }; | |
464 | size_t response_len = COMMAND_BUFFER_SIZE; | |
465 | u8 response[COMMAND_BUFFER_SIZE]; | |
466 | unsigned int pcr_sel_idx = idx / 8; | |
467 | u8 pcr_sel_bit = BIT(idx % 8); | |
468 | unsigned int counter = 0; | |
469 | int ret; | |
470 | ||
471 | if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b", | |
472 | 17 + pcr_sel_idx, pcr_sel_bit)) | |
473 | return TPM_LIB_ERROR; | |
474 | ||
abdc7b8a | 475 | ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); |
1c4ea8f4 MR |
476 | if (ret) |
477 | return ret; | |
478 | ||
2957a1e2 RG |
479 | if (digest_len > response_len) |
480 | return TPM_LIB_ERROR; | |
481 | ||
1c4ea8f4 MR |
482 | if (unpack_byte_string(response, response_len, "ds", |
483 | 10, &counter, | |
2957a1e2 RG |
484 | response_len - digest_len, data, |
485 | digest_len)) | |
1c4ea8f4 MR |
486 | return TPM_LIB_ERROR; |
487 | ||
488 | if (updates) | |
489 | *updates = counter; | |
490 | ||
491 | return 0; | |
492 | } | |
69cd8f06 | 493 | |
abdc7b8a SG |
494 | u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, |
495 | void *buf, size_t prop_count) | |
69cd8f06 MR |
496 | { |
497 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
498 | tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ | |
499 | tpm_u32(22), /* Length */ | |
500 | tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */ | |
501 | ||
502 | tpm_u32(capability), /* Capability */ | |
503 | tpm_u32(property), /* Property */ | |
504 | tpm_u32(prop_count), /* Property count */ | |
505 | }; | |
506 | u8 response[COMMAND_BUFFER_SIZE]; | |
507 | size_t response_len = COMMAND_BUFFER_SIZE; | |
508 | unsigned int properties_off; | |
509 | int ret; | |
510 | ||
abdc7b8a | 511 | ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); |
69cd8f06 MR |
512 | if (ret) |
513 | return ret; | |
514 | ||
515 | /* | |
516 | * In the response buffer, the properties are located after the: | |
517 | * tag (u16), response size (u32), response code (u32), | |
a322f54f | 518 | * YES/NO flag (u8), TPM_CAP (u32). |
69cd8f06 MR |
519 | */ |
520 | properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) + | |
a322f54f | 521 | sizeof(u8) + sizeof(u32); |
69cd8f06 MR |
522 | memcpy(buf, &response[properties_off], response_len - properties_off); |
523 | ||
524 | return 0; | |
525 | } | |
da9c3392 | 526 | |
9d2bc92b RM |
527 | u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, |
528 | struct tpml_pcr_selection *pcr, u32 *pcr_len) | |
529 | { | |
530 | int i; | |
531 | ||
532 | if (pcr->count > TPM2_NUM_PCR_BANKS) | |
533 | return TPM_LIB_ERROR; | |
534 | ||
535 | *pcr_len = sizeof(pcr->count); | |
536 | ||
537 | for (i = 0; i < pcr->count; i++) { | |
538 | struct tpms_pcr_selection *sel = &pcr->selection[i]; | |
539 | u8 pad = 0; | |
540 | int j; | |
541 | ||
542 | if (sel->size_of_select > TPM2_PCR_SELECT_MAX) | |
543 | return TPM_LIB_ERROR; | |
544 | ||
545 | /* | |
546 | * Found the algorithm (bank) that matches, and enable all PCR | |
547 | * bits. | |
548 | * TODO: only select the bits needed | |
549 | */ | |
550 | for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) { | |
551 | if (hash_algo_list[j].hash_alg != sel->hash) | |
552 | continue; | |
553 | ||
554 | if (algo_mask & hash_algo_list[j].hash_mask) | |
555 | pad = 0xff; | |
556 | } | |
557 | ||
558 | for (j = 0; j < sel->size_of_select; j++) | |
559 | sel->pcr_select[j] = pad; | |
560 | ||
561 | log_info("set bank[%d] %s %s\n", i, | |
562 | tpm2_algorithm_name(sel->hash), | |
563 | tpm2_is_active_bank(sel) ? "on" : "off"); | |
564 | ||
565 | *pcr_len += sizeof(sel->hash) + sizeof(sel->size_of_select) + | |
566 | sel->size_of_select; | |
567 | } | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, | |
573 | const ssize_t pw_sz, struct tpml_pcr_selection *pcr, | |
574 | u32 pcr_len) | |
575 | { | |
576 | /* Length of the message header, up to start of password */ | |
577 | uint offset = 27; | |
578 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
579 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
580 | tpm_u32(offset + pw_sz + pcr_len), /* Length */ | |
581 | tpm_u32(TPM2_CC_PCR_ALLOCATE), /* Command code */ | |
582 | ||
583 | /* handles 4 bytes */ | |
584 | tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ | |
585 | ||
586 | /* AUTH_SESSION */ | |
587 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
588 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
589 | tpm_u16(0), /* Size of <nonce> */ | |
590 | /* <nonce> (if any) */ | |
591 | 0, /* Attributes: Cont/Excl/Rst */ | |
592 | tpm_u16(pw_sz), /* Size of <hmac/password> */ | |
593 | /* STRING(pw) <hmac/password> (if any) */ | |
594 | ||
595 | /* TPML_PCR_SELECTION */ | |
596 | }; | |
597 | u8 response[COMMAND_BUFFER_SIZE]; | |
598 | size_t response_len = COMMAND_BUFFER_SIZE; | |
599 | u32 i; | |
600 | int ret; | |
601 | ||
602 | /* | |
603 | * Fill the command structure starting from the first buffer: | |
604 | * the password (if any) | |
605 | */ | |
606 | if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, pw, | |
607 | pw_sz)) | |
608 | return TPM_LIB_ERROR; | |
609 | ||
610 | offset += pw_sz; | |
611 | ||
612 | /* Pack the count field */ | |
613 | if (pack_byte_string(command_v2, sizeof(command_v2), "d", offset, pcr->count)) | |
614 | return TPM_LIB_ERROR; | |
615 | ||
616 | offset += sizeof(pcr->count); | |
617 | ||
618 | /* Pack each tpms_pcr_selection */ | |
619 | for (i = 0; i < pcr->count; i++) { | |
620 | struct tpms_pcr_selection *sel = &pcr->selection[i]; | |
621 | ||
622 | /* Pack hash (16-bit) */ | |
623 | if (pack_byte_string(command_v2, sizeof(command_v2), "w", offset, | |
624 | sel->hash)) | |
625 | return TPM_LIB_ERROR; | |
626 | ||
627 | offset += sizeof(sel->hash); | |
628 | ||
629 | /* Pack size_of_select (8-bit) */ | |
630 | if (pack_byte_string(command_v2, sizeof(command_v2), "b", offset, | |
631 | sel->size_of_select)) | |
632 | return TPM_LIB_ERROR; | |
633 | ||
634 | offset += sizeof(sel->size_of_select); | |
635 | ||
636 | /* Pack pcr_select array */ | |
637 | if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, | |
638 | sel->pcr_select, sel->size_of_select)) | |
639 | return TPM_LIB_ERROR; | |
640 | ||
641 | offset += sel->size_of_select; | |
642 | } | |
643 | ||
644 | ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); | |
645 | if (!ret) | |
646 | tpm_init(dev); | |
647 | ||
648 | return ret; | |
649 | } | |
650 | ||
97707f12 EJ |
651 | static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) |
652 | { | |
653 | u8 response[(sizeof(struct tpms_capability_data) - | |
654 | offsetof(struct tpms_capability_data, data))]; | |
655 | u32 properties_offset = | |
656 | offsetof(struct tpml_tagged_tpm_property, tpm_property) + | |
657 | offsetof(struct tpms_tagged_property, value); | |
658 | u32 ret; | |
659 | ||
660 | memset(response, 0, sizeof(response)); | |
661 | ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES, | |
662 | TPM2_PT_PCR_COUNT, response, 1); | |
663 | if (ret) | |
664 | return ret; | |
665 | ||
666 | *num_pcr = get_unaligned_be32(response + properties_offset); | |
667 | if (*num_pcr > TPM2_MAX_PCRS) { | |
668 | printf("%s: too many pcrs: %u\n", __func__, *num_pcr); | |
669 | return -E2BIG; | |
670 | } | |
671 | ||
672 | return 0; | |
673 | } | |
674 | ||
cba3fa90 | 675 | int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs) |
97707f12 EJ |
676 | { |
677 | u8 response[(sizeof(struct tpms_capability_data) - | |
678 | offsetof(struct tpms_capability_data, data))]; | |
97707f12 EJ |
679 | u32 num_pcr; |
680 | size_t i; | |
681 | u32 ret; | |
682 | ||
97707f12 EJ |
683 | ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1); |
684 | if (ret) | |
685 | return ret; | |
686 | ||
cba3fa90 | 687 | pcrs->count = get_unaligned_be32(response); |
97707f12 | 688 | /* |
e7505b3b | 689 | * We only support 4 algorithms for now so check against that |
97707f12 EJ |
690 | * instead of TPM2_NUM_PCR_BANKS |
691 | */ | |
e7505b3b | 692 | if (pcrs->count > 4 || pcrs->count < 1) { |
cba3fa90 | 693 | printf("%s: too many pcrs: %u\n", __func__, pcrs->count); |
97707f12 EJ |
694 | return -EMSGSIZE; |
695 | } | |
696 | ||
697 | ret = tpm2_get_num_pcr(dev, &num_pcr); | |
698 | if (ret) | |
699 | return ret; | |
700 | ||
cba3fa90 | 701 | for (i = 0; i < pcrs->count; i++) { |
97707f12 EJ |
702 | /* |
703 | * Definition of TPMS_PCR_SELECTION Structure | |
704 | * hash: u16 | |
705 | * size_of_select: u8 | |
706 | * pcr_select: u8 array | |
707 | * | |
708 | * The offsets depend on the number of the device PCRs | |
709 | * so we have to calculate them based on that | |
710 | */ | |
711 | u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) + | |
712 | i * offsetof(struct tpms_pcr_selection, pcr_select) + | |
713 | i * ((num_pcr + 7) / 8); | |
714 | u32 size_select_offset = | |
715 | hash_offset + offsetof(struct tpms_pcr_selection, | |
716 | size_of_select); | |
717 | u32 pcr_select_offset = | |
718 | hash_offset + offsetof(struct tpms_pcr_selection, | |
719 | pcr_select); | |
720 | ||
cba3fa90 | 721 | pcrs->selection[i].hash = |
97707f12 | 722 | get_unaligned_be16(response + hash_offset); |
cba3fa90 | 723 | pcrs->selection[i].size_of_select = |
97707f12 | 724 | __get_unaligned_be(response + size_select_offset); |
cba3fa90 | 725 | if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) { |
97707f12 | 726 | printf("%s: pcrs selection too large: %u\n", __func__, |
cba3fa90 | 727 | pcrs->selection[i].size_of_select); |
97707f12 EJ |
728 | return -ENOBUFS; |
729 | } | |
730 | /* copy the array of pcr_select */ | |
cba3fa90 IA |
731 | memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset, |
732 | pcrs->selection[i].size_of_select); | |
97707f12 EJ |
733 | } |
734 | ||
97707f12 EJ |
735 | return 0; |
736 | } | |
737 | ||
abdc7b8a | 738 | u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz) |
da9c3392 MR |
739 | { |
740 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
741 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
742 | tpm_u32(27 + pw_sz), /* Length */ | |
743 | tpm_u32(TPM2_CC_DAM_RESET), /* Command code */ | |
744 | ||
745 | /* HANDLE */ | |
746 | tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ | |
747 | ||
748 | /* AUTH_SESSION */ | |
749 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
750 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
751 | tpm_u16(0), /* Size of <nonce> */ | |
752 | /* <nonce> (if any) */ | |
753 | 0, /* Attributes: Cont/Excl/Rst */ | |
754 | tpm_u16(pw_sz), /* Size of <hmac/password> */ | |
755 | /* STRING(pw) <hmac/password> (if any) */ | |
756 | }; | |
757 | unsigned int offset = 27; | |
758 | int ret; | |
759 | ||
760 | /* | |
761 | * Fill the command structure starting from the first buffer: | |
762 | * - the password (if any) | |
763 | */ | |
764 | ret = pack_byte_string(command_v2, sizeof(command_v2), "s", | |
765 | offset, pw, pw_sz); | |
766 | offset += pw_sz; | |
767 | if (ret) | |
768 | return TPM_LIB_ERROR; | |
769 | ||
abdc7b8a | 770 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
da9c3392 MR |
771 | } |
772 | ||
abdc7b8a SG |
773 | u32 tpm2_dam_parameters(struct udevice *dev, const char *pw, |
774 | const ssize_t pw_sz, unsigned int max_tries, | |
775 | unsigned int recovery_time, | |
da9c3392 MR |
776 | unsigned int lockout_recovery) |
777 | { | |
778 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
779 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
780 | tpm_u32(27 + pw_sz + 12), /* Length */ | |
781 | tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */ | |
782 | ||
783 | /* HANDLE */ | |
784 | tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */ | |
785 | ||
786 | /* AUTH_SESSION */ | |
787 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
788 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
789 | tpm_u16(0), /* Size of <nonce> */ | |
790 | /* <nonce> (if any) */ | |
791 | 0, /* Attributes: Cont/Excl/Rst */ | |
792 | tpm_u16(pw_sz), /* Size of <hmac/password> */ | |
793 | /* STRING(pw) <hmac/password> (if any) */ | |
794 | ||
795 | /* LOCKOUT PARAMETERS */ | |
796 | /* tpm_u32(max_tries) Max tries (0, always lock) */ | |
797 | /* tpm_u32(recovery_time) Recovery time (0, no lock) */ | |
798 | /* tpm_u32(lockout_recovery) Lockout recovery */ | |
799 | }; | |
800 | unsigned int offset = 27; | |
801 | int ret; | |
802 | ||
803 | /* | |
804 | * Fill the command structure starting from the first buffer: | |
805 | * - the password (if any) | |
806 | * - max tries | |
807 | * - recovery time | |
808 | * - lockout recovery | |
809 | */ | |
810 | ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd", | |
811 | offset, pw, pw_sz, | |
812 | offset + pw_sz, max_tries, | |
813 | offset + pw_sz + 4, recovery_time, | |
814 | offset + pw_sz + 8, lockout_recovery); | |
815 | offset += pw_sz + 12; | |
816 | if (ret) | |
817 | return TPM_LIB_ERROR; | |
818 | ||
abdc7b8a | 819 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
da9c3392 | 820 | } |
dc26e913 | 821 | |
abdc7b8a SG |
822 | int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw, |
823 | const ssize_t newpw_sz, const char *oldpw, | |
824 | const ssize_t oldpw_sz) | |
dc26e913 MR |
825 | { |
826 | unsigned int offset = 27; | |
827 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
828 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
829 | tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */ | |
830 | tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */ | |
831 | ||
832 | /* HANDLE */ | |
833 | tpm_u32(handle), /* TPM resource handle */ | |
834 | ||
835 | /* AUTH_SESSION */ | |
836 | tpm_u32(9 + oldpw_sz), /* Authorization size */ | |
837 | tpm_u32(TPM2_RS_PW), /* Session handle */ | |
838 | tpm_u16(0), /* Size of <nonce> */ | |
839 | /* <nonce> (if any) */ | |
840 | 0, /* Attributes: Cont/Excl/Rst */ | |
841 | tpm_u16(oldpw_sz) /* Size of <hmac/password> */ | |
842 | /* STRING(oldpw) <hmac/password> (if any) */ | |
843 | ||
844 | /* TPM2B_AUTH (TPM2B_DIGEST) */ | |
845 | /* tpm_u16(newpw_sz) Digest size, new pw length */ | |
846 | /* STRING(newpw) Digest buffer, new pw */ | |
847 | }; | |
848 | int ret; | |
849 | ||
850 | /* | |
851 | * Fill the command structure starting from the first buffer: | |
852 | * - the old password (if any) | |
853 | * - size of the new password | |
854 | * - new password | |
855 | */ | |
856 | ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", | |
857 | offset, oldpw, oldpw_sz, | |
858 | offset + oldpw_sz, newpw_sz, | |
859 | offset + oldpw_sz + 2, newpw, newpw_sz); | |
860 | offset += oldpw_sz + 2 + newpw_sz; | |
861 | if (ret) | |
862 | return TPM_LIB_ERROR; | |
863 | ||
abdc7b8a | 864 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
dc26e913 | 865 | } |
b9dd4fab | 866 | |
abdc7b8a SG |
867 | u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw, |
868 | const ssize_t pw_sz, u32 index, const char *key) | |
b9dd4fab MR |
869 | { |
870 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
871 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
872 | tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */ | |
873 | tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */ | |
874 | ||
875 | /* HANDLE */ | |
876 | tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */ | |
877 | ||
878 | /* AUTH_SESSION */ | |
879 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
880 | tpm_u32(TPM2_RS_PW), /* session handle */ | |
881 | tpm_u16(0), /* Size of <nonce> */ | |
882 | /* <nonce> (if any) */ | |
883 | 0, /* Attributes: Cont/Excl/Rst */ | |
884 | tpm_u16(pw_sz) /* Size of <hmac/password> */ | |
885 | /* STRING(pw) <hmac/password> (if any) */ | |
886 | ||
887 | /* TPM2B_AUTH (TPM2B_DIGEST) */ | |
888 | /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */ | |
889 | /* STRING(key) Digest buffer (PCR key) */ | |
890 | ||
891 | /* TPMI_ALG_HASH */ | |
892 | /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */ | |
893 | ||
894 | /* TPMI_DH_PCR */ | |
895 | /* tpm_u32(index), PCR Index */ | |
896 | }; | |
897 | unsigned int offset = 27; | |
898 | int ret; | |
899 | ||
900 | /* | |
901 | * Fill the command structure starting from the first buffer: | |
902 | * - the password (if any) | |
903 | * - the PCR key length | |
904 | * - the PCR key | |
905 | * - the hash algorithm | |
906 | * - the PCR index | |
907 | */ | |
908 | ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd", | |
909 | offset, pw, pw_sz, | |
910 | offset + pw_sz, TPM2_DIGEST_LEN, | |
911 | offset + pw_sz + 2, key, TPM2_DIGEST_LEN, | |
912 | offset + pw_sz + 2 + TPM2_DIGEST_LEN, | |
913 | TPM2_ALG_SHA256, | |
914 | offset + pw_sz + 4 + TPM2_DIGEST_LEN, index); | |
915 | offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4; | |
916 | if (ret) | |
917 | return TPM_LIB_ERROR; | |
918 | ||
abdc7b8a | 919 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
b9dd4fab MR |
920 | } |
921 | ||
abdc7b8a SG |
922 | u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw, |
923 | const ssize_t pw_sz, u32 index, const char *key, | |
924 | const ssize_t key_sz) | |
b9dd4fab MR |
925 | { |
926 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
927 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
928 | tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */ | |
929 | tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */ | |
930 | ||
931 | /* HANDLE */ | |
932 | tpm_u32(index), /* Handle (PCR Index) */ | |
933 | ||
934 | /* AUTH_SESSION */ | |
935 | tpm_u32(9 + pw_sz), /* Authorization size */ | |
936 | tpm_u32(TPM2_RS_PW), /* session handle */ | |
937 | tpm_u16(0), /* Size of <nonce> */ | |
938 | /* <nonce> (if any) */ | |
939 | 0, /* Attributes: Cont/Excl/Rst */ | |
940 | tpm_u16(pw_sz), /* Size of <hmac/password> */ | |
941 | /* STRING(pw) <hmac/password> (if any) */ | |
942 | ||
943 | /* TPM2B_DIGEST */ | |
944 | /* tpm_u16(key_sz) Key length */ | |
945 | /* STRING(key) Key */ | |
946 | }; | |
947 | unsigned int offset = 27; | |
948 | int ret; | |
949 | ||
950 | /* | |
951 | * Fill the command structure starting from the first buffer: | |
952 | * - the password (if any) | |
953 | * - the number of digests, 1 in our case | |
954 | * - the algorithm, sha256 in our case | |
955 | * - the digest (64 bytes) | |
956 | */ | |
957 | ret = pack_byte_string(command_v2, sizeof(command_v2), "sws", | |
958 | offset, pw, pw_sz, | |
959 | offset + pw_sz, key_sz, | |
960 | offset + pw_sz + 2, key, key_sz); | |
961 | offset += pw_sz + 2 + key_sz; | |
962 | if (ret) | |
963 | return TPM_LIB_ERROR; | |
964 | ||
abdc7b8a | 965 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); |
b9dd4fab | 966 | } |
06bea498 DP |
967 | |
968 | u32 tpm2_get_random(struct udevice *dev, void *data, u32 count) | |
969 | { | |
970 | const u8 command_v2[10] = { | |
971 | tpm_u16(TPM2_ST_NO_SESSIONS), | |
972 | tpm_u32(12), | |
973 | tpm_u32(TPM2_CC_GET_RANDOM), | |
974 | }; | |
975 | u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; | |
976 | ||
977 | const size_t data_size_offset = 10; | |
978 | const size_t data_offset = 12; | |
979 | size_t response_length = sizeof(response); | |
980 | u32 data_size; | |
981 | u8 *out = data; | |
982 | ||
983 | while (count > 0) { | |
984 | u32 this_bytes = min((size_t)count, | |
985 | sizeof(response) - data_offset); | |
986 | u32 err; | |
987 | ||
988 | if (pack_byte_string(buf, sizeof(buf), "sw", | |
989 | 0, command_v2, sizeof(command_v2), | |
990 | sizeof(command_v2), this_bytes)) | |
991 | return TPM_LIB_ERROR; | |
992 | err = tpm_sendrecv_command(dev, buf, response, | |
993 | &response_length); | |
994 | if (err) | |
995 | return err; | |
996 | if (unpack_byte_string(response, response_length, "w", | |
997 | data_size_offset, &data_size)) | |
998 | return TPM_LIB_ERROR; | |
999 | if (data_size > this_bytes) | |
1000 | return TPM_LIB_ERROR; | |
1001 | if (unpack_byte_string(response, response_length, "s", | |
1002 | data_offset, out, data_size)) | |
1003 | return TPM_LIB_ERROR; | |
1004 | ||
1005 | count -= data_size; | |
1006 | out += data_size; | |
1007 | } | |
1008 | ||
1009 | return 0; | |
1010 | } | |
7785bc1d SG |
1011 | |
1012 | u32 tpm2_write_lock(struct udevice *dev, u32 index) | |
1013 | { | |
1014 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
1015 | /* header 10 bytes */ | |
1016 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
1017 | tpm_u32(10 + 8 + 13), /* Length */ | |
1018 | tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */ | |
1019 | ||
1020 | /* handles 8 bytes */ | |
1021 | tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ | |
1022 | tpm_u32(HR_NV_INDEX + index), /* Password authorisation */ | |
1023 | ||
1024 | /* session header 9 bytes */ | |
1025 | tpm_u32(9), /* Header size */ | |
1026 | tpm_u32(TPM2_RS_PW), /* Password authorisation */ | |
1027 | tpm_u16(0), /* nonce_size */ | |
1028 | 0, /* session_attrs */ | |
1029 | tpm_u16(0), /* auth_size */ | |
1030 | }; | |
1031 | ||
1032 | return tpm_sendrecv_command(dev, command_v2, NULL, NULL); | |
1033 | } | |
63af92e8 SG |
1034 | |
1035 | u32 tpm2_disable_platform_hierarchy(struct udevice *dev) | |
1036 | { | |
1037 | struct tpm_chip_priv *priv = dev_get_uclass_priv(dev); | |
1038 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
1039 | /* header 10 bytes */ | |
1040 | tpm_u16(TPM2_ST_SESSIONS), /* TAG */ | |
1041 | tpm_u32(10 + 4 + 13 + 5), /* Length */ | |
1042 | tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */ | |
1043 | ||
1044 | /* 4 bytes */ | |
1045 | tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ | |
1046 | ||
1047 | /* session header 9 bytes */ | |
1048 | tpm_u32(9), /* Header size */ | |
1049 | tpm_u32(TPM2_RS_PW), /* Password authorisation */ | |
1050 | tpm_u16(0), /* nonce_size */ | |
1051 | 0, /* session_attrs */ | |
1052 | tpm_u16(0), /* auth_size */ | |
1053 | ||
1054 | /* payload 5 bytes */ | |
1055 | tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */ | |
1056 | 0, /* 0=disable */ | |
1057 | }; | |
1058 | int ret; | |
1059 | ||
1060 | ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); | |
1061 | log_info("ret=%s, %x\n", dev->name, ret); | |
1062 | if (ret) | |
1063 | return ret; | |
1064 | ||
1065 | priv->plat_hier_disabled = true; | |
1066 | ||
1067 | return 0; | |
1068 | } | |
7fc93cae MK |
1069 | |
1070 | u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf, | |
1071 | u8 *recvbuf, size_t *recv_size) | |
1072 | { | |
1073 | return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size); | |
1074 | } | |
4c57ec76 SG |
1075 | |
1076 | u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd, | |
1077 | u8 *recvbuf, size_t *recv_size) | |
1078 | { | |
1079 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
1080 | /* header 10 bytes */ | |
1081 | tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ | |
1082 | tpm_u32(10 + 2), /* Length */ | |
1083 | tpm_u32(vendor_cmd), /* Command code */ | |
1084 | ||
1085 | tpm_u16(vendor_subcmd), | |
1086 | }; | |
1087 | int ret; | |
1088 | ||
1089 | ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size); | |
1090 | log_debug("ret=%s, %x\n", dev->name, ret); | |
1091 | if (ret) | |
1092 | return ret; | |
1093 | if (*recv_size < 12) | |
1094 | return -ENODATA; | |
1095 | *recv_size -= 12; | |
6c717d95 | 1096 | memmove(recvbuf, recvbuf + 12, *recv_size); |
4c57ec76 SG |
1097 | |
1098 | return 0; | |
1099 | } | |
5208ed18 SG |
1100 | |
1101 | u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, | |
1102 | uint vendor_subcmd) | |
1103 | { | |
1104 | u8 command_v2[COMMAND_BUFFER_SIZE] = { | |
1105 | /* header 10 bytes */ | |
1106 | tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */ | |
1107 | tpm_u32(10 + 2), /* Length */ | |
1108 | tpm_u32(vendor_cmd), /* Command code */ | |
1109 | ||
1110 | tpm_u16(vendor_subcmd), | |
1111 | }; | |
1112 | int ret; | |
1113 | ||
1114 | ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); | |
1115 | log_debug("ret=%s, %x\n", dev->name, ret); | |
1116 | if (ret) | |
1117 | return ret; | |
1118 | ||
1119 | return 0; | |
1120 | } | |
954b95e7 | 1121 | |
dbe08c7b | 1122 | bool tpm2_is_active_bank(struct tpms_pcr_selection *selection) |
cba3fa90 IA |
1123 | { |
1124 | int i; | |
1125 | ||
1126 | for (i = 0; i < selection->size_of_select; i++) { | |
1127 | if (selection->pcr_select[i]) | |
1128 | return true; | |
1129 | } | |
1130 | ||
1131 | return false; | |
1132 | } | |
1133 | ||
954b95e7 TH |
1134 | enum tpm2_algorithms tpm2_name_to_algorithm(const char *name) |
1135 | { | |
1136 | size_t i; | |
1137 | ||
1138 | for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { | |
1139 | if (!strcasecmp(name, hash_algo_list[i].hash_name)) | |
1140 | return hash_algo_list[i].hash_alg; | |
1141 | } | |
1142 | printf("%s: unsupported algorithm %s\n", __func__, name); | |
1143 | ||
1144 | return -EINVAL; | |
1145 | } | |
1146 | ||
1147 | const char *tpm2_algorithm_name(enum tpm2_algorithms algo) | |
1148 | { | |
1149 | size_t i; | |
1150 | ||
1151 | for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { | |
1152 | if (hash_algo_list[i].hash_alg == algo) | |
1153 | return hash_algo_list[i].hash_name; | |
1154 | } | |
1155 | ||
1156 | return ""; | |
1157 | } | |
1158 | ||
27891e85 RM |
1159 | bool tpm2_algorithm_supported(enum tpm2_algorithms algo) |
1160 | { | |
1161 | size_t i; | |
1162 | ||
1163 | for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { | |
1164 | if (hash_algo_list[i].hash_alg == algo) | |
1165 | return hash_algo_list[i].supported; | |
1166 | } | |
1167 | ||
1168 | return false; | |
1169 | } | |
1170 | ||
e7505b3b IA |
1171 | u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo) |
1172 | { | |
1173 | size_t i; | |
1174 | ||
1175 | for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) { | |
1176 | if (hash_algo_list[i].hash_alg == algo) | |
1177 | return hash_algo_list[i].hash_len; | |
1178 | } | |
1179 | ||
1180 | return 0; | |
1181 | } | |
1182 | ||
0698f133 | 1183 | bool tpm2_check_active_banks(struct udevice *dev) |
e7505b3b IA |
1184 | { |
1185 | struct tpml_pcr_selection pcrs; | |
1186 | size_t i; | |
1187 | int rc; | |
1188 | ||
1189 | rc = tpm2_get_pcr_info(dev, &pcrs); | |
1190 | if (rc) | |
1191 | return false; | |
1192 | ||
1193 | for (i = 0; i < pcrs.count; i++) { | |
dbe08c7b | 1194 | if (tpm2_is_active_bank(&pcrs.selection[i]) && |
27891e85 | 1195 | !tpm2_algorithm_supported(pcrs.selection[i].hash)) |
e7505b3b IA |
1196 | return false; |
1197 | } | |
1198 | ||
1199 | return true; | |
1200 | } | |
8dc886ce IA |
1201 | |
1202 | void tpm2_print_active_banks(struct udevice *dev) | |
1203 | { | |
1204 | struct tpml_pcr_selection pcrs; | |
1205 | size_t i; | |
1206 | int rc; | |
1207 | ||
1208 | rc = tpm2_get_pcr_info(dev, &pcrs); | |
1209 | if (rc) { | |
1210 | log_err("Can't retrieve active PCRs\n"); | |
1211 | return; | |
1212 | } | |
1213 | ||
1214 | for (i = 0; i < pcrs.count; i++) { | |
1215 | if (tpm2_is_active_bank(&pcrs.selection[i])) { | |
1216 | const char *str; | |
1217 | ||
1218 | str = tpm2_algorithm_name(pcrs.selection[i].hash); | |
1219 | if (str) | |
1220 | log_info("%s\n", str); | |
1221 | } | |
1222 | } | |
1223 | } |