xref: /openbmc/u-boot/board/gdsys/a38x/keyprogram.c (revision 9450ab2b)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
260083261SDirk Eibach /*
360083261SDirk Eibach  * (C) Copyright 2016
460083261SDirk Eibach  * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
560083261SDirk Eibach  */
660083261SDirk Eibach 
760083261SDirk Eibach #include <common.h>
8d677bfe2SMiquel Raynal #include <tpm-v1.h>
960083261SDirk Eibach #include <malloc.h>
1060083261SDirk Eibach #include <linux/ctype.h>
1160083261SDirk Eibach #include <asm/unaligned.h>
1260083261SDirk Eibach 
1360083261SDirk Eibach #include "hre.h"
1460083261SDirk Eibach 
flush_keys(struct udevice * tpm)15*abdc7b8aSSimon Glass int flush_keys(struct udevice *tpm)
1660083261SDirk Eibach {
1760083261SDirk Eibach 	u16 key_count;
1860083261SDirk Eibach 	u8 buf[288];
1960083261SDirk Eibach 	u8 *ptr;
2060083261SDirk Eibach 	u32 err;
2160083261SDirk Eibach 	uint i;
2260083261SDirk Eibach 
2360083261SDirk Eibach 	/* fetch list of already loaded keys in the TPM */
24*abdc7b8aSSimon Glass 	err = tpm_get_capability(tpm, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
25*abdc7b8aSSimon Glass 				 sizeof(buf));
2660083261SDirk Eibach 	if (err)
2760083261SDirk Eibach 		return -1;
2860083261SDirk Eibach 	key_count = get_unaligned_be16(buf);
2960083261SDirk Eibach 	ptr = buf + 2;
3060083261SDirk Eibach 	for (i = 0; i < key_count; ++i, ptr += 4) {
31*abdc7b8aSSimon Glass 		err = tpm_flush_specific(tpm, get_unaligned_be32(ptr),
32*abdc7b8aSSimon Glass 					 TPM_RT_KEY);
3360083261SDirk Eibach 		if (err && err != TPM_KEY_OWNER_CONTROL)
3460083261SDirk Eibach 			return err;
3560083261SDirk Eibach 	}
3660083261SDirk Eibach 
3760083261SDirk Eibach 	return 0;
3860083261SDirk Eibach }
3960083261SDirk Eibach 
decode_hexstr(char * hexstr,u8 ** result)4060083261SDirk Eibach int decode_hexstr(char *hexstr, u8 **result)
4160083261SDirk Eibach {
4260083261SDirk Eibach 	int len = strlen(hexstr);
4360083261SDirk Eibach 	int bytes = len / 2;
4460083261SDirk Eibach 	int i;
4560083261SDirk Eibach 	u8 acc = 0;
4660083261SDirk Eibach 
4760083261SDirk Eibach 	if (len % 2 == 1)
4860083261SDirk Eibach 		return 1;
4960083261SDirk Eibach 
5060083261SDirk Eibach 	*result = (u8 *)malloc(bytes);
5160083261SDirk Eibach 
5260083261SDirk Eibach 	for (i = 0; i < len; i++) {
5360083261SDirk Eibach 		char cur = tolower(hexstr[i]);
5460083261SDirk Eibach 		u8 val;
5560083261SDirk Eibach 
5660083261SDirk Eibach 		if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) {
5760083261SDirk Eibach 			val = cur - (cur > '9' ? 87 : 48);
5860083261SDirk Eibach 
5960083261SDirk Eibach 			if (i % 2 == 0)
6060083261SDirk Eibach 				acc = 16 * val;
6160083261SDirk Eibach 			else
6260083261SDirk Eibach 				(*result)[i / 2] = acc + val;
6360083261SDirk Eibach 		} else {
6460083261SDirk Eibach 			free(*result);
6560083261SDirk Eibach 			return 1;
6660083261SDirk Eibach 		}
6760083261SDirk Eibach 	}
6860083261SDirk Eibach 
6960083261SDirk Eibach 	return 0;
7060083261SDirk Eibach }
7160083261SDirk Eibach 
extract_subprogram(u8 ** progdata,u32 expected_magic,struct key_program ** result)7260083261SDirk Eibach int extract_subprogram(u8 **progdata, u32 expected_magic,
7360083261SDirk Eibach 		       struct key_program **result)
7460083261SDirk Eibach {
7560083261SDirk Eibach 	struct key_program *prog = *result;
7660083261SDirk Eibach 	u32 magic, code_crc, code_size;
7760083261SDirk Eibach 
7860083261SDirk Eibach 	magic = get_unaligned_be32(*progdata);
7960083261SDirk Eibach 	code_crc = get_unaligned_be32(*progdata + 4);
8060083261SDirk Eibach 	code_size = get_unaligned_be32(*progdata + 8);
8160083261SDirk Eibach 
8260083261SDirk Eibach 	*progdata += 12;
8360083261SDirk Eibach 
8460083261SDirk Eibach 	if (magic != expected_magic)
8560083261SDirk Eibach 		return -1;
8660083261SDirk Eibach 
8760083261SDirk Eibach 	*result = malloc(sizeof(struct key_program) + code_size);
8860083261SDirk Eibach 
8960083261SDirk Eibach 	if (!*result)
9060083261SDirk Eibach 		return -1;
9160083261SDirk Eibach 
9260083261SDirk Eibach 	prog->magic = magic;
9360083261SDirk Eibach 	prog->code_crc = code_crc;
9460083261SDirk Eibach 	prog->code_size = code_size;
9560083261SDirk Eibach 	memcpy(prog->code, *progdata, code_size);
9660083261SDirk Eibach 
9760083261SDirk Eibach 	*progdata += code_size;
9860083261SDirk Eibach 
9960083261SDirk Eibach 	if (hre_verify_program(prog)) {
10060083261SDirk Eibach 		free(prog);
10160083261SDirk Eibach 		return -1;
10260083261SDirk Eibach 	}
10360083261SDirk Eibach 
10460083261SDirk Eibach 	return 0;
10560083261SDirk Eibach }
10660083261SDirk Eibach 
parse_and_check_keyprog(u8 * progdata)10760083261SDirk Eibach struct key_program *parse_and_check_keyprog(u8 *progdata)
10860083261SDirk Eibach {
10960083261SDirk Eibach 	struct key_program *result = NULL, *hmac = NULL;
11060083261SDirk Eibach 
11160083261SDirk Eibach 	/* Part 1: Load key program */
11260083261SDirk Eibach 
11360083261SDirk Eibach 	if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result))
11460083261SDirk Eibach 		return NULL;
11560083261SDirk Eibach 
11660083261SDirk Eibach 	/* Part 2: Load hmac program */
11760083261SDirk Eibach 
11860083261SDirk Eibach 	if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac))
11960083261SDirk Eibach 		return NULL;
12060083261SDirk Eibach 
12160083261SDirk Eibach 	free(hmac);
12260083261SDirk Eibach 
12360083261SDirk Eibach 	return result;
12460083261SDirk Eibach }
12560083261SDirk Eibach 
load_and_run_keyprog(struct udevice * tpm)126*abdc7b8aSSimon Glass int load_and_run_keyprog(struct udevice *tpm)
12760083261SDirk Eibach {
12860083261SDirk Eibach 	char *cmd = NULL;
12960083261SDirk Eibach 	u8 *binprog = NULL;
13060083261SDirk Eibach 	char *hexprog;
13160083261SDirk Eibach 	struct key_program *prog;
13260083261SDirk Eibach 
13300caae6dSSimon Glass 	cmd = env_get("loadkeyprogram");
13460083261SDirk Eibach 
13560083261SDirk Eibach 	if (!cmd || run_command(cmd, 0))
13660083261SDirk Eibach 		return 1;
13760083261SDirk Eibach 
13800caae6dSSimon Glass 	hexprog = env_get("keyprogram");
13960083261SDirk Eibach 
14060083261SDirk Eibach 	if (decode_hexstr(hexprog, &binprog))
14160083261SDirk Eibach 		return 1;
14260083261SDirk Eibach 
14360083261SDirk Eibach 	prog = parse_and_check_keyprog(binprog);
14460083261SDirk Eibach 	free(binprog);
14560083261SDirk Eibach 
14660083261SDirk Eibach 	if (!prog)
14760083261SDirk Eibach 		return 1;
14860083261SDirk Eibach 
149*abdc7b8aSSimon Glass 	if (hre_run_program(tpm, prog->code, prog->code_size)) {
15060083261SDirk Eibach 		free(prog);
15160083261SDirk Eibach 		return 1;
15260083261SDirk Eibach 	}
15360083261SDirk Eibach 
15460083261SDirk Eibach 	printf("\nSD code ran successfully\n");
15560083261SDirk Eibach 
15660083261SDirk Eibach 	free(prog);
15760083261SDirk Eibach 
15860083261SDirk Eibach 	return 0;
15960083261SDirk Eibach }
160