1d677bfe2SMiquel Raynal // SPDX-License-Identifier: GPL-2.0+
2d677bfe2SMiquel Raynal /*
3d677bfe2SMiquel Raynal * Copyright (c) 2013 The Chromium OS Authors.
4d677bfe2SMiquel Raynal * Coypright (c) 2013 Guntermann & Drunck GmbH
5d677bfe2SMiquel Raynal */
6d677bfe2SMiquel Raynal
76e64ec12SSimon Glass #define LOG_CATEGORY UCLASS_TPM
86e64ec12SSimon Glass
9d677bfe2SMiquel Raynal #include <common.h>
10d677bfe2SMiquel Raynal #include <dm.h>
11*d7869cecSEddie James #include <log.h>
12d677bfe2SMiquel Raynal #include <asm/unaligned.h>
13d677bfe2SMiquel Raynal #include <u-boot/sha1.h>
14d677bfe2SMiquel Raynal #include <tpm-common.h>
15d677bfe2SMiquel Raynal #include <tpm-v1.h>
16d677bfe2SMiquel Raynal #include "tpm-utils.h"
17d677bfe2SMiquel Raynal
18d677bfe2SMiquel Raynal #ifdef CONFIG_TPM_AUTH_SESSIONS
19d677bfe2SMiquel Raynal
20d677bfe2SMiquel Raynal #ifndef CONFIG_SHA1
21d677bfe2SMiquel Raynal #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
22d677bfe2SMiquel Raynal #endif /* !CONFIG_SHA1 */
23d677bfe2SMiquel Raynal
24d677bfe2SMiquel Raynal struct session_data {
25d677bfe2SMiquel Raynal int valid;
26d677bfe2SMiquel Raynal u32 handle;
27d677bfe2SMiquel Raynal u8 nonce_even[DIGEST_LENGTH];
28d677bfe2SMiquel Raynal u8 nonce_odd[DIGEST_LENGTH];
29d677bfe2SMiquel Raynal };
30d677bfe2SMiquel Raynal
31d677bfe2SMiquel Raynal static struct session_data oiap_session = {0, };
32d677bfe2SMiquel Raynal
33d677bfe2SMiquel Raynal #endif /* CONFIG_TPM_AUTH_SESSIONS */
34d677bfe2SMiquel Raynal
tpm1_startup(struct udevice * dev,enum tpm_startup_type mode)35*d7869cecSEddie James u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode)
36d677bfe2SMiquel Raynal {
37d677bfe2SMiquel Raynal const u8 command[12] = {
38d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
39d677bfe2SMiquel Raynal };
40d677bfe2SMiquel Raynal const size_t mode_offset = 10;
41d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE];
42d677bfe2SMiquel Raynal
43d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sw",
44d677bfe2SMiquel Raynal 0, command, sizeof(command),
45d677bfe2SMiquel Raynal mode_offset, mode))
46d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
47d677bfe2SMiquel Raynal
48abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, buf, NULL, NULL);
49d677bfe2SMiquel Raynal }
50d677bfe2SMiquel Raynal
tpm1_resume(struct udevice * dev)51*d7869cecSEddie James u32 tpm1_resume(struct udevice *dev)
526e64ec12SSimon Glass {
53*d7869cecSEddie James return tpm1_startup(dev, TPM_ST_STATE);
546e64ec12SSimon Glass }
556e64ec12SSimon Glass
tpm1_self_test_full(struct udevice * dev)56*d7869cecSEddie James u32 tpm1_self_test_full(struct udevice *dev)
57d677bfe2SMiquel Raynal {
58d677bfe2SMiquel Raynal const u8 command[10] = {
59d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
60d677bfe2SMiquel Raynal };
61abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
62d677bfe2SMiquel Raynal }
63d677bfe2SMiquel Raynal
tpm1_continue_self_test(struct udevice * dev)64*d7869cecSEddie James u32 tpm1_continue_self_test(struct udevice *dev)
65d677bfe2SMiquel Raynal {
66d677bfe2SMiquel Raynal const u8 command[10] = {
67d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
68d677bfe2SMiquel Raynal };
69abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
70d677bfe2SMiquel Raynal }
71d677bfe2SMiquel Raynal
tpm1_clear_and_reenable(struct udevice * dev)72*d7869cecSEddie James u32 tpm1_clear_and_reenable(struct udevice *dev)
736e64ec12SSimon Glass {
746e64ec12SSimon Glass u32 ret;
756e64ec12SSimon Glass
766e64ec12SSimon Glass log_info("TPM: Clear and re-enable\n");
77*d7869cecSEddie James ret = tpm1_force_clear(dev);
786e64ec12SSimon Glass if (ret != TPM_SUCCESS) {
796e64ec12SSimon Glass log_err("Can't initiate a force clear\n");
806e64ec12SSimon Glass return ret;
816e64ec12SSimon Glass }
826e64ec12SSimon Glass
83*d7869cecSEddie James ret = tpm1_physical_enable(dev);
846e64ec12SSimon Glass if (ret != TPM_SUCCESS) {
856e64ec12SSimon Glass log_err("TPM: Can't set enabled state\n");
866e64ec12SSimon Glass return ret;
876e64ec12SSimon Glass }
886e64ec12SSimon Glass
89*d7869cecSEddie James ret = tpm1_physical_set_deactivated(dev, 0);
906e64ec12SSimon Glass if (ret != TPM_SUCCESS) {
916e64ec12SSimon Glass log_err("TPM: Can't set deactivated state\n");
926e64ec12SSimon Glass return ret;
936e64ec12SSimon Glass }
946e64ec12SSimon Glass
956e64ec12SSimon Glass return TPM_SUCCESS;
966e64ec12SSimon Glass }
976e64ec12SSimon Glass
tpm1_nv_define_space(struct udevice * dev,u32 index,u32 perm,u32 size)98*d7869cecSEddie James u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
99d677bfe2SMiquel Raynal {
100d677bfe2SMiquel Raynal const u8 command[101] = {
101d677bfe2SMiquel Raynal 0x0, 0xc1, /* TPM_TAG */
102d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x65, /* parameter size */
103d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
104d677bfe2SMiquel Raynal /* TPM_NV_DATA_PUBLIC->... */
105d677bfe2SMiquel Raynal 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
106d677bfe2SMiquel Raynal 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
107d677bfe2SMiquel Raynal /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
108d677bfe2SMiquel Raynal 0x0, 0x3,
109d677bfe2SMiquel Raynal 0, 0, 0,
110d677bfe2SMiquel Raynal 0x1f,
111d677bfe2SMiquel Raynal 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112d677bfe2SMiquel Raynal /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
113d677bfe2SMiquel Raynal 0x0, 0x3,
114d677bfe2SMiquel Raynal 0, 0, 0,
115d677bfe2SMiquel Raynal 0x1f,
116d677bfe2SMiquel Raynal 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117d677bfe2SMiquel Raynal /* TPM_NV_ATTRIBUTES->... */
118d677bfe2SMiquel Raynal 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
119d677bfe2SMiquel Raynal 0, 0, 0, 0, /* ...->attributes */
120d677bfe2SMiquel Raynal /* End of TPM_NV_ATTRIBUTES */
121d677bfe2SMiquel Raynal 0, /* bReadSTClear */
122d677bfe2SMiquel Raynal 0, /* bWriteSTClear */
123d677bfe2SMiquel Raynal 0, /* bWriteDefine */
124d677bfe2SMiquel Raynal 0, 0, 0, 0, /* size */
125d677bfe2SMiquel Raynal };
126d677bfe2SMiquel Raynal const size_t index_offset = 12;
127d677bfe2SMiquel Raynal const size_t perm_offset = 70;
128d677bfe2SMiquel Raynal const size_t size_offset = 77;
129d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE];
130d677bfe2SMiquel Raynal
131d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sddd",
132d677bfe2SMiquel Raynal 0, command, sizeof(command),
133d677bfe2SMiquel Raynal index_offset, index,
134d677bfe2SMiquel Raynal perm_offset, perm,
135d677bfe2SMiquel Raynal size_offset, size))
136d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
137d677bfe2SMiquel Raynal
138abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, buf, NULL, NULL);
139d677bfe2SMiquel Raynal }
140d677bfe2SMiquel Raynal
tpm1_nv_set_locked(struct udevice * dev)141*d7869cecSEddie James u32 tpm1_nv_set_locked(struct udevice *dev)
1426e64ec12SSimon Glass {
143*d7869cecSEddie James return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
1446e64ec12SSimon Glass }
1456e64ec12SSimon Glass
tpm1_nv_read_value(struct udevice * dev,u32 index,void * data,u32 count)146*d7869cecSEddie James u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
147d677bfe2SMiquel Raynal {
148d677bfe2SMiquel Raynal const u8 command[22] = {
149d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
150d677bfe2SMiquel Raynal };
151d677bfe2SMiquel Raynal const size_t index_offset = 10;
152d677bfe2SMiquel Raynal const size_t length_offset = 18;
153d677bfe2SMiquel Raynal const size_t data_size_offset = 10;
154d677bfe2SMiquel Raynal const size_t data_offset = 14;
155d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
156d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
157d677bfe2SMiquel Raynal u32 data_size;
158d677bfe2SMiquel Raynal u32 err;
159d677bfe2SMiquel Raynal
160d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sdd",
161d677bfe2SMiquel Raynal 0, command, sizeof(command),
162d677bfe2SMiquel Raynal index_offset, index,
163d677bfe2SMiquel Raynal length_offset, count))
164d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
165abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
166d677bfe2SMiquel Raynal if (err)
167d677bfe2SMiquel Raynal return err;
168d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
169d677bfe2SMiquel Raynal data_size_offset, &data_size))
170d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
171d677bfe2SMiquel Raynal if (data_size > count)
172d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
173d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
174d677bfe2SMiquel Raynal data_offset, data, data_size))
175d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
176d677bfe2SMiquel Raynal
177d677bfe2SMiquel Raynal return 0;
178d677bfe2SMiquel Raynal }
179d677bfe2SMiquel Raynal
tpm1_nv_write_value(struct udevice * dev,u32 index,const void * data,u32 length)180*d7869cecSEddie James u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
181abdc7b8aSSimon Glass u32 length)
182d677bfe2SMiquel Raynal {
183d677bfe2SMiquel Raynal const u8 command[256] = {
184d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
185d677bfe2SMiquel Raynal };
186d677bfe2SMiquel Raynal const size_t command_size_offset = 2;
187d677bfe2SMiquel Raynal const size_t index_offset = 10;
188d677bfe2SMiquel Raynal const size_t length_offset = 18;
189d677bfe2SMiquel Raynal const size_t data_offset = 22;
190d677bfe2SMiquel Raynal const size_t write_info_size = 12;
191d677bfe2SMiquel Raynal const u32 total_length =
192d677bfe2SMiquel Raynal TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
193d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
194d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
195d677bfe2SMiquel Raynal u32 err;
196d677bfe2SMiquel Raynal
197d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sddds",
198d677bfe2SMiquel Raynal 0, command, sizeof(command),
199d677bfe2SMiquel Raynal command_size_offset, total_length,
200d677bfe2SMiquel Raynal index_offset, index,
201d677bfe2SMiquel Raynal length_offset, length,
202d677bfe2SMiquel Raynal data_offset, data, length))
203d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
204abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
205d677bfe2SMiquel Raynal if (err)
206d677bfe2SMiquel Raynal return err;
207d677bfe2SMiquel Raynal
208d677bfe2SMiquel Raynal return 0;
209d677bfe2SMiquel Raynal }
210d677bfe2SMiquel Raynal
tpm1_extend(struct udevice * dev,u32 index,const void * in_digest,void * out_digest)211*d7869cecSEddie James u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
212abdc7b8aSSimon Glass void *out_digest)
213d677bfe2SMiquel Raynal {
214d677bfe2SMiquel Raynal const u8 command[34] = {
215d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
216d677bfe2SMiquel Raynal };
217d677bfe2SMiquel Raynal const size_t index_offset = 10;
218d677bfe2SMiquel Raynal const size_t in_digest_offset = 14;
219d677bfe2SMiquel Raynal const size_t out_digest_offset = 10;
220d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE];
221d677bfe2SMiquel Raynal u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
222d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
223d677bfe2SMiquel Raynal u32 err;
224d677bfe2SMiquel Raynal
225d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sds",
226d677bfe2SMiquel Raynal 0, command, sizeof(command),
227d677bfe2SMiquel Raynal index_offset, index,
228d677bfe2SMiquel Raynal in_digest_offset, in_digest,
229d677bfe2SMiquel Raynal PCR_DIGEST_LENGTH))
230d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
231abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
232d677bfe2SMiquel Raynal if (err)
233d677bfe2SMiquel Raynal return err;
234d677bfe2SMiquel Raynal
235d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
236d677bfe2SMiquel Raynal out_digest_offset, out_digest,
237d677bfe2SMiquel Raynal PCR_DIGEST_LENGTH))
238d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
239d677bfe2SMiquel Raynal
240d677bfe2SMiquel Raynal return 0;
241d677bfe2SMiquel Raynal }
242d677bfe2SMiquel Raynal
tpm1_pcr_read(struct udevice * dev,u32 index,void * data,size_t count)243*d7869cecSEddie James u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
244d677bfe2SMiquel Raynal {
245d677bfe2SMiquel Raynal const u8 command[14] = {
246d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
247d677bfe2SMiquel Raynal };
248d677bfe2SMiquel Raynal const size_t index_offset = 10;
249d677bfe2SMiquel Raynal const size_t out_digest_offset = 10;
250d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
251d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
252d677bfe2SMiquel Raynal u32 err;
253d677bfe2SMiquel Raynal
254d677bfe2SMiquel Raynal if (count < PCR_DIGEST_LENGTH)
255d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
256d677bfe2SMiquel Raynal
257d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sd",
258d677bfe2SMiquel Raynal 0, command, sizeof(command),
259d677bfe2SMiquel Raynal index_offset, index))
260d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
261abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
262d677bfe2SMiquel Raynal if (err)
263d677bfe2SMiquel Raynal return err;
264d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
265d677bfe2SMiquel Raynal out_digest_offset, data, PCR_DIGEST_LENGTH))
266d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
267d677bfe2SMiquel Raynal
268d677bfe2SMiquel Raynal return 0;
269d677bfe2SMiquel Raynal }
270d677bfe2SMiquel Raynal
tpm1_tsc_physical_presence(struct udevice * dev,u16 presence)271*d7869cecSEddie James u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence)
272d677bfe2SMiquel Raynal {
273d677bfe2SMiquel Raynal const u8 command[12] = {
274d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
275d677bfe2SMiquel Raynal };
276d677bfe2SMiquel Raynal const size_t presence_offset = 10;
277d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE];
278d677bfe2SMiquel Raynal
279d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sw",
280d677bfe2SMiquel Raynal 0, command, sizeof(command),
281d677bfe2SMiquel Raynal presence_offset, presence))
282d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
283d677bfe2SMiquel Raynal
284abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, buf, NULL, NULL);
285d677bfe2SMiquel Raynal }
286d677bfe2SMiquel Raynal
tpm1_finalise_physical_presence(struct udevice * dev)287*d7869cecSEddie James u32 tpm1_finalise_physical_presence(struct udevice *dev)
2886e64ec12SSimon Glass {
2896e64ec12SSimon Glass const u8 command[12] = {
2906e64ec12SSimon Glass 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
2916e64ec12SSimon Glass };
2926e64ec12SSimon Glass
293abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
2946e64ec12SSimon Glass }
2956e64ec12SSimon Glass
tpm1_read_pubek(struct udevice * dev,void * data,size_t count)296*d7869cecSEddie James u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count)
297d677bfe2SMiquel Raynal {
298d677bfe2SMiquel Raynal const u8 command[30] = {
299d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
300d677bfe2SMiquel Raynal };
301d677bfe2SMiquel Raynal const size_t response_size_offset = 2;
302d677bfe2SMiquel Raynal const size_t data_offset = 10;
303d677bfe2SMiquel Raynal const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
304d677bfe2SMiquel Raynal u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
305d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
306d677bfe2SMiquel Raynal u32 data_size;
307d677bfe2SMiquel Raynal u32 err;
308d677bfe2SMiquel Raynal
309abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, command, response, &response_length);
310d677bfe2SMiquel Raynal if (err)
311d677bfe2SMiquel Raynal return err;
312d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
313d677bfe2SMiquel Raynal response_size_offset, &data_size))
314d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
315d677bfe2SMiquel Raynal if (data_size < header_and_checksum_size)
316d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
317d677bfe2SMiquel Raynal data_size -= header_and_checksum_size;
318d677bfe2SMiquel Raynal if (data_size > count)
319d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
320d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
321d677bfe2SMiquel Raynal data_offset, data, data_size))
322d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
323d677bfe2SMiquel Raynal
324d677bfe2SMiquel Raynal return 0;
325d677bfe2SMiquel Raynal }
326d677bfe2SMiquel Raynal
tpm1_force_clear(struct udevice * dev)327*d7869cecSEddie James u32 tpm1_force_clear(struct udevice *dev)
328d677bfe2SMiquel Raynal {
329d677bfe2SMiquel Raynal const u8 command[10] = {
330d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
331d677bfe2SMiquel Raynal };
332d677bfe2SMiquel Raynal
333abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
334d677bfe2SMiquel Raynal }
335d677bfe2SMiquel Raynal
tpm1_physical_enable(struct udevice * dev)336*d7869cecSEddie James u32 tpm1_physical_enable(struct udevice *dev)
337d677bfe2SMiquel Raynal {
338d677bfe2SMiquel Raynal const u8 command[10] = {
339d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
340d677bfe2SMiquel Raynal };
341d677bfe2SMiquel Raynal
342abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
343d677bfe2SMiquel Raynal }
344d677bfe2SMiquel Raynal
tpm1_physical_disable(struct udevice * dev)345*d7869cecSEddie James u32 tpm1_physical_disable(struct udevice *dev)
346d677bfe2SMiquel Raynal {
347d677bfe2SMiquel Raynal const u8 command[10] = {
348d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
349d677bfe2SMiquel Raynal };
350d677bfe2SMiquel Raynal
351abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, command, NULL, NULL);
352d677bfe2SMiquel Raynal }
353d677bfe2SMiquel Raynal
tpm1_physical_set_deactivated(struct udevice * dev,u8 state)354*d7869cecSEddie James u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state)
355d677bfe2SMiquel Raynal {
356d677bfe2SMiquel Raynal const u8 command[11] = {
357d677bfe2SMiquel Raynal 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
358d677bfe2SMiquel Raynal };
359d677bfe2SMiquel Raynal const size_t state_offset = 10;
360d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE];
361d677bfe2SMiquel Raynal
362d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sb",
363d677bfe2SMiquel Raynal 0, command, sizeof(command),
364d677bfe2SMiquel Raynal state_offset, state))
365d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
366d677bfe2SMiquel Raynal
367abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, buf, NULL, NULL);
368d677bfe2SMiquel Raynal }
369d677bfe2SMiquel Raynal
tpm1_get_capability(struct udevice * dev,u32 cap_area,u32 sub_cap,void * cap,size_t count)370*d7869cecSEddie James u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
371abdc7b8aSSimon Glass void *cap, size_t count)
372d677bfe2SMiquel Raynal {
373d677bfe2SMiquel Raynal const u8 command[22] = {
374d677bfe2SMiquel Raynal 0x0, 0xc1, /* TPM_TAG */
375d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x16, /* parameter size */
376d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
377d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
378d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x4, /* subcap size */
379d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x0, /* subcap value */
380d677bfe2SMiquel Raynal };
381d677bfe2SMiquel Raynal const size_t cap_area_offset = 10;
382d677bfe2SMiquel Raynal const size_t sub_cap_offset = 18;
383d677bfe2SMiquel Raynal const size_t cap_offset = 14;
384d677bfe2SMiquel Raynal const size_t cap_size_offset = 10;
385d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
386d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
387d677bfe2SMiquel Raynal u32 cap_size;
388d677bfe2SMiquel Raynal u32 err;
389d677bfe2SMiquel Raynal
390d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sdd",
391d677bfe2SMiquel Raynal 0, command, sizeof(command),
392d677bfe2SMiquel Raynal cap_area_offset, cap_area,
393d677bfe2SMiquel Raynal sub_cap_offset, sub_cap))
394d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
395abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
396d677bfe2SMiquel Raynal if (err)
397d677bfe2SMiquel Raynal return err;
398d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
399d677bfe2SMiquel Raynal cap_size_offset, &cap_size))
400d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
401d677bfe2SMiquel Raynal if (cap_size > response_length || cap_size > count)
402d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
403d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
404d677bfe2SMiquel Raynal cap_offset, cap, cap_size))
405d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
406d677bfe2SMiquel Raynal
407d677bfe2SMiquel Raynal return 0;
408d677bfe2SMiquel Raynal }
409d677bfe2SMiquel Raynal
tpm1_get_permanent_flags(struct udevice * dev,struct tpm_permanent_flags * pflags)410*d7869cecSEddie James u32 tpm1_get_permanent_flags(struct udevice *dev,
411abdc7b8aSSimon Glass struct tpm_permanent_flags *pflags)
412d677bfe2SMiquel Raynal {
413d677bfe2SMiquel Raynal const u8 command[22] = {
414d677bfe2SMiquel Raynal 0x0, 0xc1, /* TPM_TAG */
415d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x16, /* parameter size */
416d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
417d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
418d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x4, /* subcap size */
419d677bfe2SMiquel Raynal 0x0, 0x0, 0x1, 0x8, /* subcap value */
420d677bfe2SMiquel Raynal };
421d677bfe2SMiquel Raynal const size_t data_size_offset = TPM_HEADER_SIZE;
422d677bfe2SMiquel Raynal const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
423d677bfe2SMiquel Raynal u8 response[COMMAND_BUFFER_SIZE];
424d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
425d677bfe2SMiquel Raynal u32 err;
426d677bfe2SMiquel Raynal u32 data_size;
427d677bfe2SMiquel Raynal
428abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, command, response, &response_length);
429d677bfe2SMiquel Raynal if (err)
430d677bfe2SMiquel Raynal return err;
431d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
4326e64ec12SSimon Glass data_size_offset, &data_size)) {
4336e64ec12SSimon Glass log_err("Cannot unpack data size\n");
434d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
4356e64ec12SSimon Glass }
4366e64ec12SSimon Glass if (data_size < sizeof(*pflags)) {
4376e64ec12SSimon Glass log_err("Data size too small\n");
438d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
4396e64ec12SSimon Glass }
440d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
4416e64ec12SSimon Glass data_offset, pflags, sizeof(*pflags))) {
4426e64ec12SSimon Glass log_err("Cannot unpack pflags\n");
443d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
4446e64ec12SSimon Glass }
445d677bfe2SMiquel Raynal
446d677bfe2SMiquel Raynal return 0;
447d677bfe2SMiquel Raynal }
448d677bfe2SMiquel Raynal
tpm1_get_permissions(struct udevice * dev,u32 index,u32 * perm)449*d7869cecSEddie James u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
450d677bfe2SMiquel Raynal {
451d677bfe2SMiquel Raynal const u8 command[22] = {
452d677bfe2SMiquel Raynal 0x0, 0xc1, /* TPM_TAG */
453d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x16, /* parameter size */
454d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
455d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x11,
456d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x4,
457d677bfe2SMiquel Raynal };
458d677bfe2SMiquel Raynal const size_t index_offset = 18;
459*d7869cecSEddie James const size_t perm_offset = 74;
460d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
461d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
462d677bfe2SMiquel Raynal u32 err;
463d677bfe2SMiquel Raynal
464*d7869cecSEddie James if (pack_byte_string(buf, sizeof(buf), "sd",
465*d7869cecSEddie James 0, command, sizeof(command),
466d677bfe2SMiquel Raynal index_offset, index))
467d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
468abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
469d677bfe2SMiquel Raynal if (err)
470d677bfe2SMiquel Raynal return err;
471d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
472d677bfe2SMiquel Raynal perm_offset, perm))
473d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
474d677bfe2SMiquel Raynal
475d677bfe2SMiquel Raynal return 0;
476d677bfe2SMiquel Raynal }
477d677bfe2SMiquel Raynal
478d677bfe2SMiquel Raynal #ifdef CONFIG_TPM_FLUSH_RESOURCES
tpm1_flush_specific(struct udevice * dev,u32 key_handle,u32 resource_type)479*d7869cecSEddie James u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
480d677bfe2SMiquel Raynal {
481d677bfe2SMiquel Raynal const u8 command[18] = {
482d677bfe2SMiquel Raynal 0x00, 0xc1, /* TPM_TAG */
483d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x12, /* parameter size */
484d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
485d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* key handle */
486d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* resource type */
487d677bfe2SMiquel Raynal };
488d677bfe2SMiquel Raynal const size_t key_handle_offset = 10;
489d677bfe2SMiquel Raynal const size_t resource_type_offset = 14;
490d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
491d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
492d677bfe2SMiquel Raynal u32 err;
493d677bfe2SMiquel Raynal
494d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sdd",
495d677bfe2SMiquel Raynal 0, command, sizeof(command),
496d677bfe2SMiquel Raynal key_handle_offset, key_handle,
497d677bfe2SMiquel Raynal resource_type_offset, resource_type))
498d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
499d677bfe2SMiquel Raynal
500abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response, &response_length);
501d677bfe2SMiquel Raynal if (err)
502d677bfe2SMiquel Raynal return err;
503d677bfe2SMiquel Raynal return 0;
504d677bfe2SMiquel Raynal }
505d677bfe2SMiquel Raynal #endif /* CONFIG_TPM_FLUSH_RESOURCES */
506d677bfe2SMiquel Raynal
507d677bfe2SMiquel Raynal #ifdef CONFIG_TPM_AUTH_SESSIONS
508d677bfe2SMiquel Raynal
509d677bfe2SMiquel Raynal /**
510d677bfe2SMiquel Raynal * Fill an authentication block in a request.
511d677bfe2SMiquel Raynal * This func can create the first as well as the second auth block (for
512d677bfe2SMiquel Raynal * double authorized commands).
513d677bfe2SMiquel Raynal *
514d677bfe2SMiquel Raynal * @param request pointer to the request (w/ uninitialised auth data)
515d677bfe2SMiquel Raynal * @param request_len0 length of the request without auth data
516d677bfe2SMiquel Raynal * @param handles_len length of the handles area in request
517d677bfe2SMiquel Raynal * @param auth_session pointer to the (valid) auth session to be used
518d677bfe2SMiquel Raynal * @param request_auth pointer to the auth block of the request to be filled
519d677bfe2SMiquel Raynal * @param auth authentication data (HMAC key)
520d677bfe2SMiquel Raynal */
create_request_auth(const void * request,size_t request_len0,size_t handles_len,struct session_data * auth_session,void * request_auth,const void * auth)521d677bfe2SMiquel Raynal static u32 create_request_auth(const void *request, size_t request_len0,
522d677bfe2SMiquel Raynal size_t handles_len,
523d677bfe2SMiquel Raynal struct session_data *auth_session,
524d677bfe2SMiquel Raynal void *request_auth, const void *auth)
525d677bfe2SMiquel Raynal {
526d677bfe2SMiquel Raynal u8 hmac_data[DIGEST_LENGTH * 3 + 1];
527d677bfe2SMiquel Raynal sha1_context hash_ctx;
528d677bfe2SMiquel Raynal const size_t command_code_offset = 6;
529d677bfe2SMiquel Raynal const size_t auth_nonce_odd_offset = 4;
530d677bfe2SMiquel Raynal const size_t auth_continue_offset = 24;
531d677bfe2SMiquel Raynal const size_t auth_auth_offset = 25;
532d677bfe2SMiquel Raynal
533d677bfe2SMiquel Raynal if (!auth_session || !auth_session->valid)
534d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
535d677bfe2SMiquel Raynal
536d677bfe2SMiquel Raynal sha1_starts(&hash_ctx);
537d677bfe2SMiquel Raynal sha1_update(&hash_ctx, request + command_code_offset, 4);
538d677bfe2SMiquel Raynal if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
539d677bfe2SMiquel Raynal sha1_update(&hash_ctx,
540d677bfe2SMiquel Raynal request + TPM_REQUEST_HEADER_LENGTH + handles_len,
541d677bfe2SMiquel Raynal request_len0 - TPM_REQUEST_HEADER_LENGTH
542d677bfe2SMiquel Raynal - handles_len);
543d677bfe2SMiquel Raynal sha1_finish(&hash_ctx, hmac_data);
544d677bfe2SMiquel Raynal
545d677bfe2SMiquel Raynal sha1_starts(&hash_ctx);
546d677bfe2SMiquel Raynal sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
547d677bfe2SMiquel Raynal sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
548d677bfe2SMiquel Raynal sha1_finish(&hash_ctx, auth_session->nonce_odd);
549d677bfe2SMiquel Raynal
550d677bfe2SMiquel Raynal if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
551d677bfe2SMiquel Raynal 0, auth_session->handle,
552d677bfe2SMiquel Raynal auth_nonce_odd_offset, auth_session->nonce_odd,
553d677bfe2SMiquel Raynal DIGEST_LENGTH,
554d677bfe2SMiquel Raynal auth_continue_offset, 1))
555d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
556d677bfe2SMiquel Raynal if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
557d677bfe2SMiquel Raynal DIGEST_LENGTH,
558d677bfe2SMiquel Raynal auth_session->nonce_even,
559d677bfe2SMiquel Raynal DIGEST_LENGTH,
560d677bfe2SMiquel Raynal 2 * DIGEST_LENGTH,
561d677bfe2SMiquel Raynal request_auth + auth_nonce_odd_offset,
562d677bfe2SMiquel Raynal DIGEST_LENGTH + 1))
563d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
564d677bfe2SMiquel Raynal sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
565d677bfe2SMiquel Raynal request_auth + auth_auth_offset);
566d677bfe2SMiquel Raynal
567d677bfe2SMiquel Raynal return TPM_SUCCESS;
568d677bfe2SMiquel Raynal }
569d677bfe2SMiquel Raynal
570d677bfe2SMiquel Raynal /**
571d677bfe2SMiquel Raynal * Verify an authentication block in a response.
572d677bfe2SMiquel Raynal * Since this func updates the nonce_even in the session data it has to be
573d677bfe2SMiquel Raynal * called when receiving a succesfull AUTH response.
574d677bfe2SMiquel Raynal * This func can verify the first as well as the second auth block (for
575d677bfe2SMiquel Raynal * double authorized commands).
576d677bfe2SMiquel Raynal *
577d677bfe2SMiquel Raynal * @param command_code command code of the request
578d677bfe2SMiquel Raynal * @param response pointer to the request (w/ uninitialised auth data)
579d677bfe2SMiquel Raynal * @param handles_len length of the handles area in response
580d677bfe2SMiquel Raynal * @param auth_session pointer to the (valid) auth session to be used
581d677bfe2SMiquel Raynal * @param response_auth pointer to the auth block of the response to be verified
582d677bfe2SMiquel Raynal * @param auth authentication data (HMAC key)
583d677bfe2SMiquel Raynal */
verify_response_auth(u32 command_code,const void * response,size_t response_len0,size_t handles_len,struct session_data * auth_session,const void * response_auth,const void * auth)584d677bfe2SMiquel Raynal static u32 verify_response_auth(u32 command_code, const void *response,
585d677bfe2SMiquel Raynal size_t response_len0, size_t handles_len,
586d677bfe2SMiquel Raynal struct session_data *auth_session,
587d677bfe2SMiquel Raynal const void *response_auth, const void *auth)
588d677bfe2SMiquel Raynal {
589d677bfe2SMiquel Raynal u8 hmac_data[DIGEST_LENGTH * 3 + 1];
590d677bfe2SMiquel Raynal u8 computed_auth[DIGEST_LENGTH];
591d677bfe2SMiquel Raynal sha1_context hash_ctx;
592d677bfe2SMiquel Raynal const size_t return_code_offset = 6;
593d677bfe2SMiquel Raynal const size_t auth_continue_offset = 20;
594d677bfe2SMiquel Raynal const size_t auth_auth_offset = 21;
595d677bfe2SMiquel Raynal u8 auth_continue;
596d677bfe2SMiquel Raynal
597d677bfe2SMiquel Raynal if (!auth_session || !auth_session->valid)
598d677bfe2SMiquel Raynal return TPM_AUTHFAIL;
599d677bfe2SMiquel Raynal if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
600d677bfe2SMiquel Raynal 0, command_code))
601d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
602d677bfe2SMiquel Raynal if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
603d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
604d677bfe2SMiquel Raynal
605d677bfe2SMiquel Raynal sha1_starts(&hash_ctx);
606d677bfe2SMiquel Raynal sha1_update(&hash_ctx, response + return_code_offset, 4);
607d677bfe2SMiquel Raynal sha1_update(&hash_ctx, hmac_data, 4);
608d677bfe2SMiquel Raynal if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
609d677bfe2SMiquel Raynal sha1_update(&hash_ctx,
610d677bfe2SMiquel Raynal response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
611d677bfe2SMiquel Raynal response_len0 - TPM_RESPONSE_HEADER_LENGTH
612d677bfe2SMiquel Raynal - handles_len);
613d677bfe2SMiquel Raynal sha1_finish(&hash_ctx, hmac_data);
614d677bfe2SMiquel Raynal
615d677bfe2SMiquel Raynal memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
616d677bfe2SMiquel Raynal auth_continue = ((u8 *)response_auth)[auth_continue_offset];
617d677bfe2SMiquel Raynal if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
618d677bfe2SMiquel Raynal DIGEST_LENGTH,
619d677bfe2SMiquel Raynal response_auth,
620d677bfe2SMiquel Raynal DIGEST_LENGTH,
621d677bfe2SMiquel Raynal 2 * DIGEST_LENGTH,
622d677bfe2SMiquel Raynal auth_session->nonce_odd,
623d677bfe2SMiquel Raynal DIGEST_LENGTH,
624d677bfe2SMiquel Raynal 3 * DIGEST_LENGTH,
625d677bfe2SMiquel Raynal auth_continue))
626d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
627d677bfe2SMiquel Raynal
628d677bfe2SMiquel Raynal sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
629d677bfe2SMiquel Raynal computed_auth);
630d677bfe2SMiquel Raynal
631d677bfe2SMiquel Raynal if (memcmp(computed_auth, response_auth + auth_auth_offset,
632d677bfe2SMiquel Raynal DIGEST_LENGTH))
633d677bfe2SMiquel Raynal return TPM_AUTHFAIL;
634d677bfe2SMiquel Raynal
635d677bfe2SMiquel Raynal return TPM_SUCCESS;
636d677bfe2SMiquel Raynal }
637d677bfe2SMiquel Raynal
tpm1_terminate_auth_session(struct udevice * dev,u32 auth_handle)638*d7869cecSEddie James u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle)
639d677bfe2SMiquel Raynal {
640d677bfe2SMiquel Raynal const u8 command[18] = {
641d677bfe2SMiquel Raynal 0x00, 0xc1, /* TPM_TAG */
642d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* parameter size */
643d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
644d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
645d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
646d677bfe2SMiquel Raynal };
647d677bfe2SMiquel Raynal const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
648d677bfe2SMiquel Raynal u8 request[COMMAND_BUFFER_SIZE];
649d677bfe2SMiquel Raynal
650d677bfe2SMiquel Raynal if (pack_byte_string(request, sizeof(request), "sd",
651d677bfe2SMiquel Raynal 0, command, sizeof(command),
652d677bfe2SMiquel Raynal req_handle_offset, auth_handle))
653d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
654d677bfe2SMiquel Raynal if (oiap_session.valid && oiap_session.handle == auth_handle)
655d677bfe2SMiquel Raynal oiap_session.valid = 0;
656d677bfe2SMiquel Raynal
657abdc7b8aSSimon Glass return tpm_sendrecv_command(dev, request, NULL, NULL);
658d677bfe2SMiquel Raynal }
659d677bfe2SMiquel Raynal
tpm1_end_oiap(struct udevice * dev)660*d7869cecSEddie James u32 tpm1_end_oiap(struct udevice *dev)
661d677bfe2SMiquel Raynal {
662d677bfe2SMiquel Raynal u32 err = TPM_SUCCESS;
663d677bfe2SMiquel Raynal
664d677bfe2SMiquel Raynal if (oiap_session.valid)
665*d7869cecSEddie James err = tpm1_terminate_auth_session(dev, oiap_session.handle);
666d677bfe2SMiquel Raynal return err;
667d677bfe2SMiquel Raynal }
668d677bfe2SMiquel Raynal
tpm1_oiap(struct udevice * dev,u32 * auth_handle)669*d7869cecSEddie James u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle)
670d677bfe2SMiquel Raynal {
671d677bfe2SMiquel Raynal const u8 command[10] = {
672d677bfe2SMiquel Raynal 0x00, 0xc1, /* TPM_TAG */
673d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x0a, /* parameter size */
674d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
675d677bfe2SMiquel Raynal };
676d677bfe2SMiquel Raynal const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
677d677bfe2SMiquel Raynal const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
678d677bfe2SMiquel Raynal u8 response[COMMAND_BUFFER_SIZE];
679d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
680d677bfe2SMiquel Raynal u32 err;
681d677bfe2SMiquel Raynal
682d677bfe2SMiquel Raynal if (oiap_session.valid)
683*d7869cecSEddie James tpm1_terminate_auth_session(dev, oiap_session.handle);
684d677bfe2SMiquel Raynal
685abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, command, response, &response_length);
686d677bfe2SMiquel Raynal if (err)
687d677bfe2SMiquel Raynal return err;
688d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "ds",
689d677bfe2SMiquel Raynal res_auth_handle_offset, &oiap_session.handle,
690d677bfe2SMiquel Raynal res_nonce_even_offset, &oiap_session.nonce_even,
691d677bfe2SMiquel Raynal (u32)DIGEST_LENGTH))
692d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
693d677bfe2SMiquel Raynal oiap_session.valid = 1;
694d677bfe2SMiquel Raynal if (auth_handle)
695d677bfe2SMiquel Raynal *auth_handle = oiap_session.handle;
696d677bfe2SMiquel Raynal return 0;
697d677bfe2SMiquel Raynal }
698d677bfe2SMiquel Raynal
tpm1_load_key2_oiap(struct udevice * dev,u32 parent_handle,const void * key,size_t key_length,const void * parent_key_usage_auth,u32 * key_handle)699*d7869cecSEddie James u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
700abdc7b8aSSimon Glass size_t key_length, const void *parent_key_usage_auth,
701abdc7b8aSSimon Glass u32 *key_handle)
702d677bfe2SMiquel Raynal {
703d677bfe2SMiquel Raynal const u8 command[14] = {
704d677bfe2SMiquel Raynal 0x00, 0xc2, /* TPM_TAG */
705d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* parameter size */
706d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
707d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* parent handle */
708d677bfe2SMiquel Raynal };
709d677bfe2SMiquel Raynal const size_t req_size_offset = 2;
710d677bfe2SMiquel Raynal const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
711d677bfe2SMiquel Raynal const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
712d677bfe2SMiquel Raynal const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
713d677bfe2SMiquel Raynal u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
714d677bfe2SMiquel Raynal TPM_REQUEST_AUTH_LENGTH];
715d677bfe2SMiquel Raynal u8 response[COMMAND_BUFFER_SIZE];
716d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
717d677bfe2SMiquel Raynal u32 err;
718d677bfe2SMiquel Raynal
719d677bfe2SMiquel Raynal if (!oiap_session.valid) {
720*d7869cecSEddie James err = tpm1_oiap(dev, NULL);
721d677bfe2SMiquel Raynal if (err)
722d677bfe2SMiquel Raynal return err;
723d677bfe2SMiquel Raynal }
724d677bfe2SMiquel Raynal if (pack_byte_string(request, sizeof(request), "sdds",
725d677bfe2SMiquel Raynal 0, command, sizeof(command),
726d677bfe2SMiquel Raynal req_size_offset,
727d677bfe2SMiquel Raynal sizeof(command) + key_length
728d677bfe2SMiquel Raynal + TPM_REQUEST_AUTH_LENGTH,
729d677bfe2SMiquel Raynal req_parent_handle_offset, parent_handle,
730d677bfe2SMiquel Raynal req_key_offset, key, key_length
731d677bfe2SMiquel Raynal ))
732d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
733d677bfe2SMiquel Raynal
734d677bfe2SMiquel Raynal err = create_request_auth(request, sizeof(command) + key_length, 4,
735d677bfe2SMiquel Raynal &oiap_session,
736d677bfe2SMiquel Raynal request + sizeof(command) + key_length,
737d677bfe2SMiquel Raynal parent_key_usage_auth);
738d677bfe2SMiquel Raynal if (err)
739d677bfe2SMiquel Raynal return err;
740abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, request, response, &response_length);
741d677bfe2SMiquel Raynal if (err) {
742d677bfe2SMiquel Raynal if (err == TPM_AUTHFAIL)
743d677bfe2SMiquel Raynal oiap_session.valid = 0;
744d677bfe2SMiquel Raynal return err;
745d677bfe2SMiquel Raynal }
746d677bfe2SMiquel Raynal
747d677bfe2SMiquel Raynal err = verify_response_auth(0x00000041, response,
748d677bfe2SMiquel Raynal response_length - TPM_RESPONSE_AUTH_LENGTH,
749d677bfe2SMiquel Raynal 4, &oiap_session,
750d677bfe2SMiquel Raynal response + response_length -
751d677bfe2SMiquel Raynal TPM_RESPONSE_AUTH_LENGTH,
752d677bfe2SMiquel Raynal parent_key_usage_auth);
753d677bfe2SMiquel Raynal if (err)
754d677bfe2SMiquel Raynal return err;
755d677bfe2SMiquel Raynal
756d677bfe2SMiquel Raynal if (key_handle) {
757d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
758d677bfe2SMiquel Raynal res_handle_offset, key_handle))
759d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
760d677bfe2SMiquel Raynal }
761d677bfe2SMiquel Raynal
762d677bfe2SMiquel Raynal return 0;
763d677bfe2SMiquel Raynal }
764d677bfe2SMiquel Raynal
tpm1_get_pub_key_oiap(struct udevice * dev,u32 key_handle,const void * usage_auth,void * pubkey,size_t * pubkey_len)765*d7869cecSEddie James u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
766abdc7b8aSSimon Glass const void *usage_auth, void *pubkey,
767d677bfe2SMiquel Raynal size_t *pubkey_len)
768d677bfe2SMiquel Raynal {
769d677bfe2SMiquel Raynal const u8 command[14] = {
770d677bfe2SMiquel Raynal 0x00, 0xc2, /* TPM_TAG */
771d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* parameter size */
772d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
773d677bfe2SMiquel Raynal 0x00, 0x00, 0x00, 0x00, /* key handle */
774d677bfe2SMiquel Raynal };
775d677bfe2SMiquel Raynal const size_t req_size_offset = 2;
776d677bfe2SMiquel Raynal const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
777d677bfe2SMiquel Raynal const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
778d677bfe2SMiquel Raynal u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
779d677bfe2SMiquel Raynal u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
780d677bfe2SMiquel Raynal TPM_RESPONSE_AUTH_LENGTH];
781d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
782d677bfe2SMiquel Raynal u32 err;
783d677bfe2SMiquel Raynal
784d677bfe2SMiquel Raynal if (!oiap_session.valid) {
785*d7869cecSEddie James err = tpm1_oiap(dev, NULL);
786d677bfe2SMiquel Raynal if (err)
787d677bfe2SMiquel Raynal return err;
788d677bfe2SMiquel Raynal }
789d677bfe2SMiquel Raynal if (pack_byte_string(request, sizeof(request), "sdd",
790d677bfe2SMiquel Raynal 0, command, sizeof(command),
791d677bfe2SMiquel Raynal req_size_offset,
792d677bfe2SMiquel Raynal (u32)(sizeof(command)
793d677bfe2SMiquel Raynal + TPM_REQUEST_AUTH_LENGTH),
794d677bfe2SMiquel Raynal req_key_handle_offset, key_handle
795d677bfe2SMiquel Raynal ))
796d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
797d677bfe2SMiquel Raynal err = create_request_auth(request, sizeof(command), 4, &oiap_session,
798d677bfe2SMiquel Raynal request + sizeof(command), usage_auth);
799d677bfe2SMiquel Raynal if (err)
800d677bfe2SMiquel Raynal return err;
801abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, request, response, &response_length);
802d677bfe2SMiquel Raynal if (err) {
803d677bfe2SMiquel Raynal if (err == TPM_AUTHFAIL)
804d677bfe2SMiquel Raynal oiap_session.valid = 0;
805d677bfe2SMiquel Raynal return err;
806d677bfe2SMiquel Raynal }
807d677bfe2SMiquel Raynal err = verify_response_auth(0x00000021, response,
808d677bfe2SMiquel Raynal response_length - TPM_RESPONSE_AUTH_LENGTH,
809d677bfe2SMiquel Raynal 0, &oiap_session,
810d677bfe2SMiquel Raynal response + response_length -
811d677bfe2SMiquel Raynal TPM_RESPONSE_AUTH_LENGTH,
812d677bfe2SMiquel Raynal usage_auth);
813d677bfe2SMiquel Raynal if (err)
814d677bfe2SMiquel Raynal return err;
815d677bfe2SMiquel Raynal
816d677bfe2SMiquel Raynal if (pubkey) {
817d677bfe2SMiquel Raynal if ((response_length - TPM_RESPONSE_HEADER_LENGTH
818d677bfe2SMiquel Raynal - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
819d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
820d677bfe2SMiquel Raynal *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
821d677bfe2SMiquel Raynal - TPM_RESPONSE_AUTH_LENGTH;
822d677bfe2SMiquel Raynal memcpy(pubkey, response + res_pubkey_offset,
823d677bfe2SMiquel Raynal response_length - TPM_RESPONSE_HEADER_LENGTH
824d677bfe2SMiquel Raynal - TPM_RESPONSE_AUTH_LENGTH);
825d677bfe2SMiquel Raynal }
826d677bfe2SMiquel Raynal
827d677bfe2SMiquel Raynal return 0;
828d677bfe2SMiquel Raynal }
829d677bfe2SMiquel Raynal
830d677bfe2SMiquel Raynal #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
tpm1_find_key_sha1(struct udevice * dev,const u8 auth[20],const u8 pubkey_digest[20],u32 * handle)831*d7869cecSEddie James u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
832abdc7b8aSSimon Glass const u8 pubkey_digest[20], u32 *handle)
833d677bfe2SMiquel Raynal {
834d677bfe2SMiquel Raynal u16 key_count;
835d677bfe2SMiquel Raynal u32 key_handles[10];
836d677bfe2SMiquel Raynal u8 buf[288];
837d677bfe2SMiquel Raynal u8 *ptr;
838d677bfe2SMiquel Raynal u32 err;
839d677bfe2SMiquel Raynal u8 digest[20];
840d677bfe2SMiquel Raynal size_t buf_len;
841d677bfe2SMiquel Raynal unsigned int i;
842d677bfe2SMiquel Raynal
843d677bfe2SMiquel Raynal /* fetch list of already loaded keys in the TPM */
844*d7869cecSEddie James err = tpm1_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
845abdc7b8aSSimon Glass sizeof(buf));
846d677bfe2SMiquel Raynal if (err)
847d677bfe2SMiquel Raynal return -1;
848d677bfe2SMiquel Raynal key_count = get_unaligned_be16(buf);
849d677bfe2SMiquel Raynal ptr = buf + 2;
850d677bfe2SMiquel Raynal for (i = 0; i < key_count; ++i, ptr += 4)
851d677bfe2SMiquel Raynal key_handles[i] = get_unaligned_be32(ptr);
852d677bfe2SMiquel Raynal
853d677bfe2SMiquel Raynal /* now search a(/ the) key which we can access with the given auth */
854d677bfe2SMiquel Raynal for (i = 0; i < key_count; ++i) {
855d677bfe2SMiquel Raynal buf_len = sizeof(buf);
856*d7869cecSEddie James err = tpm1_get_pub_key_oiap(dev, key_handles[i], auth, buf, &buf_len);
857d677bfe2SMiquel Raynal if (err && err != TPM_AUTHFAIL)
858d677bfe2SMiquel Raynal return -1;
859d677bfe2SMiquel Raynal if (err)
860d677bfe2SMiquel Raynal continue;
861d677bfe2SMiquel Raynal sha1_csum(buf, buf_len, digest);
862d677bfe2SMiquel Raynal if (!memcmp(digest, pubkey_digest, 20)) {
863d677bfe2SMiquel Raynal *handle = key_handles[i];
864d677bfe2SMiquel Raynal return 0;
865d677bfe2SMiquel Raynal }
866d677bfe2SMiquel Raynal }
867d677bfe2SMiquel Raynal return 1;
868d677bfe2SMiquel Raynal }
869d677bfe2SMiquel Raynal #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
870d677bfe2SMiquel Raynal
871d677bfe2SMiquel Raynal #endif /* CONFIG_TPM_AUTH_SESSIONS */
872d677bfe2SMiquel Raynal
tpm1_get_random(struct udevice * dev,void * data,u32 count)873*d7869cecSEddie James u32 tpm1_get_random(struct udevice *dev, void *data, u32 count)
874d677bfe2SMiquel Raynal {
875d677bfe2SMiquel Raynal const u8 command[14] = {
876d677bfe2SMiquel Raynal 0x0, 0xc1, /* TPM_TAG */
877d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0xe, /* parameter size */
878d677bfe2SMiquel Raynal 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
879d677bfe2SMiquel Raynal };
880d677bfe2SMiquel Raynal const size_t length_offset = 10;
881d677bfe2SMiquel Raynal const size_t data_size_offset = 10;
882d677bfe2SMiquel Raynal const size_t data_offset = 14;
883d677bfe2SMiquel Raynal u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
884d677bfe2SMiquel Raynal size_t response_length = sizeof(response);
885d677bfe2SMiquel Raynal u32 data_size;
886d677bfe2SMiquel Raynal u8 *out = data;
887d677bfe2SMiquel Raynal
888d677bfe2SMiquel Raynal while (count > 0) {
889d677bfe2SMiquel Raynal u32 this_bytes = min((size_t)count,
890d677bfe2SMiquel Raynal sizeof(response) - data_offset);
891d677bfe2SMiquel Raynal u32 err;
892d677bfe2SMiquel Raynal
893d677bfe2SMiquel Raynal if (pack_byte_string(buf, sizeof(buf), "sd",
894d677bfe2SMiquel Raynal 0, command, sizeof(command),
895d677bfe2SMiquel Raynal length_offset, this_bytes))
896d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
897abdc7b8aSSimon Glass err = tpm_sendrecv_command(dev, buf, response,
898abdc7b8aSSimon Glass &response_length);
899d677bfe2SMiquel Raynal if (err)
900d677bfe2SMiquel Raynal return err;
901d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "d",
902d677bfe2SMiquel Raynal data_size_offset, &data_size))
903d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
904d677bfe2SMiquel Raynal if (data_size > count)
905d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
906d677bfe2SMiquel Raynal if (unpack_byte_string(response, response_length, "s",
907d677bfe2SMiquel Raynal data_offset, out, data_size))
908d677bfe2SMiquel Raynal return TPM_LIB_ERROR;
909d677bfe2SMiquel Raynal
910d677bfe2SMiquel Raynal count -= data_size;
911d677bfe2SMiquel Raynal out += data_size;
912d677bfe2SMiquel Raynal }
913d677bfe2SMiquel Raynal
914d677bfe2SMiquel Raynal return 0;
915d677bfe2SMiquel Raynal }
916