1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2018 Bootlin
4 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
5 */
6
7#include <common.h>
8#include <command.h>
9#include <dm.h>
10#include <log.h>
11#include <mapmem.h>
12#include <tpm-common.h>
13#include <tpm-v2.h>
14#include "tpm-user-utils.h"
15
16static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
17			   char *const argv[])
18{
19	enum tpm2_startup_types mode;
20	struct udevice *dev;
21	int ret;
22
23	ret = get_tpm(&dev);
24	if (ret)
25		return ret;
26	if (argc != 2)
27		return CMD_RET_USAGE;
28
29	if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
30		mode = TPM2_SU_CLEAR;
31	} else if (!strcasecmp("TPM2_SU_STATE", argv[1])) {
32		mode = TPM2_SU_STATE;
33	} else {
34		printf("Couldn't recognize mode string: %s\n", argv[1]);
35		return CMD_RET_FAILURE;
36	}
37
38	return report_return_code(tpm2_startup(dev, mode));
39}
40
41static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc,
42			     char *const argv[])
43{
44	enum tpm2_yes_no full_test;
45	struct udevice *dev;
46	int ret;
47
48	ret = get_tpm(&dev);
49	if (ret)
50		return ret;
51	if (argc != 2)
52		return CMD_RET_USAGE;
53
54	if (!strcasecmp("full", argv[1])) {
55		full_test = TPMI_YES;
56	} else if (!strcasecmp("continue", argv[1])) {
57		full_test = TPMI_NO;
58	} else {
59		printf("Couldn't recognize test mode: %s\n", argv[1]);
60		return CMD_RET_FAILURE;
61	}
62
63	return report_return_code(tpm2_self_test(dev, full_test));
64}
65
66static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
67			 char *const argv[])
68{
69	u32 handle = 0;
70	const char *pw = (argc < 3) ? NULL : argv[2];
71	const ssize_t pw_sz = pw ? strlen(pw) : 0;
72	struct udevice *dev;
73	int ret;
74
75	ret = get_tpm(&dev);
76	if (ret)
77		return ret;
78
79	if (argc < 2 || argc > 3)
80		return CMD_RET_USAGE;
81
82	if (pw_sz > TPM2_DIGEST_LEN)
83		return -EINVAL;
84
85	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
86		handle = TPM2_RH_LOCKOUT;
87	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
88		handle = TPM2_RH_PLATFORM;
89	else
90		return CMD_RET_USAGE;
91
92	return report_return_code(tpm2_clear(dev, handle, pw, pw_sz));
93}
94
95static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
96			      char *const argv[])
97{
98	struct udevice *dev;
99	struct tpm_chip_priv *priv;
100	u32 index = simple_strtoul(argv[1], NULL, 0);
101	void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
102	int ret;
103	u32 rc;
104
105	if (argc != 3)
106		return CMD_RET_USAGE;
107
108	ret = get_tpm(&dev);
109	if (ret)
110		return ret;
111
112	priv = dev_get_uclass_priv(dev);
113	if (!priv)
114		return -EINVAL;
115
116	if (index >= priv->pcr_count)
117		return -EINVAL;
118
119	rc = tpm2_pcr_extend(dev, index, TPM2_ALG_SHA256, digest,
120			     TPM2_DIGEST_LEN);
121
122	unmap_sysmem(digest);
123
124	return report_return_code(rc);
125}
126
127static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
128			   char *const argv[])
129{
130	struct udevice *dev;
131	struct tpm_chip_priv *priv;
132	u32 index, rc;
133	unsigned int updates;
134	void *data;
135	int ret;
136
137	if (argc != 3)
138		return CMD_RET_USAGE;
139
140	ret = get_tpm(&dev);
141	if (ret)
142		return ret;
143
144	priv = dev_get_uclass_priv(dev);
145	if (!priv)
146		return -EINVAL;
147
148	index = simple_strtoul(argv[1], NULL, 0);
149	if (index >= priv->pcr_count)
150		return -EINVAL;
151
152	data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
153
154	rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, TPM2_ALG_SHA256,
155			   data, TPM2_DIGEST_LEN, &updates);
156	if (!rc) {
157		printf("PCR #%u content (%u known updates):\n", index, updates);
158		print_byte_string(data, TPM2_DIGEST_LEN);
159	}
160
161	unmap_sysmem(data);
162
163	return report_return_code(rc);
164}
165
166static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
167				 char *const argv[])
168{
169	u32 capability, property, rc;
170	u8 *data;
171	size_t count;
172	int i, j;
173	struct udevice *dev;
174	int ret;
175
176	ret = get_tpm(&dev);
177	if (ret)
178		return ret;
179
180	if (argc != 5)
181		return CMD_RET_USAGE;
182
183	capability = simple_strtoul(argv[1], NULL, 0);
184	property = simple_strtoul(argv[2], NULL, 0);
185	data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
186	count = simple_strtoul(argv[4], NULL, 0);
187
188	rc = tpm2_get_capability(dev, capability, property, data, count);
189	if (rc)
190		goto unmap_data;
191
192	printf("Capabilities read from TPM:\n");
193	for (i = 0; i < count; i++) {
194		printf("Property 0x");
195		for (j = 0; j < 4; j++)
196			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
197		printf(": 0x");
198		for (j = 4; j < 8; j++)
199			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
200		printf("\n");
201	}
202
203unmap_data:
204	unmap_sysmem(data);
205
206	return report_return_code(rc);
207}
208
209static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
210			    char *const argv[])
211{
212	const char *pw = (argc < 2) ? NULL : argv[1];
213	const ssize_t pw_sz = pw ? strlen(pw) : 0;
214	struct udevice *dev;
215	int ret;
216
217	ret = get_tpm(&dev);
218	if (ret)
219		return ret;
220
221	if (argc > 2)
222		return CMD_RET_USAGE;
223
224	if (pw_sz > TPM2_DIGEST_LEN)
225		return -EINVAL;
226
227	return report_return_code(tpm2_dam_reset(dev, pw, pw_sz));
228}
229
230static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
231				 char *const argv[])
232{
233	const char *pw = (argc < 5) ? NULL : argv[4];
234	const ssize_t pw_sz = pw ? strlen(pw) : 0;
235	/*
236	 * No Dictionary Attack Mitigation (DAM) means:
237	 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0
238	 */
239	unsigned long int max_tries;
240	unsigned long int recovery_time;
241	unsigned long int lockout_recovery;
242	struct udevice *dev;
243	int ret;
244
245	ret = get_tpm(&dev);
246	if (ret)
247		return ret;
248
249	if (argc < 4 || argc > 5)
250		return CMD_RET_USAGE;
251
252	if (pw_sz > TPM2_DIGEST_LEN)
253		return -EINVAL;
254
255	if (strict_strtoul(argv[1], 0, &max_tries))
256		return CMD_RET_USAGE;
257
258	if (strict_strtoul(argv[2], 0, &recovery_time))
259		return CMD_RET_USAGE;
260
261	if (strict_strtoul(argv[3], 0, &lockout_recovery))
262		return CMD_RET_USAGE;
263
264	log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n");
265	log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries);
266	log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time);
267	log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery);
268
269	return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries,
270						      recovery_time,
271						      lockout_recovery));
272}
273
274static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
275			      char *const argv[])
276{
277	u32 handle;
278	const char *newpw = argv[2];
279	const char *oldpw = (argc == 3) ? NULL : argv[3];
280	const ssize_t newpw_sz = strlen(newpw);
281	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
282	struct udevice *dev;
283	int ret;
284
285	ret = get_tpm(&dev);
286	if (ret)
287		return ret;
288
289	if (argc < 3 || argc > 4)
290		return CMD_RET_USAGE;
291
292	if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN)
293		return -EINVAL;
294
295	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
296		handle = TPM2_RH_LOCKOUT;
297	else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
298		handle = TPM2_RH_ENDORSEMENT;
299	else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
300		handle = TPM2_RH_OWNER;
301	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
302		handle = TPM2_RH_PLATFORM;
303	else
304		return CMD_RET_USAGE;
305
306	return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz,
307						   oldpw, oldpw_sz));
308}
309
310static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
311				    char *const argv[])
312{
313	u32 index = simple_strtoul(argv[1], NULL, 0);
314	char *key = argv[2];
315	const char *pw = (argc < 4) ? NULL : argv[3];
316	const ssize_t pw_sz = pw ? strlen(pw) : 0;
317	struct udevice *dev;
318	int ret;
319
320	ret = get_tpm(&dev);
321	if (ret)
322		return ret;
323
324	if (strlen(key) != TPM2_DIGEST_LEN)
325		return -EINVAL;
326
327	if (argc < 3 || argc > 4)
328		return CMD_RET_USAGE;
329
330	return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index,
331							 key));
332}
333
334static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
335				   int argc, char *const argv[])
336{
337	u32 index = simple_strtoul(argv[1], NULL, 0);
338	char *key = argv[2];
339	const ssize_t key_sz = strlen(key);
340	const char *pw = (argc < 4) ? NULL : argv[3];
341	const ssize_t pw_sz = pw ? strlen(pw) : 0;
342	struct udevice *dev;
343	int ret;
344
345	ret = get_tpm(&dev);
346	if (ret)
347		return ret;
348
349	if (strlen(key) != TPM2_DIGEST_LEN)
350		return -EINVAL;
351
352	if (argc < 3 || argc > 4)
353		return CMD_RET_USAGE;
354
355	return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index,
356							key, key_sz));
357}
358
359static struct cmd_tbl tpm2_commands[] = {
360	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
361	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
362	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
363	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
364	U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
365	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
366	U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""),
367	U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""),
368	U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""),
369	U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""),
370	U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""),
371	U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""),
372	U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""),
373	U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""),
374	U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1,
375			 do_tpm_pcr_setauthpolicy, "", ""),
376	U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
377			 do_tpm_pcr_setauthvalue, "", ""),
378};
379
380struct cmd_tbl *get_tpm2_commands(unsigned int *size)
381{
382	*size = ARRAY_SIZE(tpm2_commands);
383
384	return tpm2_commands;
385}
386
387U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
388"<command> [<arguments>]\n"
389"\n"
390"device [num device]\n"
391"    Show all devices or set the specified device\n"
392"info\n"
393"    Show information about the TPM.\n"
394"state\n"
395"    Show internal state from the TPM (if available)\n"
396"autostart\n"
397"    Initalize the tpm, perform a Startup(clear) and run a full selftest\n"
398"    sequence\n"
399"init\n"
400"    Initialize the software stack. Always the first command to issue.\n"
401"    'tpm startup' is the only acceptable command after a 'tpm init' has been\n"
402"    issued\n"
403"startup <mode>\n"
404"    Issue a TPM2_Startup command.\n"
405"    <mode> is one of:\n"
406"        * TPM2_SU_CLEAR (reset state)\n"
407"        * TPM2_SU_STATE (preserved state)\n"
408"self_test <type>\n"
409"    Test the TPM capabilities.\n"
410"    <type> is one of:\n"
411"        * full (perform all tests)\n"
412"        * continue (only check untested tests)\n"
413"clear <hierarchy>\n"
414"    Issue a TPM2_Clear command.\n"
415"    <hierarchy> is one of:\n"
416"        * TPM2_RH_LOCKOUT\n"
417"        * TPM2_RH_PLATFORM\n"
418"pcr_extend <pcr> <digest_addr>\n"
419"    Extend PCR #<pcr> with digest at <digest_addr>.\n"
420"    <pcr>: index of the PCR\n"
421"    <digest_addr>: address of a 32-byte SHA256 digest\n"
422"pcr_read <pcr> <digest_addr>\n"
423"    Read PCR #<pcr> to memory address <digest_addr>.\n"
424"    <pcr>: index of the PCR\n"
425"    <digest_addr>: address to store the a 32-byte SHA256 digest\n"
426"get_capability <capability> <property> <addr> <count>\n"
427"    Read and display <count> entries indexed by <capability>/<property>.\n"
428"    Values are 4 bytes long and are written at <addr>.\n"
429"    <capability>: capability\n"
430"    <property>: property\n"
431"    <addr>: address to store <count> entries of 4 bytes\n"
432"    <count>: number of entries to retrieve\n"
433"dam_reset [<password>]\n"
434"    If the TPM is not in a LOCKOUT state, reset the internal error counter.\n"
435"    <password>: optional password\n"
436"dam_parameters <max_tries> <recovery_time> <lockout_recovery> [<password>]\n"
437"    If the TPM is not in a LOCKOUT state, set the DAM parameters\n"
438"    <maxTries>: maximum number of failures before lockout,\n"
439"                0 means always locking\n"
440"    <recoveryTime>: time before decrement of the error counter,\n"
441"                    0 means no lockout\n"
442"    <lockoutRecovery>: time of a lockout (before the next try),\n"
443"                       0 means a reboot is needed\n"
444"    <password>: optional password of the LOCKOUT hierarchy\n"
445"change_auth <hierarchy> <new_pw> [<old_pw>]\n"
446"    <hierarchy>: the hierarchy\n"
447"    <new_pw>: new password for <hierarchy>\n"
448"    <old_pw>: optional previous password of <hierarchy>\n"
449"pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n"
450"    Change the <key> to access PCR #<pcr>.\n"
451"    hierarchy and may be empty.\n"
452"    /!\\WARNING: untested function, use at your own risks !\n"
453"    <pcr>: index of the PCR\n"
454"    <key>: secret to protect the access of PCR #<pcr>\n"
455"    <password>: optional password of the PLATFORM hierarchy\n"
456);
457