blob: e66023da5e67e6ee1faea5909b147d06b46a9e9d [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiouc18f9012013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfau4fece432013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiouc18f9012013-02-28 09:34:57 +00005 */
6
Simon Glassbccabbe2018-10-01 12:22:29 -06007#define LOG_CATEGORY UCLASS_TPM
8
Simon Glass3e4f2fd2015-08-22 18:31:32 -06009#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Che-liang Chiouc18f9012013-02-28 09:34:57 +000011#include <asm/unaligned.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060012#include <u-boot/sha1.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020013#include <tpm-common.h>
14#include <tpm-v1.h>
15#include "tpm-utils.h"
Che-liang Chiouc18f9012013-02-28 09:34:57 +000016
Reinhard Pfau4fece432013-06-26 15:55:13 +020017#ifdef CONFIG_TPM_AUTH_SESSIONS
18
19#ifndef CONFIG_SHA1
20#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
21#endif /* !CONFIG_SHA1 */
22
23struct session_data {
24 int valid;
Miquel Raynald790f552018-05-15 11:56:59 +020025 u32 handle;
26 u8 nonce_even[DIGEST_LENGTH];
27 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +020028};
29
30static struct session_data oiap_session = {0, };
31
32#endif /* CONFIG_TPM_AUTH_SESSIONS */
33
Simon Glass3b8692a2021-02-06 14:23:36 -070034u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000035{
Miquel Raynald790f552018-05-15 11:56:59 +020036 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000037 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
38 };
39 const size_t mode_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +020040 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +000041
42 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +020043 0, command, sizeof(command),
44 mode_offset, mode))
Che-liang Chiouc18f9012013-02-28 09:34:57 +000045 return TPM_LIB_ERROR;
46
Simon Glass8ceca1d2018-11-18 14:22:27 -070047 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000048}
49
Simon Glass3b8692a2021-02-06 14:23:36 -070050u32 tpm1_resume(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060051{
Simon Glass3b8692a2021-02-06 14:23:36 -070052 return tpm1_startup(dev, TPM_ST_STATE);
Simon Glassbccabbe2018-10-01 12:22:29 -060053}
54
Simon Glass3b8692a2021-02-06 14:23:36 -070055u32 tpm1_self_test_full(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000056{
Miquel Raynald790f552018-05-15 11:56:59 +020057 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000058 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
59 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070060 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000061}
62
Simon Glass3b8692a2021-02-06 14:23:36 -070063u32 tpm1_continue_self_test(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000064{
Miquel Raynald790f552018-05-15 11:56:59 +020065 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000066 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
67 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070068 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000069}
70
Simon Glass3467ed22023-02-21 06:24:52 -070071u32 tpm1_auto_start(struct udevice *dev)
72{
73 u32 rc;
74
75 rc = tpm1_startup(dev, TPM_ST_CLEAR);
76 /* continue on if the TPM is already inited */
77 if (rc && rc != TPM_INVALID_POSTINIT)
78 return rc;
79
80 rc = tpm1_self_test_full(dev);
81
82 return rc;
83}
84
Simon Glass3b8692a2021-02-06 14:23:36 -070085u32 tpm1_clear_and_reenable(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060086{
87 u32 ret;
88
89 log_info("TPM: Clear and re-enable\n");
Simon Glass3b8692a2021-02-06 14:23:36 -070090 ret = tpm1_force_clear(dev);
Simon Glassbccabbe2018-10-01 12:22:29 -060091 if (ret != TPM_SUCCESS) {
92 log_err("Can't initiate a force clear\n");
93 return ret;
94 }
95
Simon Glass3b8692a2021-02-06 14:23:36 -070096 ret = tpm1_physical_enable(dev);
97 if (ret != TPM_SUCCESS) {
98 log_err("TPM: Can't set enabled state\n");
99 return ret;
100 }
Simon Glassbccabbe2018-10-01 12:22:29 -0600101
Simon Glass3b8692a2021-02-06 14:23:36 -0700102 ret = tpm1_physical_set_deactivated(dev, 0);
103 if (ret != TPM_SUCCESS) {
104 log_err("TPM: Can't set deactivated state\n");
105 return ret;
Simon Glassbccabbe2018-10-01 12:22:29 -0600106 }
Simon Glassbccabbe2018-10-01 12:22:29 -0600107
108 return TPM_SUCCESS;
109}
110
Simon Glass3b8692a2021-02-06 14:23:36 -0700111u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000112{
Miquel Raynald790f552018-05-15 11:56:59 +0200113 const u8 command[101] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000114 0x0, 0xc1, /* TPM_TAG */
115 0x0, 0x0, 0x0, 0x65, /* parameter size */
116 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
117 /* TPM_NV_DATA_PUBLIC->... */
118 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
119 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
120 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
121 0x0, 0x3,
122 0, 0, 0,
123 0x1f,
124 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
126 0x0, 0x3,
127 0, 0, 0,
128 0x1f,
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130 /* TPM_NV_ATTRIBUTES->... */
131 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
132 0, 0, 0, 0, /* ...->attributes */
133 /* End of TPM_NV_ATTRIBUTES */
134 0, /* bReadSTClear */
135 0, /* bWriteSTClear */
136 0, /* bWriteDefine */
137 0, 0, 0, 0, /* size */
138 };
139 const size_t index_offset = 12;
140 const size_t perm_offset = 70;
141 const size_t size_offset = 77;
Miquel Raynald790f552018-05-15 11:56:59 +0200142 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000143
144 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200145 0, command, sizeof(command),
146 index_offset, index,
147 perm_offset, perm,
148 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000149 return TPM_LIB_ERROR;
150
Simon Glass8ceca1d2018-11-18 14:22:27 -0700151 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000152}
153
Simon Glass3b8692a2021-02-06 14:23:36 -0700154u32 tpm1_nv_set_locked(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600155{
Simon Glass3b8692a2021-02-06 14:23:36 -0700156 return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600157}
158
Simon Glass3b8692a2021-02-06 14:23:36 -0700159u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000160{
Miquel Raynald790f552018-05-15 11:56:59 +0200161 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000162 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
163 };
164 const size_t index_offset = 10;
165 const size_t length_offset = 18;
166 const size_t data_size_offset = 10;
167 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200168 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000169 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200170 u32 data_size;
171 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000172
173 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200174 0, command, sizeof(command),
175 index_offset, index,
176 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000177 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700178 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000179 if (err)
180 return err;
181 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200182 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000183 return TPM_LIB_ERROR;
184 if (data_size > count)
185 return TPM_LIB_ERROR;
186 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200187 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000188 return TPM_LIB_ERROR;
189
190 return 0;
191}
192
Simon Glass3b8692a2021-02-06 14:23:36 -0700193u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
194 u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000195{
Miquel Raynald790f552018-05-15 11:56:59 +0200196 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000197 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
198 };
199 const size_t command_size_offset = 2;
200 const size_t index_offset = 10;
201 const size_t length_offset = 18;
202 const size_t data_offset = 22;
203 const size_t write_info_size = 12;
Miquel Raynald790f552018-05-15 11:56:59 +0200204 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000205 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200206 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000207 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200208 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000209
210 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200211 0, command, sizeof(command),
212 command_size_offset, total_length,
213 index_offset, index,
214 length_offset, length,
215 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000216 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700217 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000218 if (err)
219 return err;
220
221 return 0;
222}
223
Simon Glass3b8692a2021-02-06 14:23:36 -0700224u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
225 void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000226{
Miquel Raynald790f552018-05-15 11:56:59 +0200227 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000228 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
229 };
230 const size_t index_offset = 10;
231 const size_t in_digest_offset = 14;
232 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200233 u8 buf[COMMAND_BUFFER_SIZE];
234 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000235 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200236 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000237
238 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200239 0, command, sizeof(command),
240 index_offset, index,
241 in_digest_offset, in_digest,
242 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000243 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700244 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000245 if (err)
246 return err;
247
248 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200249 out_digest_offset, out_digest,
250 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000251 return TPM_LIB_ERROR;
252
253 return 0;
254}
255
Simon Glass3b8692a2021-02-06 14:23:36 -0700256u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000257{
Miquel Raynald790f552018-05-15 11:56:59 +0200258 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000259 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
260 };
261 const size_t index_offset = 10;
262 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200263 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000264 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200265 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000266
267 if (count < PCR_DIGEST_LENGTH)
268 return TPM_LIB_ERROR;
269
270 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200271 0, command, sizeof(command),
272 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000273 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700274 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000275 if (err)
276 return err;
277 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200278 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000279 return TPM_LIB_ERROR;
280
281 return 0;
282}
283
Simon Glass3b8692a2021-02-06 14:23:36 -0700284u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000285{
Miquel Raynald790f552018-05-15 11:56:59 +0200286 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000287 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
288 };
289 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200290 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000291
292 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200293 0, command, sizeof(command),
294 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000295 return TPM_LIB_ERROR;
296
Simon Glass8ceca1d2018-11-18 14:22:27 -0700297 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000298}
299
Simon Glass3b8692a2021-02-06 14:23:36 -0700300u32 tpm1_finalise_physical_presence(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600301{
302 const u8 command[12] = {
303 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
304 };
305
Simon Glass8ceca1d2018-11-18 14:22:27 -0700306 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glassbccabbe2018-10-01 12:22:29 -0600307}
308
Simon Glass3b8692a2021-02-06 14:23:36 -0700309u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000310{
Miquel Raynald790f552018-05-15 11:56:59 +0200311 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000312 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
313 };
314 const size_t response_size_offset = 2;
315 const size_t data_offset = 10;
316 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynald790f552018-05-15 11:56:59 +0200317 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000318 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200319 u32 data_size;
320 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000321
Simon Glass8ceca1d2018-11-18 14:22:27 -0700322 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000323 if (err)
324 return err;
325 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200326 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000327 return TPM_LIB_ERROR;
328 if (data_size < header_and_checksum_size)
329 return TPM_LIB_ERROR;
330 data_size -= header_and_checksum_size;
331 if (data_size > count)
332 return TPM_LIB_ERROR;
333 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200334 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000335 return TPM_LIB_ERROR;
336
337 return 0;
338}
339
Simon Glass3b8692a2021-02-06 14:23:36 -0700340u32 tpm1_force_clear(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000341{
Miquel Raynald790f552018-05-15 11:56:59 +0200342 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000343 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
344 };
345
Simon Glass8ceca1d2018-11-18 14:22:27 -0700346 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000347}
348
Simon Glass3b8692a2021-02-06 14:23:36 -0700349u32 tpm1_physical_enable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000350{
Miquel Raynald790f552018-05-15 11:56:59 +0200351 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000352 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
353 };
354
Simon Glass8ceca1d2018-11-18 14:22:27 -0700355 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000356}
357
Simon Glass3b8692a2021-02-06 14:23:36 -0700358u32 tpm1_physical_disable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000359{
Miquel Raynald790f552018-05-15 11:56:59 +0200360 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000361 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
362 };
363
Simon Glass8ceca1d2018-11-18 14:22:27 -0700364 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000365}
366
Simon Glass3b8692a2021-02-06 14:23:36 -0700367u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000368{
Miquel Raynald790f552018-05-15 11:56:59 +0200369 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000370 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
371 };
372 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200373 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000374
375 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200376 0, command, sizeof(command),
377 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000378 return TPM_LIB_ERROR;
379
Simon Glass8ceca1d2018-11-18 14:22:27 -0700380 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000381}
382
Simon Glass3b8692a2021-02-06 14:23:36 -0700383u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
384 void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000385{
Miquel Raynald790f552018-05-15 11:56:59 +0200386 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000387 0x0, 0xc1, /* TPM_TAG */
388 0x0, 0x0, 0x0, 0x16, /* parameter size */
389 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
390 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
391 0x0, 0x0, 0x0, 0x4, /* subcap size */
392 0x0, 0x0, 0x0, 0x0, /* subcap value */
393 };
394 const size_t cap_area_offset = 10;
395 const size_t sub_cap_offset = 18;
396 const size_t cap_offset = 14;
397 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200398 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000399 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200400 u32 cap_size;
401 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000402
403 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200404 0, command, sizeof(command),
405 cap_area_offset, cap_area,
406 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000407 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700408 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000409 if (err)
410 return err;
411 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200412 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000413 return TPM_LIB_ERROR;
414 if (cap_size > response_length || cap_size > count)
415 return TPM_LIB_ERROR;
416 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200417 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000418 return TPM_LIB_ERROR;
419
420 return 0;
421}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200422
Simon Glass3b8692a2021-02-06 14:23:36 -0700423u32 tpm1_get_permanent_flags(struct udevice *dev,
424 struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600425{
Miquel Raynald790f552018-05-15 11:56:59 +0200426 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600427 0x0, 0xc1, /* TPM_TAG */
428 0x0, 0x0, 0x0, 0x16, /* parameter size */
429 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
430 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
431 0x0, 0x0, 0x0, 0x4, /* subcap size */
432 0x0, 0x0, 0x1, 0x8, /* subcap value */
433 };
André Draszik1361fbc2017-10-03 16:55:51 +0100434 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200435 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
436 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600437 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200438 u32 err;
439 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600440
Simon Glass8ceca1d2018-11-18 14:22:27 -0700441 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600442 if (err)
443 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100444 if (unpack_byte_string(response, response_length, "d",
Simon Glassbccabbe2018-10-01 12:22:29 -0600445 data_size_offset, &data_size)) {
446 log_err("Cannot unpack data size\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100447 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600448 }
449 if (data_size < sizeof(*pflags)) {
450 log_err("Data size too small\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100451 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600452 }
André Draszik1361fbc2017-10-03 16:55:51 +0100453 if (unpack_byte_string(response, response_length, "s",
Simon Glassbccabbe2018-10-01 12:22:29 -0600454 data_offset, pflags, sizeof(*pflags))) {
455 log_err("Cannot unpack pflags\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100456 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600457 }
Simon Glassff9f04a2015-08-22 18:31:41 -0600458
459 return 0;
460}
461
Simon Glass3b8692a2021-02-06 14:23:36 -0700462u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600463{
Miquel Raynald790f552018-05-15 11:56:59 +0200464 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600465 0x0, 0xc1, /* TPM_TAG */
466 0x0, 0x0, 0x0, 0x16, /* parameter size */
467 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
468 0x0, 0x0, 0x0, 0x11,
469 0x0, 0x0, 0x0, 0x4,
470 };
471 const size_t index_offset = 18;
Simon Glass9523a4e2022-08-30 21:05:33 -0600472 const size_t perm_offset = 74;
Miquel Raynald790f552018-05-15 11:56:59 +0200473 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600474 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200475 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600476
Simon Glass9523a4e2022-08-30 21:05:33 -0600477 if (pack_byte_string(buf, sizeof(buf), "sd",
478 0, command, sizeof(command),
Simon Glassff9f04a2015-08-22 18:31:41 -0600479 index_offset, index))
480 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700481 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600482 if (err)
483 return err;
484 if (unpack_byte_string(response, response_length, "d",
485 perm_offset, perm))
486 return TPM_LIB_ERROR;
487
488 return 0;
489}
490
Mario Six4eceb6c2017-01-11 16:00:50 +0100491#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glass3b8692a2021-02-06 14:23:36 -0700492u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100493{
Miquel Raynald790f552018-05-15 11:56:59 +0200494 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100495 0x00, 0xc1, /* TPM_TAG */
496 0x00, 0x00, 0x00, 0x12, /* parameter size */
497 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
498 0x00, 0x00, 0x00, 0x00, /* key handle */
499 0x00, 0x00, 0x00, 0x00, /* resource type */
500 };
501 const size_t key_handle_offset = 10;
502 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200503 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100504 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200505 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100506
507 if (pack_byte_string(buf, sizeof(buf), "sdd",
508 0, command, sizeof(command),
509 key_handle_offset, key_handle,
510 resource_type_offset, resource_type))
511 return TPM_LIB_ERROR;
512
Simon Glass8ceca1d2018-11-18 14:22:27 -0700513 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six4eceb6c2017-01-11 16:00:50 +0100514 if (err)
515 return err;
516 return 0;
517}
518#endif /* CONFIG_TPM_FLUSH_RESOURCES */
519
Reinhard Pfau4fece432013-06-26 15:55:13 +0200520#ifdef CONFIG_TPM_AUTH_SESSIONS
521
522/**
523 * Fill an authentication block in a request.
524 * This func can create the first as well as the second auth block (for
525 * double authorized commands).
526 *
527 * @param request pointer to the request (w/ uninitialised auth data)
528 * @param request_len0 length of the request without auth data
529 * @param handles_len length of the handles area in request
530 * @param auth_session pointer to the (valid) auth session to be used
531 * @param request_auth pointer to the auth block of the request to be filled
532 * @param auth authentication data (HMAC key)
533 */
Miquel Raynald790f552018-05-15 11:56:59 +0200534static u32 create_request_auth(const void *request, size_t request_len0,
535 size_t handles_len,
536 struct session_data *auth_session,
537 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200538{
Miquel Raynald790f552018-05-15 11:56:59 +0200539 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200540 sha1_context hash_ctx;
541 const size_t command_code_offset = 6;
542 const size_t auth_nonce_odd_offset = 4;
543 const size_t auth_continue_offset = 24;
544 const size_t auth_auth_offset = 25;
545
546 if (!auth_session || !auth_session->valid)
547 return TPM_LIB_ERROR;
548
549 sha1_starts(&hash_ctx);
550 sha1_update(&hash_ctx, request + command_code_offset, 4);
551 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
552 sha1_update(&hash_ctx,
553 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
554 request_len0 - TPM_REQUEST_HEADER_LENGTH
555 - handles_len);
556 sha1_finish(&hash_ctx, hmac_data);
557
558 sha1_starts(&hash_ctx);
559 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
560 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
561 sha1_finish(&hash_ctx, auth_session->nonce_odd);
562
563 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
564 0, auth_session->handle,
565 auth_nonce_odd_offset, auth_session->nonce_odd,
566 DIGEST_LENGTH,
567 auth_continue_offset, 1))
568 return TPM_LIB_ERROR;
569 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
570 DIGEST_LENGTH,
571 auth_session->nonce_even,
572 DIGEST_LENGTH,
573 2 * DIGEST_LENGTH,
574 request_auth + auth_nonce_odd_offset,
575 DIGEST_LENGTH + 1))
576 return TPM_LIB_ERROR;
577 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
578 request_auth + auth_auth_offset);
579
580 return TPM_SUCCESS;
581}
582
583/**
584 * Verify an authentication block in a response.
585 * Since this func updates the nonce_even in the session data it has to be
586 * called when receiving a succesfull AUTH response.
587 * This func can verify the first as well as the second auth block (for
588 * double authorized commands).
589 *
590 * @param command_code command code of the request
591 * @param response pointer to the request (w/ uninitialised auth data)
592 * @param handles_len length of the handles area in response
593 * @param auth_session pointer to the (valid) auth session to be used
594 * @param response_auth pointer to the auth block of the response to be verified
595 * @param auth authentication data (HMAC key)
596 */
Miquel Raynald790f552018-05-15 11:56:59 +0200597static u32 verify_response_auth(u32 command_code, const void *response,
598 size_t response_len0, size_t handles_len,
599 struct session_data *auth_session,
600 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200601{
Miquel Raynald790f552018-05-15 11:56:59 +0200602 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
603 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200604 sha1_context hash_ctx;
605 const size_t return_code_offset = 6;
606 const size_t auth_continue_offset = 20;
607 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200608 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200609
610 if (!auth_session || !auth_session->valid)
611 return TPM_AUTHFAIL;
612 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
613 0, command_code))
614 return TPM_LIB_ERROR;
615 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
616 return TPM_LIB_ERROR;
617
618 sha1_starts(&hash_ctx);
619 sha1_update(&hash_ctx, response + return_code_offset, 4);
620 sha1_update(&hash_ctx, hmac_data, 4);
621 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
622 sha1_update(&hash_ctx,
623 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
624 response_len0 - TPM_RESPONSE_HEADER_LENGTH
625 - handles_len);
626 sha1_finish(&hash_ctx, hmac_data);
627
628 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200629 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200630 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
631 DIGEST_LENGTH,
632 response_auth,
633 DIGEST_LENGTH,
634 2 * DIGEST_LENGTH,
635 auth_session->nonce_odd,
636 DIGEST_LENGTH,
637 3 * DIGEST_LENGTH,
638 auth_continue))
639 return TPM_LIB_ERROR;
640
641 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
642 computed_auth);
643
644 if (memcmp(computed_auth, response_auth + auth_auth_offset,
645 DIGEST_LENGTH))
646 return TPM_AUTHFAIL;
647
648 return TPM_SUCCESS;
649}
650
Simon Glass3b8692a2021-02-06 14:23:36 -0700651u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200652{
Miquel Raynald790f552018-05-15 11:56:59 +0200653 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200654 0x00, 0xc1, /* TPM_TAG */
655 0x00, 0x00, 0x00, 0x00, /* parameter size */
656 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
657 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200658 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200659 };
660 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200661 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200662
663 if (pack_byte_string(request, sizeof(request), "sd",
664 0, command, sizeof(command),
665 req_handle_offset, auth_handle))
666 return TPM_LIB_ERROR;
667 if (oiap_session.valid && oiap_session.handle == auth_handle)
668 oiap_session.valid = 0;
669
Simon Glass8ceca1d2018-11-18 14:22:27 -0700670 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200671}
672
Simon Glass3b8692a2021-02-06 14:23:36 -0700673u32 tpm1_end_oiap(struct udevice *dev)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200674{
Miquel Raynald790f552018-05-15 11:56:59 +0200675 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200676
Reinhard Pfau4fece432013-06-26 15:55:13 +0200677 if (oiap_session.valid)
Simon Glass3b8692a2021-02-06 14:23:36 -0700678 err = tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200679 return err;
680}
681
Simon Glass3b8692a2021-02-06 14:23:36 -0700682u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200683{
Miquel Raynald790f552018-05-15 11:56:59 +0200684 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200685 0x00, 0xc1, /* TPM_TAG */
686 0x00, 0x00, 0x00, 0x0a, /* parameter size */
687 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
688 };
689 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
690 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200691 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200692 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200693 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200694
695 if (oiap_session.valid)
Simon Glass3b8692a2021-02-06 14:23:36 -0700696 tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200697
Simon Glass8ceca1d2018-11-18 14:22:27 -0700698 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200699 if (err)
700 return err;
701 if (unpack_byte_string(response, response_length, "ds",
702 res_auth_handle_offset, &oiap_session.handle,
703 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200704 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200705 return TPM_LIB_ERROR;
706 oiap_session.valid = 1;
707 if (auth_handle)
708 *auth_handle = oiap_session.handle;
709 return 0;
710}
711
Simon Glass3b8692a2021-02-06 14:23:36 -0700712u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
713 size_t key_length, const void *parent_key_usage_auth,
714 u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200715{
Miquel Raynald790f552018-05-15 11:56:59 +0200716 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200717 0x00, 0xc2, /* TPM_TAG */
718 0x00, 0x00, 0x00, 0x00, /* parameter size */
719 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
720 0x00, 0x00, 0x00, 0x00, /* parent handle */
721 };
722 const size_t req_size_offset = 2;
723 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
724 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
725 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200726 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
727 TPM_REQUEST_AUTH_LENGTH];
728 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200729 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200730 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200731
732 if (!oiap_session.valid) {
Simon Glass3b8692a2021-02-06 14:23:36 -0700733 err = tpm1_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200734 if (err)
735 return err;
736 }
737 if (pack_byte_string(request, sizeof(request), "sdds",
738 0, command, sizeof(command),
739 req_size_offset,
740 sizeof(command) + key_length
741 + TPM_REQUEST_AUTH_LENGTH,
742 req_parent_handle_offset, parent_handle,
743 req_key_offset, key, key_length
744 ))
745 return TPM_LIB_ERROR;
746
747 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200748 &oiap_session,
749 request + sizeof(command) + key_length,
750 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200751 if (err)
752 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700753 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200754 if (err) {
755 if (err == TPM_AUTHFAIL)
756 oiap_session.valid = 0;
757 return err;
758 }
759
760 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200761 response_length - TPM_RESPONSE_AUTH_LENGTH,
762 4, &oiap_session,
763 response + response_length -
764 TPM_RESPONSE_AUTH_LENGTH,
765 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200766 if (err)
767 return err;
768
769 if (key_handle) {
770 if (unpack_byte_string(response, response_length, "d",
771 res_handle_offset, key_handle))
772 return TPM_LIB_ERROR;
773 }
774
775 return 0;
776}
777
Simon Glass3b8692a2021-02-06 14:23:36 -0700778u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
779 const void *usage_auth, void *pubkey,
780 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200781{
Miquel Raynald790f552018-05-15 11:56:59 +0200782 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200783 0x00, 0xc2, /* TPM_TAG */
784 0x00, 0x00, 0x00, 0x00, /* parameter size */
785 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
786 0x00, 0x00, 0x00, 0x00, /* key handle */
787 };
788 const size_t req_size_offset = 2;
789 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
790 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200791 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
792 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
793 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200794 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200795 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200796
797 if (!oiap_session.valid) {
Simon Glass3b8692a2021-02-06 14:23:36 -0700798 err = tpm1_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200799 if (err)
800 return err;
801 }
802 if (pack_byte_string(request, sizeof(request), "sdd",
803 0, command, sizeof(command),
804 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200805 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200806 + TPM_REQUEST_AUTH_LENGTH),
807 req_key_handle_offset, key_handle
808 ))
809 return TPM_LIB_ERROR;
810 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200811 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200812 if (err)
813 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700814 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200815 if (err) {
816 if (err == TPM_AUTHFAIL)
817 oiap_session.valid = 0;
818 return err;
819 }
820 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200821 response_length - TPM_RESPONSE_AUTH_LENGTH,
822 0, &oiap_session,
823 response + response_length -
824 TPM_RESPONSE_AUTH_LENGTH,
825 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200826 if (err)
827 return err;
828
829 if (pubkey) {
830 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200831 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200832 return TPM_LIB_ERROR;
833 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
834 - TPM_RESPONSE_AUTH_LENGTH;
835 memcpy(pubkey, response + res_pubkey_offset,
836 response_length - TPM_RESPONSE_HEADER_LENGTH
837 - TPM_RESPONSE_AUTH_LENGTH);
838 }
839
840 return 0;
841}
842
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100843#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glass3b8692a2021-02-06 14:23:36 -0700844u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
845 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100846{
Miquel Raynald790f552018-05-15 11:56:59 +0200847 u16 key_count;
848 u32 key_handles[10];
849 u8 buf[288];
850 u8 *ptr;
851 u32 err;
852 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100853 size_t buf_len;
854 unsigned int i;
855
856 /* fetch list of already loaded keys in the TPM */
Mathew McBride10f24eb2021-11-11 04:06:27 +0000857 err = tpm1_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
Simon Glass8ceca1d2018-11-18 14:22:27 -0700858 sizeof(buf));
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100859 if (err)
860 return -1;
861 key_count = get_unaligned_be16(buf);
862 ptr = buf + 2;
863 for (i = 0; i < key_count; ++i, ptr += 4)
864 key_handles[i] = get_unaligned_be32(ptr);
865
866 /* now search a(/ the) key which we can access with the given auth */
867 for (i = 0; i < key_count; ++i) {
868 buf_len = sizeof(buf);
Mathew McBride10f24eb2021-11-11 04:06:27 +0000869 err = tpm1_get_pub_key_oiap(dev, key_handles[i], auth, buf, &buf_len);
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100870 if (err && err != TPM_AUTHFAIL)
871 return -1;
872 if (err)
873 continue;
874 sha1_csum(buf, buf_len, digest);
875 if (!memcmp(digest, pubkey_digest, 20)) {
876 *handle = key_handles[i];
877 return 0;
878 }
879 }
880 return 1;
881}
882#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
883
Reinhard Pfau4fece432013-06-26 15:55:13 +0200884#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100885
Simon Glass3b8692a2021-02-06 14:23:36 -0700886u32 tpm1_get_random(struct udevice *dev, void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100887{
Miquel Raynald790f552018-05-15 11:56:59 +0200888 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100889 0x0, 0xc1, /* TPM_TAG */
890 0x0, 0x0, 0x0, 0xe, /* parameter size */
891 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
892 };
893 const size_t length_offset = 10;
894 const size_t data_size_offset = 10;
895 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200896 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100897 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200898 u32 data_size;
899 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100900
901 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200902 u32 this_bytes = min((size_t)count,
903 sizeof(response) - data_offset);
904 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100905
906 if (pack_byte_string(buf, sizeof(buf), "sd",
907 0, command, sizeof(command),
908 length_offset, this_bytes))
909 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700910 err = tpm_sendrecv_command(dev, buf, response,
911 &response_length);
André Draszik2c6e5ff2017-10-03 16:55:52 +0100912 if (err)
913 return err;
914 if (unpack_byte_string(response, response_length, "d",
915 data_size_offset, &data_size))
916 return TPM_LIB_ERROR;
917 if (data_size > count)
918 return TPM_LIB_ERROR;
919 if (unpack_byte_string(response, response_length, "s",
920 data_offset, out, data_size))
921 return TPM_LIB_ERROR;
922
923 count -= data_size;
924 out += data_size;
925 }
926
927 return 0;
928}