1 /*
2  * Copyright (C) 2019-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <types.h>
7 #include <asm/cpu.h>
8 #include <asm/pgtable.h>
9 #include <rtl.h>
10 #include <asm/mmu.h>
11 #include <sprintf.h>
12 #include <asm/guest/ept.h>
13 #include <logmsg.h>
14 #include <boot.h>
15 #include <crypto_api.h>
16 #include <asm/seed.h>
17 #include "seed_abl.h"
18 #include "seed_sbl.h"
19 
20 #define BOOTLOADER_SBL  0U
21 #define BOOTLOADER_ABL  1U
22 #define BOOTLOADER_INVD (~0U)
23 
24 struct seed_argument {
25 	const char *str;
26 	uint32_t bootloader_id;
27 	uint64_t addr;
28 };
29 
30 #define SEED_ARG_NUM 4U
31 static struct seed_argument seed_arg[SEED_ARG_NUM] = {
32 	{ "ImageBootParamsAddr=",        BOOTLOADER_SBL, 0UL },
33 	{ "ABL.svnseed=",                BOOTLOADER_ABL, 0UL },
34 	{ "dev_sec_info.param_addr=",    BOOTLOADER_ABL, 0UL },
35 	{ NULL, BOOTLOADER_INVD, 0UL }
36 };
37 
38 static struct physical_seed g_phy_seed;
39 
parse_seed_arg(void)40 static uint32_t parse_seed_arg(void)
41 {
42 	const char *cmd_src = NULL;
43 	char *arg, *arg_end;
44 	struct acrn_boot_info *abi = get_acrn_boot_info();
45 	uint32_t i = SEED_ARG_NUM - 1U;
46 	uint32_t len;
47 
48 	cmd_src = abi->cmdline;
49 
50 	if (cmd_src != NULL) {
51 		for (i = 0U; seed_arg[i].str != NULL; i++) {
52 			len = strnlen_s(seed_arg[i].str, MEM_1K);
53 			arg = strstr_s((const char *)cmd_src, MAX_BOOTARGS_SIZE, seed_arg[i].str, len);
54 			if (arg != NULL) {
55 				arg += len;
56 				seed_arg[i].addr = strtoul_hex(arg);
57 
58 				/*
59 				 * Replace original arguments with spaces since Guest's GPA might not
60 				 * identity mapped to HPA. The argument will be appended later when
61 				 * compose cmdline for Guest.
62 				 */
63 				arg_end = strchr(arg, ' ');
64 				arg -= len;
65 				len = (arg_end != NULL) ? (uint32_t)(arg_end - arg) :
66 					strnlen_s(arg, MAX_BOOTARGS_SIZE);
67 				(void)memset((void *)arg, (uint8_t)' ', len);
68 				break;
69 			}
70 		}
71 	}
72 
73 	return i;
74 }
75 
76 /*
77  * fill_seed_arg
78  *
79  * description:
80  *     fill seed argument to cmdline buffer which has MAX size of MAX_SEED_ARG_SIZE
81  *
82  * input:
83  *    cmd_dst   pointer to cmdline buffer
84  *    cmd_sz    size of cmd_dst buffer
85  *
86  * output:
87  *    cmd_dst   pointer to cmdline buffer
88  *
89  * return value:
90  *    none
91  *
92  * @pre cmd_dst != NULL
93  */
fill_seed_arg(char * cmd_dst,size_t cmd_sz)94 void fill_seed_arg(char *cmd_dst, size_t cmd_sz)
95 {
96 	uint32_t i;
97 
98 	for (i = 0U; seed_arg[i].str != NULL; i++) {
99 		if (seed_arg[i].addr != 0UL) {
100 
101 			snprintf(cmd_dst, cmd_sz, "%s0x%X ", seed_arg[i].str, service_vm_hpa2gpa(seed_arg[i].addr));
102 
103 			if (seed_arg[i].bootloader_id == BOOTLOADER_SBL) {
104 				struct image_boot_params *boot_params =
105 					(struct image_boot_params *)hpa2hva(seed_arg[i].addr);
106 
107 				boot_params->p_seed_list = service_vm_hpa2gpa(boot_params->p_seed_list);
108 
109 				boot_params->p_platform_info = service_vm_hpa2gpa(boot_params->p_platform_info);
110 			}
111 
112 			break;
113 		}
114 	}
115 }
116 
117 /*
118  * derive_virtual_seed
119  *
120  * description:
121  *     derive virtual seed list from physical seed list
122  *
123  * input:
124  *    salt        pointer to salt
125  *    salt_len    length of salt
126  *    info        pointer to info
127  *    info_len    length of info
128  *
129  * output:
130  *    seed_list   pointer to seed_list
131  *    num_seed    seed number in seed_list
132  *
133  * return value:
134  *    true if derive successfully, otherwise false
135  */
derive_virtual_seed(struct seed_info * seed_list,uint32_t * num_seeds,const uint8_t * salt,size_t salt_len,const uint8_t * info,size_t info_len)136 bool derive_virtual_seed(struct seed_info *seed_list, uint32_t *num_seeds,
137 			 const uint8_t *salt, size_t salt_len, const uint8_t *info, size_t info_len)
138 {
139 	uint32_t i;
140 	bool ret = true;
141 
142 	if ((seed_list == NULL) || (g_phy_seed.num_seeds == 0U)) {
143 		ret = false;
144 	} else {
145 		for (i = 0U; i < g_phy_seed.num_seeds; i++) {
146 			if (hkdf_sha256(seed_list[i].seed,
147 					sizeof(seed_list[i].seed),
148 					g_phy_seed.seed_list[i].seed,
149 					sizeof(g_phy_seed.seed_list[i].seed),
150 					salt, salt_len,
151 					info, info_len) == 0) {
152 				*num_seeds = 0U;
153 				(void)memset(seed_list, 0U, sizeof(struct seed_info) * BOOTLOADER_SEED_MAX_ENTRIES);
154 				pr_err("%s: derive virtual seed list failed!", __func__);
155 				ret = false;
156 				break;
157 			}
158 			seed_list[i].cse_svn = g_phy_seed.seed_list[i].cse_svn;
159 		}
160 		*num_seeds = g_phy_seed.num_seeds;
161 	}
162 
163 	return ret;
164 }
165 
get_max_svn_index(void)166 static inline uint32_t get_max_svn_index(void)
167 {
168 	uint32_t i, max_svn_idx = 0U;
169 
170 	for (i = 1U; i < g_phy_seed.num_seeds; i++) {
171 		if (g_phy_seed.seed_list[i].cse_svn > g_phy_seed.seed_list[i - 1U].cse_svn) {
172 			max_svn_idx = i;
173 		}
174 	}
175 
176 	return max_svn_idx;
177 }
178 
179 /*
180  * derive_attkb_enc_key
181  *
182  * description:
183  *     derive attestation keybox encryption key from physical seed(max svn)
184  *
185  * input:
186  *    none
187  *
188  * output:
189  *    out_key     pointer to output key
190  *
191  * return value:
192  *    true if derive successfully, otherwise false
193  */
derive_attkb_enc_key(uint8_t * out_key)194 bool derive_attkb_enc_key(uint8_t *out_key)
195 {
196 	bool ret = true;
197 	const uint8_t *ikm;
198 	uint32_t ikm_len;
199 	uint32_t max_svn_idx;
200 	const uint8_t salt[] = "Attestation Keybox Encryption Key";
201 
202 	if ((out_key == NULL) || (g_phy_seed.num_seeds == 0U) ||
203 	    (g_phy_seed.num_seeds > BOOTLOADER_SEED_MAX_ENTRIES)) {
204 		ret = false;
205 	} else {
206 		max_svn_idx = get_max_svn_index();
207 		ikm = &(g_phy_seed.seed_list[max_svn_idx].seed[0]);
208 		/* only the low 32 bytes of seed are valid */
209 		ikm_len = 32U;
210 
211 		if (hmac_sha256(out_key, ikm, ikm_len, salt, sizeof(salt)) != 1) {
212 			pr_err("%s: failed to derive key!\n", __func__);
213 			ret = false;
214 		}
215 	}
216 
217 	return ret;
218 }
219 
init_seed(void)220 void init_seed(void)
221 {
222 	bool status;
223 	uint32_t index;
224 
225 	index = parse_seed_arg();
226 
227 	switch (seed_arg[index].bootloader_id) {
228 	case BOOTLOADER_SBL:
229 		status = parse_seed_sbl(seed_arg[index].addr, &g_phy_seed);
230 		break;
231 	case BOOTLOADER_ABL:
232 		status = parse_seed_abl(seed_arg[index].addr, &g_phy_seed);
233 		break;
234 	default:
235 		status = false;
236 		break;
237 	}
238 
239 	/* Failed to parse seed from Bootloader, using dummy seed */
240 	if (!status) {
241 		g_phy_seed.num_seeds = 1U;
242 		(void)memset(&g_phy_seed.seed_list[0], 0xA5U, sizeof(g_phy_seed.seed_list));
243 	}
244 }
245