Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
7a1d7e6d | 2 | /* |
954650ef | 3 | * Copyright (C) 2014, 2015 Intel Corporation |
7a1d7e6d JS |
4 | * |
5 | * Authors: | |
6 | * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | |
7 | * | |
8 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | |
9 | * | |
10 | * This file contains TPM2 protocol implementations of the commands | |
11 | * used by the kernel internally. | |
7a1d7e6d JS |
12 | */ |
13 | ||
14 | #include "tpm.h" | |
5ca4c20c | 15 | #include <crypto/hash_info.h> |
5ca4c20c JS |
16 | |
17 | static struct tpm2_hash tpm2_hash_map[] = { | |
aa042475 RS |
18 | {HASH_ALGO_SHA1, TPM_ALG_SHA1}, |
19 | {HASH_ALGO_SHA256, TPM_ALG_SHA256}, | |
20 | {HASH_ALGO_SHA384, TPM_ALG_SHA384}, | |
21 | {HASH_ALGO_SHA512, TPM_ALG_SHA512}, | |
22 | {HASH_ALGO_SM3_256, TPM_ALG_SM3_256}, | |
5ca4c20c JS |
23 | }; |
24 | ||
70a3199a TW |
25 | int tpm2_get_timeouts(struct tpm_chip *chip) |
26 | { | |
27 | /* Fixed timeouts for TPM2 */ | |
28 | chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); | |
29 | chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B); | |
30 | chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C); | |
31 | chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D); | |
32 | ||
33 | /* PTP spec timeouts */ | |
34 | chip->duration[TPM_SHORT] = msecs_to_jiffies(TPM2_DURATION_SHORT); | |
35 | chip->duration[TPM_MEDIUM] = msecs_to_jiffies(TPM2_DURATION_MEDIUM); | |
36 | chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG); | |
37 | ||
38 | /* Key creation commands long timeouts */ | |
39 | chip->duration[TPM_LONG_LONG] = | |
40 | msecs_to_jiffies(TPM2_DURATION_LONG_LONG); | |
41 | ||
42 | chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; | |
43 | ||
44 | return 0; | |
45 | } | |
46 | ||
899102bc TW |
47 | /** |
48 | * tpm2_ordinal_duration_index() - returns an index to the chip duration table | |
49 | * @ordinal: TPM command ordinal. | |
50 | * | |
51 | * The function returns an index to the chip duration table | |
52 | * (enum tpm_duration), that describes the maximum amount of | |
53 | * time the chip could take to return the result for a particular ordinal. | |
54 | * | |
55 | * The values of the MEDIUM, and LONG durations are taken | |
56 | * from the PC Client Profile (PTP) specification (750, 2000 msec) | |
57 | * | |
58 | * LONG_LONG is for commands that generates keys which empirically takes | |
59 | * a longer time on some systems. | |
60 | * | |
61 | * Return: | |
62 | * * TPM_MEDIUM | |
63 | * * TPM_LONG | |
64 | * * TPM_LONG_LONG | |
65 | * * TPM_UNDEFINED | |
7a1d7e6d | 66 | */ |
899102bc TW |
67 | static u8 tpm2_ordinal_duration_index(u32 ordinal) |
68 | { | |
69 | switch (ordinal) { | |
70 | /* Startup */ | |
71 | case TPM2_CC_STARTUP: /* 144 */ | |
72 | return TPM_MEDIUM; | |
73 | ||
74 | case TPM2_CC_SELF_TEST: /* 143 */ | |
75 | return TPM_LONG; | |
76 | ||
77 | case TPM2_CC_GET_RANDOM: /* 17B */ | |
78 | return TPM_LONG; | |
79 | ||
80 | case TPM2_CC_SEQUENCE_UPDATE: /* 15C */ | |
81 | return TPM_MEDIUM; | |
82 | case TPM2_CC_SEQUENCE_COMPLETE: /* 13E */ | |
83 | return TPM_MEDIUM; | |
84 | case TPM2_CC_EVENT_SEQUENCE_COMPLETE: /* 185 */ | |
85 | return TPM_MEDIUM; | |
86 | case TPM2_CC_HASH_SEQUENCE_START: /* 186 */ | |
87 | return TPM_MEDIUM; | |
88 | ||
89 | case TPM2_CC_VERIFY_SIGNATURE: /* 177 */ | |
5317677d | 90 | return TPM_LONG_LONG; |
899102bc TW |
91 | |
92 | case TPM2_CC_PCR_EXTEND: /* 182 */ | |
93 | return TPM_MEDIUM; | |
94 | ||
95 | case TPM2_CC_HIERARCHY_CONTROL: /* 121 */ | |
96 | return TPM_LONG; | |
97 | case TPM2_CC_HIERARCHY_CHANGE_AUTH: /* 129 */ | |
98 | return TPM_LONG; | |
99 | ||
100 | case TPM2_CC_GET_CAPABILITY: /* 17A */ | |
101 | return TPM_MEDIUM; | |
102 | ||
103 | case TPM2_CC_NV_READ: /* 14E */ | |
104 | return TPM_LONG; | |
105 | ||
106 | case TPM2_CC_CREATE_PRIMARY: /* 131 */ | |
107 | return TPM_LONG_LONG; | |
108 | case TPM2_CC_CREATE: /* 153 */ | |
109 | return TPM_LONG_LONG; | |
110 | case TPM2_CC_CREATE_LOADED: /* 191 */ | |
111 | return TPM_LONG_LONG; | |
112 | ||
113 | default: | |
114 | return TPM_UNDEFINED; | |
115 | } | |
116 | } | |
117 | ||
118 | /** | |
119 | * tpm2_calc_ordinal_duration() - calculate the maximum command duration | |
120 | * @chip: TPM chip to use. | |
121 | * @ordinal: TPM command ordinal. | |
122 | * | |
123 | * The function returns the maximum amount of time the chip could take | |
124 | * to return the result for a particular ordinal in jiffies. | |
125 | * | |
126 | * Return: A maximal duration time for an ordinal in jiffies. | |
127 | */ | |
128 | unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) | |
129 | { | |
130 | unsigned int index; | |
131 | ||
132 | index = tpm2_ordinal_duration_index(ordinal); | |
133 | ||
134 | if (index != TPM_UNDEFINED) | |
135 | return chip->duration[index]; | |
136 | else | |
137 | return msecs_to_jiffies(TPM2_DURATION_DEFAULT); | |
138 | } | |
899102bc | 139 | |
7a1d7e6d | 140 | |
91f7f3d7 RS |
141 | struct tpm2_pcr_read_out { |
142 | __be32 update_cnt; | |
143 | __be32 pcr_selects_cnt; | |
144 | __be16 hash_alg; | |
145 | u8 pcr_select_size; | |
146 | u8 pcr_select[TPM2_PCR_SELECT_MIN]; | |
147 | __be32 digests_cnt; | |
148 | __be16 digest_size; | |
149 | u8 digest[]; | |
150 | } __packed; | |
151 | ||
7a1d7e6d JS |
152 | /** |
153 | * tpm2_pcr_read() - read a PCR value | |
154 | * @chip: TPM chip to use. | |
155 | * @pcr_idx: index of the PCR to read. | |
879b5892 RS |
156 | * @digest: PCR bank and buffer current PCR value is written to. |
157 | * @digest_size_ptr: pointer to variable that stores the digest size. | |
7a1d7e6d | 158 | * |
794c6e10 | 159 | * Return: Same as with tpm_transmit_cmd. |
7a1d7e6d | 160 | */ |
879b5892 RS |
161 | int tpm2_pcr_read(struct tpm_chip *chip, u32 pcr_idx, |
162 | struct tpm_digest *digest, u16 *digest_size_ptr) | |
7a1d7e6d | 163 | { |
879b5892 | 164 | int i; |
7a1d7e6d | 165 | int rc; |
91f7f3d7 RS |
166 | struct tpm_buf buf; |
167 | struct tpm2_pcr_read_out *out; | |
168 | u8 pcr_select[TPM2_PCR_SELECT_MIN] = {0}; | |
879b5892 RS |
169 | u16 digest_size; |
170 | u16 expected_digest_size = 0; | |
7a1d7e6d JS |
171 | |
172 | if (pcr_idx >= TPM2_PLATFORM_PCR) | |
173 | return -EINVAL; | |
174 | ||
879b5892 RS |
175 | if (!digest_size_ptr) { |
176 | for (i = 0; i < chip->nr_allocated_banks && | |
177 | chip->allocated_banks[i].alg_id != digest->alg_id; i++) | |
178 | ; | |
179 | ||
180 | if (i == chip->nr_allocated_banks) | |
181 | return -EINVAL; | |
182 | ||
183 | expected_digest_size = chip->allocated_banks[i].digest_size; | |
184 | } | |
185 | ||
91f7f3d7 RS |
186 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_PCR_READ); |
187 | if (rc) | |
188 | return rc; | |
189 | ||
190 | pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); | |
191 | ||
192 | tpm_buf_append_u32(&buf, 1); | |
879b5892 | 193 | tpm_buf_append_u16(&buf, digest->alg_id); |
91f7f3d7 RS |
194 | tpm_buf_append_u8(&buf, TPM2_PCR_SELECT_MIN); |
195 | tpm_buf_append(&buf, (const unsigned char *)pcr_select, | |
196 | sizeof(pcr_select)); | |
197 | ||
879b5892 RS |
198 | rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to read a pcr value"); |
199 | if (rc) | |
200 | goto out; | |
201 | ||
202 | out = (struct tpm2_pcr_read_out *)&buf.data[TPM_HEADER_SIZE]; | |
203 | digest_size = be16_to_cpu(out->digest_size); | |
204 | if (digest_size > sizeof(digest->digest) || | |
205 | (!digest_size_ptr && digest_size != expected_digest_size)) { | |
206 | rc = -EINVAL; | |
207 | goto out; | |
7a1d7e6d JS |
208 | } |
209 | ||
879b5892 RS |
210 | if (digest_size_ptr) |
211 | *digest_size_ptr = digest_size; | |
212 | ||
213 | memcpy(digest->digest, out->digest, digest_size); | |
214 | out: | |
91f7f3d7 | 215 | tpm_buf_destroy(&buf); |
7a1d7e6d JS |
216 | return rc; |
217 | } | |
218 | ||
c1f92b4b NJ |
219 | struct tpm2_null_auth_area { |
220 | __be32 handle; | |
221 | __be16 nonce_size; | |
222 | u8 attributes; | |
223 | __be16 auth_size; | |
224 | } __packed; | |
7a1d7e6d JS |
225 | |
226 | /** | |
227 | * tpm2_pcr_extend() - extend a PCR value | |
794c6e10 | 228 | * |
7a1d7e6d JS |
229 | * @chip: TPM chip to use. |
230 | * @pcr_idx: index of the PCR. | |
c1f92b4b | 231 | * @digests: list of pcr banks and corresponding digest values to extend. |
7a1d7e6d | 232 | * |
794c6e10 | 233 | * Return: Same as with tpm_transmit_cmd. |
7a1d7e6d | 234 | */ |
0b6cf6b9 | 235 | int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, |
aa042475 | 236 | struct tpm_digest *digests) |
7a1d7e6d | 237 | { |
c1f92b4b NJ |
238 | struct tpm_buf buf; |
239 | struct tpm2_null_auth_area auth_area; | |
7a1d7e6d | 240 | int rc; |
c1f92b4b | 241 | int i; |
7a1d7e6d | 242 | |
c1f92b4b NJ |
243 | rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); |
244 | if (rc) | |
245 | return rc; | |
246 | ||
247 | tpm_buf_append_u32(&buf, pcr_idx); | |
248 | ||
249 | auth_area.handle = cpu_to_be32(TPM2_RS_PW); | |
250 | auth_area.nonce_size = 0; | |
251 | auth_area.attributes = 0; | |
252 | auth_area.auth_size = 0; | |
253 | ||
254 | tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area)); | |
255 | tpm_buf_append(&buf, (const unsigned char *)&auth_area, | |
256 | sizeof(auth_area)); | |
0b6cf6b9 | 257 | tpm_buf_append_u32(&buf, chip->nr_allocated_banks); |
c1f92b4b | 258 | |
0b6cf6b9 | 259 | for (i = 0; i < chip->nr_allocated_banks; i++) { |
879b5892 RS |
260 | tpm_buf_append_u16(&buf, digests[i].alg_id); |
261 | tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest, | |
262 | chip->allocated_banks[i].digest_size); | |
c1f92b4b NJ |
263 | } |
264 | ||
47a6c28b | 265 | rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); |
7a1d7e6d | 266 | |
c1f92b4b NJ |
267 | tpm_buf_destroy(&buf); |
268 | ||
7a1d7e6d JS |
269 | return rc; |
270 | } | |
271 | ||
ce63c05b JS |
272 | struct tpm2_get_random_out { |
273 | __be16 size; | |
274 | u8 buffer[TPM_MAX_RNG_DATA]; | |
275 | } __packed; | |
7a1d7e6d JS |
276 | |
277 | /** | |
278 | * tpm2_get_random() - get random bytes from the TPM RNG | |
794c6e10 | 279 | * |
ce63c05b JS |
280 | * @chip: a &tpm_chip instance |
281 | * @dest: destination buffer | |
282 | * @max: the max number of random bytes to pull | |
7a1d7e6d | 283 | * |
794c6e10 | 284 | * Return: |
ce63c05b | 285 | * size of the buffer on success, |
782779b6 | 286 | * -errno otherwise (positive TPM return codes are masked to -EIO) |
7a1d7e6d | 287 | */ |
ce63c05b | 288 | int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) |
7a1d7e6d | 289 | { |
ce63c05b JS |
290 | struct tpm2_get_random_out *out; |
291 | struct tpm_buf buf; | |
292 | u32 recd; | |
293 | u32 num_bytes = max; | |
7a1d7e6d JS |
294 | int err; |
295 | int total = 0; | |
296 | int retries = 5; | |
ce63c05b | 297 | u8 *dest_ptr = dest; |
7a1d7e6d | 298 | |
ce63c05b | 299 | if (!num_bytes || max > TPM_MAX_RNG_DATA) |
7a1d7e6d JS |
300 | return -EINVAL; |
301 | ||
ce63c05b JS |
302 | err = tpm_buf_init(&buf, 0, 0); |
303 | if (err) | |
304 | return err; | |
7a1d7e6d | 305 | |
ce63c05b JS |
306 | do { |
307 | tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM); | |
308 | tpm_buf_append_u16(&buf, num_bytes); | |
5faafbab | 309 | err = tpm_transmit_cmd(chip, &buf, |
c659af78 SB |
310 | offsetof(struct tpm2_get_random_out, |
311 | buffer), | |
47a6c28b | 312 | "attempting get random"); |
782779b6 KC |
313 | if (err) { |
314 | if (err > 0) | |
315 | err = -EIO; | |
ce63c05b | 316 | goto out; |
782779b6 | 317 | } |
7a1d7e6d | 318 | |
ce63c05b JS |
319 | out = (struct tpm2_get_random_out *) |
320 | &buf.data[TPM_HEADER_SIZE]; | |
321 | recd = min_t(u32, be16_to_cpu(out->size), num_bytes); | |
322 | if (tpm_buf_length(&buf) < | |
84b59f64 JS |
323 | TPM_HEADER_SIZE + |
324 | offsetof(struct tpm2_get_random_out, buffer) + | |
325 | recd) { | |
ce63c05b JS |
326 | err = -EFAULT; |
327 | goto out; | |
328 | } | |
329 | memcpy(dest_ptr, out->buffer, recd); | |
7a1d7e6d | 330 | |
ce63c05b | 331 | dest_ptr += recd; |
7a1d7e6d JS |
332 | total += recd; |
333 | num_bytes -= recd; | |
334 | } while (retries-- && total < max); | |
335 | ||
ce63c05b | 336 | tpm_buf_destroy(&buf); |
7a1d7e6d | 337 | return total ? total : -EIO; |
ce63c05b JS |
338 | out: |
339 | tpm_buf_destroy(&buf); | |
340 | return err; | |
7a1d7e6d JS |
341 | } |
342 | ||
9aa36b39 | 343 | /** |
47a6c28b | 344 | * tpm2_flush_context() - execute a TPM2_FlushContext command |
5122b5f0 TW |
345 | * @chip: TPM chip to use |
346 | * @handle: context handle | |
9aa36b39 | 347 | */ |
47a6c28b | 348 | void tpm2_flush_context(struct tpm_chip *chip, u32 handle) |
9aa36b39 JS |
349 | { |
350 | struct tpm_buf buf; | |
351 | int rc; | |
352 | ||
353 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); | |
354 | if (rc) { | |
355 | dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", | |
356 | handle); | |
357 | return; | |
358 | } | |
359 | ||
360 | tpm_buf_append_u32(&buf, handle); | |
361 | ||
47a6c28b | 362 | tpm_transmit_cmd(chip, &buf, 0, "flushing context"); |
9aa36b39 JS |
363 | tpm_buf_destroy(&buf); |
364 | } | |
45477b3f | 365 | EXPORT_SYMBOL_GPL(tpm2_flush_context); |
9aa36b39 | 366 | |
2ab32411 JS |
367 | struct tpm2_get_cap_out { |
368 | u8 more_data; | |
369 | __be32 subcap_id; | |
370 | __be32 property_cnt; | |
371 | __be32 property_id; | |
372 | __be32 value; | |
373 | } __packed; | |
374 | ||
7a1d7e6d JS |
375 | /** |
376 | * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property | |
2ab32411 | 377 | * @chip: a &tpm_chip instance |
7a1d7e6d JS |
378 | * @property_id: property ID. |
379 | * @value: output variable. | |
380 | * @desc: passed to tpm_transmit_cmd() | |
381 | * | |
2ab32411 JS |
382 | * Return: |
383 | * 0 on success, | |
384 | * -errno or a TPM return code otherwise | |
7a1d7e6d JS |
385 | */ |
386 | ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, | |
387 | const char *desc) | |
388 | { | |
2ab32411 JS |
389 | struct tpm2_get_cap_out *out; |
390 | struct tpm_buf buf; | |
7a1d7e6d JS |
391 | int rc; |
392 | ||
2ab32411 JS |
393 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); |
394 | if (rc) | |
395 | return rc; | |
396 | tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); | |
397 | tpm_buf_append_u32(&buf, property_id); | |
398 | tpm_buf_append_u32(&buf, 1); | |
47a6c28b | 399 | rc = tpm_transmit_cmd(chip, &buf, 0, NULL); |
2ab32411 JS |
400 | if (!rc) { |
401 | out = (struct tpm2_get_cap_out *) | |
402 | &buf.data[TPM_HEADER_SIZE]; | |
e57b2523 SMH |
403 | /* |
404 | * To prevent failing boot up of some systems, Infineon TPM2.0 | |
405 | * returns SUCCESS on TPM2_Startup in field upgrade mode. Also | |
406 | * the TPM2_Getcapability command returns a zero length list | |
407 | * in field upgrade mode. | |
408 | */ | |
409 | if (be32_to_cpu(out->property_cnt) > 0) | |
410 | *value = be32_to_cpu(out->value); | |
411 | else | |
412 | rc = -ENODATA; | |
2ab32411 JS |
413 | } |
414 | tpm_buf_destroy(&buf); | |
7a1d7e6d JS |
415 | return rc; |
416 | } | |
eb5854e7 | 417 | EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); |
7a1d7e6d | 418 | |
7a1d7e6d | 419 | /** |
cc26c6ef | 420 | * tpm2_shutdown() - send a TPM shutdown command |
794c6e10 | 421 | * |
cc26c6ef JS |
422 | * Sends a TPM shutdown command. The shutdown command is used in call |
423 | * sites where the system is going down. If it fails, there is not much | |
424 | * that can be done except print an error message. | |
425 | * | |
426 | * @chip: a &tpm_chip instance | |
427 | * @shutdown_type: TPM_SU_CLEAR or TPM_SU_STATE. | |
7a1d7e6d | 428 | */ |
74d6b3ce | 429 | void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) |
7a1d7e6d | 430 | { |
cc26c6ef | 431 | struct tpm_buf buf; |
74d6b3ce | 432 | int rc; |
7a1d7e6d | 433 | |
cc26c6ef JS |
434 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN); |
435 | if (rc) | |
436 | return; | |
437 | tpm_buf_append_u16(&buf, shutdown_type); | |
47a6c28b | 438 | tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM"); |
cc26c6ef | 439 | tpm_buf_destroy(&buf); |
7a1d7e6d | 440 | } |
7a1d7e6d | 441 | |
7a1d7e6d | 442 | /** |
2482b1bb | 443 | * tpm2_do_selftest() - ensure that all self tests have passed |
794c6e10 | 444 | * |
7a1d7e6d JS |
445 | * @chip: TPM chip to use |
446 | * | |
794c6e10 WT |
447 | * Return: Same as with tpm_transmit_cmd. |
448 | * | |
125a2210 AS |
449 | * The TPM can either run all self tests synchronously and then return |
450 | * RC_SUCCESS once all tests were successful. Or it can choose to run the tests | |
451 | * asynchronously and return RC_TESTING immediately while the self tests still | |
452 | * execute in the background. This function handles both cases and waits until | |
453 | * all tests have completed. | |
7a1d7e6d | 454 | */ |
cae8b441 | 455 | static int tpm2_do_selftest(struct tpm_chip *chip) |
7a1d7e6d | 456 | { |
2be8ffed JB |
457 | struct tpm_buf buf; |
458 | int full; | |
7a1d7e6d | 459 | int rc; |
7a1d7e6d | 460 | |
2be8ffed JB |
461 | for (full = 0; full < 2; full++) { |
462 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST); | |
463 | if (rc) | |
464 | return rc; | |
7a1d7e6d | 465 | |
2be8ffed | 466 | tpm_buf_append_u8(&buf, full); |
47a6c28b | 467 | rc = tpm_transmit_cmd(chip, &buf, 0, |
2be8ffed JB |
468 | "attempting the self test"); |
469 | tpm_buf_destroy(&buf); | |
7a1d7e6d | 470 | |
2be8ffed JB |
471 | if (rc == TPM2_RC_TESTING) |
472 | rc = TPM2_RC_SUCCESS; | |
473 | if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS) | |
474 | return rc; | |
7a1d7e6d JS |
475 | } |
476 | ||
477 | return rc; | |
478 | } | |
7a1d7e6d | 479 | |
4d5f2051 | 480 | /** |
94e266ba JS |
481 | * tpm2_probe() - probe for the TPM 2.0 protocol |
482 | * @chip: a &tpm_chip instance | |
4d5f2051 | 483 | * |
94e266ba JS |
484 | * Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the |
485 | * other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by | |
486 | * this function if this is the case. | |
794c6e10 | 487 | * |
94e266ba JS |
488 | * Return: |
489 | * 0 on success, | |
490 | * -errno otherwise | |
4d5f2051 JS |
491 | */ |
492 | int tpm2_probe(struct tpm_chip *chip) | |
493 | { | |
b34b77a9 | 494 | struct tpm_header *out; |
94e266ba | 495 | struct tpm_buf buf; |
4d5f2051 JS |
496 | int rc; |
497 | ||
94e266ba JS |
498 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); |
499 | if (rc) | |
4d5f2051 | 500 | return rc; |
94e266ba JS |
501 | tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); |
502 | tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS); | |
503 | tpm_buf_append_u32(&buf, 1); | |
47a6c28b | 504 | rc = tpm_transmit_cmd(chip, &buf, 0, NULL); |
94e266ba JS |
505 | /* We ignore TPM return codes on purpose. */ |
506 | if (rc >= 0) { | |
b34b77a9 | 507 | out = (struct tpm_header *)buf.data; |
94e266ba JS |
508 | if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS) |
509 | chip->flags |= TPM_CHIP_FLAG_TPM2; | |
510 | } | |
511 | tpm_buf_destroy(&buf); | |
4d5f2051 JS |
512 | return 0; |
513 | } | |
514 | EXPORT_SYMBOL_GPL(tpm2_probe); | |
cae8b441 | 515 | |
879b5892 RS |
516 | static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index) |
517 | { | |
518 | struct tpm_bank_info *bank = chip->allocated_banks + bank_index; | |
519 | struct tpm_digest digest = { .alg_id = bank->alg_id }; | |
520 | int i; | |
521 | ||
522 | /* | |
523 | * Avoid unnecessary PCR read operations to reduce overhead | |
524 | * and obtain identifiers of the crypto subsystem. | |
525 | */ | |
526 | for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { | |
527 | enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id; | |
528 | ||
529 | if (bank->alg_id != tpm2_hash_map[i].tpm_id) | |
530 | continue; | |
531 | ||
532 | bank->digest_size = hash_digest_size[crypto_algo]; | |
533 | bank->crypto_id = crypto_algo; | |
534 | return 0; | |
535 | } | |
536 | ||
dc10e418 RS |
537 | bank->crypto_id = HASH_ALGO__LAST; |
538 | ||
879b5892 RS |
539 | return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size); |
540 | } | |
541 | ||
1db15344 NJ |
542 | struct tpm2_pcr_selection { |
543 | __be16 hash_alg; | |
544 | u8 size_of_select; | |
545 | u8 pcr_select[3]; | |
546 | } __packed; | |
547 | ||
fa4f99c0 | 548 | ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) |
1db15344 NJ |
549 | { |
550 | struct tpm2_pcr_selection pcr_selection; | |
551 | struct tpm_buf buf; | |
552 | void *marker; | |
553 | void *end; | |
554 | void *pcr_select_offset; | |
1db15344 | 555 | u32 sizeof_pcr_selection; |
bcfff838 RS |
556 | u32 nr_possible_banks; |
557 | u32 nr_alloc_banks = 0; | |
558 | u16 hash_alg; | |
1db15344 NJ |
559 | u32 rsp_len; |
560 | int rc; | |
561 | int i = 0; | |
562 | ||
563 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); | |
564 | if (rc) | |
565 | return rc; | |
566 | ||
567 | tpm_buf_append_u32(&buf, TPM2_CAP_PCRS); | |
568 | tpm_buf_append_u32(&buf, 0); | |
569 | tpm_buf_append_u32(&buf, 1); | |
570 | ||
47a6c28b | 571 | rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation"); |
1db15344 NJ |
572 | if (rc) |
573 | goto out; | |
574 | ||
bcfff838 | 575 | nr_possible_banks = be32_to_cpup( |
1db15344 NJ |
576 | (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); |
577 | ||
bcfff838 RS |
578 | chip->allocated_banks = kcalloc(nr_possible_banks, |
579 | sizeof(*chip->allocated_banks), | |
580 | GFP_KERNEL); | |
581 | if (!chip->allocated_banks) { | |
582 | rc = -ENOMEM; | |
1db15344 NJ |
583 | goto out; |
584 | } | |
585 | ||
586 | marker = &buf.data[TPM_HEADER_SIZE + 9]; | |
587 | ||
588 | rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); | |
589 | end = &buf.data[rsp_len]; | |
590 | ||
bcfff838 | 591 | for (i = 0; i < nr_possible_banks; i++) { |
1db15344 NJ |
592 | pcr_select_offset = marker + |
593 | offsetof(struct tpm2_pcr_selection, size_of_select); | |
594 | if (pcr_select_offset >= end) { | |
595 | rc = -EFAULT; | |
596 | break; | |
597 | } | |
598 | ||
599 | memcpy(&pcr_selection, marker, sizeof(pcr_selection)); | |
bcfff838 RS |
600 | hash_alg = be16_to_cpu(pcr_selection.hash_alg); |
601 | ||
602 | pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0, | |
603 | pcr_selection.size_of_select); | |
604 | if (pcr_select_offset) { | |
879b5892 RS |
605 | chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg; |
606 | ||
607 | rc = tpm2_init_bank_info(chip, nr_alloc_banks); | |
608 | if (rc < 0) | |
609 | break; | |
610 | ||
bcfff838 RS |
611 | nr_alloc_banks++; |
612 | } | |
613 | ||
1db15344 NJ |
614 | sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + |
615 | sizeof(pcr_selection.size_of_select) + | |
616 | pcr_selection.size_of_select; | |
617 | marker = marker + sizeof_pcr_selection; | |
618 | } | |
619 | ||
bcfff838 | 620 | chip->nr_allocated_banks = nr_alloc_banks; |
1db15344 | 621 | out: |
1db15344 NJ |
622 | tpm_buf_destroy(&buf); |
623 | ||
624 | return rc; | |
625 | } | |
61841be6 | 626 | |
18b3670d | 627 | int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) |
58472f5c JS |
628 | { |
629 | struct tpm_buf buf; | |
630 | u32 nr_commands; | |
171360d7 | 631 | __be32 *attrs; |
58472f5c JS |
632 | u32 cc; |
633 | int i; | |
634 | int rc; | |
635 | ||
636 | rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL); | |
637 | if (rc) | |
638 | goto out; | |
639 | ||
640 | if (nr_commands > 0xFFFFF) { | |
641 | rc = -EFAULT; | |
642 | goto out; | |
643 | } | |
644 | ||
a86854d0 | 645 | chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands, |
58472f5c | 646 | GFP_KERNEL); |
f1689114 TS |
647 | if (!chip->cc_attrs_tbl) { |
648 | rc = -ENOMEM; | |
649 | goto out; | |
650 | } | |
58472f5c JS |
651 | |
652 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); | |
653 | if (rc) | |
654 | goto out; | |
655 | ||
656 | tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS); | |
657 | tpm_buf_append_u32(&buf, TPM2_CC_FIRST); | |
658 | tpm_buf_append_u32(&buf, nr_commands); | |
659 | ||
47a6c28b | 660 | rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL); |
58472f5c JS |
661 | if (rc) { |
662 | tpm_buf_destroy(&buf); | |
663 | goto out; | |
664 | } | |
665 | ||
666 | if (nr_commands != | |
667 | be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) { | |
1df83992 | 668 | rc = -EFAULT; |
58472f5c JS |
669 | tpm_buf_destroy(&buf); |
670 | goto out; | |
671 | } | |
672 | ||
673 | chip->nr_commands = nr_commands; | |
674 | ||
171360d7 | 675 | attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9]; |
58472f5c JS |
676 | for (i = 0; i < nr_commands; i++, attrs++) { |
677 | chip->cc_attrs_tbl[i] = be32_to_cpup(attrs); | |
678 | cc = chip->cc_attrs_tbl[i] & 0xFFFF; | |
679 | ||
680 | if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) { | |
681 | chip->cc_attrs_tbl[i] &= | |
682 | ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES); | |
683 | chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES; | |
684 | } | |
685 | } | |
686 | ||
687 | tpm_buf_destroy(&buf); | |
688 | ||
689 | out: | |
690 | if (rc > 0) | |
691 | rc = -ENODEV; | |
692 | return rc; | |
693 | } | |
684c6bd8 | 694 | EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl); |
58472f5c | 695 | |
9db7fe18 TW |
696 | /** |
697 | * tpm2_startup - turn on the TPM | |
698 | * @chip: TPM chip to use | |
699 | * | |
700 | * Normally the firmware should start the TPM. This function is provided as a | |
701 | * workaround if this does not happen. A legal case for this could be for | |
702 | * example when a TPM emulator is used. | |
703 | * | |
704 | * Return: same as tpm_transmit_cmd() | |
705 | */ | |
706 | ||
707 | static int tpm2_startup(struct tpm_chip *chip) | |
708 | { | |
709 | struct tpm_buf buf; | |
710 | int rc; | |
711 | ||
712 | dev_info(&chip->dev, "starting up the TPM manually\n"); | |
713 | ||
714 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP); | |
715 | if (rc < 0) | |
716 | return rc; | |
717 | ||
718 | tpm_buf_append_u16(&buf, TPM2_SU_CLEAR); | |
47a6c28b | 719 | rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM"); |
9db7fe18 TW |
720 | tpm_buf_destroy(&buf); |
721 | ||
722 | return rc; | |
723 | } | |
724 | ||
61841be6 JS |
725 | /** |
726 | * tpm2_auto_startup - Perform the standard automatic TPM initialization | |
727 | * sequence | |
728 | * @chip: TPM chip to use | |
729 | * | |
58472f5c | 730 | * Returns 0 on success, < 0 in case of fatal error. |
61841be6 JS |
731 | */ |
732 | int tpm2_auto_startup(struct tpm_chip *chip) | |
733 | { | |
734 | int rc; | |
735 | ||
9db7fe18 | 736 | rc = tpm2_get_timeouts(chip); |
61841be6 JS |
737 | if (rc) |
738 | goto out; | |
739 | ||
740 | rc = tpm2_do_selftest(chip); | |
2be8ffed | 741 | if (rc && rc != TPM2_RC_INITIALIZE) |
61841be6 | 742 | goto out; |
61841be6 JS |
743 | |
744 | if (rc == TPM2_RC_INITIALIZE) { | |
9db7fe18 | 745 | rc = tpm2_startup(chip); |
61841be6 JS |
746 | if (rc) |
747 | goto out; | |
748 | ||
749 | rc = tpm2_do_selftest(chip); | |
2be8ffed | 750 | if (rc) |
61841be6 | 751 | goto out; |
61841be6 JS |
752 | } |
753 | ||
58472f5c | 754 | rc = tpm2_get_cc_attrs_tbl(chip); |
863ed94c ML |
755 | if (rc == TPM2_RC_FAILURE || (rc < 0 && rc != -ENOMEM)) { |
756 | dev_info(&chip->dev, | |
757 | "TPM in field failure mode, requires firmware upgrade\n"); | |
758 | chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; | |
759 | rc = 0; | |
760 | } | |
61841be6 JS |
761 | |
762 | out: | |
af402ee3 SMH |
763 | /* |
764 | * Infineon TPM in field upgrade mode will return no data for the number | |
765 | * of supported commands. | |
766 | */ | |
767 | if (rc == TPM2_RC_UPGRADE || rc == -ENODATA) { | |
0aa69878 | 768 | dev_info(&chip->dev, "TPM in field upgrade mode, requires firmware upgrade\n"); |
769 | chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; | |
770 | rc = 0; | |
771 | } | |
772 | ||
61841be6 JS |
773 | if (rc > 0) |
774 | rc = -ENODEV; | |
775 | return rc; | |
776 | } | |
58472f5c JS |
777 | |
778 | int tpm2_find_cc(struct tpm_chip *chip, u32 cc) | |
779 | { | |
85b93bbd | 780 | u32 cc_mask; |
58472f5c JS |
781 | int i; |
782 | ||
85b93bbd | 783 | cc_mask = 1 << TPM2_CC_ATTR_VENDOR | GENMASK(15, 0); |
58472f5c | 784 | for (i = 0; i < chip->nr_commands; i++) |
85b93bbd | 785 | if (cc == (chip->cc_attrs_tbl[i] & cc_mask)) |
58472f5c JS |
786 | return i; |
787 | ||
788 | return -1; | |
789 | } |