xref: /openbmc/u-boot/lib/tpm-v1.c (revision d7869cec072d613a4b9ee7e7432e295155d372f3)
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