xref: /openbmc/u-boot/board/gdsys/a38x/keyprogram.c (revision 60083261)
1*60083261SDirk Eibach /*
2*60083261SDirk Eibach  * (C) Copyright 2016
3*60083261SDirk Eibach  * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
4*60083261SDirk Eibach  *
5*60083261SDirk Eibach  * SPDX-License-Identifier:    GPL-2.0+
6*60083261SDirk Eibach  */
7*60083261SDirk Eibach 
8*60083261SDirk Eibach #include <common.h>
9*60083261SDirk Eibach #include <tpm.h>
10*60083261SDirk Eibach #include <malloc.h>
11*60083261SDirk Eibach #include <linux/ctype.h>
12*60083261SDirk Eibach #include <asm/unaligned.h>
13*60083261SDirk Eibach 
14*60083261SDirk Eibach #include "hre.h"
15*60083261SDirk Eibach 
16*60083261SDirk Eibach int flush_keys(void)
17*60083261SDirk Eibach {
18*60083261SDirk Eibach 	u16 key_count;
19*60083261SDirk Eibach 	u8 buf[288];
20*60083261SDirk Eibach 	u8 *ptr;
21*60083261SDirk Eibach 	u32 err;
22*60083261SDirk Eibach 	uint i;
23*60083261SDirk Eibach 
24*60083261SDirk Eibach 	/* fetch list of already loaded keys in the TPM */
25*60083261SDirk Eibach 	err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
26*60083261SDirk Eibach 	if (err)
27*60083261SDirk Eibach 		return -1;
28*60083261SDirk Eibach 	key_count = get_unaligned_be16(buf);
29*60083261SDirk Eibach 	ptr = buf + 2;
30*60083261SDirk Eibach 	for (i = 0; i < key_count; ++i, ptr += 4) {
31*60083261SDirk Eibach 		err = tpm_flush_specific(get_unaligned_be32(ptr), TPM_RT_KEY);
32*60083261SDirk Eibach 		if (err && err != TPM_KEY_OWNER_CONTROL)
33*60083261SDirk Eibach 			return err;
34*60083261SDirk Eibach 	}
35*60083261SDirk Eibach 
36*60083261SDirk Eibach 	return 0;
37*60083261SDirk Eibach }
38*60083261SDirk Eibach 
39*60083261SDirk Eibach int decode_hexstr(char *hexstr, u8 **result)
40*60083261SDirk Eibach {
41*60083261SDirk Eibach 	int len = strlen(hexstr);
42*60083261SDirk Eibach 	int bytes = len / 2;
43*60083261SDirk Eibach 	int i;
44*60083261SDirk Eibach 	u8 acc = 0;
45*60083261SDirk Eibach 
46*60083261SDirk Eibach 	if (len % 2 == 1)
47*60083261SDirk Eibach 		return 1;
48*60083261SDirk Eibach 
49*60083261SDirk Eibach 	*result = (u8 *)malloc(bytes);
50*60083261SDirk Eibach 
51*60083261SDirk Eibach 	for (i = 0; i < len; i++) {
52*60083261SDirk Eibach 		char cur = tolower(hexstr[i]);
53*60083261SDirk Eibach 		u8 val;
54*60083261SDirk Eibach 
55*60083261SDirk Eibach 		if ((cur >= 'a' && cur <= 'f') || (cur >= '0' && cur <= '9')) {
56*60083261SDirk Eibach 			val = cur - (cur > '9' ? 87 : 48);
57*60083261SDirk Eibach 
58*60083261SDirk Eibach 			if (i % 2 == 0)
59*60083261SDirk Eibach 				acc = 16 * val;
60*60083261SDirk Eibach 			else
61*60083261SDirk Eibach 				(*result)[i / 2] = acc + val;
62*60083261SDirk Eibach 		} else {
63*60083261SDirk Eibach 			free(*result);
64*60083261SDirk Eibach 			return 1;
65*60083261SDirk Eibach 		}
66*60083261SDirk Eibach 	}
67*60083261SDirk Eibach 
68*60083261SDirk Eibach 	return 0;
69*60083261SDirk Eibach }
70*60083261SDirk Eibach 
71*60083261SDirk Eibach int extract_subprogram(u8 **progdata, u32 expected_magic,
72*60083261SDirk Eibach 		       struct key_program **result)
73*60083261SDirk Eibach {
74*60083261SDirk Eibach 	struct key_program *prog = *result;
75*60083261SDirk Eibach 	u32 magic, code_crc, code_size;
76*60083261SDirk Eibach 
77*60083261SDirk Eibach 	magic = get_unaligned_be32(*progdata);
78*60083261SDirk Eibach 	code_crc = get_unaligned_be32(*progdata + 4);
79*60083261SDirk Eibach 	code_size = get_unaligned_be32(*progdata + 8);
80*60083261SDirk Eibach 
81*60083261SDirk Eibach 	*progdata += 12;
82*60083261SDirk Eibach 
83*60083261SDirk Eibach 	if (magic != expected_magic)
84*60083261SDirk Eibach 		return -1;
85*60083261SDirk Eibach 
86*60083261SDirk Eibach 	*result = malloc(sizeof(struct key_program) + code_size);
87*60083261SDirk Eibach 
88*60083261SDirk Eibach 	if (!*result)
89*60083261SDirk Eibach 		return -1;
90*60083261SDirk Eibach 
91*60083261SDirk Eibach 	prog->magic = magic;
92*60083261SDirk Eibach 	prog->code_crc = code_crc;
93*60083261SDirk Eibach 	prog->code_size = code_size;
94*60083261SDirk Eibach 	memcpy(prog->code, *progdata, code_size);
95*60083261SDirk Eibach 
96*60083261SDirk Eibach 	*progdata += code_size;
97*60083261SDirk Eibach 
98*60083261SDirk Eibach 	if (hre_verify_program(prog)) {
99*60083261SDirk Eibach 		free(prog);
100*60083261SDirk Eibach 		return -1;
101*60083261SDirk Eibach 	}
102*60083261SDirk Eibach 
103*60083261SDirk Eibach 	return 0;
104*60083261SDirk Eibach }
105*60083261SDirk Eibach 
106*60083261SDirk Eibach struct key_program *parse_and_check_keyprog(u8 *progdata)
107*60083261SDirk Eibach {
108*60083261SDirk Eibach 	struct key_program *result = NULL, *hmac = NULL;
109*60083261SDirk Eibach 
110*60083261SDirk Eibach 	/* Part 1: Load key program */
111*60083261SDirk Eibach 
112*60083261SDirk Eibach 	if (extract_subprogram(&progdata, MAGIC_KEY_PROGRAM, &result))
113*60083261SDirk Eibach 		return NULL;
114*60083261SDirk Eibach 
115*60083261SDirk Eibach 	/* Part 2: Load hmac program */
116*60083261SDirk Eibach 
117*60083261SDirk Eibach 	if (extract_subprogram(&progdata, MAGIC_HMAC, &hmac))
118*60083261SDirk Eibach 		return NULL;
119*60083261SDirk Eibach 
120*60083261SDirk Eibach 	free(hmac);
121*60083261SDirk Eibach 
122*60083261SDirk Eibach 	return result;
123*60083261SDirk Eibach }
124*60083261SDirk Eibach 
125*60083261SDirk Eibach int load_and_run_keyprog(void)
126*60083261SDirk Eibach {
127*60083261SDirk Eibach 	char *cmd = NULL;
128*60083261SDirk Eibach 	u8 *binprog = NULL;
129*60083261SDirk Eibach 	char *hexprog;
130*60083261SDirk Eibach 	struct key_program *prog;
131*60083261SDirk Eibach 
132*60083261SDirk Eibach 	cmd = getenv("loadkeyprogram");
133*60083261SDirk Eibach 
134*60083261SDirk Eibach 	if (!cmd || run_command(cmd, 0))
135*60083261SDirk Eibach 		return 1;
136*60083261SDirk Eibach 
137*60083261SDirk Eibach 	hexprog = getenv("keyprogram");
138*60083261SDirk Eibach 
139*60083261SDirk Eibach 	if (decode_hexstr(hexprog, &binprog))
140*60083261SDirk Eibach 		return 1;
141*60083261SDirk Eibach 
142*60083261SDirk Eibach 	prog = parse_and_check_keyprog(binprog);
143*60083261SDirk Eibach 	free(binprog);
144*60083261SDirk Eibach 
145*60083261SDirk Eibach 	if (!prog)
146*60083261SDirk Eibach 		return 1;
147*60083261SDirk Eibach 
148*60083261SDirk Eibach 	if (hre_run_program(prog->code, prog->code_size)) {
149*60083261SDirk Eibach 		free(prog);
150*60083261SDirk Eibach 		return 1;
151*60083261SDirk Eibach 	}
152*60083261SDirk Eibach 
153*60083261SDirk Eibach 	printf("\nSD code ran successfully\n");
154*60083261SDirk Eibach 
155*60083261SDirk Eibach 	free(prog);
156*60083261SDirk Eibach 
157*60083261SDirk Eibach 	return 0;
158*60083261SDirk Eibach }
159