Skip to content

Commit 7a6baad

Browse files
committed
core: pta: add Rockchip secure boot PTA
The S_OTP area for the Rockchip secure boot RSA hash and status register is accessible only from the secure world. Thus, secure boot must be enabled from the secure world on these board. The PTA implements 3 functions: 1. Ask the TA from the non-secure world about the current status and hash of the hardware. This allows to inspect the current status of secure boot on a specific device. 2. Write an RSA hash into the OTP fuses. It's the responsibility of the user to calculate the hash and ensure that it matches the key, which will be used to sign the images. 3. Actually lockdown the device by enabling secure boot. This is a separate step to allow the user to verify the setup before potentially bricking a device. With these functions, a user may use a client running in the normal world (for example in a boot loader or operating system) to enable secure boot on a Rockchip device. Implementing secure boot setup as an OP-TEE PTA has the advantage that secure boot can be enabled at any time during the device setup instead of during early boot. This allows a developer/user or additional scripts to interact with the secure boot setup process. The hash of the root key is accepted and reported as calculated by sha256sum and internally converted to the correct byte order that needs to be burned into the fuses. Signed-off-by: Michael Tretter <[email protected]>
1 parent 347caf9 commit 7a6baad

File tree

4 files changed

+338
-1
lines changed

4 files changed

+338
-1
lines changed

core/pta/rockchip/rk_secure_boot.c

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
// SPDX-License-Identifier: BSD-2-Clause
2+
/*
3+
* Copyright (C) 2025, Pengutronix, Michael Tretter <[email protected]>
4+
*/
5+
6+
#include <config.h>
7+
#include <kernel/pseudo_ta.h>
8+
#include <kernel/tee_misc.h>
9+
#include <tee/uuid.h>
10+
#include <utee_defines.h>
11+
#include <string.h>
12+
13+
#include <pta_rk_secure_boot.h>
14+
15+
#include <drivers/rockchip_otp.h>
16+
17+
#define PTA_NAME "rk_secure_boot.pta"
18+
19+
static void u32_to_bytes(uint32_t u32, uint8_t *bytes)
20+
{
21+
size_t i;
22+
23+
for (i = 0; i < sizeof(u32); i++)
24+
*(bytes + i) = (uint8_t) (u32 >> (i * 8));
25+
}
26+
27+
static void bytes_to_u32(uint8_t *bytes, uint32_t *u32)
28+
{
29+
size_t i;
30+
31+
*u32 = 0;
32+
for (i = 0; i < sizeof(u32); i++)
33+
*u32 += (uint32_t)*(bytes + i) << (i * 8);
34+
}
35+
36+
static void print_hash(const char *name, uint32_t *hash)
37+
{
38+
EMSG("%s0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
39+
name, hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]);
40+
}
41+
42+
static bool secure_boot_status_enabled(uint32_t status)
43+
{
44+
return (status & SECURE_BOOT_STATUS_ENABLE) == SECURE_BOOT_STATUS_ENABLE;
45+
}
46+
47+
static TEE_Result get_info(uint32_t param_types,
48+
TEE_Param params[TEE_NUM_PARAMS])
49+
{
50+
TEE_Result res = TEE_ERROR_GENERIC;
51+
struct pta_rk_secure_boot_info *info = NULL;
52+
uint32_t status = 0;
53+
uint32_t hash[RSA_HASH_LENGTH];
54+
size_t i;
55+
56+
if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT,
57+
TEE_PARAM_TYPE_NONE,
58+
TEE_PARAM_TYPE_NONE,
59+
TEE_PARAM_TYPE_NONE))
60+
return TEE_ERROR_BAD_PARAMETERS;
61+
62+
if (!IS_ALIGNED_WITH_TYPE(params[0].memref.buffer, typeof(*info)))
63+
return TEE_ERROR_BAD_PARAMETERS;
64+
65+
info = params[0].memref.buffer;
66+
if (!info || params[0].memref.size != sizeof(*info))
67+
return TEE_ERROR_BAD_PARAMETERS;
68+
69+
memset(info, 0, sizeof(*info));
70+
71+
res = tee_otp_read_secure(&status,
72+
SECURE_BOOT_STATUS_INDEX,
73+
SECURE_BOOT_STATUS_LENGTH);
74+
if (res)
75+
return res;
76+
77+
res = tee_otp_read_secure(hash, RSA_HASH_INDEX, RSA_HASH_LENGTH);
78+
if (res)
79+
return res;
80+
81+
info->enabled = secure_boot_status_enabled(status);
82+
for (i = 0; i < ARRAY_SIZE(hash); i++)
83+
u32_to_bytes(hash[i], &info->hash.value[i * sizeof(uint32_t)]);
84+
#if !defined(SECURE_BOOT_ENABLE_DANGEROUS)
85+
info->simulation = 1;
86+
#else
87+
info->simulation = 0;
88+
#endif
89+
90+
return TEE_SUCCESS;
91+
}
92+
93+
/* Compare the hashes and return the number of identical bytes */
94+
static size_t hash_cmp(uint32_t *a, uint32_t *b, size_t s)
95+
{
96+
size_t i;
97+
98+
for (i = 0; i < s; i++) {
99+
if (b && a[i] == b[i]) {
100+
continue;
101+
} else if (a[i] == 0x0) {
102+
break;
103+
} else if (!b) {
104+
continue;
105+
} else {
106+
EMSG("Burned hash differs from new hash");
107+
return TEE_ERROR_GENERIC;
108+
}
109+
}
110+
111+
return i;
112+
}
113+
114+
static TEE_Result burn_hash(uint32_t param_types,
115+
TEE_Param params[TEE_NUM_PARAMS])
116+
{
117+
TEE_Result res = TEE_SUCCESS;
118+
struct pta_rk_secure_boot_hash *hash;
119+
size_t hash_sz;
120+
uint32_t status;
121+
uint32_t new_hash[RSA_HASH_LENGTH];
122+
uint32_t old_hash[RSA_HASH_LENGTH];
123+
size_t i;
124+
125+
if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
126+
TEE_PARAM_TYPE_NONE,
127+
TEE_PARAM_TYPE_NONE,
128+
TEE_PARAM_TYPE_NONE))
129+
return TEE_ERROR_BAD_PARAMETERS;
130+
131+
hash = params[0].memref.buffer;
132+
hash_sz = params[0].memref.size;
133+
if (!hash || hash_sz != sizeof(*hash))
134+
return TEE_ERROR_BAD_PARAMETERS;
135+
136+
res = tee_otp_read_secure(&status,
137+
SECURE_BOOT_STATUS_INDEX,
138+
SECURE_BOOT_STATUS_LENGTH);
139+
if (res)
140+
return res;
141+
if (secure_boot_status_enabled(status))
142+
return TEE_SUCCESS;
143+
144+
for (i = 0; i < ARRAY_SIZE(new_hash); i++)
145+
bytes_to_u32(&hash->value[i * sizeof(uint32_t)], &new_hash[i]);
146+
147+
print_hash("Burning new hash ", new_hash);
148+
res = tee_otp_read_secure(old_hash, RSA_HASH_INDEX, RSA_HASH_LENGTH);
149+
if (res)
150+
return res;
151+
i = hash_cmp(old_hash, new_hash, ARRAY_SIZE(new_hash));
152+
if (i == TEE_ERROR_GENERIC) {
153+
print_hash("Refuse to write new hash. Burned hash is ", old_hash);
154+
return TEE_ERROR_GENERIC;
155+
}
156+
157+
#if !defined(SECURE_BOOT_ENABLE_DANGEROUS)
158+
print_hash("Skip burning new hash ", new_hash);
159+
#else
160+
print_hash("Burning new hash ", new_hash);
161+
res = tee_otp_write_secure(new_hash,
162+
RSA_HASH_INDEX + i,
163+
RSA_HASH_LENGTH - i);
164+
if (res)
165+
return res;
166+
167+
res = tee_otp_read_secure(old_hash, RSA_HASH_INDEX, RSA_HASH_LENGTH);
168+
if (res)
169+
return res;
170+
if (hash_cmp(old_hash, new_hash, ARRAY_SIZE(new_hash)) != ARRAY_SIZE(new_hash)) {
171+
print_hash("Failed to burn hash. Burned hash is ", old_hash);
172+
return TEE_ERROR_GENERIC;
173+
}
174+
#endif
175+
176+
/* TODO Pass RSA key length as an argument */
177+
status = SECURE_BOOT_STATUS_RSA4096;
178+
#if !defined(SECURE_BOOT_ENABLE_DANGEROUS)
179+
IMSG("Skip writing RSA4096 enable bit: %x", status);
180+
#else
181+
IMSG("Writing RSA4096 enable bit: %x", status);
182+
res = tee_otp_write_secure(&status,
183+
SECURE_BOOT_STATUS_INDEX,
184+
SECURE_BOOT_STATUS_LENGTH);
185+
if (res)
186+
return res;
187+
188+
res = tee_otp_read_secure(&status,
189+
SECURE_BOOT_STATUS_INDEX,
190+
SECURE_BOOT_STATUS_LENGTH);
191+
if (res)
192+
return res;
193+
#endif
194+
195+
return TEE_SUCCESS;
196+
}
197+
198+
static TEE_Result lockdown_device(uint32_t param_types,
199+
TEE_Param params[TEE_NUM_PARAMS] __unused)
200+
{
201+
TEE_Result res = TEE_ERROR_GENERIC;
202+
uint32_t status;
203+
uint32_t hash[RSA_HASH_LENGTH];
204+
205+
if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_NONE,
206+
TEE_PARAM_TYPE_NONE,
207+
TEE_PARAM_TYPE_NONE,
208+
TEE_PARAM_TYPE_NONE))
209+
return TEE_ERROR_BAD_PARAMETERS;
210+
211+
res = tee_otp_read_secure(&status,
212+
SECURE_BOOT_STATUS_INDEX,
213+
SECURE_BOOT_STATUS_LENGTH);
214+
if (res)
215+
return res;
216+
if (secure_boot_status_enabled(status))
217+
return TEE_SUCCESS;
218+
219+
res = tee_otp_read_secure(hash, RSA_HASH_INDEX, RSA_HASH_LENGTH);
220+
if (res)
221+
return res;
222+
if (hash_cmp(hash, NULL, ARRAY_SIZE(hash) < ARRAY_SIZE(hash))) {
223+
print_hash("Hash not burned yet. Burned hash is ", hash);
224+
return TEE_ERROR_GENERIC;
225+
}
226+
227+
status = SECURE_BOOT_STATUS_ENABLE;
228+
#if !defined(SECURE_BOOT_ENABLE_DANGEROUS)
229+
IMSG("Skip writing secure boot enable bit: %x", status);
230+
#else
231+
IMSG("Writing secure boot enable bit: %x", status);
232+
res = tee_otp_write_secure(&status,
233+
SECURE_BOOT_STATUS_INDEX,
234+
SECURE_BOOT_STATUS_LENGTH);
235+
if (res)
236+
return res;
237+
238+
res = tee_otp_read_secure(&status,
239+
SECURE_BOOT_STATUS_INDEX,
240+
SECURE_BOOT_STATUS_LENGTH);
241+
if (res)
242+
return res;
243+
if (secure_boot_status_enabled(status)) {
244+
EMSG("Failed to enable secure boot");
245+
return TEE_ERROR_GENERIC;
246+
}
247+
#endif
248+
249+
return TEE_SUCCESS;
250+
}
251+
252+
static TEE_Result invoke_command(void *sess_ctx __unused, uint32_t cmd_id,
253+
uint32_t param_types,
254+
TEE_Param params[TEE_NUM_PARAMS])
255+
{
256+
TEE_Result res = TEE_ERROR_BAD_PARAMETERS;
257+
TEE_Result res2 = TEE_ERROR_GENERIC;
258+
TEE_Param bparams[TEE_NUM_PARAMS] = { };
259+
TEE_Param *eparams = NULL;
260+
261+
res = to_bounce_params(param_types, params, bparams, &eparams);
262+
if (res)
263+
return res;
264+
265+
switch (cmd_id) {
266+
case PTA_RK_SECURE_BOOT_GET_INFO:
267+
res = get_info(param_types, eparams);
268+
break;
269+
case PTA_RK_SECURE_BOOT_BURN_HASH:
270+
res = burn_hash(param_types, eparams);
271+
break;
272+
case PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE:
273+
res = lockdown_device(param_types, eparams);
274+
break;
275+
default:
276+
break;
277+
}
278+
279+
res2 = from_bounce_params(param_types, params, bparams, eparams);
280+
if (!res && res2)
281+
res = res2;
282+
283+
return res;
284+
}
285+
286+
pseudo_ta_register(.uuid = PTA_RK_SECURE_BOOT_UUID,
287+
.name = PTA_NAME,
288+
.flags = PTA_DEFAULT_FLAGS,
289+
.invoke_command_entry_point = invoke_command);

core/pta/rockchip/sub.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# TODO Add actual config item
2+
srcs-y += rk_secure_boot.c

core/pta/sub.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ subdirs-y += bcm
1919
subdirs-y += stm32mp
2020
subdirs-y += imx
2121
subdirs-y += k3
22+
subdirs-y += rockchip
2223
subdirs-y += veraison_attestation
2324

2425
ifeq ($(CFG_REMOTEPROC_PTA),y)
@@ -28,4 +29,4 @@ depends-rproc_pub_key = $(RPROC_SIGN_KEY) scripts/pem_to_pub_c.py
2829
recipe-rproc_pub_key = $(PYTHON3) scripts/pem_to_pub_c.py \
2930
--prefix rproc_pub_key --key $(RPROC_SIGN_KEY) \
3031
--out $(sub-dir-out)/rproc_pub_key.c
31-
endif
32+
endif
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/* SPDX-License-Identifier: BSD-2-Clause */
2+
/*
3+
* Copyright (C) 2025, Pengutronix, Michael Tretter <[email protected]>
4+
*/
5+
6+
#ifndef __PTA_RK_SECURE_BOOT_H
7+
#define __PTA_RK_SECURE_BOOT_H
8+
9+
#include <tee_api_types.h>
10+
11+
#define PTA_RK_SECURE_BOOT_UUID { 0x5cfa57f6, 0x1a4c, 0x407f, \
12+
{ 0x94, 0xa7, 0xa5, 0x6c, 0x8c, 0x47, 0x01, 0x9d } }
13+
14+
struct pta_rk_secure_boot_hash {
15+
/* sha256 has 256 bit */
16+
uint8_t value[32];
17+
};
18+
19+
/* TODO Add a version field for this struct? */
20+
struct pta_rk_secure_boot_info {
21+
uint8_t enabled;
22+
uint8_t simulation;
23+
struct pta_rk_secure_boot_hash hash;
24+
};
25+
26+
/*
27+
* PTA_RK_SECURE_BOOT_GET_INFO - Get secure boot status info
28+
*
29+
* [out] memref[0] buffer memory reference containing a struct pta_rk_secure_boot_info
30+
*/
31+
#define PTA_RK_SECURE_BOOT_GET_INFO 0x0
32+
33+
/*
34+
* PTA_RK_SECURE_BOOT_BURN_HASH - Burn the RSA key hash to fuses
35+
*
36+
* [in] memref[0] buffer memory reference containing a struct pta_rk_secure_boot_hash
37+
*/
38+
#define PTA_RK_SECURE_BOOT_BURN_HASH 0x1
39+
40+
/*
41+
* PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE - Lockdown the device with secure boot
42+
*/
43+
#define PTA_RK_SECURE_BOOT_LOCKDOWN_DEVICE 0x2
44+
45+
#endif /* __PTA_ROCKCHIP_OTP_H */

0 commit comments

Comments
 (0)