xref: /openbmc/u-boot/drivers/tpm/tpm2_tis_sandbox.c (revision cd1a9812a1e2407d1daa53c9cfe785beedbeeb9d)
12bae712fSMiquel Raynal // SPDX-License-Identifier: GPL-2.0+
22bae712fSMiquel Raynal /*
32bae712fSMiquel Raynal  * Copyright (c) 2018, Bootlin
42bae712fSMiquel Raynal  * Author: Miquel Raynal <miquel.raynal@bootlin.com>
52bae712fSMiquel Raynal  */
62bae712fSMiquel Raynal 
72bae712fSMiquel Raynal #include <common.h>
82bae712fSMiquel Raynal #include <dm.h>
92bae712fSMiquel Raynal #include <tpm-v2.h>
102bae712fSMiquel Raynal #include <asm/state.h>
112bae712fSMiquel Raynal #include <asm/unaligned.h>
122bae712fSMiquel Raynal #include <linux/crc8.h>
132bae712fSMiquel Raynal 
142bae712fSMiquel Raynal /* Hierarchies */
152bae712fSMiquel Raynal enum tpm2_hierarchy {
162bae712fSMiquel Raynal 	TPM2_HIERARCHY_LOCKOUT = 0,
172bae712fSMiquel Raynal 	TPM2_HIERARCHY_ENDORSEMENT,
182bae712fSMiquel Raynal 	TPM2_HIERARCHY_PLATFORM,
192bae712fSMiquel Raynal 	TPM2_HIERARCHY_NB,
202bae712fSMiquel Raynal };
212bae712fSMiquel Raynal 
222bae712fSMiquel Raynal /* Subset of supported properties */
232bae712fSMiquel Raynal #define TPM2_PROPERTIES_OFFSET 0x0000020E
242bae712fSMiquel Raynal 
252bae712fSMiquel Raynal enum tpm2_cap_tpm_property {
262bae712fSMiquel Raynal 	TPM2_FAIL_COUNTER = 0,
272bae712fSMiquel Raynal 	TPM2_PROP_MAX_TRIES,
282bae712fSMiquel Raynal 	TPM2_RECOVERY_TIME,
292bae712fSMiquel Raynal 	TPM2_LOCKOUT_RECOVERY,
302bae712fSMiquel Raynal 	TPM2_PROPERTY_NB,
312bae712fSMiquel Raynal };
322bae712fSMiquel Raynal 
33*cd1a9812SEddie James #define SANDBOX_TPM_PCR_NB TPM2_MAX_PCRS
34*cd1a9812SEddie James #define SANDBOX_TPM_PCR_SELECT_MAX	((SANDBOX_TPM_PCR_NB + 7) / 8)
352bae712fSMiquel Raynal 
362bae712fSMiquel Raynal static const u8 sandbox_extended_once_pcr[] = {
372bae712fSMiquel Raynal 	0xf5, 0xa5, 0xfd, 0x42, 0xd1, 0x6a, 0x20, 0x30,
382bae712fSMiquel Raynal 	0x27, 0x98, 0xef, 0x6e, 0xd3, 0x09, 0x97, 0x9b,
392bae712fSMiquel Raynal 	0x43, 0x00, 0x3d, 0x23, 0x20, 0xd9, 0xf0, 0xe8,
402bae712fSMiquel Raynal 	0xea, 0x98, 0x31, 0xa9, 0x27, 0x59, 0xfb, 0x4b,
412bae712fSMiquel Raynal };
422bae712fSMiquel Raynal 
432bae712fSMiquel Raynal struct sandbox_tpm2 {
442bae712fSMiquel Raynal 	/* TPM internal states */
452bae712fSMiquel Raynal 	bool init_done;
462bae712fSMiquel Raynal 	bool startup_done;
472bae712fSMiquel Raynal 	bool tests_done;
482bae712fSMiquel Raynal 	/* TPM password per hierarchy */
492bae712fSMiquel Raynal 	char pw[TPM2_HIERARCHY_NB][TPM2_DIGEST_LEN + 1];
502bae712fSMiquel Raynal 	int pw_sz[TPM2_HIERARCHY_NB];
512bae712fSMiquel Raynal 	/* TPM properties */
522bae712fSMiquel Raynal 	u32 properties[TPM2_PROPERTY_NB];
532bae712fSMiquel Raynal 	/* TPM PCRs */
542bae712fSMiquel Raynal 	u8 pcr[SANDBOX_TPM_PCR_NB][TPM2_DIGEST_LEN];
552bae712fSMiquel Raynal 	/* TPM PCR extensions */
562bae712fSMiquel Raynal 	u32 pcr_extensions[SANDBOX_TPM_PCR_NB];
572bae712fSMiquel Raynal };
582bae712fSMiquel Raynal 
592bae712fSMiquel Raynal /*
602bae712fSMiquel Raynal  * Check the tag validity depending on the command (authentication required or
612bae712fSMiquel Raynal  * not). If authentication is required, check it is valid. Update the auth
622bae712fSMiquel Raynal  * pointer to point to the next chunk of data to process if needed.
632bae712fSMiquel Raynal  */
sandbox_tpm2_check_session(struct udevice * dev,u32 command,u16 tag,const u8 ** auth,enum tpm2_hierarchy * hierarchy)642bae712fSMiquel Raynal static int sandbox_tpm2_check_session(struct udevice *dev, u32 command, u16 tag,
652bae712fSMiquel Raynal 				      const u8 **auth,
662bae712fSMiquel Raynal 				      enum tpm2_hierarchy *hierarchy)
672bae712fSMiquel Raynal {
682bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
692bae712fSMiquel Raynal 	u32 handle, auth_sz, session_handle;
702bae712fSMiquel Raynal 	u16 nonce_sz, pw_sz;
712bae712fSMiquel Raynal 	const char *pw;
722bae712fSMiquel Raynal 
732bae712fSMiquel Raynal 	switch (command) {
742bae712fSMiquel Raynal 	case TPM2_CC_STARTUP:
752bae712fSMiquel Raynal 	case TPM2_CC_SELF_TEST:
762bae712fSMiquel Raynal 	case TPM2_CC_GET_CAPABILITY:
772bae712fSMiquel Raynal 	case TPM2_CC_PCR_READ:
782bae712fSMiquel Raynal 		if (tag != TPM2_ST_NO_SESSIONS) {
792bae712fSMiquel Raynal 			printf("No session required for command 0x%x\n",
802bae712fSMiquel Raynal 			       command);
812bae712fSMiquel Raynal 			return TPM2_RC_BAD_TAG;
822bae712fSMiquel Raynal 		}
832bae712fSMiquel Raynal 
842bae712fSMiquel Raynal 		return 0;
852bae712fSMiquel Raynal 
862bae712fSMiquel Raynal 	case TPM2_CC_CLEAR:
872bae712fSMiquel Raynal 	case TPM2_CC_HIERCHANGEAUTH:
882bae712fSMiquel Raynal 	case TPM2_CC_DAM_RESET:
892bae712fSMiquel Raynal 	case TPM2_CC_DAM_PARAMETERS:
902bae712fSMiquel Raynal 	case TPM2_CC_PCR_EXTEND:
912bae712fSMiquel Raynal 		if (tag != TPM2_ST_SESSIONS) {
922bae712fSMiquel Raynal 			printf("Session required for command 0x%x\n", command);
932bae712fSMiquel Raynal 			return TPM2_RC_AUTH_CONTEXT;
942bae712fSMiquel Raynal 		}
952bae712fSMiquel Raynal 
962bae712fSMiquel Raynal 		handle = get_unaligned_be32(*auth);
972bae712fSMiquel Raynal 		*auth += sizeof(handle);
982bae712fSMiquel Raynal 
992bae712fSMiquel Raynal 		/*
1002bae712fSMiquel Raynal 		 * PCR_Extend had a different protection mechanism and does not
1012bae712fSMiquel Raynal 		 * use the same standards as other commands.
1022bae712fSMiquel Raynal 		 */
1032bae712fSMiquel Raynal 		if (command == TPM2_CC_PCR_EXTEND)
1042bae712fSMiquel Raynal 			break;
1052bae712fSMiquel Raynal 
1062bae712fSMiquel Raynal 		switch (handle) {
1072bae712fSMiquel Raynal 		case TPM2_RH_LOCKOUT:
1082bae712fSMiquel Raynal 			*hierarchy = TPM2_HIERARCHY_LOCKOUT;
1092bae712fSMiquel Raynal 			break;
1102bae712fSMiquel Raynal 		case TPM2_RH_ENDORSEMENT:
1112bae712fSMiquel Raynal 			if (command == TPM2_CC_CLEAR) {
1122bae712fSMiquel Raynal 				printf("Endorsement hierarchy unsupported\n");
1132bae712fSMiquel Raynal 				return TPM2_RC_AUTH_MISSING;
1142bae712fSMiquel Raynal 			}
1152bae712fSMiquel Raynal 			*hierarchy = TPM2_HIERARCHY_ENDORSEMENT;
1162bae712fSMiquel Raynal 			break;
1172bae712fSMiquel Raynal 		case TPM2_RH_PLATFORM:
1182bae712fSMiquel Raynal 			*hierarchy = TPM2_HIERARCHY_PLATFORM;
1192bae712fSMiquel Raynal 			break;
1202bae712fSMiquel Raynal 		default:
1212bae712fSMiquel Raynal 			printf("Wrong handle 0x%x\n", handle);
1222bae712fSMiquel Raynal 			return TPM2_RC_VALUE;
1232bae712fSMiquel Raynal 		}
1242bae712fSMiquel Raynal 
1252bae712fSMiquel Raynal 		break;
1262bae712fSMiquel Raynal 
1272bae712fSMiquel Raynal 	default:
1282bae712fSMiquel Raynal 		printf("Command code not recognized: 0x%x\n", command);
1292bae712fSMiquel Raynal 		return TPM2_RC_COMMAND_CODE;
1302bae712fSMiquel Raynal 	}
1312bae712fSMiquel Raynal 
1322bae712fSMiquel Raynal 	auth_sz = get_unaligned_be32(*auth);
1332bae712fSMiquel Raynal 	*auth += sizeof(auth_sz);
1342bae712fSMiquel Raynal 
1352bae712fSMiquel Raynal 	session_handle = get_unaligned_be32(*auth);
1362bae712fSMiquel Raynal 	*auth += sizeof(session_handle);
1372bae712fSMiquel Raynal 	if (session_handle != TPM2_RS_PW) {
1382bae712fSMiquel Raynal 		printf("Wrong session handle 0x%x\n", session_handle);
1392bae712fSMiquel Raynal 		return TPM2_RC_VALUE;
1402bae712fSMiquel Raynal 	}
1412bae712fSMiquel Raynal 
1422bae712fSMiquel Raynal 	nonce_sz = get_unaligned_be16(*auth);
1432bae712fSMiquel Raynal 	*auth += sizeof(nonce_sz);
1442bae712fSMiquel Raynal 	if (nonce_sz) {
1452bae712fSMiquel Raynal 		printf("Nonces not supported in Sandbox, aborting\n");
1462bae712fSMiquel Raynal 		return TPM2_RC_HANDLE;
1472bae712fSMiquel Raynal 	}
1482bae712fSMiquel Raynal 
1492bae712fSMiquel Raynal 	/* Ignore attributes */
1502bae712fSMiquel Raynal 	*auth += sizeof(u8);
1512bae712fSMiquel Raynal 
1522bae712fSMiquel Raynal 	pw_sz = get_unaligned_be16(*auth);
1532bae712fSMiquel Raynal 	*auth += sizeof(pw_sz);
1542bae712fSMiquel Raynal 	if (auth_sz != (9 + nonce_sz + pw_sz)) {
1552bae712fSMiquel Raynal 		printf("Authentication size (%d) do not match %d\n",
1562bae712fSMiquel Raynal 		       auth_sz, 9 + nonce_sz + pw_sz);
1572bae712fSMiquel Raynal 		return TPM2_RC_SIZE;
1582bae712fSMiquel Raynal 	}
1592bae712fSMiquel Raynal 
1602bae712fSMiquel Raynal 	/* No passwork is acceptable */
1612bae712fSMiquel Raynal 	if (!pw_sz && !tpm->pw_sz[*hierarchy])
1622bae712fSMiquel Raynal 		return TPM2_RC_SUCCESS;
1632bae712fSMiquel Raynal 
1642bae712fSMiquel Raynal 	/* Password is too long */
1652bae712fSMiquel Raynal 	if (pw_sz > TPM2_DIGEST_LEN) {
1662bae712fSMiquel Raynal 		printf("Password should not be more than %dB\n",
1672bae712fSMiquel Raynal 		       TPM2_DIGEST_LEN);
1682bae712fSMiquel Raynal 		return TPM2_RC_AUTHSIZE;
1692bae712fSMiquel Raynal 	}
1702bae712fSMiquel Raynal 
1712bae712fSMiquel Raynal 	pw = (const char *)*auth;
1722bae712fSMiquel Raynal 	*auth += pw_sz;
1732bae712fSMiquel Raynal 
1742bae712fSMiquel Raynal 	/* Password is wrong */
1752bae712fSMiquel Raynal 	if (pw_sz != tpm->pw_sz[*hierarchy] ||
1762bae712fSMiquel Raynal 	    strncmp(pw, tpm->pw[*hierarchy], tpm->pw_sz[*hierarchy])) {
1772bae712fSMiquel Raynal 		printf("Authentication failed: wrong password.\n");
1782bae712fSMiquel Raynal 		return TPM2_RC_BAD_AUTH;
1792bae712fSMiquel Raynal 	}
1802bae712fSMiquel Raynal 
1812bae712fSMiquel Raynal 	return TPM2_RC_SUCCESS;
1822bae712fSMiquel Raynal }
1832bae712fSMiquel Raynal 
sandbox_tpm2_check_readyness(struct udevice * dev,int command)1842bae712fSMiquel Raynal static int sandbox_tpm2_check_readyness(struct udevice *dev, int command)
1852bae712fSMiquel Raynal {
1862bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
1872bae712fSMiquel Raynal 
1882bae712fSMiquel Raynal 	switch (command) {
1892bae712fSMiquel Raynal 	case TPM2_CC_STARTUP:
1902bae712fSMiquel Raynal 		if (!tpm->init_done || tpm->startup_done)
1912bae712fSMiquel Raynal 			return TPM2_RC_INITIALIZE;
1922bae712fSMiquel Raynal 
1932bae712fSMiquel Raynal 		break;
1942bae712fSMiquel Raynal 	case TPM2_CC_GET_CAPABILITY:
1952bae712fSMiquel Raynal 		if (!tpm->init_done || !tpm->startup_done)
1962bae712fSMiquel Raynal 			return TPM2_RC_INITIALIZE;
1972bae712fSMiquel Raynal 
1982bae712fSMiquel Raynal 		break;
1992bae712fSMiquel Raynal 	case TPM2_CC_SELF_TEST:
2002bae712fSMiquel Raynal 		if (!tpm->startup_done)
2012bae712fSMiquel Raynal 			return TPM2_RC_INITIALIZE;
2022bae712fSMiquel Raynal 
2032bae712fSMiquel Raynal 		break;
2042bae712fSMiquel Raynal 	default:
2052bae712fSMiquel Raynal 		if (!tpm->tests_done)
2062bae712fSMiquel Raynal 			return TPM2_RC_NEEDS_TEST;
2072bae712fSMiquel Raynal 
2082bae712fSMiquel Raynal 		break;
2092bae712fSMiquel Raynal 	}
2102bae712fSMiquel Raynal 
2112bae712fSMiquel Raynal 	return 0;
2122bae712fSMiquel Raynal }
2132bae712fSMiquel Raynal 
sandbox_tpm2_fill_buf(u8 * recv,size_t * recv_len,u16 tag,u32 rc)21446703cd9SMiquel Raynal static int sandbox_tpm2_fill_buf(u8 *recv, size_t *recv_len, u16 tag, u32 rc)
2152bae712fSMiquel Raynal {
2162bae712fSMiquel Raynal 	*recv_len = sizeof(tag) + sizeof(u32) + sizeof(rc);
2172bae712fSMiquel Raynal 
2182bae712fSMiquel Raynal 	/* Write tag */
21946703cd9SMiquel Raynal 	put_unaligned_be16(tag, recv);
22046703cd9SMiquel Raynal 	recv += sizeof(tag);
2212bae712fSMiquel Raynal 
2222bae712fSMiquel Raynal 	/* Write length */
22346703cd9SMiquel Raynal 	put_unaligned_be32(*recv_len, recv);
22446703cd9SMiquel Raynal 	recv += sizeof(u32);
2252bae712fSMiquel Raynal 
2262bae712fSMiquel Raynal 	/* Write return code */
22746703cd9SMiquel Raynal 	put_unaligned_be32(rc, recv);
22846703cd9SMiquel Raynal 	recv += sizeof(rc);
2292bae712fSMiquel Raynal 
2302bae712fSMiquel Raynal 	/* Add trailing \0 */
23146703cd9SMiquel Raynal 	*recv = '\0';
2322bae712fSMiquel Raynal 
2332bae712fSMiquel Raynal 	return 0;
2342bae712fSMiquel Raynal }
2352bae712fSMiquel Raynal 
sandbox_tpm2_extend(struct udevice * dev,int pcr_index,const u8 * extension)2362bae712fSMiquel Raynal static int sandbox_tpm2_extend(struct udevice *dev, int pcr_index,
2372bae712fSMiquel Raynal 			       const u8 *extension)
2382bae712fSMiquel Raynal {
2392bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
2402bae712fSMiquel Raynal 	int i;
2412bae712fSMiquel Raynal 
2422bae712fSMiquel Raynal 	/* Only simulate the first extensions from all '0' with only '0' */
2432bae712fSMiquel Raynal 	for (i = 0; i < TPM2_DIGEST_LEN; i++)
2442bae712fSMiquel Raynal 		if (tpm->pcr[pcr_index][i] || extension[i])
2452bae712fSMiquel Raynal 			return TPM2_RC_FAILURE;
2462bae712fSMiquel Raynal 
2472bae712fSMiquel Raynal 	memcpy(tpm->pcr[pcr_index], sandbox_extended_once_pcr,
2482bae712fSMiquel Raynal 	       TPM2_DIGEST_LEN);
2492bae712fSMiquel Raynal 	tpm->pcr_extensions[pcr_index]++;
2502bae712fSMiquel Raynal 
2512bae712fSMiquel Raynal 	return 0;
2522bae712fSMiquel Raynal };
2532bae712fSMiquel Raynal 
sandbox_tpm2_xfer(struct udevice * dev,const u8 * sendbuf,size_t send_size,u8 * recvbuf,size_t * recv_len)2542bae712fSMiquel Raynal static int sandbox_tpm2_xfer(struct udevice *dev, const u8 *sendbuf,
2552bae712fSMiquel Raynal 			     size_t send_size, u8 *recvbuf,
2562bae712fSMiquel Raynal 			     size_t *recv_len)
2572bae712fSMiquel Raynal {
2582bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
2592bae712fSMiquel Raynal 	enum tpm2_hierarchy hierarchy = 0;
2602bae712fSMiquel Raynal 	const u8 *sent = sendbuf;
2612bae712fSMiquel Raynal 	u8 *recv = recvbuf;
2622bae712fSMiquel Raynal 	u32 length, command, rc = 0;
2632bae712fSMiquel Raynal 	u16 tag, mode, new_pw_sz;
2642bae712fSMiquel Raynal 	u8 yes_no;
2652bae712fSMiquel Raynal 	int i, j;
2662bae712fSMiquel Raynal 
2672bae712fSMiquel Raynal 	/* TPM2_GetProperty */
268*cd1a9812SEddie James 	u32 capability, property, property_count, val;
2692bae712fSMiquel Raynal 
2702bae712fSMiquel Raynal 	/* TPM2_PCR_Read/Extend variables */
271fd973ca6SMiquel Raynal 	int pcr_index = 0;
2722bae712fSMiquel Raynal 	u64 pcr_map = 0;
2732bae712fSMiquel Raynal 	u32 selections, pcr_nb;
2742bae712fSMiquel Raynal 	u16 alg;
2752bae712fSMiquel Raynal 	u8 pcr_array_sz;
2762bae712fSMiquel Raynal 
2772bae712fSMiquel Raynal 	tag = get_unaligned_be16(sent);
2782bae712fSMiquel Raynal 	sent += sizeof(tag);
2792bae712fSMiquel Raynal 
2802bae712fSMiquel Raynal 	length = get_unaligned_be32(sent);
2812bae712fSMiquel Raynal 	sent += sizeof(length);
2822bae712fSMiquel Raynal 	if (length != send_size) {
2832bae712fSMiquel Raynal 		printf("TPM2: Unmatching length, received: %ld, expected: %d\n",
2842bae712fSMiquel Raynal 		       send_size, length);
2852bae712fSMiquel Raynal 		rc = TPM2_RC_SIZE;
28646703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
2872bae712fSMiquel Raynal 		return 0;
2882bae712fSMiquel Raynal 	}
2892bae712fSMiquel Raynal 
2902bae712fSMiquel Raynal 	command = get_unaligned_be32(sent);
2912bae712fSMiquel Raynal 	sent += sizeof(command);
2922bae712fSMiquel Raynal 	rc = sandbox_tpm2_check_readyness(dev, command);
2932bae712fSMiquel Raynal 	if (rc) {
29446703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
2952bae712fSMiquel Raynal 		return 0;
2962bae712fSMiquel Raynal 	}
2972bae712fSMiquel Raynal 
2982bae712fSMiquel Raynal 	rc = sandbox_tpm2_check_session(dev, command, tag, &sent, &hierarchy);
2992bae712fSMiquel Raynal 	if (rc) {
30046703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
3012bae712fSMiquel Raynal 		return 0;
3022bae712fSMiquel Raynal 	}
3032bae712fSMiquel Raynal 
3042bae712fSMiquel Raynal 	switch (command) {
3052bae712fSMiquel Raynal 	case TPM2_CC_STARTUP:
3062bae712fSMiquel Raynal 		mode = get_unaligned_be16(sent);
3072bae712fSMiquel Raynal 		sent += sizeof(mode);
3082bae712fSMiquel Raynal 		switch (mode) {
3092bae712fSMiquel Raynal 		case TPM2_SU_CLEAR:
3102bae712fSMiquel Raynal 		case TPM2_SU_STATE:
3112bae712fSMiquel Raynal 			break;
3122bae712fSMiquel Raynal 		default:
3132bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
3142bae712fSMiquel Raynal 		}
3152bae712fSMiquel Raynal 
3162bae712fSMiquel Raynal 		tpm->startup_done = true;
3172bae712fSMiquel Raynal 
31846703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
3192bae712fSMiquel Raynal 		break;
3202bae712fSMiquel Raynal 
3212bae712fSMiquel Raynal 	case TPM2_CC_SELF_TEST:
3222bae712fSMiquel Raynal 		yes_no = *sent;
3232bae712fSMiquel Raynal 		sent += sizeof(yes_no);
3242bae712fSMiquel Raynal 		switch (yes_no) {
3252bae712fSMiquel Raynal 		case TPMI_YES:
3262bae712fSMiquel Raynal 		case TPMI_NO:
3272bae712fSMiquel Raynal 			break;
3282bae712fSMiquel Raynal 		default:
3292bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
3302bae712fSMiquel Raynal 		}
3312bae712fSMiquel Raynal 
3322bae712fSMiquel Raynal 		tpm->tests_done = true;
3332bae712fSMiquel Raynal 
33446703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
3352bae712fSMiquel Raynal 		break;
3362bae712fSMiquel Raynal 
3372bae712fSMiquel Raynal 	case TPM2_CC_CLEAR:
3382bae712fSMiquel Raynal 		/* Reset this hierarchy password */
3392bae712fSMiquel Raynal 		tpm->pw_sz[hierarchy] = 0;
3402bae712fSMiquel Raynal 
3412bae712fSMiquel Raynal 		/* Reset all password if thisis the PLATFORM hierarchy */
3422bae712fSMiquel Raynal 		if (hierarchy == TPM2_HIERARCHY_PLATFORM)
3432bae712fSMiquel Raynal 			for (i = 0; i < TPM2_HIERARCHY_NB; i++)
3442bae712fSMiquel Raynal 				tpm->pw_sz[i] = 0;
3452bae712fSMiquel Raynal 
3462bae712fSMiquel Raynal 		/* Reset the properties */
3472bae712fSMiquel Raynal 		for (i = 0; i < TPM2_PROPERTY_NB; i++)
3482bae712fSMiquel Raynal 			tpm->properties[i] = 0;
3492bae712fSMiquel Raynal 
3502bae712fSMiquel Raynal 		/* Reset the PCRs and their number of extensions */
3512bae712fSMiquel Raynal 		for (i = 0; i < SANDBOX_TPM_PCR_NB; i++) {
3522bae712fSMiquel Raynal 			tpm->pcr_extensions[i] = 0;
3532bae712fSMiquel Raynal 			for (j = 0; j < TPM2_DIGEST_LEN; j++)
3542bae712fSMiquel Raynal 				tpm->pcr[i][j] = 0;
3552bae712fSMiquel Raynal 		}
3562bae712fSMiquel Raynal 
35746703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
3582bae712fSMiquel Raynal 		break;
3592bae712fSMiquel Raynal 
3602bae712fSMiquel Raynal 	case TPM2_CC_HIERCHANGEAUTH:
3612bae712fSMiquel Raynal 		new_pw_sz = get_unaligned_be16(sent);
3622bae712fSMiquel Raynal 		sent += sizeof(new_pw_sz);
3632bae712fSMiquel Raynal 		if (new_pw_sz > TPM2_DIGEST_LEN) {
3642bae712fSMiquel Raynal 			rc = TPM2_RC_SIZE;
3652bae712fSMiquel Raynal 		} else if (new_pw_sz) {
3662bae712fSMiquel Raynal 			tpm->pw_sz[hierarchy] = new_pw_sz;
3672bae712fSMiquel Raynal 			memcpy(tpm->pw[hierarchy], sent, new_pw_sz);
3682bae712fSMiquel Raynal 			sent += new_pw_sz;
3692bae712fSMiquel Raynal 		}
3702bae712fSMiquel Raynal 
37146703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
3722bae712fSMiquel Raynal 		break;
3732bae712fSMiquel Raynal 
3742bae712fSMiquel Raynal 	case TPM2_CC_GET_CAPABILITY:
3752bae712fSMiquel Raynal 		capability = get_unaligned_be32(sent);
3762bae712fSMiquel Raynal 		sent += sizeof(capability);
3772bae712fSMiquel Raynal 		property = get_unaligned_be32(sent);
3782bae712fSMiquel Raynal 		sent += sizeof(property);
3792bae712fSMiquel Raynal 		property_count = get_unaligned_be32(sent);
3802bae712fSMiquel Raynal 		sent += sizeof(property_count);
381*cd1a9812SEddie James 
382*cd1a9812SEddie James 		switch (capability) {
383*cd1a9812SEddie James 		case TPM2_CAP_PCRS:
384*cd1a9812SEddie James 			break;
385*cd1a9812SEddie James 		case TPM2_CAP_TPM_PROPERTIES:
386*cd1a9812SEddie James 			if (!property_count) {
387*cd1a9812SEddie James 				rc = TPM2_RC_HANDLE;
388*cd1a9812SEddie James 				return sandbox_tpm2_fill_buf(recv, recv_len,
389*cd1a9812SEddie James 							     tag, rc);
390*cd1a9812SEddie James 			}
391*cd1a9812SEddie James 
392*cd1a9812SEddie James 			if (property >= TPM2_PROPERTIES_OFFSET &&
393*cd1a9812SEddie James 			    ((property - TPM2_PROPERTIES_OFFSET) +
394*cd1a9812SEddie James 			     property_count > TPM2_PROPERTY_NB)) {
395*cd1a9812SEddie James 				rc = TPM2_RC_HANDLE;
396*cd1a9812SEddie James 				return sandbox_tpm2_fill_buf(recv, recv_len,
397*cd1a9812SEddie James 							     tag, rc);
398*cd1a9812SEddie James 			}
399*cd1a9812SEddie James 			break;
400*cd1a9812SEddie James 		default:
401*cd1a9812SEddie James 			printf("Sandbox TPM2 only supports TPM2_CAP_PCRS or "
402*cd1a9812SEddie James 			       "TPM2_CAP_TPM_PROPERTIES\n");
4032bae712fSMiquel Raynal 			rc = TPM2_RC_HANDLE;
40446703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
4052bae712fSMiquel Raynal 		}
4062bae712fSMiquel Raynal 
4072bae712fSMiquel Raynal 		/* Write tag */
4082bae712fSMiquel Raynal 		put_unaligned_be16(tag, recv);
4092bae712fSMiquel Raynal 		recv += sizeof(tag);
4102bae712fSMiquel Raynal 
4112bae712fSMiquel Raynal 		/* Ignore length for now */
4122bae712fSMiquel Raynal 		recv += sizeof(u32);
4132bae712fSMiquel Raynal 
4142bae712fSMiquel Raynal 		/* Write return code */
4152bae712fSMiquel Raynal 		put_unaligned_be32(rc, recv);
4162bae712fSMiquel Raynal 		recv += sizeof(rc);
4172bae712fSMiquel Raynal 
4182bae712fSMiquel Raynal 		/* Tell there is more data to read */
4192bae712fSMiquel Raynal 		*recv = TPMI_YES;
4202bae712fSMiquel Raynal 		recv += sizeof(yes_no);
4212bae712fSMiquel Raynal 
4222bae712fSMiquel Raynal 		/* Repeat the capability */
4232bae712fSMiquel Raynal 		put_unaligned_be32(capability, recv);
4242bae712fSMiquel Raynal 		recv += sizeof(capability);
4252bae712fSMiquel Raynal 
426*cd1a9812SEddie James 		switch (capability) {
427*cd1a9812SEddie James 		case TPM2_CAP_PCRS:
428*cd1a9812SEddie James 			/* Give the number of algorithms supported - just SHA256 */
429*cd1a9812SEddie James 			put_unaligned_be32(1, recv);
430*cd1a9812SEddie James 			recv += sizeof(u32);
431*cd1a9812SEddie James 
432*cd1a9812SEddie James 			/* Give SHA256 algorithm */
433*cd1a9812SEddie James 			put_unaligned_be16(TPM2_ALG_SHA256, recv);
434*cd1a9812SEddie James 			recv += sizeof(u16);
435*cd1a9812SEddie James 
436*cd1a9812SEddie James 			/* Select the PCRs supported */
437*cd1a9812SEddie James 			*recv = SANDBOX_TPM_PCR_SELECT_MAX;
438*cd1a9812SEddie James 			recv++;
439*cd1a9812SEddie James 
440*cd1a9812SEddie James 			/* Activate all the PCR bits */
441*cd1a9812SEddie James 			for (i = 0; i < SANDBOX_TPM_PCR_SELECT_MAX; ++i) {
442*cd1a9812SEddie James 				*recv = 0xff;
443*cd1a9812SEddie James 				recv++;
444*cd1a9812SEddie James 			}
445*cd1a9812SEddie James 			break;
446*cd1a9812SEddie James 		case TPM2_CAP_TPM_PROPERTIES:
4472bae712fSMiquel Raynal 			/* Give the number of properties that follow */
4482bae712fSMiquel Raynal 			put_unaligned_be32(property_count, recv);
4492bae712fSMiquel Raynal 			recv += sizeof(property_count);
4502bae712fSMiquel Raynal 
4512bae712fSMiquel Raynal 			/* Fill with the properties */
4522bae712fSMiquel Raynal 			for (i = 0; i < property_count; i++) {
453*cd1a9812SEddie James 				put_unaligned_be32(property + i, recv);
4542bae712fSMiquel Raynal 				recv += sizeof(property);
455*cd1a9812SEddie James 				if (property >= TPM2_PROPERTIES_OFFSET) {
456*cd1a9812SEddie James 					val = tpm->properties[(property -
457*cd1a9812SEddie James 						TPM2_PROPERTIES_OFFSET) + i];
458*cd1a9812SEddie James 				} else {
459*cd1a9812SEddie James 					switch (property) {
460*cd1a9812SEddie James 					case TPM2_PT_PCR_COUNT:
461*cd1a9812SEddie James 						val = SANDBOX_TPM_PCR_NB;
462*cd1a9812SEddie James 						break;
463*cd1a9812SEddie James 					default:
464*cd1a9812SEddie James 						val = 0xffffffff;
465*cd1a9812SEddie James 						break;
466*cd1a9812SEddie James 					}
467*cd1a9812SEddie James 				}
468*cd1a9812SEddie James 
469*cd1a9812SEddie James 				put_unaligned_be32(val, recv);
4702bae712fSMiquel Raynal 				recv += sizeof(property);
4712bae712fSMiquel Raynal 			}
472*cd1a9812SEddie James 			break;
473*cd1a9812SEddie James 		}
4742bae712fSMiquel Raynal 
4752bae712fSMiquel Raynal 		/* Add trailing \0 */
4762bae712fSMiquel Raynal 		*recv = '\0';
4772bae712fSMiquel Raynal 
4782bae712fSMiquel Raynal 		/* Write response length */
4792bae712fSMiquel Raynal 		*recv_len = recv - recvbuf;
4802bae712fSMiquel Raynal 		put_unaligned_be32(*recv_len, recvbuf + sizeof(tag));
4812bae712fSMiquel Raynal 
4822bae712fSMiquel Raynal 		break;
4832bae712fSMiquel Raynal 
4842bae712fSMiquel Raynal 	case TPM2_CC_DAM_PARAMETERS:
4852bae712fSMiquel Raynal 		tpm->properties[TPM2_PROP_MAX_TRIES] = get_unaligned_be32(sent);
4862bae712fSMiquel Raynal 		sent += sizeof(*tpm->properties);
4872bae712fSMiquel Raynal 		tpm->properties[TPM2_RECOVERY_TIME] = get_unaligned_be32(sent);
4882bae712fSMiquel Raynal 		sent += sizeof(*tpm->properties);
4892bae712fSMiquel Raynal 		tpm->properties[TPM2_LOCKOUT_RECOVERY] = get_unaligned_be32(sent);
4902bae712fSMiquel Raynal 		sent += sizeof(*tpm->properties);
4912bae712fSMiquel Raynal 
49246703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
4932bae712fSMiquel Raynal 		break;
4942bae712fSMiquel Raynal 
4952bae712fSMiquel Raynal 	case TPM2_CC_PCR_READ:
4962bae712fSMiquel Raynal 		selections = get_unaligned_be32(sent);
4972bae712fSMiquel Raynal 		sent += sizeof(selections);
4982bae712fSMiquel Raynal 		if (selections != 1) {
4992bae712fSMiquel Raynal 			printf("Sandbox cannot handle more than one PCR\n");
5002bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
50146703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5022bae712fSMiquel Raynal 		}
5032bae712fSMiquel Raynal 
5042bae712fSMiquel Raynal 		alg = get_unaligned_be16(sent);
5052bae712fSMiquel Raynal 		sent += sizeof(alg);
5062bae712fSMiquel Raynal 		if (alg != TPM2_ALG_SHA256) {
5072bae712fSMiquel Raynal 			printf("Sandbox TPM only handle SHA256 algorithm\n");
5082bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
50946703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5102bae712fSMiquel Raynal 		}
5112bae712fSMiquel Raynal 
5122bae712fSMiquel Raynal 		pcr_array_sz = *sent;
5132bae712fSMiquel Raynal 		sent += sizeof(pcr_array_sz);
5142bae712fSMiquel Raynal 		if (!pcr_array_sz || pcr_array_sz > 8) {
5152bae712fSMiquel Raynal 			printf("Sandbox TPM cannot handle so much PCRs\n");
5162bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
51746703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5182bae712fSMiquel Raynal 		}
5192bae712fSMiquel Raynal 
5202bae712fSMiquel Raynal 		for (i = 0; i < pcr_array_sz; i++)
5212bae712fSMiquel Raynal 			pcr_map += (u64)sent[i] << (i * 8);
5222bae712fSMiquel Raynal 
5232bae712fSMiquel Raynal 		if (pcr_map >> SANDBOX_TPM_PCR_NB) {
5242bae712fSMiquel Raynal 			printf("Sandbox TPM handles up to %d PCR(s)\n",
5252bae712fSMiquel Raynal 			       SANDBOX_TPM_PCR_NB);
5262bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
52746703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5282bae712fSMiquel Raynal 		}
5292bae712fSMiquel Raynal 
530fd973ca6SMiquel Raynal 		if (!pcr_map) {
531fd973ca6SMiquel Raynal 			printf("Empty PCR map.\n");
5322bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
53346703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5342bae712fSMiquel Raynal 		}
5352bae712fSMiquel Raynal 
5362bae712fSMiquel Raynal 		for (i = 0; i < SANDBOX_TPM_PCR_NB; i++)
5372bae712fSMiquel Raynal 			if (pcr_map & BIT(i))
5382bae712fSMiquel Raynal 				pcr_index = i;
5392bae712fSMiquel Raynal 
5402bae712fSMiquel Raynal 		/* Write tag */
5412bae712fSMiquel Raynal 		put_unaligned_be16(tag, recv);
5422bae712fSMiquel Raynal 		recv += sizeof(tag);
5432bae712fSMiquel Raynal 
5442bae712fSMiquel Raynal 		/* Ignore length for now */
5452bae712fSMiquel Raynal 		recv += sizeof(u32);
5462bae712fSMiquel Raynal 
5472bae712fSMiquel Raynal 		/* Write return code */
5482bae712fSMiquel Raynal 		put_unaligned_be32(rc, recv);
5492bae712fSMiquel Raynal 		recv += sizeof(rc);
5502bae712fSMiquel Raynal 
5512bae712fSMiquel Raynal 		/* Number of extensions */
5522bae712fSMiquel Raynal 		put_unaligned_be32(tpm->pcr_extensions[pcr_index], recv);
5532bae712fSMiquel Raynal 		recv += sizeof(u32);
5542bae712fSMiquel Raynal 
5552bae712fSMiquel Raynal 		/* Copy the PCR */
5562bae712fSMiquel Raynal 		memcpy(recv, tpm->pcr[pcr_index], TPM2_DIGEST_LEN);
5572bae712fSMiquel Raynal 		recv += TPM2_DIGEST_LEN;
5582bae712fSMiquel Raynal 
5592bae712fSMiquel Raynal 		/* Add trailing \0 */
5602bae712fSMiquel Raynal 		*recv = '\0';
5612bae712fSMiquel Raynal 
5622bae712fSMiquel Raynal 		/* Write response length */
5632bae712fSMiquel Raynal 		*recv_len = recv - recvbuf;
5642bae712fSMiquel Raynal 		put_unaligned_be32(*recv_len, recvbuf + sizeof(tag));
5652bae712fSMiquel Raynal 
5662bae712fSMiquel Raynal 		break;
5672bae712fSMiquel Raynal 
5682bae712fSMiquel Raynal 	case TPM2_CC_PCR_EXTEND:
5692bae712fSMiquel Raynal 		/* Get the PCR index */
5702bae712fSMiquel Raynal 		pcr_index = get_unaligned_be32(sendbuf + sizeof(tag) +
5712bae712fSMiquel Raynal 					       sizeof(length) +
5722bae712fSMiquel Raynal 					       sizeof(command));
5732bae712fSMiquel Raynal 		if (pcr_index > SANDBOX_TPM_PCR_NB) {
5742bae712fSMiquel Raynal 			printf("Sandbox TPM handles up to %d PCR(s)\n",
5752bae712fSMiquel Raynal 			       SANDBOX_TPM_PCR_NB);
5762bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
5772bae712fSMiquel Raynal 		}
5782bae712fSMiquel Raynal 
5792bae712fSMiquel Raynal 		/* Check the number of hashes */
5802bae712fSMiquel Raynal 		pcr_nb = get_unaligned_be32(sent);
5812bae712fSMiquel Raynal 		sent += sizeof(pcr_nb);
5822bae712fSMiquel Raynal 		if (pcr_nb != 1) {
5832bae712fSMiquel Raynal 			printf("Sandbox cannot handle more than one PCR\n");
5842bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
58546703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5862bae712fSMiquel Raynal 		}
5872bae712fSMiquel Raynal 
5882bae712fSMiquel Raynal 		/* Check the hash algorithm */
5892bae712fSMiquel Raynal 		alg = get_unaligned_be16(sent);
5902bae712fSMiquel Raynal 		sent += sizeof(alg);
5912bae712fSMiquel Raynal 		if (alg != TPM2_ALG_SHA256) {
5922bae712fSMiquel Raynal 			printf("Sandbox TPM only handle SHA256 algorithm\n");
5932bae712fSMiquel Raynal 			rc = TPM2_RC_VALUE;
59446703cd9SMiquel Raynal 			return sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
5952bae712fSMiquel Raynal 		}
5962bae712fSMiquel Raynal 
5972bae712fSMiquel Raynal 		/* Extend the PCR */
5982bae712fSMiquel Raynal 		rc = sandbox_tpm2_extend(dev, pcr_index, sent);
5992bae712fSMiquel Raynal 
60046703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
6012bae712fSMiquel Raynal 		break;
6022bae712fSMiquel Raynal 
6032bae712fSMiquel Raynal 	default:
6042bae712fSMiquel Raynal 		printf("TPM2 command %02x unknown in Sandbox\n", command);
6052bae712fSMiquel Raynal 		rc = TPM2_RC_COMMAND_CODE;
60646703cd9SMiquel Raynal 		sandbox_tpm2_fill_buf(recv, recv_len, tag, rc);
6072bae712fSMiquel Raynal 	}
6082bae712fSMiquel Raynal 
6092bae712fSMiquel Raynal 	return 0;
6102bae712fSMiquel Raynal }
6112bae712fSMiquel Raynal 
sandbox_tpm2_get_desc(struct udevice * dev,char * buf,int size)6122bae712fSMiquel Raynal static int sandbox_tpm2_get_desc(struct udevice *dev, char *buf, int size)
6132bae712fSMiquel Raynal {
6142bae712fSMiquel Raynal 	if (size < 15)
6152bae712fSMiquel Raynal 		return -ENOSPC;
6162bae712fSMiquel Raynal 
6172bae712fSMiquel Raynal 	return snprintf(buf, size, "Sandbox TPM2.x");
6182bae712fSMiquel Raynal }
6192bae712fSMiquel Raynal 
sandbox_tpm2_open(struct udevice * dev)6202bae712fSMiquel Raynal static int sandbox_tpm2_open(struct udevice *dev)
6212bae712fSMiquel Raynal {
6222bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
6232bae712fSMiquel Raynal 
6242bae712fSMiquel Raynal 	if (tpm->init_done)
6252bae712fSMiquel Raynal 		return -EIO;
6262bae712fSMiquel Raynal 
6272bae712fSMiquel Raynal 	tpm->init_done = true;
6282bae712fSMiquel Raynal 
6292bae712fSMiquel Raynal 	return 0;
6302bae712fSMiquel Raynal }
6312bae712fSMiquel Raynal 
sandbox_tpm2_probe(struct udevice * dev)6322bae712fSMiquel Raynal static int sandbox_tpm2_probe(struct udevice *dev)
6332bae712fSMiquel Raynal {
6342bae712fSMiquel Raynal 	struct sandbox_tpm2 *tpm = dev_get_priv(dev);
6352bae712fSMiquel Raynal 	struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
6362bae712fSMiquel Raynal 
6372a2096eaSMiquel Raynal 	/* Use the TPM v2 stack */
6382a2096eaSMiquel Raynal 	priv->version = TPM_V2;
6392a2096eaSMiquel Raynal 
6402bae712fSMiquel Raynal 	memset(tpm, 0, sizeof(*tpm));
6412bae712fSMiquel Raynal 
6422bae712fSMiquel Raynal 	priv->pcr_count = 32;
6432bae712fSMiquel Raynal 	priv->pcr_select_min = 2;
6442bae712fSMiquel Raynal 
6452bae712fSMiquel Raynal 	return 0;
6462bae712fSMiquel Raynal }
6472bae712fSMiquel Raynal 
sandbox_tpm2_close(struct udevice * dev)6482bae712fSMiquel Raynal static int sandbox_tpm2_close(struct udevice *dev)
6492bae712fSMiquel Raynal {
6502bae712fSMiquel Raynal 	return 0;
6512bae712fSMiquel Raynal }
6522bae712fSMiquel Raynal 
6532bae712fSMiquel Raynal static const struct tpm_ops sandbox_tpm2_ops = {
6542bae712fSMiquel Raynal 	.open		= sandbox_tpm2_open,
6552bae712fSMiquel Raynal 	.close		= sandbox_tpm2_close,
6562bae712fSMiquel Raynal 	.get_desc	= sandbox_tpm2_get_desc,
6572bae712fSMiquel Raynal 	.xfer		= sandbox_tpm2_xfer,
6582bae712fSMiquel Raynal };
6592bae712fSMiquel Raynal 
6602bae712fSMiquel Raynal static const struct udevice_id sandbox_tpm2_ids[] = {
6612bae712fSMiquel Raynal 	{ .compatible = "sandbox,tpm2" },
6622bae712fSMiquel Raynal 	{ }
6632bae712fSMiquel Raynal };
6642bae712fSMiquel Raynal 
6652bae712fSMiquel Raynal U_BOOT_DRIVER(sandbox_tpm2) = {
6662bae712fSMiquel Raynal 	.name   = "sandbox_tpm2",
6672bae712fSMiquel Raynal 	.id     = UCLASS_TPM,
6682bae712fSMiquel Raynal 	.of_match = sandbox_tpm2_ids,
6692bae712fSMiquel Raynal 	.ops    = &sandbox_tpm2_ops,
6702bae712fSMiquel Raynal 	.probe	= sandbox_tpm2_probe,
6712bae712fSMiquel Raynal 	.priv_auto_alloc_size = sizeof(struct sandbox_tpm2),
6722bae712fSMiquel Raynal };
673