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 | ||
7a1d7e6d JS |
219 | /** |
220 | * tpm2_pcr_extend() - extend a PCR value | |
794c6e10 | 221 | * |
7a1d7e6d JS |
222 | * @chip: TPM chip to use. |
223 | * @pcr_idx: index of the PCR. | |
c1f92b4b | 224 | * @digests: list of pcr banks and corresponding digest values to extend. |
7a1d7e6d | 225 | * |
794c6e10 | 226 | * Return: Same as with tpm_transmit_cmd. |
7a1d7e6d | 227 | */ |
0b6cf6b9 | 228 | int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, |
aa042475 | 229 | struct tpm_digest *digests) |
7a1d7e6d | 230 | { |
c1f92b4b | 231 | struct tpm_buf buf; |
7a1d7e6d | 232 | int rc; |
c1f92b4b | 233 | int i; |
7a1d7e6d | 234 | |
6519fea6 | 235 | rc = tpm2_start_auth_session(chip); |
c1f92b4b NJ |
236 | if (rc) |
237 | return rc; | |
238 | ||
6519fea6 JB |
239 | rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); |
240 | if (rc) { | |
241 | tpm2_end_auth_session(chip); | |
242 | return rc; | |
243 | } | |
c1f92b4b | 244 | |
6519fea6 JB |
245 | tpm_buf_append_name(chip, &buf, pcr_idx, NULL); |
246 | tpm_buf_append_hmac_session(chip, &buf, 0, NULL, 0); | |
c1f92b4b | 247 | |
0b6cf6b9 | 248 | tpm_buf_append_u32(&buf, chip->nr_allocated_banks); |
c1f92b4b | 249 | |
0b6cf6b9 | 250 | for (i = 0; i < chip->nr_allocated_banks; i++) { |
879b5892 RS |
251 | tpm_buf_append_u16(&buf, digests[i].alg_id); |
252 | tpm_buf_append(&buf, (const unsigned char *)&digests[i].digest, | |
253 | chip->allocated_banks[i].digest_size); | |
c1f92b4b NJ |
254 | } |
255 | ||
6519fea6 | 256 | tpm_buf_fill_hmac_session(chip, &buf); |
47a6c28b | 257 | rc = tpm_transmit_cmd(chip, &buf, 0, "attempting extend a PCR value"); |
6519fea6 | 258 | rc = tpm_buf_check_hmac_response(chip, &buf, rc); |
7a1d7e6d | 259 | |
c1f92b4b NJ |
260 | tpm_buf_destroy(&buf); |
261 | ||
7a1d7e6d JS |
262 | return rc; |
263 | } | |
264 | ||
ce63c05b JS |
265 | struct tpm2_get_random_out { |
266 | __be16 size; | |
267 | u8 buffer[TPM_MAX_RNG_DATA]; | |
268 | } __packed; | |
7a1d7e6d JS |
269 | |
270 | /** | |
271 | * tpm2_get_random() - get random bytes from the TPM RNG | |
794c6e10 | 272 | * |
ce63c05b JS |
273 | * @chip: a &tpm_chip instance |
274 | * @dest: destination buffer | |
275 | * @max: the max number of random bytes to pull | |
7a1d7e6d | 276 | * |
794c6e10 | 277 | * Return: |
ce63c05b | 278 | * size of the buffer on success, |
782779b6 | 279 | * -errno otherwise (positive TPM return codes are masked to -EIO) |
7a1d7e6d | 280 | */ |
ce63c05b | 281 | int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) |
7a1d7e6d | 282 | { |
ce63c05b JS |
283 | struct tpm2_get_random_out *out; |
284 | struct tpm_buf buf; | |
285 | u32 recd; | |
286 | u32 num_bytes = max; | |
7a1d7e6d JS |
287 | int err; |
288 | int total = 0; | |
289 | int retries = 5; | |
ce63c05b | 290 | u8 *dest_ptr = dest; |
7a1d7e6d | 291 | |
ce63c05b | 292 | if (!num_bytes || max > TPM_MAX_RNG_DATA) |
7a1d7e6d JS |
293 | return -EINVAL; |
294 | ||
ce63c05b JS |
295 | err = tpm_buf_init(&buf, 0, 0); |
296 | if (err) | |
297 | return err; | |
7a1d7e6d | 298 | |
ce63c05b JS |
299 | do { |
300 | tpm_buf_reset(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_RANDOM); | |
301 | tpm_buf_append_u16(&buf, num_bytes); | |
5faafbab | 302 | err = tpm_transmit_cmd(chip, &buf, |
c659af78 SB |
303 | offsetof(struct tpm2_get_random_out, |
304 | buffer), | |
47a6c28b | 305 | "attempting get random"); |
782779b6 KC |
306 | if (err) { |
307 | if (err > 0) | |
308 | err = -EIO; | |
ce63c05b | 309 | goto out; |
782779b6 | 310 | } |
7a1d7e6d | 311 | |
ce63c05b JS |
312 | out = (struct tpm2_get_random_out *) |
313 | &buf.data[TPM_HEADER_SIZE]; | |
314 | recd = min_t(u32, be16_to_cpu(out->size), num_bytes); | |
315 | if (tpm_buf_length(&buf) < | |
84b59f64 JS |
316 | TPM_HEADER_SIZE + |
317 | offsetof(struct tpm2_get_random_out, buffer) + | |
318 | recd) { | |
ce63c05b JS |
319 | err = -EFAULT; |
320 | goto out; | |
321 | } | |
322 | memcpy(dest_ptr, out->buffer, recd); | |
7a1d7e6d | 323 | |
ce63c05b | 324 | dest_ptr += recd; |
7a1d7e6d JS |
325 | total += recd; |
326 | num_bytes -= recd; | |
327 | } while (retries-- && total < max); | |
328 | ||
ce63c05b | 329 | tpm_buf_destroy(&buf); |
7a1d7e6d | 330 | return total ? total : -EIO; |
ce63c05b JS |
331 | out: |
332 | tpm_buf_destroy(&buf); | |
333 | return err; | |
7a1d7e6d JS |
334 | } |
335 | ||
9aa36b39 | 336 | /** |
47a6c28b | 337 | * tpm2_flush_context() - execute a TPM2_FlushContext command |
5122b5f0 TW |
338 | * @chip: TPM chip to use |
339 | * @handle: context handle | |
9aa36b39 | 340 | */ |
47a6c28b | 341 | void tpm2_flush_context(struct tpm_chip *chip, u32 handle) |
9aa36b39 JS |
342 | { |
343 | struct tpm_buf buf; | |
344 | int rc; | |
345 | ||
346 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_FLUSH_CONTEXT); | |
347 | if (rc) { | |
348 | dev_warn(&chip->dev, "0x%08x was not flushed, out of memory\n", | |
349 | handle); | |
350 | return; | |
351 | } | |
352 | ||
353 | tpm_buf_append_u32(&buf, handle); | |
354 | ||
47a6c28b | 355 | tpm_transmit_cmd(chip, &buf, 0, "flushing context"); |
9aa36b39 JS |
356 | tpm_buf_destroy(&buf); |
357 | } | |
45477b3f | 358 | EXPORT_SYMBOL_GPL(tpm2_flush_context); |
9aa36b39 | 359 | |
2ab32411 JS |
360 | struct tpm2_get_cap_out { |
361 | u8 more_data; | |
362 | __be32 subcap_id; | |
363 | __be32 property_cnt; | |
364 | __be32 property_id; | |
365 | __be32 value; | |
366 | } __packed; | |
367 | ||
7a1d7e6d JS |
368 | /** |
369 | * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property | |
2ab32411 | 370 | * @chip: a &tpm_chip instance |
7a1d7e6d JS |
371 | * @property_id: property ID. |
372 | * @value: output variable. | |
373 | * @desc: passed to tpm_transmit_cmd() | |
374 | * | |
2ab32411 JS |
375 | * Return: |
376 | * 0 on success, | |
377 | * -errno or a TPM return code otherwise | |
7a1d7e6d JS |
378 | */ |
379 | ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, | |
380 | const char *desc) | |
381 | { | |
2ab32411 JS |
382 | struct tpm2_get_cap_out *out; |
383 | struct tpm_buf buf; | |
7a1d7e6d JS |
384 | int rc; |
385 | ||
2ab32411 JS |
386 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); |
387 | if (rc) | |
388 | return rc; | |
389 | tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); | |
390 | tpm_buf_append_u32(&buf, property_id); | |
391 | tpm_buf_append_u32(&buf, 1); | |
47a6c28b | 392 | rc = tpm_transmit_cmd(chip, &buf, 0, NULL); |
2ab32411 JS |
393 | if (!rc) { |
394 | out = (struct tpm2_get_cap_out *) | |
395 | &buf.data[TPM_HEADER_SIZE]; | |
e57b2523 SMH |
396 | /* |
397 | * To prevent failing boot up of some systems, Infineon TPM2.0 | |
398 | * returns SUCCESS on TPM2_Startup in field upgrade mode. Also | |
399 | * the TPM2_Getcapability command returns a zero length list | |
400 | * in field upgrade mode. | |
401 | */ | |
402 | if (be32_to_cpu(out->property_cnt) > 0) | |
403 | *value = be32_to_cpu(out->value); | |
404 | else | |
405 | rc = -ENODATA; | |
2ab32411 JS |
406 | } |
407 | tpm_buf_destroy(&buf); | |
7a1d7e6d JS |
408 | return rc; |
409 | } | |
eb5854e7 | 410 | EXPORT_SYMBOL_GPL(tpm2_get_tpm_pt); |
7a1d7e6d | 411 | |
7a1d7e6d | 412 | /** |
cc26c6ef | 413 | * tpm2_shutdown() - send a TPM shutdown command |
794c6e10 | 414 | * |
cc26c6ef JS |
415 | * Sends a TPM shutdown command. The shutdown command is used in call |
416 | * sites where the system is going down. If it fails, there is not much | |
417 | * that can be done except print an error message. | |
418 | * | |
419 | * @chip: a &tpm_chip instance | |
420 | * @shutdown_type: TPM_SU_CLEAR or TPM_SU_STATE. | |
7a1d7e6d | 421 | */ |
74d6b3ce | 422 | void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) |
7a1d7e6d | 423 | { |
cc26c6ef | 424 | struct tpm_buf buf; |
74d6b3ce | 425 | int rc; |
7a1d7e6d | 426 | |
cc26c6ef JS |
427 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SHUTDOWN); |
428 | if (rc) | |
429 | return; | |
430 | tpm_buf_append_u16(&buf, shutdown_type); | |
47a6c28b | 431 | tpm_transmit_cmd(chip, &buf, 0, "stopping the TPM"); |
cc26c6ef | 432 | tpm_buf_destroy(&buf); |
7a1d7e6d | 433 | } |
7a1d7e6d | 434 | |
7a1d7e6d | 435 | /** |
2482b1bb | 436 | * tpm2_do_selftest() - ensure that all self tests have passed |
794c6e10 | 437 | * |
7a1d7e6d JS |
438 | * @chip: TPM chip to use |
439 | * | |
794c6e10 WT |
440 | * Return: Same as with tpm_transmit_cmd. |
441 | * | |
125a2210 AS |
442 | * The TPM can either run all self tests synchronously and then return |
443 | * RC_SUCCESS once all tests were successful. Or it can choose to run the tests | |
444 | * asynchronously and return RC_TESTING immediately while the self tests still | |
445 | * execute in the background. This function handles both cases and waits until | |
446 | * all tests have completed. | |
7a1d7e6d | 447 | */ |
cae8b441 | 448 | static int tpm2_do_selftest(struct tpm_chip *chip) |
7a1d7e6d | 449 | { |
2be8ffed JB |
450 | struct tpm_buf buf; |
451 | int full; | |
7a1d7e6d | 452 | int rc; |
7a1d7e6d | 453 | |
2be8ffed JB |
454 | for (full = 0; full < 2; full++) { |
455 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_SELF_TEST); | |
456 | if (rc) | |
457 | return rc; | |
7a1d7e6d | 458 | |
2be8ffed | 459 | tpm_buf_append_u8(&buf, full); |
47a6c28b | 460 | rc = tpm_transmit_cmd(chip, &buf, 0, |
2be8ffed JB |
461 | "attempting the self test"); |
462 | tpm_buf_destroy(&buf); | |
7a1d7e6d | 463 | |
2be8ffed JB |
464 | if (rc == TPM2_RC_TESTING) |
465 | rc = TPM2_RC_SUCCESS; | |
466 | if (rc == TPM2_RC_INITIALIZE || rc == TPM2_RC_SUCCESS) | |
467 | return rc; | |
7a1d7e6d JS |
468 | } |
469 | ||
470 | return rc; | |
471 | } | |
7a1d7e6d | 472 | |
4d5f2051 | 473 | /** |
94e266ba JS |
474 | * tpm2_probe() - probe for the TPM 2.0 protocol |
475 | * @chip: a &tpm_chip instance | |
4d5f2051 | 476 | * |
94e266ba JS |
477 | * Send an idempotent TPM 2.0 command and see whether there is TPM2 chip in the |
478 | * other end based on the response tag. The flag TPM_CHIP_FLAG_TPM2 is set by | |
479 | * this function if this is the case. | |
794c6e10 | 480 | * |
94e266ba JS |
481 | * Return: |
482 | * 0 on success, | |
483 | * -errno otherwise | |
4d5f2051 JS |
484 | */ |
485 | int tpm2_probe(struct tpm_chip *chip) | |
486 | { | |
b34b77a9 | 487 | struct tpm_header *out; |
94e266ba | 488 | struct tpm_buf buf; |
4d5f2051 JS |
489 | int rc; |
490 | ||
94e266ba JS |
491 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); |
492 | if (rc) | |
4d5f2051 | 493 | return rc; |
94e266ba JS |
494 | tpm_buf_append_u32(&buf, TPM2_CAP_TPM_PROPERTIES); |
495 | tpm_buf_append_u32(&buf, TPM_PT_TOTAL_COMMANDS); | |
496 | tpm_buf_append_u32(&buf, 1); | |
47a6c28b | 497 | rc = tpm_transmit_cmd(chip, &buf, 0, NULL); |
94e266ba JS |
498 | /* We ignore TPM return codes on purpose. */ |
499 | if (rc >= 0) { | |
b34b77a9 | 500 | out = (struct tpm_header *)buf.data; |
94e266ba JS |
501 | if (be16_to_cpu(out->tag) == TPM2_ST_NO_SESSIONS) |
502 | chip->flags |= TPM_CHIP_FLAG_TPM2; | |
503 | } | |
504 | tpm_buf_destroy(&buf); | |
4d5f2051 JS |
505 | return 0; |
506 | } | |
507 | EXPORT_SYMBOL_GPL(tpm2_probe); | |
cae8b441 | 508 | |
879b5892 RS |
509 | static int tpm2_init_bank_info(struct tpm_chip *chip, u32 bank_index) |
510 | { | |
511 | struct tpm_bank_info *bank = chip->allocated_banks + bank_index; | |
512 | struct tpm_digest digest = { .alg_id = bank->alg_id }; | |
513 | int i; | |
514 | ||
515 | /* | |
516 | * Avoid unnecessary PCR read operations to reduce overhead | |
517 | * and obtain identifiers of the crypto subsystem. | |
518 | */ | |
519 | for (i = 0; i < ARRAY_SIZE(tpm2_hash_map); i++) { | |
520 | enum hash_algo crypto_algo = tpm2_hash_map[i].crypto_id; | |
521 | ||
522 | if (bank->alg_id != tpm2_hash_map[i].tpm_id) | |
523 | continue; | |
524 | ||
525 | bank->digest_size = hash_digest_size[crypto_algo]; | |
526 | bank->crypto_id = crypto_algo; | |
527 | return 0; | |
528 | } | |
529 | ||
dc10e418 RS |
530 | bank->crypto_id = HASH_ALGO__LAST; |
531 | ||
879b5892 RS |
532 | return tpm2_pcr_read(chip, 0, &digest, &bank->digest_size); |
533 | } | |
534 | ||
1db15344 NJ |
535 | struct tpm2_pcr_selection { |
536 | __be16 hash_alg; | |
537 | u8 size_of_select; | |
538 | u8 pcr_select[3]; | |
539 | } __packed; | |
540 | ||
fa4f99c0 | 541 | ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) |
1db15344 NJ |
542 | { |
543 | struct tpm2_pcr_selection pcr_selection; | |
544 | struct tpm_buf buf; | |
545 | void *marker; | |
546 | void *end; | |
547 | void *pcr_select_offset; | |
1db15344 | 548 | u32 sizeof_pcr_selection; |
bcfff838 RS |
549 | u32 nr_possible_banks; |
550 | u32 nr_alloc_banks = 0; | |
551 | u16 hash_alg; | |
1db15344 NJ |
552 | u32 rsp_len; |
553 | int rc; | |
554 | int i = 0; | |
555 | ||
556 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); | |
557 | if (rc) | |
558 | return rc; | |
559 | ||
560 | tpm_buf_append_u32(&buf, TPM2_CAP_PCRS); | |
561 | tpm_buf_append_u32(&buf, 0); | |
562 | tpm_buf_append_u32(&buf, 1); | |
563 | ||
47a6c28b | 564 | rc = tpm_transmit_cmd(chip, &buf, 9, "get tpm pcr allocation"); |
1db15344 NJ |
565 | if (rc) |
566 | goto out; | |
567 | ||
bcfff838 | 568 | nr_possible_banks = be32_to_cpup( |
1db15344 NJ |
569 | (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); |
570 | ||
bcfff838 RS |
571 | chip->allocated_banks = kcalloc(nr_possible_banks, |
572 | sizeof(*chip->allocated_banks), | |
573 | GFP_KERNEL); | |
574 | if (!chip->allocated_banks) { | |
575 | rc = -ENOMEM; | |
1db15344 NJ |
576 | goto out; |
577 | } | |
578 | ||
579 | marker = &buf.data[TPM_HEADER_SIZE + 9]; | |
580 | ||
581 | rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); | |
582 | end = &buf.data[rsp_len]; | |
583 | ||
bcfff838 | 584 | for (i = 0; i < nr_possible_banks; i++) { |
1db15344 NJ |
585 | pcr_select_offset = marker + |
586 | offsetof(struct tpm2_pcr_selection, size_of_select); | |
587 | if (pcr_select_offset >= end) { | |
588 | rc = -EFAULT; | |
589 | break; | |
590 | } | |
591 | ||
592 | memcpy(&pcr_selection, marker, sizeof(pcr_selection)); | |
bcfff838 RS |
593 | hash_alg = be16_to_cpu(pcr_selection.hash_alg); |
594 | ||
595 | pcr_select_offset = memchr_inv(pcr_selection.pcr_select, 0, | |
596 | pcr_selection.size_of_select); | |
597 | if (pcr_select_offset) { | |
879b5892 RS |
598 | chip->allocated_banks[nr_alloc_banks].alg_id = hash_alg; |
599 | ||
600 | rc = tpm2_init_bank_info(chip, nr_alloc_banks); | |
601 | if (rc < 0) | |
602 | break; | |
603 | ||
bcfff838 RS |
604 | nr_alloc_banks++; |
605 | } | |
606 | ||
1db15344 NJ |
607 | sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + |
608 | sizeof(pcr_selection.size_of_select) + | |
609 | pcr_selection.size_of_select; | |
610 | marker = marker + sizeof_pcr_selection; | |
611 | } | |
612 | ||
bcfff838 | 613 | chip->nr_allocated_banks = nr_alloc_banks; |
1db15344 | 614 | out: |
1db15344 NJ |
615 | tpm_buf_destroy(&buf); |
616 | ||
617 | return rc; | |
618 | } | |
61841be6 | 619 | |
18b3670d | 620 | int tpm2_get_cc_attrs_tbl(struct tpm_chip *chip) |
58472f5c JS |
621 | { |
622 | struct tpm_buf buf; | |
623 | u32 nr_commands; | |
171360d7 | 624 | __be32 *attrs; |
58472f5c JS |
625 | u32 cc; |
626 | int i; | |
627 | int rc; | |
628 | ||
629 | rc = tpm2_get_tpm_pt(chip, TPM_PT_TOTAL_COMMANDS, &nr_commands, NULL); | |
630 | if (rc) | |
631 | goto out; | |
632 | ||
633 | if (nr_commands > 0xFFFFF) { | |
634 | rc = -EFAULT; | |
635 | goto out; | |
636 | } | |
637 | ||
a86854d0 | 638 | chip->cc_attrs_tbl = devm_kcalloc(&chip->dev, 4, nr_commands, |
58472f5c | 639 | GFP_KERNEL); |
f1689114 TS |
640 | if (!chip->cc_attrs_tbl) { |
641 | rc = -ENOMEM; | |
642 | goto out; | |
643 | } | |
58472f5c JS |
644 | |
645 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); | |
646 | if (rc) | |
647 | goto out; | |
648 | ||
649 | tpm_buf_append_u32(&buf, TPM2_CAP_COMMANDS); | |
650 | tpm_buf_append_u32(&buf, TPM2_CC_FIRST); | |
651 | tpm_buf_append_u32(&buf, nr_commands); | |
652 | ||
47a6c28b | 653 | rc = tpm_transmit_cmd(chip, &buf, 9 + 4 * nr_commands, NULL); |
58472f5c JS |
654 | if (rc) { |
655 | tpm_buf_destroy(&buf); | |
656 | goto out; | |
657 | } | |
658 | ||
659 | if (nr_commands != | |
660 | be32_to_cpup((__be32 *)&buf.data[TPM_HEADER_SIZE + 5])) { | |
1df83992 | 661 | rc = -EFAULT; |
58472f5c JS |
662 | tpm_buf_destroy(&buf); |
663 | goto out; | |
664 | } | |
665 | ||
666 | chip->nr_commands = nr_commands; | |
667 | ||
171360d7 | 668 | attrs = (__be32 *)&buf.data[TPM_HEADER_SIZE + 9]; |
58472f5c JS |
669 | for (i = 0; i < nr_commands; i++, attrs++) { |
670 | chip->cc_attrs_tbl[i] = be32_to_cpup(attrs); | |
671 | cc = chip->cc_attrs_tbl[i] & 0xFFFF; | |
672 | ||
673 | if (cc == TPM2_CC_CONTEXT_SAVE || cc == TPM2_CC_FLUSH_CONTEXT) { | |
674 | chip->cc_attrs_tbl[i] &= | |
675 | ~(GENMASK(2, 0) << TPM2_CC_ATTR_CHANDLES); | |
676 | chip->cc_attrs_tbl[i] |= 1 << TPM2_CC_ATTR_CHANDLES; | |
677 | } | |
678 | } | |
679 | ||
680 | tpm_buf_destroy(&buf); | |
681 | ||
682 | out: | |
683 | if (rc > 0) | |
684 | rc = -ENODEV; | |
685 | return rc; | |
686 | } | |
684c6bd8 | 687 | EXPORT_SYMBOL_GPL(tpm2_get_cc_attrs_tbl); |
58472f5c | 688 | |
9db7fe18 TW |
689 | /** |
690 | * tpm2_startup - turn on the TPM | |
691 | * @chip: TPM chip to use | |
692 | * | |
693 | * Normally the firmware should start the TPM. This function is provided as a | |
694 | * workaround if this does not happen. A legal case for this could be for | |
695 | * example when a TPM emulator is used. | |
696 | * | |
697 | * Return: same as tpm_transmit_cmd() | |
698 | */ | |
699 | ||
700 | static int tpm2_startup(struct tpm_chip *chip) | |
701 | { | |
702 | struct tpm_buf buf; | |
703 | int rc; | |
704 | ||
705 | dev_info(&chip->dev, "starting up the TPM manually\n"); | |
706 | ||
707 | rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP); | |
708 | if (rc < 0) | |
709 | return rc; | |
710 | ||
711 | tpm_buf_append_u16(&buf, TPM2_SU_CLEAR); | |
47a6c28b | 712 | rc = tpm_transmit_cmd(chip, &buf, 0, "attempting to start the TPM"); |
9db7fe18 TW |
713 | tpm_buf_destroy(&buf); |
714 | ||
715 | return rc; | |
716 | } | |
717 | ||
61841be6 JS |
718 | /** |
719 | * tpm2_auto_startup - Perform the standard automatic TPM initialization | |
720 | * sequence | |
721 | * @chip: TPM chip to use | |
722 | * | |
58472f5c | 723 | * Returns 0 on success, < 0 in case of fatal error. |
61841be6 JS |
724 | */ |
725 | int tpm2_auto_startup(struct tpm_chip *chip) | |
726 | { | |
727 | int rc; | |
728 | ||
9db7fe18 | 729 | rc = tpm2_get_timeouts(chip); |
61841be6 JS |
730 | if (rc) |
731 | goto out; | |
732 | ||
733 | rc = tpm2_do_selftest(chip); | |
2be8ffed | 734 | if (rc && rc != TPM2_RC_INITIALIZE) |
61841be6 | 735 | goto out; |
61841be6 JS |
736 | |
737 | if (rc == TPM2_RC_INITIALIZE) { | |
9db7fe18 | 738 | rc = tpm2_startup(chip); |
61841be6 JS |
739 | if (rc) |
740 | goto out; | |
741 | ||
742 | rc = tpm2_do_selftest(chip); | |
2be8ffed | 743 | if (rc) |
61841be6 | 744 | goto out; |
61841be6 JS |
745 | } |
746 | ||
58472f5c | 747 | rc = tpm2_get_cc_attrs_tbl(chip); |
863ed94c ML |
748 | if (rc == TPM2_RC_FAILURE || (rc < 0 && rc != -ENOMEM)) { |
749 | dev_info(&chip->dev, | |
750 | "TPM in field failure mode, requires firmware upgrade\n"); | |
751 | chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; | |
752 | rc = 0; | |
753 | } | |
61841be6 | 754 | |
d2add27c JB |
755 | if (rc) |
756 | goto out; | |
757 | ||
758 | rc = tpm2_sessions_init(chip); | |
759 | ||
61841be6 | 760 | out: |
af402ee3 SMH |
761 | /* |
762 | * Infineon TPM in field upgrade mode will return no data for the number | |
763 | * of supported commands. | |
764 | */ | |
765 | if (rc == TPM2_RC_UPGRADE || rc == -ENODATA) { | |
0aa69878 | 766 | dev_info(&chip->dev, "TPM in field upgrade mode, requires firmware upgrade\n"); |
767 | chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE; | |
768 | rc = 0; | |
769 | } | |
770 | ||
61841be6 JS |
771 | if (rc > 0) |
772 | rc = -ENODEV; | |
773 | return rc; | |
774 | } | |
58472f5c JS |
775 | |
776 | int tpm2_find_cc(struct tpm_chip *chip, u32 cc) | |
777 | { | |
85b93bbd | 778 | u32 cc_mask; |
58472f5c JS |
779 | int i; |
780 | ||
85b93bbd | 781 | cc_mask = 1 << TPM2_CC_ATTR_VENDOR | GENMASK(15, 0); |
58472f5c | 782 | for (i = 0; i < chip->nr_commands; i++) |
85b93bbd | 783 | if (cc == (chip->cc_attrs_tbl[i] & cc_mask)) |
58472f5c JS |
784 | return i; |
785 | ||
786 | return -1; | |
787 | } |