xref: /optee_os/core/pta/rockchip/rk_secure_boot.c (revision 2949576eb4b8e0eb7a6d9c97e38a30841f621b61)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2025, Pengutronix, Michael Tretter <entwicklung@pengutronix.de>
4  */
5 
6 #include <config.h>
7 #include <drivers/rockchip_otp.h>
8 #include <kernel/pseudo_ta.h>
9 #include <kernel/tee_misc.h>
10 #include <tee/uuid.h>
11 #include <utee_defines.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <platform_config.h>
15 
16 #include <pta_rk_secure_boot.h>
17 
18 #define PTA_NAME "rk_secure_boot.pta"
19 
20 /*
21  * The hash is stored in OTP in little endian. The PTA assumes that OP-TEE is
22  * in little endian and may copy the hash from memory to OTP without ensuring
23  * the byte order.
24  */
25 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
26 
test_bit_mask(uint32_t value,uint32_t mask)27 static inline bool test_bit_mask(uint32_t value, uint32_t mask)
28 {
29 	return (value & mask) == mask;
30 }
31 
32 #define HASH_STRING_SIZE 88
33 static_assert(ROCKCHIP_OTP_RSA_HASH_SIZE == 8);
otp_to_string(uint32_t * otp,char * str,size_t str_size)34 static __maybe_unused char *otp_to_string(uint32_t *otp,
35 					  char *str, size_t str_size)
36 {
37 	snprintf(str, str_size,
38 		 "0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32
39 		 " 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32" 0x%"PRIx32,
40 		 otp[0], otp[1], otp[2], otp[3],
41 		 otp[4], otp[5], otp[6], otp[7]);
42 
43 	return str;
44 }
45 
write_key_size(uint32_t key_size_bits)46 static TEE_Result write_key_size(uint32_t key_size_bits)
47 {
48 	uint32_t idx = ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX;
49 	uint32_t sz = ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE;
50 	TEE_Result res = TEE_SUCCESS;
51 	uint32_t status = 0;
52 
53 	IMSG("Setting key size to %"PRId32, key_size_bits);
54 
55 	switch (key_size_bits) {
56 	case 4096:
57 		status |= ROCKCHIP_OTP_SECURE_BOOT_STATUS_RSA4096;
58 
59 		res = rockchip_otp_write_secure(&status, idx, sz);
60 		if (res)
61 			return res;
62 
63 		res = rockchip_otp_read_secure(&status, idx, sz);
64 		if (res)
65 			return res;
66 		if (!test_bit_mask(status,
67 				   ROCKCHIP_OTP_SECURE_BOOT_STATUS_RSA4096))
68 			return TEE_ERROR_GENERIC;
69 		break;
70 	case 2048:
71 		/* Nothing to do */
72 		break;
73 	default:
74 		res = TEE_ERROR_BAD_PARAMETERS;
75 		break;
76 	}
77 
78 	return res;
79 }
80 
write_hash(uint32_t * hash,size_t size)81 static TEE_Result write_hash(uint32_t *hash, size_t size)
82 {
83 	char __maybe_unused str[HASH_STRING_SIZE] = {};
84 	uint32_t tmp[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
85 	TEE_Result res = TEE_SUCCESS;
86 
87 	if (size != ROCKCHIP_OTP_RSA_HASH_SIZE)
88 		return TEE_ERROR_GENERIC;
89 
90 	IMSG("Burning hash %s", otp_to_string(hash, str, sizeof(str)));
91 
92 	res = rockchip_otp_write_secure(hash,
93 					ROCKCHIP_OTP_RSA_HASH_INDEX,
94 					ROCKCHIP_OTP_RSA_HASH_SIZE);
95 	if (res)
96 		return res;
97 
98 	res = rockchip_otp_read_secure(tmp,
99 				       ROCKCHIP_OTP_RSA_HASH_INDEX,
100 				       ROCKCHIP_OTP_RSA_HASH_SIZE);
101 	if (res)
102 		return res;
103 	if (memcmp(tmp, hash, sizeof(tmp))) {
104 		EMSG("Failed to burn hash. OTP is %s",
105 		     otp_to_string(tmp, str, sizeof(str)));
106 		return res;
107 	}
108 
109 	return res;
110 }
111 
get_info(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])112 static TEE_Result get_info(uint32_t param_types,
113 			   TEE_Param params[TEE_NUM_PARAMS])
114 {
115 	uint32_t hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
116 	char __maybe_unused str[HASH_STRING_SIZE] = {};
117 	struct pta_rk_secure_boot_info *info = NULL;
118 	TEE_Result res = TEE_ERROR_GENERIC;
119 	uint32_t status = 0;
120 
121 	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
122 					   TEE_PARAM_TYPE_NONE,
123 					   TEE_PARAM_TYPE_NONE,
124 					   TEE_PARAM_TYPE_NONE))
125 		return TEE_ERROR_BAD_PARAMETERS;
126 
127 	if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*info)))
128 		return TEE_ERROR_BAD_PARAMETERS;
129 
130 	info = params[0].memref.buffer;
131 	if (!info || params[0].memref.size != sizeof(*info))
132 		return TEE_ERROR_BAD_PARAMETERS;
133 
134 	memset(info, 0, sizeof(*info));
135 
136 	res = rockchip_otp_read_secure(&status,
137 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
138 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
139 	if (res)
140 		return res;
141 
142 	res = rockchip_otp_read_secure(hash,
143 				       ROCKCHIP_OTP_RSA_HASH_INDEX,
144 				       ROCKCHIP_OTP_RSA_HASH_SIZE);
145 	if (res)
146 		return res;
147 
148 	DMSG("Current hash: %s", otp_to_string(hash, str, sizeof(str)));
149 
150 	info->enabled = test_bit_mask(status,
151 				      ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE);
152 	info->simulation = IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION);
153 	memcpy(info->hash.value, hash, sizeof(info->hash.value));
154 
155 	return TEE_SUCCESS;
156 }
157 
burn_hash(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])158 static TEE_Result burn_hash(uint32_t param_types,
159 			    TEE_Param params[TEE_NUM_PARAMS])
160 {
161 	uint32_t new_hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
162 	uint32_t old_hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
163 	char __maybe_unused str[HASH_STRING_SIZE] = {};
164 	struct pta_rk_secure_boot_hash *hash = NULL;
165 	TEE_Result res = TEE_SUCCESS;
166 	uint32_t key_size_bits = 0;
167 	uint32_t status = 0;
168 	size_t hash_sz = 0;
169 
170 	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
171 					   TEE_PARAM_TYPE_VALUE_INPUT,
172 					   TEE_PARAM_TYPE_NONE,
173 					   TEE_PARAM_TYPE_NONE))
174 		return TEE_ERROR_BAD_PARAMETERS;
175 
176 	hash = params[0].memref.buffer;
177 	hash_sz = params[0].memref.size;
178 	if (!hash || hash_sz != sizeof(*hash))
179 		return TEE_ERROR_BAD_PARAMETERS;
180 	memcpy(new_hash, hash->value, sizeof(new_hash));
181 
182 	key_size_bits = params[1].value.a;
183 	if (key_size_bits != 4096 && key_size_bits != 2048) {
184 		EMSG("Invalid key size: %"PRId32, key_size_bits);
185 		return TEE_ERROR_BAD_PARAMETERS;
186 	}
187 
188 	res = rockchip_otp_read_secure(old_hash,
189 				       ROCKCHIP_OTP_RSA_HASH_INDEX,
190 				       ROCKCHIP_OTP_RSA_HASH_SIZE);
191 	if (res)
192 		return res;
193 	if (memcmp(old_hash, new_hash, sizeof(new_hash))) {
194 		EMSG("Refusing to burn hash %s",
195 		     otp_to_string(new_hash, str, sizeof(str)));
196 		EMSG("OTP hash is %s",
197 		     otp_to_string(old_hash, str, sizeof(str)));
198 		return res;
199 	}
200 
201 	/*
202 	 * Check if secure boot is already enabled after verifying the
203 	 * parameters for reporting the correct error if the command would
204 	 * result in the same state as the already fused board.
205 	 */
206 	res = rockchip_otp_read_secure(&status,
207 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
208 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
209 	if (res)
210 		return res;
211 	if (test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
212 		DMSG("Secure boot already enabled");
213 		return TEE_SUCCESS;
214 	}
215 
216 	if (IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION)) {
217 		IMSG("Simulation mode: Skip burning hash %s, key size %"PRId32,
218 		     otp_to_string(new_hash, str, sizeof(str)), key_size_bits);
219 		return TEE_SUCCESS;
220 	}
221 
222 	res = write_hash(new_hash, ARRAY_SIZE(new_hash));
223 	if (res) {
224 		EMSG("Failed to write hash");
225 		return res;
226 	}
227 
228 	res = write_key_size(key_size_bits);
229 	if (res) {
230 		EMSG("Failed to write key size");
231 		return res;
232 	}
233 
234 	return TEE_SUCCESS;
235 }
236 
lockdown_device(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS]__unused)237 static TEE_Result lockdown_device(uint32_t param_types,
238 				  TEE_Param params[TEE_NUM_PARAMS] __unused)
239 {
240 	uint32_t hash[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
241 	uint32_t zero[ROCKCHIP_OTP_RSA_HASH_SIZE] = {};
242 	TEE_Result res = TEE_ERROR_GENERIC;
243 	uint32_t status = 0;
244 
245 	if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
246 					   TEE_PARAM_TYPE_NONE,
247 					   TEE_PARAM_TYPE_NONE,
248 					   TEE_PARAM_TYPE_NONE))
249 		return TEE_ERROR_BAD_PARAMETERS;
250 
251 	res = rockchip_otp_read_secure(hash,
252 				       ROCKCHIP_OTP_RSA_HASH_INDEX,
253 				       ROCKCHIP_OTP_RSA_HASH_SIZE);
254 	if (res)
255 		return res;
256 	if (!memcmp(zero, hash, sizeof(hash))) {
257 		EMSG("OTP hash is all zeros. Refuse lockdown.");
258 		return TEE_ERROR_GENERIC;
259 	}
260 
261 	res = rockchip_otp_read_secure(&status,
262 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
263 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
264 	if (res)
265 		return res;
266 	if (test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
267 		DMSG("Secure boot already enabled");
268 		return TEE_SUCCESS;
269 	}
270 
271 	status = ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE;
272 
273 	if (IS_ENABLED(CFG_RK_SECURE_BOOT_SIMULATION)) {
274 		IMSG("Simulation mode: Skip writing status: %"PRIx32,
275 		     status);
276 		return TEE_SUCCESS;
277 	}
278 
279 	IMSG("Writing secure boot status: %"PRIx32, status);
280 	res = rockchip_otp_write_secure(&status,
281 					ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
282 					ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
283 	if (res)
284 		return res;
285 
286 	res = rockchip_otp_read_secure(&status,
287 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_INDEX,
288 				       ROCKCHIP_OTP_SECURE_BOOT_STATUS_SIZE);
289 	if (res)
290 		return res;
291 	if (test_bit_mask(status, ROCKCHIP_OTP_SECURE_BOOT_STATUS_ENABLE)) {
292 		EMSG("Failed to write secure boot status");
293 		return TEE_ERROR_GENERIC;
294 	}
295 
296 	return TEE_SUCCESS;
297 }
298 
invoke_command(void * sess_ctx __unused,uint32_t cmd_id,uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])299 static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
300 				 uint32_t param_types,
301 				 TEE_Param params[TEE_NUM_PARAMS])
302 {
303 	TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
304 	TEE_Param bparams[TEE_NUM_PARAMS] = { };
305 	TEE_Result res2 = TEE_ERROR_GENERIC;
306 	TEE_Param *eparams = NULL;
307 
308 	res = to_bounce_params(param_types, params, bparams, &eparams);
309 	if (res)
310 		return res;
311 
312 	switch (cmd_id) {
313 	case PTA_RK_SECURE_BOOT_GET_INFO:
314 		res = get_info(param_types, eparams);
315 		break;
316 	case PTA_RK_SECURE_BOOT_BURN_HASH:
317 		res = burn_hash(param_types, eparams);
318 		break;
319 	case PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE:
320 		res = lockdown_device(param_types, eparams);
321 		break;
322 	default:
323 		break;
324 	}
325 
326 	res2 = from_bounce_params(param_types, params, bparams, eparams);
327 	if (!res && res2)
328 		res = res2;
329 
330 	return res;
331 }
332 
333 pseudo_ta_register(.uuid = PTA_RK_SECURE_BOOT_UUID,
334 		   .name = PTA_NAME,
335 		   .flags = PTA_DEFAULT_FLAGS,
336 		   .invoke_command_entry_point = invoke_command);
337