xref: /optee_os/core/drivers/stm32mp15_huk.c (revision 7e203c671c2209805fae80e370f6b2aa706670b4)
1*7e203c67SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
2*7e203c67SJorge Ramirez-Ortiz /*
3*7e203c67SJorge Ramirez-Ortiz  * Copyright (c) 2022, Linaro Limited
4*7e203c67SJorge Ramirez-Ortiz  * Copyright (c) 2022, Foundries.io Limited
5*7e203c67SJorge Ramirez-Ortiz  */
6*7e203c67SJorge Ramirez-Ortiz 
7*7e203c67SJorge Ramirez-Ortiz #include <assert.h>
8*7e203c67SJorge Ramirez-Ortiz #include <config.h>
9*7e203c67SJorge Ramirez-Ortiz #include <crypto/crypto.h>
10*7e203c67SJorge Ramirez-Ortiz #include <drivers/stm32_bsec.h>
11*7e203c67SJorge Ramirez-Ortiz #include <kernel/tee_common_otp.h>
12*7e203c67SJorge Ramirez-Ortiz #include <mempool.h>
13*7e203c67SJorge Ramirez-Ortiz #include <platform_config.h>
14*7e203c67SJorge Ramirez-Ortiz #include <stm32_util.h>
15*7e203c67SJorge Ramirez-Ortiz #include <string.h>
16*7e203c67SJorge Ramirez-Ortiz #include <string_ext.h>
17*7e203c67SJorge Ramirez-Ortiz 
18*7e203c67SJorge Ramirez-Ortiz static bool stm32mp15_huk_init;
19*7e203c67SJorge Ramirez-Ortiz 
20*7e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_uid(uint32_t *uid)
21*7e203c67SJorge Ramirez-Ortiz {
22*7e203c67SJorge Ramirez-Ortiz 	uint32_t *q = uid;
23*7e203c67SJorge Ramirez-Ortiz 
24*7e203c67SJorge Ramirez-Ortiz 	/*
25*7e203c67SJorge Ramirez-Ortiz 	 * Shadow memory for UID words might not be locked: to guarante that
26*7e203c67SJorge Ramirez-Ortiz 	 * the final values are read we must lock them.
27*7e203c67SJorge Ramirez-Ortiz 	 */
28*7e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID0_OTP) ||
29*7e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID0_OTP))
30*7e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
31*7e203c67SJorge Ramirez-Ortiz 
32*7e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID1_OTP) ||
33*7e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID1_OTP))
34*7e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
35*7e203c67SJorge Ramirez-Ortiz 
36*7e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID2_OTP) ||
37*7e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID2_OTP))
38*7e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
39*7e203c67SJorge Ramirez-Ortiz 
40*7e203c67SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
41*7e203c67SJorge Ramirez-Ortiz }
42*7e203c67SJorge Ramirez-Ortiz 
43*7e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_otp(uint32_t otp, uint32_t *key, bool *locked)
44*7e203c67SJorge Ramirez-Ortiz {
45*7e203c67SJorge Ramirez-Ortiz 	bool tmp = true;
46*7e203c67SJorge Ramirez-Ortiz 
47*7e203c67SJorge Ramirez-Ortiz 	if (!stm32mp_is_closed_device()) {
48*7e203c67SJorge Ramirez-Ortiz 		/*
49*7e203c67SJorge Ramirez-Ortiz 		 * When the device is not closed, the shadow memory for these
50*7e203c67SJorge Ramirez-Ortiz 		 * words might not be locked: check and report them
51*7e203c67SJorge Ramirez-Ortiz 		 */
52*7e203c67SJorge Ramirez-Ortiz 		if (stm32_bsec_read_permanent_lock(otp, &tmp))
53*7e203c67SJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
54*7e203c67SJorge Ramirez-Ortiz 
55*7e203c67SJorge Ramirez-Ortiz 		if (tmp && stm32_bsec_read_sw_lock(otp, &tmp))
56*7e203c67SJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
57*7e203c67SJorge Ramirez-Ortiz 	}
58*7e203c67SJorge Ramirez-Ortiz 
59*7e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_shadow_read_otp(key, otp))
60*7e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
61*7e203c67SJorge Ramirez-Ortiz 
62*7e203c67SJorge Ramirez-Ortiz 	*locked = *locked && tmp;
63*7e203c67SJorge Ramirez-Ortiz 
64*7e203c67SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
65*7e203c67SJorge Ramirez-Ortiz }
66*7e203c67SJorge Ramirez-Ortiz 
67*7e203c67SJorge Ramirez-Ortiz /*
68*7e203c67SJorge Ramirez-Ortiz  *  AES-GCM: nonce must be unique per message and key.
69*7e203c67SJorge Ramirez-Ortiz  *
70*7e203c67SJorge Ramirez-Ortiz  *  This function always uses the same key - once its locked - with the same
71*7e203c67SJorge Ramirez-Ortiz  *  unique message hence the nonce can be any constant.
72*7e203c67SJorge Ramirez-Ortiz  */
73*7e203c67SJorge Ramirez-Ortiz static TEE_Result aes_gcm_encrypt_uid(uint8_t *key, size_t key_len,
74*7e203c67SJorge Ramirez-Ortiz 				      uint8_t *out, size_t *out_len)
75*7e203c67SJorge Ramirez-Ortiz {
76*7e203c67SJorge Ramirez-Ortiz 	TEE_Result ret = TEE_ERROR_GENERIC;
77*7e203c67SJorge Ramirez-Ortiz 	const uint8_t nonce[12] = { 0x55 };
78*7e203c67SJorge Ramirez-Ortiz 	uint32_t uid[4] = { 0 };
79*7e203c67SJorge Ramirez-Ortiz 	uint8_t tag[16] = { 0 };
80*7e203c67SJorge Ramirez-Ortiz 	size_t nonce_len = sizeof(nonce);
81*7e203c67SJorge Ramirez-Ortiz 	size_t tag_len = sizeof(tag);
82*7e203c67SJorge Ramirez-Ortiz 	size_t uid_len = sizeof(uid);
83*7e203c67SJorge Ramirez-Ortiz 	void *ctx = NULL;
84*7e203c67SJorge Ramirez-Ortiz 
85*7e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_uid(uid);
86*7e203c67SJorge Ramirez-Ortiz 	if (ret)
87*7e203c67SJorge Ramirez-Ortiz 		goto out;
88*7e203c67SJorge Ramirez-Ortiz 
89*7e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_alloc_ctx(&ctx, TEE_ALG_AES_GCM);
90*7e203c67SJorge Ramirez-Ortiz 	if (ret)
91*7e203c67SJorge Ramirez-Ortiz 		goto out;
92*7e203c67SJorge Ramirez-Ortiz 
93*7e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_init(ctx, TEE_MODE_ENCRYPT, key, key_len, nonce,
94*7e203c67SJorge Ramirez-Ortiz 				  nonce_len, TEE_AES_BLOCK_SIZE, 0, uid_len);
95*7e203c67SJorge Ramirez-Ortiz 	if (ret)
96*7e203c67SJorge Ramirez-Ortiz 		goto out_free_ctx;
97*7e203c67SJorge Ramirez-Ortiz 
98*7e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_enc_final(ctx, (uint8_t *)uid, sizeof(uid),
99*7e203c67SJorge Ramirez-Ortiz 				       out, out_len, tag, &tag_len);
100*7e203c67SJorge Ramirez-Ortiz 	if (ret)
101*7e203c67SJorge Ramirez-Ortiz 		goto out_free_ctx;
102*7e203c67SJorge Ramirez-Ortiz 
103*7e203c67SJorge Ramirez-Ortiz 	crypto_authenc_final(ctx);
104*7e203c67SJorge Ramirez-Ortiz out_free_ctx:
105*7e203c67SJorge Ramirez-Ortiz 	crypto_authenc_free_ctx(ctx);
106*7e203c67SJorge Ramirez-Ortiz out:
107*7e203c67SJorge Ramirez-Ortiz 	if (ret)
108*7e203c67SJorge Ramirez-Ortiz 		memzero_explicit(out, *out_len);
109*7e203c67SJorge Ramirez-Ortiz 
110*7e203c67SJorge Ramirez-Ortiz 	return ret;
111*7e203c67SJorge Ramirez-Ortiz }
112*7e203c67SJorge Ramirez-Ortiz 
113*7e203c67SJorge Ramirez-Ortiz TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
114*7e203c67SJorge Ramirez-Ortiz {
115*7e203c67SJorge Ramirez-Ortiz 	uint32_t otp_key[4] = { 0 };
116*7e203c67SJorge Ramirez-Ortiz 	size_t len = sizeof(otp_key);
117*7e203c67SJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
118*7e203c67SJorge Ramirez-Ortiz 	uint32_t *key = otp_key;
119*7e203c67SJorge Ramirez-Ortiz 	bool lock = true;
120*7e203c67SJorge Ramirez-Ortiz 
121*7e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_0 < STM32MP1_OTP_MAX_ID);
122*7e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_1 < STM32MP1_OTP_MAX_ID);
123*7e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_2 < STM32MP1_OTP_MAX_ID);
124*7e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_3 < STM32MP1_OTP_MAX_ID);
125*7e203c67SJorge Ramirez-Ortiz 
126*7e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_0, key++, &lock);
127*7e203c67SJorge Ramirez-Ortiz 	if (ret)
128*7e203c67SJorge Ramirez-Ortiz 		goto out;
129*7e203c67SJorge Ramirez-Ortiz 
130*7e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_1, key++, &lock);
131*7e203c67SJorge Ramirez-Ortiz 	if (ret)
132*7e203c67SJorge Ramirez-Ortiz 		goto out;
133*7e203c67SJorge Ramirez-Ortiz 
134*7e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_2, key++, &lock);
135*7e203c67SJorge Ramirez-Ortiz 	if (ret)
136*7e203c67SJorge Ramirez-Ortiz 		goto out;
137*7e203c67SJorge Ramirez-Ortiz 
138*7e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_3, key++, &lock);
139*7e203c67SJorge Ramirez-Ortiz 	if (ret)
140*7e203c67SJorge Ramirez-Ortiz 		goto out;
141*7e203c67SJorge Ramirez-Ortiz 
142*7e203c67SJorge Ramirez-Ortiz 	ret = aes_gcm_encrypt_uid((uint8_t *)otp_key, len, hwkey->data, &len);
143*7e203c67SJorge Ramirez-Ortiz 
144*7e203c67SJorge Ramirez-Ortiz 	if (len != HW_UNIQUE_KEY_LENGTH)
145*7e203c67SJorge Ramirez-Ortiz 		ret = TEE_ERROR_GENERIC;
146*7e203c67SJorge Ramirez-Ortiz out:
147*7e203c67SJorge Ramirez-Ortiz 	memzero_explicit(otp_key, HW_UNIQUE_KEY_LENGTH);
148*7e203c67SJorge Ramirez-Ortiz 
149*7e203c67SJorge Ramirez-Ortiz 	if (!ret && !stm32mp15_huk_init) {
150*7e203c67SJorge Ramirez-Ortiz 		stm32mp15_huk_init = true;
151*7e203c67SJorge Ramirez-Ortiz 		IMSG("HUK %slocked", lock ? "" : "un");
152*7e203c67SJorge Ramirez-Ortiz 		DHEXDUMP(hwkey->data, HW_UNIQUE_KEY_LENGTH);
153*7e203c67SJorge Ramirez-Ortiz 	}
154*7e203c67SJorge Ramirez-Ortiz 
155*7e203c67SJorge Ramirez-Ortiz 	return ret;
156*7e203c67SJorge Ramirez-Ortiz }
157*7e203c67SJorge Ramirez-Ortiz 
158