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